From cb07599f6ddbd52b1c26574f3656dc4a25f0d0df Mon Sep 17 00:00:00 2001 From: Jon Jensen Date: Sun, 15 Feb 2015 17:46:50 -0700 Subject: [PATCH] require wrappers prop, rather than inferring from children this ensures that 1. wrappers can be reused and 2. wrapper order can change (kinda critical for i18n) also remove some cruft from copying over from --- ComponentInterpolator.js | 107 ++++++++++-------------- __tests__/ComponentInterpolator.test.js | 16 +++- 2 files changed, 55 insertions(+), 68 deletions(-) diff --git a/ComponentInterpolator.js b/ComponentInterpolator.js index 189871e..19627c7 100644 --- a/ComponentInterpolator.js +++ b/ComponentInterpolator.js @@ -1,98 +1,75 @@ -/* -Given: - -Ohai {this.props.user}, click here right now please! - -Pre-process it into: - - - - - -*/ +/** + * Given: + * + * Ohai {this.props.user}, click here right now please! + * + * Pre-process it into: + * + * , + * '**': , + * '***': }} + * /> + * + * Which is equivalent to: + * + * Ohai {this.props.user}, click here right now please! + * + * ... but completely localizable :) + */ var React = require('react'); var cloneWithProps = require('react/lib/cloneWithProps'); var invariant = require('react/lib/invariant'); -var { string } = React.PropTypes; - -var OWN_PROPS = ['defaultValue', 'translateKey', 'children']; +var { string, object } = React.PropTypes; var ComponentInterpolator = React.createClass({ propTypes: { - string: string.isRequired + string: string.isRequired, + wrappers: object.isRequired }, componentWillMount() { - var textCount = this.textCount(); - var componentCount = this.componentCount(); invariant( - textCount === 0, - ' cannot have any text children' + !this.props.children, + ' cannot have any children' ); }, - textCount(node) { - node = node || this; - count = 0; - React.Children.forEach(node.props.children, (child) => { - count += typeof child === 'string' ? 1 : this.textCount(child); - }); - return count; - }, - - componentCount(node) { - node = node || this; - count = 0; - React.Children.forEach(node.props.children, (child) => { - count += typeof child === 'string' ? 0 : 1 + this.componentCount(child); - }); - return count; + inferChildren() { + var tokens = (this.props.string || '').split(/(\*+)/); + return this.interpolateComponents(tokens); }, - inferChildren(string, children) { - var tokens = (string || '').split(/(\*+)/); - return this.interpolateChildren(tokens, children); - }, - - interpolateChildren(tokens, children, eof) { - children = children instanceof Array ? children.slice() : children ? [children] : []; - var token, child, newChildren = []; + interpolateComponents(tokens, eof) { + var token, child + var children = []; + var wrappers = this.props.wrappers || {}; while (tokens.length) { token = tokens.shift(); if (token === eof) break; if (token.match(/\*/)) { - child = children.shift(); + invariant( + child = wrappers[token], + `'s string expected ${token} wrapper, none found` + ) child = cloneWithProps(child, { - key: child.props.key, - children: this.interpolateChildren(tokens, child.props.children, token) + key: token, + children: this.interpolateComponents(tokens, token) }); } else { child = token; } - newChildren.push(child); - } - return newChildren; - }, - - extraProps() { - var props = {}; - for (var key in this.props) { - if (OWN_PROPS.indexOf(key) === -1) - props[key] = this.props[key]; + children.push(child); } - return props; + return children; }, render() { - var options = this.extraProps(); - var translateKey = this.props.translateKey; - var defaultValue = this.props.defaultValue || this.props.children; - options.defaultValue = defaultValue; - - var children = this.inferChildren(this.props.string, this.props.children); - return React.createElement('span', { children }); + return React.createElement('span', {}, this.inferChildren()); } }); diff --git a/__tests__/ComponentInterpolator.test.js b/__tests__/ComponentInterpolator.test.js index aee5a3e..4418f68 100644 --- a/__tests__/ComponentInterpolator.test.js +++ b/__tests__/ComponentInterpolator.test.js @@ -9,20 +9,30 @@ var removeNoise = function(string) { describe('ComponentInterpolator', function() { it('renders', function() { - var subject = Subject({string: 'Hello World'}); + var subject = Subject({ + string: 'Hello World', + wrappers: {} + }); expect(subject.isMounted()).toEqual(true); expect(subject.getDOMNode().textContent).toEqual('Hello World'); }); it('escapes html in the string', function() { - var subject = Subject({string: 'My favorite tag is