UNPKG

framer-label

Version:

Label module with multi-line truncation support for Framer.js.

147 lines (128 loc) 3.68 kB
aliasProperty = (property, alias) -> get: -> @[property] set: (value) -> @[property] = value @emit "change:#{alias}", value class Label extends Layer constructor: (opts={}) -> opts.text ?= "Label Text" opts.lineHeight ?= "normal" opts.backgroundColor ?= "transparent" opts.color ?= "black" @_constrained = true if opts.maxWidth super _.extend opts, # add multi-line truncation styles style: display: '-webkit-box' webkitBoxOrient: 'vertical' overflow: 'hidden' textOverflow: 'ellipsis' webkitLineClamp: opts.lineNumber # size layer @update() update: -> style = lineHeight: @style.lineHeight textTransform: @style.textTransform letterSpacing: @style.letterSpacing fontFamily: @style.fontFamily fontStyle: @style.fontStyle fontVariant: @style.fontVariant fontSize: @style.fontSize fontWeight: @style.fontWeight # create and style a temporary element tempEl = document.createElement "div" tempEl.innerHTML = @text tempEl.style.display = "inline-block" tempEl.style.visibility = "hidden" tempEl.style.whiteSpace = "nowrap" _.extend tempEl.style, style document.body.appendChild tempEl # get intrinsic width/height size = tempEl.getBoundingClientRect() # compute the max height if we are constraining maxHeight = => tempEl.style.whiteSpace = "normal" tempEl.style.width = "#{@maxWidth}px" intrinsicHeight = tempEl.getBoundingClientRect().height # If `lineCount` is falsey, then make intrinsic height if !@lineCount intrinsicHeight else Math.min size.height * @lineCount, intrinsicHeight # set width/height @width = if @_constrained then @maxWidth else size.width @height = if @_constrained then maxHeight() else size.height # remove temporary element tempEl.remove() @define "maxWidth", get: -> @_maxWidth set: (value) -> @_maxWidth = value @_constrained = if value then true else false @update() @emit "change:maxWidth", value @define "text", get: -> @_text?.replace " \xA0", "" set: (value) -> @_text = value # append a non-breaking space to correct # truncation for the last word in the string @html = if @_constrained then "#{value} \xA0" else value @update() @emit "change:text", value @define "lineCount", get: -> @_lineCount set: (value) -> @_lineCount = value @style.webkitLineClamp = if value then value else "" @update() @emit "change:lineCount", value # set aliases for `lineCount` for alias in ["numberOfLines", "lineNumber", "lineClamp"] Label.define alias, aliasProperty "lineCount", alias # create getters/setters for all typography-related style props # thant aren't already `Layer` properties _.keys document.createElement("div").style .filter (prop) -> /^font|text|letter|line/.test(prop) and !Layer.prototype.hasOwnProperty(prop) .forEach (prop) -> Label.define prop, get: -> p = @style[prop].replace "px", "" if isNaN p then p else +p set: (value) -> # add 'px' suffix when appropriate @style[prop] = if typeof value is "number" and unitlessNumbers.indexOf(prop) is -1 then "#{value}px" else value @emit "change:#{prop}", value # CSS properties which accept numbers but are not in units of "px". # Taken from facebook/react: http://git.io/vt1XW unitlessNumbers = [ "boxFlex" "boxFlexGroup" "columnCount" "flex" "flexGrow" "flexPositive" "flexShrink" "flexNegative" "fontWeight" "lineClamp" "lineHeight" "opacity" "order" "orphans" "tabSize" "widows" "zIndex" "zoom" # SVG-related properties "fillOpacity" "strokeDashoffset" "strokeOpacity" "strokeWidth" ] module?.exports = Label