react-script
Version:
Elegant DSL for React
105 lines (85 loc) • 2.83 kB
text/coffeescript
React = @React ? require "react"
is_plainish_object = (o)->
o? and typeof o is "object" and not (
o instanceof Array or # (e.g. [])
React.isValidElement o # (e.g. E())
)
add = (from, {to})->
if from instanceof Array
add thing, {to} for thing in from
return yes
else if is_plainish_object from
for k, v of from when v
to.push hyphenate k
return yes
else if from?
to.push from
return no
hyphenate = (v)->
"#{v}"
.replace /_/g, "-"
.replace /([a-z])([A-Z])/g, (m, az, AZ)->
"#{az}-#{AZ.toLowerCase()}"
E = (element_type, args...)->
element_type ?= ""
if is_plainish_object args[0]
[ ] = args
else
[ ] = args
attr_args = null
switch typeof element_type
when "string"
selector = element_type
element_type = "div"
partial_selector = selector.replace /^[a-z][a-z0-9\-_]*/i, (match)->
element_type = match
""
final_attributes = {}
class_names = []
addAttr = (attr_k, attr_v, aria)->
final_attributes[attr_k] = attr_v unless attr_v is false and not aria
for attr_k, attr_v of attr_args
if attr_k in ["class", "className", "classes", "classNames", "classList"]
add attr_v, to: class_names
else if attr_k is "data"
for data_k, data_v of attr_v
addAttr "data-#{hyphenate data_k}", data_v
else if attr_k is "aria"
for aria_k, aria_v of attr_v
addAttr "aria-#{hyphenate aria_k}", aria_v, yes
else if attr_k.match /^data/
addAttr (hyphenate attr_k), attr_v
else if attr_k.match /^aria/
addAttr (hyphenate attr_k), attr_v, yes
else
addAttr attr_k, attr_v
if partial_selector
unhandled = partial_selector
.replace /\.([a-z][a-z0-9\-_]*)/gi, (m, className)->
class_names.push className
""
.replace /
final_attributes.id = id
""
if unhandled
throw new Error "Unhandled selector fragment '#{unhandled}' in selector: '#{selector}'"
final_attributes.className = class_names.join " " if class_names.length
when "function"
final_attributes = attr_args
else
throw new Error "Invalid first argument to ReactScript: #{element_type}"
final_child_args = []
was_dynamic = no
for child_arg in child_args
will_have_been_dynamic = add child_arg, to: final_child_args
was_dynamic or= will_have_been_dynamic
if was_dynamic
React.createElement element_type, final_attributes, final_child_args
else
React.createElement element_type, final_attributes, final_child_args...
if module?.exports?
module.exports = E
else
@ReactScript = E