<script src="http://fb.me/react-js-fiddle-integration.js"></script> <script type="text/jsx">/** @jsx React.DOM */ <component extends="span" name="tickTockClock"> {function(template, props, state, update){ var now = new Date; if (!state.now || +now - +state.now > 1000) { state.now = now; if (props.onchange) props.onchange(state.now); } state.alt = state.now.getSeconds() % 2; var hour = state.now.getHours(); if (hour > 12) hour -= 12; <template style={{background:"blue", color:"white"}}> <span>{hour}</span> <span id="sep" style={{ visibility:state.alt ? 'hidden':'visible' }}>:</span> <span>{state.now.getMinutes()}</span> <span id="sep" style={{ visibility:state.alt ? 'hidden':'visible' }}>:</span> <span>{state.now.getSeconds()}</span> </template> setTimeout(update, 500); }} </component> </script> <script type="text/jsx">/** @jsx React.DOM */ <component extends="form" name="inputToy"> {function(template, props, state, redrawSoon){ if (!state.foo) state.foo = (props.max - props.min) * Math.random() + props.min; var step = (props.max - props.min) / (props.steps || 100); if (state.shouldRound) state.foo = Math.round(state.foo); if (props.value) state.foo = props.value; <Spring input={+state.foo} precision={1000}>{state.springState || (state.springState = {value:state.foo})}</Spring>; if (state.springState.isDirty) redrawSoon(); <template style={props.style}> <label>Round? <input type="checkbox" onChange={state.handlerFor('shouldRound')} /></label> <input type="range" min={props.min} max={props.max} step={step} value={state.foo} onChange={state.handlerFor('foo')} /> <input type="number" min={props.min} max={props.max} step={step} value={state.foo} onChange={state.handlerFor('foo')} /> <input value={state.foo} readOnly size="4" /> <input value={state.springState.value} readOnly size="4" /> <Layer flow left={0} opacity={.25} w='100%' h="1.4em" scaleX={(state.springState.value - props.min) / props.max} origin='left center' /> </template> }} </component> </script> <script type="text/jsx">/** @jsx React.DOM */ <component extends="div" name="demo"> {function(template, props, state, update){ <template data-name="demo"> <tickTockClock onchange={state.setterFor('time')} /> <inputToy min="0" max="59" steps="1" value={state.time && state.time.getSeconds() || 0} /> <inputToy min="0" max="11" steps="33" /> <inputToy min="0" max="1" steps="8" /> <inputToy min="123" max="456" /> </template> }} </component> </script> <script type="text/jsx">/** @jsx React.DOM */ <Root><demo /></Root> </script>
function Root(props, firstChild){ var parentNode = props && (props.parentNode || props.mountNode || (props.parentNodeId && document.getElementById(props.parentNodeId))) || document.body; if (!parentNode) return setTimeout(Root.bind(this, props, firstChild), 1000/60); var children = Array.prototype.slice.call(arguments, 1); if (children.length > 1) firstChild = React.DOM[props && props.nodeName || 'div'](null, children); React.renderComponent( firstChild, parentNode ); } function component(componentProps, render){ var root; var superComponent, superComponentId = componentProps && componentProps["extends"]; superComponent = React.DOM[superComponentId] || window[superComponentId] || React.DOM.div; function template(props){ var children = Array.prototype.slice.call(arguments, 1); return root = superComponent(props, children); } window[componentProps.name] = React.createClass({ getInitialState: ComponentState.getInitialState, _render:render, render: function(){ this._render(template, this.props, this.state, this.state.updateEventually); return root; } }); } var requestAnimationFrame = (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback){return setTimeout(callback, 1000/30);}).bind(window); var cancelAnimationFrame = (window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame || function(timerId){return clearTimeout(timerId);}).bind(window); function ComponentState(component){ if (!(this instanceof ComponentState)) throw TypeError('ComponentState must be called with `new`'); var state = this; state.update = component.replaceState.bind(component, state, undefined); state.updateEventually = state.updateEventually.bind(state); } ComponentState.getInitialState = function(){ return new ComponentState(this); } ComponentState.prototype = { constructor: ComponentState, handlerFor: function(key){ if (this[key + 'Handler']) return this[key + 'Handler']; return this[key + 'Handler'] = this.handler.bind(this, key); }, handler: function(key, event){ var value = event.target.value; if (event.target.type == 'checkbox'){ if (event.target.checked){ if (!value) value = true; } else value = null; } this.set(key, value); }, setterFor: function(key){ if (this[key + 'Setter']) return this[key + 'Setter']; return this[key + 'Setter'] = this.set.bind(this, key); }, set: function(key, value){ this[key] = value; this.updateEventually(); }, updateEventually: function(){ if (this._updateTimer) cancelAnimationFrame(this._updateTimer); this._updateTimer = requestAnimationFrame(this.update); }, update: function(callback){ throw Error('Update is an abstract method. You need to override it'); } } function CSSTransform(props){ var cssText = '', value; for (var key in props) { if (!props.hasOwnProperty(key)) continue; value = props[key]; if (value == null) continue; cssText += key + '(' + value + ') '; } return cssText; } function px(value){ if (typeof value == 'number') return value + 'px'; if (Array.isArray(value)) return value.map(px); return value; } function valueFromRangeToRange(value, fromMin, fromMax, toMin, toMax){ if (typeof value != number) return value; var fromRange = fromMax - fromMin; var toRange = toMax - toMin; return (((fromValue - fromMin) * toRange) / fromRange) + toMin; } function Layer(props, firstChild){ var children = firstChild && Array.prototype.slice.call(arguments, 1); var origin = props.origin; var transform = CSSTransform({ matrix: props.matrix || props.m, matrix3d: props.matrix3d || props.m3d, translate: px(props.translate || props.t), translate3d: px(props.translate3d || props.t3d), translateX: px(props.translateX || props.tX), translateY: px(props.translateY || props.tY), translateZ: px(props.translateZ || props.tZ), scale: props.scale || props.s, scale3d: props.scale3d || props.s3d, scaleX: props.scaleX || props.sX, scaleY: props.scaleY || props.sY, scaleZ: props.scaleZ || props.sZ, skewX: props.skewX || props.kX, skewY: props.skewY || props.sY, rotate: props.rotate || props.r, rotate3d: props.rotate3d || props.r3d, rotateX: props.rotateX || props.rX, rotateY: props.rotateY || props.rY, rotateZ: props.rotateZ || props.rZ, perspective: props.perspective || props.p, }); var filter = CSSTransform({ "grayscale": props.grayscale, "sepia": props.sepia, "saturate": props.saturate, "hue-rotate": props.hue, "invert": props.invert, "opacity": props.opacity, "brightness": props.brightness, "contrast": props.contrast, "blur": px(props.blur), "drop-shadow": props.shadow, }); var style = { display: 'inline-block', position: 'absolute', backgroundColor: props.fill || '#f00', opacity: props.alpha || props.opacity, width: props.width || props.w, height: props.height || props.h, 'pointer-events': props.touchable ? 'auto' : 'none', 'filter': filter, 'transform-origin': origin, 'transform': transform, }; if (props.flow) style.top = style.left = 'auto'; else style.top = style.left = 0; if ('top' in props) style.top = props.top; if ('left' in props) style.left = props.left; expandCSSCompat(style, 'filter'); expandCSSCompat(style, 'transform'); expandCSSCompat(style, 'transform-origin'); return React.DOM.div({style:style}, children); } function expandCSSCompat(style, key){ style['-webkit-' + key] = style[key]; style['-moz-' + key] = style[key]; style['-ms-' + key] = style[key]; style['-o-' + key] = style[key]; } function Spring(config, state){ // config var mass = state.mass = config.mass || state.mass || Spring.prototype.mass; var friction = state.friction = config.friction || state.friction || Spring.prototype.friction; var stiffness = state.stiffness = config.stiffness || state.stiffness || Spring.prototype.stiffness; var precision = state.precision = config.precision || state.precision || Spring.prototype.precision || 1000; var min = state.min = config.min || state.min || Spring.prototype.min; var input = config.input || state.input || Spring.prototype.input; input = Math.round((input * precision)) / precision; var value = config.value || state.value || 0; // state.targetValue = value; var speed = config.speed || state.speed || 0; // if (typeof value != 'number') throw TypeError('expected "value" to be a number'); var scale = config.scale || state.scale || 0; if (!scale){ var ts = state.ts || Date.now(); state.ts = Date.now(); scale = (state.ts - ts) / 30 || 1; } // calculate var distance = value - input; if (!(distance > min && distance > -min || distance < min && distance < -min)){ if (!(speed > min && speed > -min || speed < min && speed < -min)){ distance = 0; value = input; speed = 0; } } state.isDirty = distance + speed; var dampingForce = -friction * speed; var springForce = -stiffness * distance; var totalForce = springForce + dampingForce; var acceleration = totalForce / mass; // output state.speed = speed + acceleration * scale; state.value = value + state.speed; // state.value = Math.round((state.value * precision)) / precision; return state.value } Spring.prototype.enabled = true; Spring.prototype.mass = 10; Spring.prototype.friction = 3; Spring.prototype.stiffness = 120 / 100; Spring.prototype.precision = 100; Spring.prototype.min = 0.01; Spring.prototype.input = 0;