framer-material
Version:
Google material design properties for your Framer layers.
440 lines (407 loc) • 9.2 kB
text/coffeescript
# Material properties
defaults =
elevation: 0
rippleColor: "rgba(0,0,0,0.05)"
surfaceReaction: false
# Material Design colors
colors =
Red:
"50": "#ffebee"
"100": "#ffcdd2"
"200": "#ef9a9a"
"300": "#e57373"
"400": "#ef5350"
"500": "#f44336"
"600": "#e53935"
"700": "#d32f2f"
"800": "#c62828"
"900": "#b71c1c"
"A100": "#ff8a80"
"A200": "#ff5252"
"A400": "#ff1744"
"A700": "#d50000"
Pink:
"50": "#fce4ec"
"100": "#f8bbd0"
"200": "#f48fb1"
"300": "#f06292"
"400": "#ec407a"
"500": "#e91e63"
"600": "#d81b60"
"700": "#c2185b"
"800": "#ad1457"
"900": "#880e4f"
"A100": "#ff80ab"
"A200": "#ff4081"
"A400": "#f50057"
"A700": "#c51162"
Purple:
"50": "#f3e5f5"
"100": "#e1bee7"
"200": "#ce93d8"
"300": "#ba68c8"
"400": "#ab47bc"
"500": "#9c27b0"
"600": "#8e24aa"
"700": "#7b1fa2"
"800": "#6a1b9a"
"900": "#4a148c"
"A100": "#ea80fc"
"A200": "#e040fb"
"A400": "#d500f9"
"A700": "#aa00ff"
DeepPurple:
"50": "#ede7f6"
"100": "#d1c4e9"
"200": "#b39ddb"
"300": "#9575cd"
"400": "#7e57c2"
"500": "#673ab7"
"600": "#5e35b1"
"700": "#512da8"
"800": "#4527a0"
"900": "#311b92"
"A100": "#b388ff"
"A200": "#7c4dff"
"A400": "#651fff"
"A700": "#6200ea"
Indigo:
"50": "#e8eaf6"
"100": "#c5cae9"
"200": "#9fa8da"
"300": "#7986cb"
"400": "#5c6bc0"
"500": "#3f51b5"
"600": "#3949ab"
"700": "#303f9f"
"800": "#283593"
"900": "#1a237e"
"A100": "#8c9eff"
"A200": "#536dfe"
"A400": "#3d5afe"
"A700": "#304ffe"
Blue:
"50": "#e3f2fd"
"100": "#bbdefb"
"200": "#90caf9"
"300": "#64b5f6"
"400": "#42a5f5"
"500": "#2196f3"
"600": "#1e88e5"
"700": "#1976d2"
"800": "#1565c0"
"900": "#0d47a1"
"A100": "#82b1ff"
"A200": "#448aff"
"A400": "#2979ff"
"A700": "#2962ff"
LightBlue:
"50": "#e1f5fe"
"100": "#b3e5fc"
"200": "#81d4fa"
"300": "#4fc3f7"
"400": "#29b6f6"
"500": "#03a9f4"
"600": "#039be5"
"700": "#0288d1"
"800": "#0277bd"
"900": "#01579b"
"A100": "#80d8ff"
"A200": "#40c4ff"
"A400": "#00b0ff"
"A700": "#0091ea"
Cyan:
"50": "#e0f7fa"
"100": "#b2ebf2"
"200": "#80deea"
"300": "#4dd0e1"
"400": "#26c6da"
"500": "#00bcd4"
"600": "#00acc1"
"700": "#0097a7"
"800": "#00838f"
"900": "#006064"
"A100": "#84ffff"
"A200": "#18ffff"
"A400": "#00e5ff"
"A700": "#00b8d4"
Teal:
"50": "#e0f2f1"
"100": "#b2dfdb"
"200": "#80cbc4"
"300": "#4db6ac"
"400": "#26a69a"
"500": "#009688"
"600": "#00897b"
"700": "#00796b"
"800": "#00695c"
"900": "#004d40"
"A100": "#a7ffeb"
"A200": "#64ffda"
"A400": "#1de9b6"
"A700": "#00bfa5"
Green:
"50": "#e8f5e9"
"100": "#c8e6c9"
"200": "#a5d6a7"
"300": "#81c784"
"400": "#66bb6a"
"500": "#4caf50"
"600": "#43a047"
"700": "#388e3c"
"800": "#2e7d32"
"900": "#1b5e20"
"A100": "#b9f6ca"
"A200": "#69f0ae"
"A400": "#00e676"
"A700": "#00c853"
LightGreen:
"50": "#f1f8e9"
"100": "#dcedc8"
"200": "#c5e1a5"
"300": "#aed581"
"400": "#9ccc65"
"500": "#8bc34a"
"600": "#7cb342"
"700": "#689f38"
"800": "#558b2f"
"900": "#33691e"
"A100": "#ccff90"
"A200": "#b2ff59"
"A400": "#76ff03"
"A700": "#64dd17"
Lime:
"50": "#f9fbe7"
"100": "#f0f4c3"
"200": "#e6ee9c"
"300": "#dce775"
"400": "#d4e157"
"500": "#cddc39"
"600": "#c0ca33"
"700": "#afb42b"
"800": "#9e9d24"
"900": "#827717"
"A100": "#f4ff81"
"A200": "#eeff41"
"A400": "#c6ff00"
"A700": "#aeea00"
Yellow:
"50": "#fffde7"
"100": "#fff9c4"
"200": "#fff59d"
"300": "#fff176"
"400": "#ffee58"
"500": "#ffeb3b"
"600": "#fdd835"
"700": "#fbc02d"
"800": "#f9a825"
"900": "#f57f17"
"A100": "#ffff8d"
"A200": "#ffff00"
"A400": "#ffea00"
"A700": "#ffd600"
Amber:
"50": "#fff8e1"
"100": "#ffecb3"
"200": "#ffe082"
"300": "#ffd54f"
"400": "#ffca28"
"500": "#ffc107"
"600": "#ffb300"
"700": "#ffa000"
"800": "#ff8f00"
"900": "#ff6f00"
"A100": "#ffe57f"
"A200": "#ffd740"
"A400": "#ffc400"
"A700": "#ffab00"
Orange:
"50": "#fff3e0"
"100": "#ffe0b2"
"200": "#ffcc80"
"300": "#ffb74d"
"400": "#ffa726"
"500": "#ff9800"
"600": "#fb8c00"
"700": "#f57c00"
"800": "#ef6c00"
"900": "#e65100"
"A100": "#ffd180"
"A200": "#ffab40"
"A400": "#ff9100"
"A700": "#ff6d00"
DeepOrange:
"50": "#fbe9e7"
"100": "#ffccbc"
"200": "#ffab91"
"300": "#ff8a65"
"400": "#ff7043"
"500": "#ff5722"
"600": "#f4511e"
"700": "#e64a19"
"800": "#d84315"
"900": "#bf360c"
"A100": "#ff9e80"
"A200": "#ff6e40"
"A400": "#ff3d00"
"A700": "#dd2c00"
Brown:
"50": "#efebe9"
"100": "#d7ccc8"
"200": "#bcaaa4"
"300": "#a1887f"
"400": "#8d6e63"
"500": "#795548"
"600": "#6d4c41"
"700": "#5d4037"
"800": "#4e342e"
"900": "#3e2723"
Grey:
"50": "#fafafa"
"100": "#f5f5f5"
"200": "#eeeeee"
"300": "#e0e0e0"
"400": "#bdbdbd"
"500": "#9e9e9e"
"600": "#757575"
"700": "#616161"
"800": "#424242"
"900": "#212121"
BlueGrey:
"50": "#eceff1"
"100": "#cfd8dc"
"200": "#b0bec5"
"300": "#90a4ae"
"400": "#78909c"
"500": "#607d8b"
"600": "#546e7a"
"700": "#455a64"
"800": "#37474f"
"900": "#263238"
class Material extends Layer
constructor: (opts={}) ->
for key, value of defaults
opts[key] ?= value
super opts
showRipple: (args...) ->
[x, y] = if args.length is 0 then [@width/2, @height/2]
else [args[0].offsetX or args[0], args[0].offsetY or args[1]]
unless @_ink
@_inkMask = new Layer
name: "inkMask"
superLayer: @
width: @width
height: @height
borderRadius: @borderRadius
backgroundColor: "transparent"
@_ink = new Layer
name: "ink"
superLayer: @_inkMask
borderRadius: "50%"
force2d: true
scale: 0
backgroundColor: @rippleColor
deltaX = Math.max x, @width - x
deltaY = Math.max y, @height - y
radius = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2))
@_ink.scale = 0
@_ink.opacity = 1
@_ink.bringToFront()
@_ink.width = @_ink.height = radius * 2
@_ink.midX = x
@_ink.midY = y
@_ink.animateStop()
@_ink.animate
properties: scale: 1
curve: "cubic-bezier(0, 0, 0.2, 1)"
time: 1
hideRipple: ->
@_ink.animate
properties: opacity: 0
curve: "cubic-bezier(0.4, 0, 0.2, 1)"
time: 0.8
@define "surfaceReaction",
get: -> @_surfaceReaction
set: (value) ->
@_surfaceReaction = if value then true else false
if value
@on Events.TouchStart, @showRipple
@on Events.TouchEnd, @hideRipple
else
@off Events.TouchStart, @showRipple
@off Events.TouchEnd, @hideRipple
@define "rippleColor",
get: -> @_rippleColor
set: (value) ->
@_rippleColor = value
@_ink.backgroundColor = value if @_ink
@define "elevation",
get: -> @_elevation
set: (value) ->
if typeof value isnt "number"
throw Error "Elevation must be a number."
if value > 24 or value < 0
throw Error "Elevation must be between 0–24. See https://www.google.com/design/spec/what-is-material/elevation-shadows.html#elevation-shadows-elevation-android-"
@_elevation = value
return if value is 0
# create shadows if they don't exist
unless @_shadow1
# make sure we don't clip our shadows
@clip = false
# TODO: Fix upstream.
# This is a hack because `Layer#_subLayers`
# is set after construction.
@_subLayers = []
@_shadow1 = new Layer
name: "shadow1"
superLayer: @
width: @width
height: @height
borderRadius: @borderRadius
backgroundColor: null
@_shadow2 = @_shadow1.copy()
@_shadow2.name = "shadow2"
@_shadow2.superLayer = @
# resize shadows and ink mask with parent material
@on "change:width", (value) ->
@_shadow1.width = @_shadow2.width = value
@_inkMask?.width = value
@on "change:height", (value) ->
@_shadow1.height = @_shadow2.height = value
@_inkMask?.height = value
# set elevation (shadow styles)
@shadowSpread = 1
@shadowBlur = value
@shadowColor = "rgba(0,0,0,0.04)"
@_shadow1.shadowY = value
@_shadow1.shadowBlur = value
@_shadow1.shadowColor = "rgba(0,0,0,0.24)"
@_shadow2.shadowY = value / 2
@_shadow2.shadowBlur = value / 2
@_shadow2.shadowColor = """rgba(
0,0,0,
#{Utils.modulate value, [1, 24], [0, 0.24], true }
)"""
# Material color palette
# e.g. Material.Color.Red[50]
@Color: colors
# Add `Material` properties to other classes
@mixin: (ClassName) ->
# TODO: consider if this even makes sense
# to mixin to other classes.
# This is a temporary fix for `MobileScrollFixLayer` on mobile.
sanitizedClassName =
if /layer/i.test ClassName.name then "Layer" else ClassName.name
capitalizeFirstLetter = (string) ->
string.charAt(0).toUpperCase() + string.slice(1)
for key, value of defaults
# Set defaults
Framer.Defaults[sanitizedClassName][key] = value
# Add getter/setter properties
ClassName.define key,
configurable: true
get: @::["get#{capitalizeFirstLetter key}"]
set: @::["set#{capitalizeFirstLetter key}"]
ClassName::showRipple = @::showRipple
ClassName::hideRipple = @::hideRipple
module?.exports = Material