Framer employs lowerCamelCase
for almost everything: functions, variables properties, etc. Classes, however, use TitleCase
. Events are a bit of a special case, as explained under Events.
Users are accustomed to instantiating objects with constructor syntax, so try to follow this approach in building your own classes.
myCustomClassInstance = new CustomClass
# simple instance properties
property: value0
anotherProperty: value1
# arrays in properties
propertyArray: [
value0,
value1,
value2, # trailing comma for consistency
]
actionArray: [
-> action0(),
-> action1(),
]
# objects in properties
propertyObject:
subObject0:
key0: value0
subObject1:
key1: value1
Instance properties should be written as adjectives or nouns. myClass.hidden
or myClass.titleFontWeight
.
class MyClass extends Layer
constructor: () ->
@hidden = false
@titleFontWeight = 400
Represent functions as meaningful verb phrases: updateLayout()
.
For purposes of memory optimization, try to design class functions as prototype functions so they are not recreated for each instance.
Prototype functions are included in the class
definition but not in the constructor, and use a colon in place of an equals sign.
class MyLayer extends Layer
constructor: () ->
@performPropertyFunction = () =>
print "property" # try to avoid this type
performPrototypeFunction: () ->
print "prototype"
Utility functions you intend to expose to the user outside of a class will tend to live on the exports
object, but should follow the same capitalization and wording guidelines.
exports.performFunction = () ->
If your function takes more than two parameters, or if the user is likely to confuse their order, consider using named parameters.
makeApple: ({appleColor, leafColor, size} = {}) ->
appleColor ?= "red"
leafColor ?= "green"
size ?= 10
makeApple(appleColor: "green", leafColor: "yellow", size: 20)
When an operation begins or ends, it can be helpful to emit an event so the user can chain other operations to it. Generally, only layers emit events. The emit
statement is very simple:
myLayer.emit "myevent"
Event names are lowercase
, but TitleCase
when referenced as properties of the global Events
variable (scroll.on Events.ScrollStart
). Event shortcuts (scroll.onScrollStart
) use lowerCamelCase
.
If you want to support all these methods, you might extend Layer
and Events
like so:
myLayer.emit "myevent"
Events.MyEvent = "myevent"
Layer::onMyEvent = (cb) -> @on(Events.MyEvent, cb)
However, this is potentially risky -- you might overwrite an existing Event property. It is sufficient to provide the emitter, in lowercase
.
Events are present tense verbs. Supply start
and end
event points as a pair or don't include start
in the event name.
If your module generates layers, make sure each layer has a name to display in the Framer Studio sidebar. Arrange layers in a sensible hierarchy.
classInstance
└── row
└── contentBlock
└── label
For any layer you'd like the user to be able to reference directly, provide a means to do this via dot syntax.
Within the module this is done by storing layers as properties of their parents.
@.row = rowLayer
rowLayer.contentBlock = contentBlockLayer
contentBlockLayer.label = labelLayer
Readmes can vary, but we try to make sure every module's readme includes the following.
- License, contributing and maintenance shields
- Module name
- Brief description
- Installation (npm, manual, via Framer Modules app)
- Adding it to your project (the
require
statement) - API / How to Use
- Topics within API
- Example project
- Known issues, if applicable
- Footer (Web, Github, Twitter, Medium)
It's also good to include the following in the module's header comment:
- Adding it to your project (the
require
statement) - API / How to Use
- Topics within API
- Known issues, if applicable