aui
Version:
Aui is Semantic-UI + React
142 lines (131 loc) • 6.22 kB
text/coffeescript
{React, jQuery} = window or global
unless React? then throw new Error "Aui: window.React not found."
unless jQuery? then console.warn "Aui: window.jQuery not found, Modules and Semantic-UI will be disabled."
unless jQuery?.site?.settings?.modules? then console.warn 'Aui: No Semantic-UI window.jQuery.site.settings.modules found, Semantic will be disabled.'
# [JSFiddle around with the examples here!](http://javascriptismagic.github.io/aui/)
## Aui.Mixin
# Aui.Mixin is the main wrapper around React Components
# it recursively goes through all it's children,
# finding props that === true or are on the `Aui.modules` list,
# and merges them into the className of each element.
AuiMixin =
## this.$('react ref')
# jQuery wraps a React ref `<div ref="react ref" />` or jQuery selector `this.$('react ref')`.
# This is the intended way to interact with jQuery to supply utility functionality.
# **Warning!** Use this only in `componentDidMount` or event handlers!
# Do NOT use jQuery to re-arange the dom or you will run into Invarient erros in React,
# use React to arange your dom ahead of time as React is expecting.
$: (ref) -> jQuery React.findDOMNode @refs[ref] or ref
componentWillMount: ->
render = @render
@render = ->
element = render?.apply? @, arguments
if React.isValidElement element
Aui.classify element
else
Aui.classify Aui.warning 'Aui.Mixin: Child is not a React.isValidElement', element
# (depricated) `<Aui/>` tag, use Aui.Mixin instead.
Aui = React.createClass
mixins: [AuiMixin]
render: ->
Aui.warning '<Aui/> tag is depricated, use Aui.Mixin instead', @props.children
componentDidMount: ->
console.warn React.findDOMNode @
Aui.Mixin = Aui.AuiMixin = AuiMixin
Aui.Aui = Aui
## Aui.$
# The instance of jQuery Aui is using, if needed.
Aui.$ = jQuery
## Aui.classify(element)
# finds all the props that === true or are on the `Aui.modules` list,
# and merging them with the className prop.
# Use this inside the render function like a React helper function.
# Example: `Aui.classify(<div ui grid><div column>content</div></div>)`
# returns `<div ui grid className="ui grid"><div column className="column">content</div></div>`
Aui.classify = (element, options) ->
options = AuiOptions options
unless React.isValidElement element
element = Aui.warning 'Aui.classify: element is not a React.isValidElement', element
classify = (element) ->
return element unless React.isValidElement element
classNames = {}
modules = null
props = {}
if element.props.className?
for className in "#{element.props.className}".split /\s+/g
classNames[className] = yes
for own key, value of element.props
classNames[key] = yes if value is yes
if (not options.disableModules) and (Array.isArray value) and (key in Aui.modules)
classNames[key] = yes
modules or= {}
modules[key] = value
props[key] = value
props.className = Object.keys(classNames).join ' '
unless props.className.length
delete props.className
element = React.cloneElement element, props, if options.ignoreChildren then element.props.children else React.Children.map element.props.children, classify
if modules
React.createElement Aui.Module, { modules, options }, element
else element
classify element
## Aui.warning('string', element)
# console.warn a warning message inside a ReactElement durring a React Component's render function.
# returns the element wrapped in a warning span.
# Use inside the render function of a React Component
Aui.warning = (message, element) ->
console.warn message, element
React.DOM.span { 'data-warning': message }, element
Aui.settings =
## Aui.settings.disableModules
# disables jQuery based Aui.modules from calling
disableModules: not jQuery?
## Aui.settings.ignoreChildren
# disables recursively calling `Aui.classify` to `props.children`.
ignoreChildren: no
# (internal) AuiOptions defaults options for `Aui.classify`
class AuiOptions
constructor: (options) ->
if options instanceof AuiOptions
return options
unless @ instanceof AuiOptions
return new AuiOptions options
options or= {}
for own key, value of Aui.settings
@[key] = if options[key]? then options[key] else value
## Aui.modules
# A whitelist of jQuery modules.
# `Aui.modules.push('widget')` to configure Aui to support `$.fn.widget`.
# By default this includes `window.jQuery.site.settings.modules` from Semantic-UI.
# When a property is encountered on a ReactElement that matches this whitelist and is an Array,
# the corisponding `window.jQuery.fn[modulename]` will be called with the property's array value.
# This is mostly intended for use with Semantic-UI's javascript,
# but in theory could be used to call any `$.fn` function.
Aui.modules = (jQuery?.site?.settings?.modules or []).slice()
# internal global cache of options passed to module functions.
cache = {}
# (internal) `<Aui.Module/>`
# This class provides support for `Aui.modules` internally and generally is not used directly.
# `<Aui.Module/>` handles calling jQuery.fn[module] calls when used inside a React Component's render.
# `<div ui checkbox={[]}/>` will automatically call `$.fn.checkbox()`, and
# `<form ui form={[{...}]}></form>` will automatically call `$.fn.form({...})`
Aui.Module = React.createClass
render: -> React.Children.only @props.children
componentDidMount: ->
@callModules @props.children.props
componentWillReceiveProps: (props) ->
@callModules props.children.props
callModules: (props) ->
$element = jQuery React.findDOMNode @
@id = $element.attr 'data-reactid'
cache[@id] or= {}
for own module, options of @props.modules
stringifiedOptions = JSON.stringify options
if cache[@id][module] isnt stringifiedOptions
cache[@id][module] = stringifiedOptions
$element[module]? @props.children.props[module]...
return
componentWillUnmount: ->
delete cache[@id]
window?.Aui = Aui
module?.exports = Aui