+ {/* NOTE(charlie): This element must be styled with inline
+ styles rather than with Aphrodite classes, as MathQuill
+ modifies the class names on the DOM node. */}
+
{
+ this._mathContainer = ReactDOM.findDOMNode(node);
+ }}
+ style={innerStyle}
+ />
+
+ {focused && handle.visible &&
}
+ ;
+ },
+});
+
+const fontSizePt = 18;
+
+// The height of numerals in Symbola (rendered at 18pt) is about 20px (though
+// they render at 24px due to padding for ascenders and descenders). We want our
+// box to be laid out such that there's 8px of padding between a numeral and the
+// edge of the input, so we use this 20px number as our 'base height' and
+// account for the ascender and descender padding when computing the additional
+// padding in our `render` method.
+const numeralHeightPx = 20;
+const totalDesiredPadding = 8;
+const minHeightPx = numeralHeightPx + totalDesiredPadding * 2;
+const minWidthPx = 64;
+
+const styles = StyleSheet.create({
+ input: {
+ position: 'relative',
+ display: 'inline-block',
+ verticalAlign: 'middle',
+ },
+});
+
+const inlineStyles = {
+ // Styles for the inner, MathQuill-ified input element. It's important that
+ // these are done with regular inline styles rather than Aphrodite classes
+ // as MathQuill adds CSS class names to the element outside of the typical
+ // React flow; assigning a class to the element can thus disrupt MathQuill
+ // behavior. For example, if the client provided new styles to be applied
+ // on focus and the styles here were applied with Aphrodite, then Aphrodite
+ // would merge the provided styles with the base styles here, producing a
+ // new CSS class name that we would apply to the element, clobbering any CSS
+ // class names that MathQuill had applied itself.
+ innerContainer: {
+ backgroundColor: 'white',
+ display: 'flex',
+ minHeight: minHeightPx,
+ minWidth: minWidthPx,
+ boxSizing: 'border-box',
+ position: 'relative',
+ overflow: 'hidden',
+ borderStyle: 'solid',
+ borderColor: gray76,
+ borderRadius: 4,
+ color: gray17,
+ },
+};
+
+module.exports = MathInput;
diff --git a/src/components/math-input/components/input/math-wrapper.js b/src/components/math-input/components/input/math-wrapper.js
new file mode 100644
index 0000000..958b5fa
--- /dev/null
+++ b/src/components/math-input/components/input/math-wrapper.js
@@ -0,0 +1,917 @@
+/**
+ * This file contains a wrapper around MathQuill so that we can provide a
+ * more regular interface for the functionality we need while insulating us
+ * from MathQuill changes.
+ */
+
+const $ = require('jquery');
+// TODO(kevinb) allow test code to use const MathQuill = require('mathquill');
+const MathQuill = window.MathQuill;
+
+const Keys = require('../../data/keys');
+const CursorContexts = require('./cursor-contexts');
+const { DecimalSeparators } = require('../../consts');
+const { decimalSeparator } = require('../../utils');
+
+const decimalSymbol = decimalSeparator === DecimalSeparators.COMMA ? ',' : '.';
+
+const WRITE = 'write';
+const CMD = 'cmd';
+const KEYSTROKE = 'keystroke';
+const MQ_END = 0;
+
+// A mapping from keys that can be pressed on a keypad to the way in which
+// MathQuill should modify its input in response to that key-press. Any keys
+// that do not provide explicit actions (like the numeral keys) will merely
+// write their contents to MathQuill.
+const KeyActions = {
+ [Keys.PLUS]: { str: '+', fn: WRITE },
+ [Keys.MINUS]: { str: '-', fn: WRITE },
+ [Keys.NEGATIVE]: { str: '-', fn: WRITE },
+ [Keys.TIMES]: { str: '\\times', fn: WRITE },
+ [Keys.DIVIDE]: { str: '\\div', fn: WRITE },
+ [Keys.DECIMAL]: {
+ str: decimalSymbol,
+ fn: WRITE,
+ },
+ [Keys.EQUAL]: { str: '=', fn: WRITE },
+ [Keys.NEQ]: { str: '\\neq', fn: WRITE },
+ [Keys.CDOT]: { str: '\\cdot', fn: WRITE },
+ [Keys.PERCENT]: { str: '%', fn: WRITE },
+ [Keys.LEFT_PAREN]: { str: '(', fn: CMD },
+ [Keys.RIGHT_PAREN]: { str: ')', fn: CMD },
+ [Keys.SQRT]: { str: 'sqrt', fn: CMD },
+ [Keys.PI]: { str: 'pi', fn: CMD },
+ [Keys.THETA]: { str: 'theta', fn: CMD },
+ [Keys.RADICAL]: { str: 'nthroot', fn: CMD },
+ [Keys.LT]: { str: '<', fn: WRITE },
+ [Keys.LEQ]: { str: '\\leq', fn: WRITE },
+ [Keys.GT]: { str: '>', fn: WRITE },
+ [Keys.GEQ]: { str: '\\geq', fn: WRITE },
+ [Keys.UP]: { str: 'Up', fn: KEYSTROKE },
+ [Keys.DOWN]: { str: 'Down', fn: KEYSTROKE },
+ // The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
+ // some additional navigation depending on the cursor position.
+ [Keys.FRAC_INCLUSIVE]: { str: '/', fn: CMD },
+};
+
+const NormalCommands = {
+ [Keys.LOG]: 'log',
+ [Keys.LN]: 'ln',
+ [Keys.SIN]: 'sin',
+ [Keys.COS]: 'cos',
+ [Keys.TAN]: 'tan',
+};
+
+const ArithmeticOperators = ['+', '-', '\\cdot', '\\times', '\\div'];
+const EqualityOperators = ['=', '\\neq', '<', '\\leq', '>', '\\geq'];
+
+const Numerals = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+const GreekLetters = ['\\theta', '\\pi'];
+const Letters = [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+];
+
+// We only consider numerals, variables, and Greek Letters to be proper
+// leaf nodes.
+const ValidLeaves = [
+ ...Numerals,
+ ...GreekLetters,
+ ...Letters.map(letter => letter.toLowerCase()),
+ ...Letters.map(letter => letter.toUpperCase()),
+];
+
+const KeysForJumpContext = {
+ [CursorContexts.IN_PARENS]: Keys.JUMP_OUT_PARENTHESES,
+ [CursorContexts.IN_SUPER_SCRIPT]: Keys.JUMP_OUT_EXPONENT,
+ [CursorContexts.IN_SUB_SCRIPT]: Keys.JUMP_OUT_BASE,
+ [CursorContexts.BEFORE_FRACTION]: Keys.JUMP_INTO_NUMERATOR,
+ [CursorContexts.IN_NUMERATOR]: Keys.JUMP_OUT_NUMERATOR,
+ [CursorContexts.IN_DENOMINATOR]: Keys.JUMP_OUT_DENOMINATOR,
+};
+
+class MathWrapper {
+
+ constructor(element, options = {}, callbacks = {}) {
+ this.MQ = MathQuill.getInterface(2);
+ this.mathField = this.MQ.MathField(element, {
+ // use a span instead of a textarea so that we don't bring up the
+ // native keyboard on mobile when selecting the input
+ substituteTextarea: () => {
+ return this.fakeTextarea = document.createElement('span');
+ },
+ });
+ this.callbacks = callbacks;
+ }
+
+ focus() {
+ // HACK(charlie): We shouldn't reaching into MathQuill internals like
+ // this, but it's the easiest way to allow us to manage the focus state
+ // ourselves.
+ const controller = this.mathField.__controller;
+ controller.cursor.show();
+
+ // Set MathQuill's internal state to reflect the focus, otherwise it
+ // will consistently try to hide the cursor on key-press and introduce
+ // layout jank.
+ controller.blurred = false;
+ }
+
+ blur() {
+ const controller = this.mathField.__controller;
+ controller.cursor.hide();
+ controller.blurred = true;
+ }
+
+ _writeNormalFunction(name) {
+ this.mathField.write(`\\${name}\\left(\\right)`);
+ this.mathField.keystroke('Left');
+ }
+
+ /**
+ * Handle a key press and return the resulting cursor state.
+ *
+ * @param {Key} key - an enum representing the key that was pressed
+ * @returns {object} a cursor object, consisting of a cursor context
+ */
+ pressKey(key) {
+ const cursor = this.mathField.__controller.cursor;
+
+ if (key in KeyActions) {
+ const { str, fn } = KeyActions[key];
+
+ if (str && fn) {
+ this.mathField[fn](str);
+ }
+ } else if (Object.keys(NormalCommands).includes(key)) {
+ this._writeNormalFunction(NormalCommands[key]);
+ } else if (key === Keys.FRAC_EXCLUSIVE) {
+ // If there's nothing to the left of the cursor, then we want to
+ // leave the cursor to the left of the fraction after creating it.
+ const shouldNavigateLeft = cursor[this.MQ.L] === MQ_END;
+ this.mathField.cmd('\\frac');
+ if (shouldNavigateLeft) {
+ this.mathField.keystroke('Left');
+ }
+ } else if (key === Keys.LOG_N) {
+ this.mathField.write('log_{ }\\left(\\right)');
+ this.mathField.keystroke('Left'); // into parentheses
+ this.mathField.keystroke('Left'); // out of parentheses
+ this.mathField.keystroke('Left'); // into index
+ } else if (key === Keys.CUBE_ROOT) {
+ this.mathField.write('\\sqrt[3]{}');
+ this.mathField.keystroke('Left'); // under the root
+ } else if (key === Keys.EXP || key === Keys.EXP_2 ||
+ key === Keys.EXP_3) {
+ this._handleExponent(cursor, key);
+ } else if (key === Keys.JUMP_OUT_PARENTHESES ||
+ key === Keys.JUMP_OUT_EXPONENT ||
+ key === Keys.JUMP_OUT_BASE ||
+ key === Keys.JUMP_INTO_NUMERATOR ||
+ key === Keys.JUMP_OUT_NUMERATOR ||
+ key === Keys.JUMP_OUT_DENOMINATOR) {
+ this._handleJumpOut(cursor, key);
+ } else if (key === Keys.BACKSPACE) {
+ this._handleBackspace(cursor);
+ } else if (key === Keys.LEFT) {
+ this._handleLeftArrow(cursor);
+ } else if (key === Keys.RIGHT || key === Keys.JUMP_OUT) {
+ this._handleRightArrow(cursor);
+ } else if (/^[a-zA-Z]$/.test(key)) {
+ this.mathField[WRITE](key);
+ } else if (/^NUM_\d/.test(key)) {
+ this.mathField[WRITE](key[4]);
+ }
+
+ if (!cursor.selection) { // don't show the cursor for selections
+ cursor.show();
+ }
+
+ if (this.callbacks.onSelectionChanged) {
+ this.callbacks.onSelectionChanged(cursor.selection);
+ }
+
+ // NOTE(charlie): It's insufficient to do this as an `edited` handler
+ // on the MathField, as that handler isn't triggered on navigation
+ // events.
+ return {
+ context: this.contextForCursor(cursor),
+ };
+ }
+
+ /**
+ * Place the cursor beside the node located at the given coordinates.
+ *
+ * @param {number} x - the x coordinate in the viewport
+ * @param {number} y - the y coordinate in the viewport
+ * @param {Node} hitNode - the node next to which the cursor should be
+ * placed; if provided, the coordinates will be used
+ * to determine on which side of the node the cursor
+ * should be placed
+ */
+ setCursorPosition(x, y, hitNode) {
+ const el = hitNode || document.elementFromPoint(x, y);
+
+ if (el) {
+ const cursor = this.getCursor();
+
+ if (el.hasAttribute('mq-root-block')) {
+ // If we're in the empty area place the cursor at the right
+ // end of the expression.
+ cursor.insAtRightEnd(this.mathField.__controller.root);
+ } else {
+ // Otherwise place beside the element at x, y.
+ const controller = this.mathField.__controller;
+
+ const pageX = x - document.body.scrollLeft;
+ const pageY = y - document.body.scrollTop;
+ controller.seek($(el), pageX, pageY).cursor.startSelection();
+
+ // Unless that would leave us mid-command, in which case, we
+ // need to adjust and place the cursor inside the parens
+ // following the command.
+ const command = this._maybeFindCommand(cursor[this.MQ.L]);
+ if (command && command.endNode) {
+ // NOTE(charlie): endNode should definitely be \left(.
+ cursor.insLeftOf(command.endNode);
+ this.mathField.keystroke('Right');
+ }
+ }
+
+ if (this.callbacks.onCursorMove) {
+ this.callbacks.onCursorMove({
+ context: this.contextForCursor(cursor),
+ });
+ }
+ }
+ }
+
+ getCursor() {
+ return this.mathField.__controller.cursor;
+ }
+
+ getSelection() {
+ return this.getCursor().selection;
+ }
+
+ getContent() {
+ return this.mathField.latex();
+ }
+
+ setContent(latex) {
+ this.mathField.latex(latex);
+ }
+
+ isEmpty() {
+ const cursor = this.getCursor();
+ return cursor.parent.id === 1 && cursor[1] === 0 && cursor[-1] === 0;
+ }
+
+ // Notes about MathQuill
+ //
+ // MathQuill's stores its layout as nested linked lists. Each node in the
+ // list has this.MQ.L '-1' and this.MQ.R '1' properties that define links to
+ // the left and right nodes respectively. They also have
+ //
+ // ctrlSeq: contains the latex code snippet that defines that node.
+ // jQ: jQuery object for the DOM node(s) for this MathQuill node.
+ // ends: pointers to the nodes at the ends of the container.
+ // parent: parent node.
+ // blocks: an array containing one or more nodes that make up the node.
+ // sub?: subscript node if there is one as is the case in log_n
+ //
+ // All of the code below is super fragile. Please be especially careful
+ // when upgrading MathQuill.
+
+ _handleBackspaceInNthRoot(cursor) {
+ const isAtLeftEnd = cursor[this.MQ.L] === MQ_END;
+
+ const isRootEmpty = this._isInsideEmptyNode(
+ cursor.parent.parent.blocks[0].ends
+ );
+
+ if (isAtLeftEnd) {
+ this._selectNode(cursor.parent.parent, cursor);
+
+ if (isRootEmpty) {
+ this.mathField.keystroke('Backspace');
+ }
+ } else {
+ this.mathField.keystroke('Backspace');
+ }
+ }
+
+ /**
+ * Advances the cursor to the next logical position.
+ *
+ * @param {cursor} cursor
+ * @private
+ */
+ _handleJumpOut(cursor, key) {
+ const context = this.contextForCursor(cursor);
+
+ // Validate that the current cursor context matches the key's intent.
+ if (KeysForJumpContext[context] !== key) {
+ // If we don't have a valid cursor context, yet the user was able
+ // to trigger a jump-out key, that's a broken invariant. Rather
+ // than throw an error (which would kick the user out of the
+ // exercise), we do nothing, as a fallback strategy. The user can
+ // still move the cursor manually.
+ return;
+ }
+
+ switch (context) {
+ case CursorContexts.IN_PARENS:
+ // Insert at the end of the parentheses, and then navigate right
+ // once more to get 'beyond' the parentheses.
+ cursor.insRightOf(cursor.parent.parent);
+ break;
+
+ case CursorContexts.BEFORE_FRACTION:
+ // Find the nearest fraction to the right of the cursor.
+ let fractionNode;
+ let visitor = cursor;
+ while (visitor[this.MQ.R] !== MQ_END) {
+ if (this._isFraction(visitor[this.MQ.R])) {
+ fractionNode = visitor[this.MQ.R];
+ }
+ visitor = visitor[this.MQ.R];
+ }
+
+ // Jump into it!
+ cursor.insLeftOf(fractionNode);
+ this.mathField.keystroke('Right');
+ break;
+
+ case CursorContexts.IN_NUMERATOR:
+ // HACK(charlie): I can't find a better way to do this. The goal
+ // is to place the cursor at the start of the matching
+ // denominator. So, we identify the appropriate node, and
+ // continue rightwards until we find ourselves inside of it.
+ // It's possible that there are cases in which we don't reach
+ // the denominator, though I can't think of any.
+ const siblingDenominator = cursor.parent.parent.blocks[1];
+ while (cursor.parent !== siblingDenominator) {
+ this.mathField.keystroke('Right');
+ }
+ break;
+
+ case CursorContexts.IN_DENOMINATOR:
+ cursor.insRightOf(cursor.parent.parent);
+ break;
+
+ case CursorContexts.IN_SUB_SCRIPT:
+ // Insert just beyond the superscript.
+ cursor.insRightOf(cursor.parent.parent);
+
+ // Navigate right once more, if we're right before parens. This
+ // is to handle the standard case in which the subscript is the
+ // base of a custom log.
+ if (this._isParens(cursor[this.MQ.R])) {
+ this.mathField.keystroke('Right');
+ }
+ break;
+
+ case CursorContexts.IN_SUPER_SCRIPT:
+ // Insert just beyond the superscript.
+ cursor.insRightOf(cursor.parent.parent);
+ break;
+
+ default:
+ throw new Error(
+ `Attempted to 'Jump Out' from node, but found no ` +
+ `appropriate cursor context: ${context}`
+ );
+ }
+ }
+
+ /**
+ * Selects and deletes part of the expression based on the cursor location.
+ * See inline comments for precise behavior of different cases.
+ *
+ * @param {cursor} cursor
+ * @private
+ */
+ _handleBackspace(cursor) {
+ if (!cursor.selection) {
+ const parent = cursor.parent;
+ const grandparent = parent.parent;
+ const leftNode = cursor[this.MQ.L];
+
+ if (this._isFraction(leftNode)) {
+ this._selectNode(leftNode, cursor);
+
+ } else if (this._isSquareRoot(leftNode)) {
+ this._selectNode(leftNode, cursor);
+
+ } else if (this._isNthRoot(leftNode)) {
+ this._selectNode(leftNode, cursor);
+
+ } else if (this._isNthRootIndex(parent)) {
+ this._handleBackspaceInRootIndex(cursor);
+
+ } else if (leftNode.ctrlSeq === '\\left(') {
+ this._handleBackspaceOutsideParens(cursor);
+
+ } else if (grandparent.ctrlSeq === '\\left(') {
+ this._handleBackspaceInsideParens(cursor);
+
+ } else if (this._isInsideLogIndex(cursor)) {
+ this._handleBackspaceInLogIndex(cursor);
+
+ } else if (leftNode.ctrlSeq === '\\ge ' ||
+ leftNode.ctrlSeq === '\\le ') {
+ this._handleBackspaceAfterLigaturedSymbol(cursor);
+
+ } else if (this._isNthRoot(grandparent) && leftNode === MQ_END) {
+ this._handleBackspaceInNthRoot(cursor);
+
+ } else {
+ this.mathField.keystroke('Backspace');
+ }
+ } else {
+ this.mathField.keystroke('Backspace');
+ }
+ }
+
+ _handleLeftArrow(cursor) {
+ // If we're inside a function, and just after the left parentheses, we
+ // need to skip the entire function name, rather than move the cursor
+ // inside of it. For example, when hitting left from within the
+ // parentheses in `cos()`, we want to place the cursor to the left of
+ // the entire expression, rather than between the `s` and the left
+ // parenthesis.
+ // From the cursor's perspective, this requires that our left node is
+ // the MQ_END node, that our grandparent is the left parenthesis, and
+ // the nodes to the left of our grandparent comprise a valid function
+ // name.
+ if (cursor[this.MQ.L] === MQ_END) {
+ const parent = cursor.parent;
+ const grandparent = parent.parent;
+ if (grandparent.ctrlSeq === '\\left(') {
+ const command = this._maybeFindCommandBeforeParens(grandparent);
+ if (command) {
+ cursor.insLeftOf(command.startNode);
+ return;
+ }
+ }
+ }
+
+ // Otherwise, we default to the standard MathQull left behavior.
+ this.mathField.keystroke('Left');
+ }
+
+ _handleRightArrow(cursor) {
+ const command = this._maybeFindCommand(cursor[this.MQ.R]);
+ if (command) {
+ // Similarly, if a function is to our right, then we need to place
+ // the cursor at the start of its parenthetical content, which is
+ // done by putting it to the left of ites parentheses and then
+ // moving right once.
+ cursor.insLeftOf(command.endNode);
+ this.mathField.keystroke('Right');
+ } else {
+ // Otherwise, we default to the standard MathQull right behavior.
+ this.mathField.keystroke('Right');
+ }
+ }
+
+ _handleExponent(cursor, key) {
+ // If there's an invalid operator preceding the cursor (anything that
+ // knowingly cannot be raised to a power), add an empty set of
+ // parentheses and apply the exponent to that.
+ const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
+
+ const precedingNode = cursor[this.MQ.L];
+ const shouldPrefixWithParens = precedingNode === MQ_END ||
+ invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
+ if (shouldPrefixWithParens) {
+ this.mathField.write('\\left(\\right)');
+ }
+
+ // Insert the appropriate exponent operator.
+ switch (key) {
+ case Keys.EXP:
+ this.mathField.cmd('^');
+ break;
+
+ case Keys.EXP_2:
+ case Keys.EXP_3:
+ this.mathField.write(`^${key === Keys.EXP_2 ? 2 : 3}`);
+
+ // If we enter a square or a cube, we should leave the cursor
+ // within the newly inserted parens, if they exist. This takes
+ // exactly four left strokes, since the cursor by default would
+ // end up to the right of the exponent.
+ if (shouldPrefixWithParens) {
+ this.mathField.keystroke('Left');
+ this.mathField.keystroke('Left');
+ this.mathField.keystroke('Left');
+ this.mathField.keystroke('Left');
+ }
+ break;
+
+ default:
+ throw new Error(`Invalid exponent key: ${key}`);
+ }
+ }
+
+ /**
+ * Return the start node, end node, and full name of the command of which
+ * the initial node is a part, or `null` if the node is not part of a
+ * command.
+ *
+ * @param {node} initialNode - the node to included as part of the command
+ * @returns {null|object} - `null` or an object containing the start node
+ * (`startNode`), end node (`endNode`), and full
+ * name (`name`) of the command
+ * @private
+ */
+ _maybeFindCommand(initialNode) {
+ if (!initialNode) {
+ return null;
+ }
+
+ // MathQuill stores commands as separate characters so that
+ // users can delete commands one character at a time. We iterate over
+ // the nodes from right to left until we hit a sequence starting with a
+ // '\\', which signifies the start of a command; then we iterate from
+ // left to right until we hit a '\\left(', which signifies the end of a
+ // command. If we encounter any character that doesn't belong in a
+ // command, we return null. We match a single character at a time.
+ // Ex) ['\\l', 'o', 'g ', '\\left(', ...]
+ const commandCharRegex = /^[a-z]$/;
+ const commandStartRegex = /^\\[a-z]$/;
+ const commandEndSeq = '\\left(';
+
+ // Note: We whitelist the set of valid commands, since relying solely on
+ // a command being prefixed with a backslash leads to undesired
+ // behavior. For example, Greek symbols, left parentheses, and square
+ // roots all get treated as commands.
+ const validCommands = ['\\log', '\\ln', '\\cos', '\\sin', '\\tan'];
+
+ let name = '';
+ let startNode;
+ let endNode;
+
+ // Collect the portion of the command from the current node, leftwards
+ // until the start of the command.
+ let node = initialNode;
+ while (node !== 0) {
+ const ctrlSeq = node.ctrlSeq.trim();
+ if (commandCharRegex.test(ctrlSeq)) {
+ name = ctrlSeq + name;
+ } else if (commandStartRegex.test(ctrlSeq)) {
+ name = ctrlSeq + name;
+ startNode = node;
+ break;
+ } else {
+ break;
+ }
+
+ node = node[this.MQ.L];
+ }
+
+ // If we hit the start of a command, then grab the rest of it by
+ // iterating rightwards to compute the full name of the command, along
+ // with its terminal node.
+ if (startNode) {
+ // Next, iterate from the start to the right.
+ node = initialNode[this.MQ.R];
+ while (node !== 0) {
+ const ctrlSeq = node.ctrlSeq.trim();
+ if (commandCharRegex.test(ctrlSeq)) {
+ // If we have a single character, add it to the command
+ // name.
+ name = name + ctrlSeq;
+ } else if (ctrlSeq === commandEndSeq) {
+ // If we hit the command end delimiter (the left
+ // parentheses surrounding its arguments), stop.
+ endNode = node;
+ break;
+ }
+
+ node = node[this.MQ.R];
+ }
+ if (validCommands.includes(name)) {
+ return { name, startNode, endNode };
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the start node, end node, and full name of the command to the left
+ * of `\\left(`, or `null` if there is no command.
+ *
+ * @param {node} leftParenNode - node where .ctrlSeq == `\\left(`
+ * @returns {null|object} - `null` or an object containing the start node
+ * (`startNode`), end node (`endNode`), and full
+ * name (`name`) of the command
+ * @private
+ */
+ _maybeFindCommandBeforeParens(leftParenNode) {
+ return this._maybeFindCommand(leftParenNode[this.MQ.L]);
+ }
+
+ _selectNode(node, cursor) {
+ cursor.insLeftOf(node);
+ cursor.startSelection();
+ cursor.insRightOf(node);
+ cursor.select();
+ cursor.endSelection();
+ }
+
+ _isFraction(node) {
+ return node.jQ && node.jQ.hasClass('mq-fraction');
+ }
+
+ _isNumerator(node) {
+ return node.jQ && node.jQ.hasClass('mq-numerator');
+ }
+
+ _isDenominator(node) {
+ return node.jQ && node.jQ.hasClass('mq-denominator');
+ }
+
+ _isSubScript(node) {
+ // NOTE(charlie): MyScript has a structure whereby its superscripts seem
+ // to be represented as a parent node with 'mq-sup-only' containing a
+ // single child with 'mq-sup'.
+ return node.jQ &&
+ (node.jQ.hasClass('mq-sub-only') || node.jQ.hasClass('mq-sub'));
+ }
+
+ _isSuperScript(node) {
+ // NOTE(charlie): MyScript has a structure whereby its superscripts seem
+ // to be represented as a parent node with 'mq-sup-only' containing a
+ // single child with 'mq-sup'.
+ return node.jQ &&
+ (node.jQ.hasClass('mq-sup-only') || node.jQ.hasClass('mq-sup'));
+ }
+
+ _isParens(node) {
+ return node && node.ctrlSeq === '\\left(';
+ }
+
+ _isLeaf(node) {
+ return node && node.ctrlSeq &&
+ ValidLeaves.includes(node.ctrlSeq.trim());
+ }
+
+ _isSquareRoot(node) {
+ return node.blocks && node.blocks[0].jQ &&
+ node.blocks[0].jQ.hasClass('mq-sqrt-stem');
+ }
+
+ _isNthRoot(node) {
+ return node.blocks && node.blocks[0].jQ &&
+ node.blocks[0].jQ.hasClass('mq-nthroot');
+ }
+
+ _isNthRootIndex(node) {
+ return node.jQ && node.jQ.hasClass('mq-nthroot');
+ }
+
+ _isInsideLogIndex(cursor) {
+ const grandparent = cursor.parent.parent;
+
+ if (grandparent && grandparent.jQ.hasClass('mq-supsub')) {
+ const command = this._maybeFindCommandBeforeParens(grandparent);
+
+ if (command && command.name === '\\log') {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ _isInsideEmptyNode(cursor) {
+ return cursor[this.MQ.L] === MQ_END && cursor[this.MQ.R] === MQ_END;
+ }
+
+ _handleBackspaceInRootIndex(cursor) {
+ if (this._isInsideEmptyNode(cursor)) {
+ // When deleting the index in a nthroot, we change from the nthroot
+ // to a sqrt, e.g. \sqrt[|]{35x-5} => |\sqrt{35x-5}. If there's no
+ // content under the root, then we delete the whole thing.
+
+ const grandparent = cursor.parent.parent;
+ const latex = grandparent.latex();
+ const reinsertionPoint = grandparent[this.MQ.L];
+
+ this._selectNode(grandparent, cursor);
+
+ const rootIsEmpty = grandparent.blocks[1].jQ.text() === '';
+
+ if (rootIsEmpty) {
+ // If there is not content under the root then simply delete
+ // the whole thing.
+ this.mathField.keystroke('Backspace');
+ } else {
+ // Replace the nthroot with a sqrt if there was content under
+ // the root.
+
+ // Start by deleting the selection.
+ this.mathField.keystroke('Backspace');
+
+ // Replace the nth-root with a sqrt.
+ this.mathField.write(
+ latex.replace(/^\\sqrt\[\]/, '\\sqrt'));
+
+ // Adjust the cursor to be to the left the sqrt.
+ if (reinsertionPoint === MQ_END) {
+ this.mathField.moveToDirEnd(this.MQ.L);
+ } else {
+ cursor.insRightOf(reinsertionPoint);
+ }
+ }
+ } else {
+ if (cursor[this.MQ.L] !== MQ_END) {
+ // If the cursor is not at the leftmost position inside the
+ // root's index, delete a character.
+ this.mathField.keystroke('Backspace');
+ } else {
+ // TODO(kevinb) verify that we want this behavior after testing
+ // Do nothing because we haven't completely deleted the
+ // index of the radical.
+ }
+ }
+ }
+
+ _handleBackspaceInLogIndex(cursor) {
+ if (this._isInsideEmptyNode(cursor)) {
+ const grandparent = cursor.parent.parent;
+ const command = this._maybeFindCommandBeforeParens(grandparent);
+
+ cursor.insLeftOf(command.startNode);
+ cursor.startSelection();
+
+ if (grandparent[this.MQ.R] !== MQ_END) {
+ cursor.insRightOf(grandparent[this.MQ.R]);
+ } else {
+ cursor.insRightOf(grandparent);
+ }
+
+ cursor.select();
+ cursor.endSelection();
+
+ const isLogBodyEmpty =
+ grandparent[this.MQ.R].contentjQ.text() === '';
+
+ if (isLogBodyEmpty) {
+ // If there's no content inside the log's parens then delete the
+ // whole thing.
+ this.mathField.keystroke('Backspace');
+ }
+ } else {
+ this.mathField.keystroke('Backspace');
+ }
+ }
+
+ _handleBackspaceOutsideParens(cursor) {
+ // In this case the node with '\\left(' for its ctrlSeq
+ // is the parent of the expression contained within the
+ // parentheses.
+ //
+ // Handle selecting an expression before deleting:
+ // (x+1)| => |(x+1)|
+ // \log(x+1)| => |\log(x+1)|
+
+ const leftNode = cursor[this.MQ.L];
+ const rightNode = cursor[this.MQ.R];
+ const command = this._maybeFindCommandBeforeParens(leftNode);
+
+ if (command && command.startNode) {
+ // There's a command before the parens so we select it as well as
+ // the parens.
+ cursor.insLeftOf(command.startNode);
+ cursor.startSelection();
+ if (rightNode === MQ_END) {
+ cursor.insAtRightEnd(cursor.parent);
+ } else {
+ cursor.insLeftOf(rightNode);
+ }
+ cursor.select();
+ cursor.endSelection();
+ } else {
+ cursor.startSelection();
+ cursor.insLeftOf(leftNode); // left of \\left(
+ cursor.select();
+ cursor.endSelection();
+ }
+ }
+
+ _handleBackspaceInsideParens(cursor) {
+ // Handle situations when the cursor is inside parens or a
+ // command that uses parens, e.g. \log() or \tan()
+ //
+ // MathQuill represents log(x+1) in roughly the following way
+ // [l, o, g, \\left[parent:[x, +, 1]]]
+ //
+ // If the cursor is inside the parentheses it's next to one of:
+ // x, +, or 1. This makes sub_sub_expr its parent and sub_expr
+ // it's parent.
+ //
+ // Interestingly parent doesn't have any nodes to the left or
+ // right of it (even though the corresponding DOM node has
+ // ( and ) characters on either side.
+ //
+ // The grandparent's ctrlSeq is `\\left(`. The `\\right)` isn't
+ // stored anywhere. NOTE(kevinb): I believe this is because
+ // MathQuill knows what the close paren should be and does the
+ // right thing at render time.
+ //
+ // This conditional branch handles the following cases:
+ // - \log(x+1|) => \log(x+|)
+ // - \log(|x+1) => |\log(x+1)|
+ // - \log(|) => |
+
+ if (cursor[this.MQ.L] !== MQ_END) {
+ // This command contains math and there's some math to
+ // the left of the cursor that we should delete normally
+ // before doing anything special.
+ this.mathField.keystroke('Backspace');
+ return;
+ }
+
+ const grandparent = cursor.parent.parent;
+
+ // If the cursors is inside the parens at the start but the command
+ // has a subscript as is the case in log_n then move the cursor into
+ // the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
+
+ if (grandparent[this.MQ.L].sub) { // if there is a subscript
+ if (grandparent[this.MQ.L].sub.jQ.text()) { // and it contains text
+ // move the cursor to the right end of the subscript
+ cursor.insAtRightEnd(grandparent[this.MQ.L].sub);
+ return;
+ }
+ }
+
+ // Determine if the parens are empty before we modify the
+ // cursor's position.
+ const isEmpty = this._isInsideEmptyNode(cursor);
+
+ // Insert the cursor to the left of the command if there is one
+ // or before the '\\left(` if there isn't
+ const command = this._maybeFindCommandBeforeParens(grandparent);
+
+ cursor.insLeftOf((command && command.startNode) || grandparent);
+ cursor.startSelection();
+ cursor.insRightOf(grandparent);
+ cursor.select();
+ cursor.endSelection();
+
+ // Delete the selection, but only if the parens were empty to
+ // begin with.
+ if (isEmpty) {
+ this.mathField.keystroke('Backspace');
+ }
+ }
+
+ _handleBackspaceAfterLigaturedSymbol(cursor) {
+ this.mathField.keystroke('Backspace');
+ this.mathField.keystroke('Backspace');
+ }
+
+ contextForCursor(cursor) {
+ // First, try to find any fraction to the right, unimpeded.
+ let visitor = cursor;
+ while (visitor[this.MQ.R] !== MQ_END) {
+ if (this._isFraction(visitor[this.MQ.R])) {
+ return CursorContexts.BEFORE_FRACTION;
+ } else if (!this._isLeaf(visitor[this.MQ.R])) {
+ break;
+ }
+ visitor = visitor[this.MQ.R];
+ }
+
+ // If that didn't work, check if the parent or grandparent is a special
+ // context, so that we can jump outwards.
+ if (this._isParens(cursor.parent && cursor.parent.parent)) {
+ return CursorContexts.IN_PARENS;
+ } else if (this._isNumerator(cursor.parent)) {
+ return CursorContexts.IN_NUMERATOR;
+ } else if (this._isDenominator(cursor.parent)) {
+ return CursorContexts.IN_DENOMINATOR;
+ } else if (this._isSubScript(cursor.parent)) {
+ return CursorContexts.IN_SUB_SCRIPT;
+ } else if (this._isSuperScript(cursor.parent)) {
+ return CursorContexts.IN_SUPER_SCRIPT;
+ } else {
+ return CursorContexts.NONE;
+ }
+ }
+
+ _isAtTopLevel(cursor) {
+ return !cursor.parent.parent;
+ }
+}
+
+module.exports = MathWrapper;
diff --git a/src/components/math-input/components/input/scroll-into-view.js b/src/components/math-input/components/input/scroll-into-view.js
new file mode 100644
index 0000000..93786be
--- /dev/null
+++ b/src/components/math-input/components/input/scroll-into-view.js
@@ -0,0 +1,59 @@
+/**
+ * A single function used to scroll a DOM node into view, optionally taking into
+ * account that it may be obscured by the custom keypad. The logic makes the
+ * strong assumption that the keypad will be anchored to the bottom of the page
+ * in calculating its height, as this method may be called before the keypad has
+ * animated into view.
+ *
+ * TODO(charlie): Move this scroll logic out of our components and into a higher
+ * level in the component tree--perhaps even into webapp, beyond Perseus.
+ */
+
+const { toolbarHeightPx } = require('../common-style');
+
+const scrollIntoView = (containerNode, keypadNode) => {
+ // TODO(charlie): There's no need for us to be reading the keypad bounds
+ // here, since they're pre-determined by logic in the store. We should
+ // instead pass around an object that knows the bounds.
+ const containerBounds = containerNode.getBoundingClientRect();
+ const containerBottomPx = containerBounds.bottom;
+ const containerTopPx = containerBounds.top;
+
+ const desiredMarginPx = 16;
+
+ if (keypadNode) {
+ // NOTE(charlie): We can't use the bounding rect of the keypad,
+ // as it is likely in the process of animating in. Instead, to
+ // calculate its top, we make the strong assumption that the
+ // keypad will end up anchored at the bottom of the page, but above the
+ // toolbar, and use its height, which is known at this point. Note that,
+ // in the native apps (where the toolbar is rendered natively), this
+ // will result in us leaving excess space between the input and the
+ // keypad, but that seems okay.
+ const pageHeightPx = window.innerHeight;
+ const keypadHeightPx = keypadNode.clientHeight;
+ const keypadTopPx = pageHeightPx - (keypadHeightPx + toolbarHeightPx);
+
+ if (containerBottomPx > keypadTopPx) {
+ // If the input would be obscured by the keypad, scroll such that
+ // the bottom of the input is just above the top of the keypad,
+ // taking care not to scroll the input out of view.
+ const scrollOffset = Math.min(
+ containerBottomPx - keypadTopPx + desiredMarginPx,
+ containerTopPx
+ );
+
+ document.body.scrollTop += scrollOffset;
+ return;
+ }
+ }
+
+ // Alternatively, if the input is out of the viewport or nearly out
+ // of the viewport, scroll it into view. We can do this regardless
+ // of whether the keypad has been provided.
+ if (containerTopPx < desiredMarginPx) {
+ document.body.scrollTop -= containerBounds.height + desiredMarginPx;
+ }
+};
+
+module.exports = scrollIntoView;
diff --git a/src/components/math-input/components/keypad-button.js b/src/components/math-input/components/keypad-button.js
new file mode 100644
index 0000000..c22a9ea
--- /dev/null
+++ b/src/components/math-input/components/keypad-button.js
@@ -0,0 +1,351 @@
+/**
+ * A component that renders a keypad button.
+ */
+
+const React = require('react');
+const PureRenderMixin = require('react-addons-pure-render-mixin');
+const { connect } = require('react-redux');
+
+const { StyleSheet, css } = require('aphrodite');
+const { View } = require('../fake-react-native-web');
+const Icon = require('./icon');
+const MultiSymbolGrid = require('./multi-symbol-grid');
+const CornerDecal = require('./corner-decal');
+const { KeyTypes, BorderDirections, BorderStyles } = require('../consts');
+const {
+ brightGreen,
+ innerBorderColor,
+ innerBorderStyle,
+ innerBorderWidthPx,
+ valueGrey,
+ operatorGrey,
+ controlGrey,
+ emptyGrey,
+} = require('./common-style');
+const {
+ bordersPropType,
+ iconPropType,
+ keyConfigPropType,
+} = require('./prop-types');
+
+const KeypadButton = React.createClass({
+ propTypes: {
+ ariaLabel: React.PropTypes.string,
+ // The borders to display on the button. Typically, this should be set
+ // using one of the preset `BorderStyles` options.
+ borders: bordersPropType,
+ // Any additional keys that can be accessed by long-pressing on the
+ // button.
+ childKeys: React.PropTypes.arrayOf(keyConfigPropType),
+ // Whether the button should be rendered in a 'disabled' state, i.e.,
+ // without any touch feedback.
+ disabled: React.PropTypes.bool,
+ focused: React.PropTypes.bool,
+ heightPx: React.PropTypes.number.isRequired,
+ icon: iconPropType,
+ onTouchCancel: React.PropTypes.func,
+ onTouchEnd: React.PropTypes.func,
+ onTouchMove: React.PropTypes.func,
+ onTouchStart: React.PropTypes.func,
+ popoverEnabled: React.PropTypes.bool,
+ style: React.PropTypes.any,
+ type: React.PropTypes.oneOf(Object.keys(KeyTypes)).isRequired,
+ // NOTE(charlie): We may want to make this optional for phone layouts
+ // (and rely on Flexbox instead), since it might not be pixel perfect
+ // with borders and such.
+ widthPx: React.PropTypes.number.isRequired,
+ },
+
+ mixins: [PureRenderMixin],
+
+ getDefaultProps() {
+ return {
+ borders: BorderStyles.ALL,
+ childKeys: [],
+ disabled: false,
+ focused: false,
+ popoverEnabled: false,
+ };
+ },
+
+ componentWillMount() {
+ this.buttonSizeStyle = styleForButtonDimensions(
+ this.props.heightPx,
+ this.props.widthPx
+ );
+ },
+
+ componentDidMount() {
+ this._preInjectStyles();
+ },
+
+ componentWillUpdate(newProps, newState) {
+ // Only recompute the Aphrodite StyleSheet when the button height has
+ // changed. Though it is safe to recompute the StyleSheet (since
+ // they're content-addressable), it saves us a bunch of hashing and
+ // other work to cache it here.
+ if (newProps.heightPx !== this.props.heightPx ||
+ newProps.widthPx !== this.props.widthPx) {
+ this.buttonSizeStyle = styleForButtonDimensions(
+ newProps.heightPx, newProps.widthPx
+ );
+
+ this._preInjectStyles();
+ }
+ },
+
+ _preInjectStyles() {
+ // HACK(charlie): Pre-inject all of the possible styles for the button.
+ // This avoids a flickering effect in the echo animation whereby the
+ // echoes vary in size as they animate. Note that we need to account for
+ // the "initial" styles that `View` will include, as these styles are
+ // applied to `View` components and Aphrodite will consolidate the style
+ // object. This method must be called whenever a property that
+ // influences the possible outcomes of `this._getFocusStyle` and
+ // `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
+ for (const type of Object.keys(KeyTypes)) {
+ css(
+ View.styles.initial,
+ ...this._getFocusStyle(type)
+ );
+
+ for (const borders of Object.values(BorderStyles)) {
+ css(
+ View.styles.initial,
+ ...this._getButtonStyle(type, borders)
+ );
+ }
+ }
+ },
+
+ _getFocusStyle(type) {
+ let focusBackgroundStyle;
+ if (type === KeyTypes.INPUT_NAVIGATION ||
+ type === KeyTypes.KEYPAD_NAVIGATION) {
+ focusBackgroundStyle = styles.light;
+ } else {
+ focusBackgroundStyle = styles.bright;
+ }
+
+ return [styles.focusBox, focusBackgroundStyle];
+ },
+
+ _getButtonStyle(type, borders, style) {
+ // Select the appropriate style for the button.
+ let backgroundStyle;
+ switch (type) {
+ case KeyTypes.EMPTY:
+ backgroundStyle = styles.empty;
+ break;
+
+ case KeyTypes.MANY:
+ case KeyTypes.VALUE:
+ backgroundStyle = styles.value;
+ break;
+
+ case KeyTypes.OPERATOR:
+ backgroundStyle = styles.operator;
+ break;
+
+ case KeyTypes.INPUT_NAVIGATION:
+ case KeyTypes.KEYPAD_NAVIGATION:
+ backgroundStyle = styles.control;
+ break;
+
+ case KeyTypes.ECHO:
+ backgroundStyle = null;
+ break;
+ }
+
+ const borderStyle = [];
+ if (borders.indexOf(BorderDirections.LEFT) !== -1) {
+ borderStyle.push(styles.leftBorder);
+ }
+ if (borders.indexOf(BorderDirections.BOTTOM) !== -1) {
+ borderStyle.push(styles.bottomBorder);
+ }
+
+ return [
+ styles.buttonBase,
+ backgroundStyle,
+ ...borderStyle,
+ type === KeyTypes.ECHO && styles.echo,
+ this.buttonSizeStyle,
+ // React Native allows you to set the 'style' props on user defined
+ // components.
+ // See: https://facebook.github.io/react-native/docs/style.html
+ ...(Array.isArray(style) ? style : [style]),
+ ];
+ },
+
+ render() {
+ const {
+ ariaLabel,
+ borders,
+ childKeys,
+ disabled,
+ focused,
+ icon,
+ onTouchCancel,
+ onTouchEnd,
+ onTouchMove,
+ onTouchStart,
+ popoverEnabled,
+ style,
+ type,
+ } = this.props;
+
+ // We render in the focus state if the key is focused, or if it's an
+ // echo.
+ const renderFocused = !disabled && focused || popoverEnabled ||
+ type === KeyTypes.ECHO;
+ const buttonStyle = this._getButtonStyle(type, borders, style);
+ const focusStyle = this._getFocusStyle(type);
+ const iconWrapperStyle = [
+ styles.iconWrapper,
+ disabled && styles.disabled,
+ ];
+
+ const eventHandlers = {
+ onTouchCancel, onTouchEnd, onTouchMove, onTouchStart,
+ };
+
+ const maybeFocusBox = renderFocused &&
;
+ const maybeCornerDecal = !renderFocused && !disabled && childKeys &&
+ childKeys.length > 0 &&
;
+
+ if (type === KeyTypes.EMPTY) {
+ return
;
+ } else if (type === KeyTypes.MANY) {
+ // TODO(charlie): Make the long-press interaction accessible. See
+ // the TODO in key-configs.js for more.
+ const manyButtonA11yMarkup = {
+ role: 'button',
+ ariaLabel: childKeys[0].ariaLabel,
+ };
+ const icons = childKeys.map(keyConfig => {
+ return keyConfig.icon;
+ });
+ return
+ {maybeFocusBox}
+
+
+
+ {maybeCornerDecal}
+ ;
+ } else {
+ const a11yMarkup = {
+ role: 'button',
+ ariaLabel: ariaLabel,
+ };
+
+ return
+ {maybeFocusBox}
+
+
+
+ {maybeCornerDecal}
+ ;
+ }
+ },
+});
+
+const focusInsetPx = 4;
+const focusBoxZIndex = 0;
+
+const styles = StyleSheet.create({
+ buttonBase: {
+ // HACK(benkomalo): support old style flex box in Android browsers
+ '-webkit-box-flex': '1',
+ flex: 1,
+ cursor: 'pointer',
+ // Make the text unselectable
+ userSelect: 'none',
+ justifyContent: 'center',
+ alignItems: 'center',
+ // Borders are made selectively visible.
+ borderColor: innerBorderColor,
+ borderStyle: innerBorderStyle,
+ boxSizing: 'border-box',
+ },
+
+ decalInset: {
+ top: focusInsetPx,
+ right: focusInsetPx,
+ },
+
+ // Overrides for the echo state, where we want to render the borders for
+ // layout purposes, but we don't want them to be visible.
+ echo: {
+ borderColor: 'transparent',
+ },
+
+ // Background colors and other base styles that may vary between key types.
+ value: {
+ backgroundColor: valueGrey,
+ },
+ operator: {
+ backgroundColor: operatorGrey,
+ },
+ control: {
+ backgroundColor: controlGrey,
+ },
+ empty: {
+ backgroundColor: emptyGrey,
+ cursor: 'default',
+ },
+
+ bright: {
+ backgroundColor: brightGreen,
+ },
+ light: {
+ backgroundColor: 'rgba(33, 36, 44, 0.1)',
+ },
+
+ iconWrapper: {
+ zIndex: focusBoxZIndex + 1,
+ },
+
+ focusBox: {
+ position: 'absolute',
+ zIndex: focusBoxZIndex,
+ left: focusInsetPx,
+ right: focusInsetPx,
+ bottom: focusInsetPx,
+ top: focusInsetPx,
+ borderRadius: 1,
+ },
+
+ disabled: {
+ opacity: 0.3,
+ },
+
+ // Styles used to render the appropriate borders. Buttons are only allowed
+ // to render left and bottom borders, to simplify layout.
+ leftBorder: {
+ borderLeftWidth: innerBorderWidthPx,
+ },
+ bottomBorder: {
+ borderBottomWidth: innerBorderWidthPx,
+ },
+});
+
+const styleForButtonDimensions = (heightPx, widthPx) => {
+ return StyleSheet.create({
+ buttonSize: {
+ height: heightPx,
+ width: widthPx,
+ maxWidth: widthPx,
+ },
+ }).buttonSize;
+};
+
+const mapStateToProps = (state) => {
+ return state.layout.buttonDimensions;
+};
+
+module.exports = connect(mapStateToProps)(KeypadButton);
diff --git a/src/components/math-input/components/keypad-container.js b/src/components/math-input/components/keypad-container.js
new file mode 100644
index 0000000..366dfe5
--- /dev/null
+++ b/src/components/math-input/components/keypad-container.js
@@ -0,0 +1,298 @@
+const React = require('react');
+const { connect } = require('react-redux');
+const { StyleSheet } = require('aphrodite');
+
+const { View } = require('../fake-react-native-web');
+const FractionKeypad = require('./fraction-keypad');
+const ExpressionKeypad = require('./expression-keypad');
+const NavigationPad = require('./navigation-pad');
+const zIndexes = require('./z-indexes');
+const { setPageSize } = require('../actions');
+const { keyIdPropType } = require('./prop-types');
+const { KeypadTypes, LayoutModes } = require('../consts');
+const { row, centered, fullWidth } = require('./styles');
+const {
+ innerBorderColor,
+ innerBorderStyle,
+ innerBorderWidthPx,
+ compactKeypadBorderRadiusPx,
+} = require('./common-style');
+
+const KeypadContainer = React.createClass({
+ propTypes: {
+ active: React.PropTypes.bool,
+ extraKeys: React.PropTypes.arrayOf(keyIdPropType),
+ keypadType: React.PropTypes.oneOf(Object.keys(KeypadTypes)).isRequired,
+ layoutMode: React.PropTypes.oneOf(Object.keys(LayoutModes)).isRequired,
+ navigationPadEnabled: React.PropTypes.bool.isRequired,
+ onDismiss: React.PropTypes.func,
+ // A callback that should be triggered with the root React element on
+ // mount.
+ onElementMounted: React.PropTypes.func,
+ onPageSizeChange: React.PropTypes.func.isRequired,
+ style: React.PropTypes.any,
+ },
+
+ getInitialState() {
+ // Use (partially unsupported) viewport units until componentDidMount.
+ // It's okay to use the viewport units since they'll be overridden as
+ // soon as the JavaScript kicks in.
+ return {
+ hasBeenActivated: false,
+ viewportWidth: "100vw",
+ };
+ },
+
+ componentWillMount() {
+ if (this.props.active) {
+ this.setState({
+ hasBeenActivated: this.props.active,
+ });
+ }
+ },
+
+ componentDidMount() {
+ // Relay the initial size metrics.
+ this._onResize();
+
+ // And update it on resize.
+ window.addEventListener("resize", this._throttleResizeHandler);
+ window.addEventListener(
+ "orientationchange", this._throttleResizeHandler
+ );
+ },
+
+ componentWillReceiveProps(nextProps) {
+ if (!this.state.hasBeenActivated && nextProps.active) {
+ this.setState({
+ hasBeenActivated: true,
+ });
+ }
+ },
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.active && !this.props.active) {
+ this.props.onDismiss && this.props.onDismiss();
+ }
+ },
+
+ componentWillUnmount() {
+ window.removeEventListener("resize", this._throttleResizeHandler);
+ window.removeEventListener(
+ "orientationchange", this._throttleResizeHandler
+ );
+ },
+
+ _throttleResizeHandler() {
+ // Throttle the resize callbacks.
+ // https://developer.mozilla.org/en-US/docs/Web/Events/resize
+ if (this._resizeTimeout == null) {
+ this._resizeTimeout = setTimeout(() => {
+ this._resizeTimeout = null;
+
+ this._onResize();
+ }, 66);
+ }
+ },
+
+ _onResize() {
+ // Whenever the page resizes, we need to force an update, as the button
+ // heights and keypad width are computed based on horizontal space.
+ this.setState({
+ viewportWidth: window.innerWidth,
+ });
+
+ this.props.onPageSizeChange(window.innerWidth, window.innerHeight);
+ },
+
+ renderKeypad() {
+ const {
+ extraKeys,
+ keypadType,
+ layoutMode,
+ navigationPadEnabled,
+ } = this.props;
+
+ const keypadProps = {
+ extraKeys,
+ // HACK(charlie): In order to properly round the corners of the
+ // compact keypad, we need to instruct some of our child views to
+ // crop themselves. At least we're colocating all the layout
+ // information in this component, though.
+ roundTopLeft: layoutMode === LayoutModes.COMPACT && !navigationPadEnabled,
+ roundTopRight: layoutMode === LayoutModes.COMPACT,
+ };
+
+ // Select the appropriate keyboard given the type.
+ // TODO(charlie): In the future, we might want to move towards a
+ // data-driven approach to defining keyboard layouts, and have a
+ // generic keyboard that takes some "keyboard data" and renders it.
+ // However, the keyboards differ pretty heavily right now and it's not
+ // clear what that format would look like exactly. Plus, there aren't
+ // very many of them. So to keep us moving, we'll just hardcode.
+ switch (keypadType) {
+ case KeypadTypes.FRACTION:
+ return
;
+
+ case KeypadTypes.EXPRESSION:
+ return
;
+
+ default:
+ throw new Error("Invalid keypad type: " + keypadType);
+ }
+ },
+
+ render() {
+ const {
+ active,
+ layoutMode,
+ navigationPadEnabled,
+ onElementMounted,
+ style,
+ } = this.props;
+ const { hasBeenActivated } = this.state;
+
+ // NOTE(charlie): We render the transforms as pure inline styles to
+ // avoid an Aphrodite bug in mobile Safari.
+ // See: https://github.com/Khan/aphrodite/issues/68.
+ const dynamicStyle = {
+ ...(active ? inlineStyles.active : inlineStyles.hidden),
+ ...(!active && !hasBeenActivated ? inlineStyles.invisible : {}),
+ };
+
+ const keypadContainerStyle = [
+ row,
+ centered,
+ fullWidth,
+ styles.keypadContainer,
+ ...(Array.isArray(style) ? style : [style]),
+ ];
+
+ const keypadStyle = [
+ row,
+ styles.keypadBorder,
+ layoutMode === LayoutModes.FULLSCREEN ? styles.fullscreen
+ : styles.compact,
+ ];
+
+ // TODO(charlie): When the keypad is shorter than the width of the
+ // screen, add a border on its left and right edges, and round out the
+ // corners.
+ return
+ {
+ if (!this.hasMounted && element) {
+ this.hasMounted = true;
+ onElementMounted(element);
+ }
+ }}
+ >
+ {navigationPadEnabled &&
+
+ }
+
+ {this.renderKeypad()}
+
+
+ ;
+ },
+});
+
+const keypadAnimationDurationMs = 300;
+const borderWidthPx = 1;
+
+const styles = StyleSheet.create({
+ keypadContainer: {
+ bottom: 0,
+ left: 0,
+ right: 0,
+ position: 'fixed',
+ transition: `${keypadAnimationDurationMs}ms ease-out`,
+ transitionProperty: 'transform',
+ zIndex: zIndexes.keypad,
+ },
+
+ keypadBorder: {
+ boxShadow: '0 1px 4px 0 rgba(0, 0, 0, 0.1)',
+ borderColor: 'rgba(0, 0, 0, 0.2)',
+ borderStyle: 'solid',
+ },
+
+ fullscreen: {
+ borderTopWidth: borderWidthPx,
+ },
+
+ compact: {
+ borderTopRightRadius: compactKeypadBorderRadiusPx,
+ borderTopLeftRadius: compactKeypadBorderRadiusPx,
+
+ borderTopWidth: borderWidthPx,
+ borderRightWidth: borderWidthPx,
+ borderLeftWidth: borderWidthPx,
+ },
+
+ navigationPadContainer: {
+ // Add a separator between the navigation pad and the keypad.
+ borderRight: `${innerBorderWidthPx}px ${innerBorderStyle} `
+ + `${innerBorderColor}`,
+ boxSizing: 'content-box',
+ },
+
+ // Defer to the navigation pad, such that the navigation pad is always
+ // rendered at full-width, and the keypad takes up just the remaining space.
+ // TODO(charlie): Avoid shrinking the keys and, instead, make the keypad
+ // scrollable.
+ keypadLayout: {
+ flexGrow: 1,
+ // Avoid unitless flex-basis, per: https://philipwalton.com/articles/normalizing-cross-browser-flexbox-bugs/
+ flexBasis: '0%',
+ },
+});
+
+// Note: these don't go through an autoprefixer/aphrodite.
+const inlineStyles = {
+ // If the keypad is yet to have ever been activated, we keep it invisible
+ // so as to avoid, e.g., the keypad flashing at the bottom of the page
+ // during the initial render.
+ invisible: {
+ visibility: 'hidden',
+ },
+
+ hidden: {
+ msTransform: 'translate3d(0, 100%, 0)',
+ WebkitTransform: 'translate3d(0, 100%, 0)',
+ transform: 'translate3d(0, 100%, 0)',
+ },
+
+ active: {
+ msTransform: 'translate3d(0, 0, 0)',
+ WebkitTransform: 'translate3d(0, 0, 0)',
+ transform: 'translate3d(0, 0, 0)',
+ },
+};
+
+const mapStateToProps = (state) => {
+ return {
+ ...state.keypad,
+ layoutMode: state.layout.layoutMode,
+ navigationPadEnabled: state.layout.navigationPadEnabled,
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onPageSizeChange: (pageWidthPx, pageHeightPx) => {
+ dispatch(setPageSize(pageWidthPx, pageHeightPx));
+ },
+ };
+};
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(KeypadContainer);
diff --git a/src/components/math-input/components/keypad.js b/src/components/math-input/components/keypad.js
new file mode 100644
index 0000000..8e86547
--- /dev/null
+++ b/src/components/math-input/components/keypad.js
@@ -0,0 +1,145 @@
+/**
+ * A keypad component that acts as a container for rows or columns of buttons,
+ * and manages the rendering of echo animations on top of those buttons.
+ */
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+const { connect } = require('react-redux');
+
+const { removeEcho } = require('../actions');
+const { View } = require('../fake-react-native-web');
+const EchoManager = require('./echo-manager');
+const PopoverManager = require('./popover-manager');
+const { echoPropType, popoverPropType } = require('./prop-types');
+
+const Keypad = React.createClass({
+ propTypes: {
+ // Whether the keypad is active, i.e., whether it should be rendered as
+ // visible or invisible.
+ active: React.PropTypes.bool,
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.node),
+ React.PropTypes.node,
+ ]),
+ echoes: React.PropTypes.arrayOf(echoPropType).isRequired,
+ popover: popoverPropType,
+ removeEcho: React.PropTypes.func.isRequired,
+ style: React.PropTypes.any,
+ },
+
+ componentDidMount() {
+ window.addEventListener("resize", this._onResize);
+ this._updateSizeAndPosition();
+ },
+
+ componentWillReceiveProps(newProps) {
+ if (!this._container && (newProps.popover || newProps.echoes.length)) {
+ this._computeContainer();
+ }
+ },
+
+ componentWillUnmount() {
+ window.removeEventListener("resize", this._onResize);
+ },
+
+ _computeContainer() {
+ const domNode = ReactDOM.findDOMNode(this);
+ this._container = domNode.getBoundingClientRect();
+ },
+
+ _updateSizeAndPosition() {
+ // Mark the container for recalculation next time the keypad is
+ // opened.
+ // TODO(charlie): Since we're not recalculating the container
+ // immediately, if you were to resize the page while a popover were
+ // active, you'd likely get unexpected behavior. This seems very
+ // difficult to do and, as such, incredibly unlikely, but we may
+ // want to reconsider the caching here.
+ this._container = null;
+ },
+
+ _onResize() {
+ // Whenever the page resizes, we need to recompute the container's
+ // bounding box. This is the only time that the bounding box can change.
+
+ // Throttle resize events -- taken from:
+ // https://developer.mozilla.org/en-US/docs/Web/Events/resize
+ if (this._resizeTimeout == null) {
+ this._resizeTimeout = setTimeout(() => {
+ this._resizeTimeout = null;
+
+ if (this.isMounted()) {
+ this._updateSizeAndPosition();
+ }
+ }, 66);
+ }
+ },
+
+ render() {
+ const {
+ children,
+ echoes,
+ removeEcho,
+ popover,
+ style,
+ } = this.props;
+
+ // Translate the echo boxes, as they'll be positioned absolutely to
+ // this relative container.
+ const relativeEchoes = echoes.map(echo => {
+ const { initialBounds, ...rest } = echo;
+ return {
+ ...rest,
+ initialBounds: {
+ top: initialBounds.top - this._container.top,
+ right: initialBounds.right - this._container.left,
+ bottom: initialBounds.bottom - this._container.top,
+ left: initialBounds.left - this._container.left,
+ width: initialBounds.width,
+ height: initialBounds.height,
+ },
+ };
+ });
+
+ // Translate the popover bounds from page-absolute to keypad-relative.
+ // Note that we only need three bounds, since popovers are anchored to
+ // the bottom left corners of the keys over which they appear.
+ const relativePopover = popover && {
+ ...popover,
+ bounds: {
+ bottom: this._container.height - (popover.bounds.bottom -
+ this._container.top),
+ left: popover.bounds.left - this._container.left,
+ width: popover.bounds.width,
+ },
+ };
+
+ return
+ {children}
+
+
+ ;
+ },
+});
+
+const mapStateToProps = (state) => {
+ return {
+ ...state.echoes,
+ active: state.keypad.active,
+ popover: state.gestures.popover,
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ removeEcho: (animationId) => {
+ dispatch(removeEcho(animationId));
+ },
+ };
+};
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(Keypad);
diff --git a/src/components/math-input/components/many-keypad-button.js b/src/components/math-input/components/many-keypad-button.js
new file mode 100644
index 0000000..321c238
--- /dev/null
+++ b/src/components/math-input/components/many-keypad-button.js
@@ -0,0 +1,43 @@
+/**
+ * A keypad button that displays an arbitrary number of symbols, with no
+ * 'default' symbol.
+ */
+
+const React = require('react');
+
+const EmptyKeypadButton = require('./empty-keypad-button');
+const TouchableKeypadButton = require('./touchable-keypad-button');
+
+const Keys = require('../data/keys');
+const KeyConfigs = require('../data/key-configs');
+const { KeyTypes } = require('../consts');
+const { keyIdPropType } = require('./prop-types');
+
+const ManyKeypadButton = React.createClass({
+ propTypes: {
+ keys: React.PropTypes.arrayOf(keyIdPropType).isRequired,
+ },
+
+ render() {
+ const { keys, ...rest } = this.props;
+
+ // If we have no extra symbols, render an empty button. If we have just
+ // one, render a standard button. Otherwise, capture them all in a
+ // single button.
+ if (keys.length === 0) {
+ return
;
+ } else if (keys.length === 1) {
+ const keyConfig = KeyConfigs[keys[0]];
+ return
;
+ } else {
+ const keyConfig = {
+ id: Keys.MANY,
+ type: KeyTypes.MANY,
+ childKeyIds: keys,
+ };
+ return
;
+ }
+ },
+});
+
+module.exports = ManyKeypadButton;
diff --git a/src/components/math-input/components/math-icon.js b/src/components/math-input/components/math-icon.js
new file mode 100644
index 0000000..bd26d6d
--- /dev/null
+++ b/src/components/math-input/components/math-icon.js
@@ -0,0 +1,61 @@
+/**
+ * A component that renders an icon with math (via KaTeX).
+ */
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+const { StyleSheet } = require('aphrodite');
+const katex = require('katex');
+
+const { View } = require('../fake-react-native-web');
+const { row, centered } = require('./styles');
+const { iconSizeHeightPx, iconSizeWidthPx } = require('./common-style');
+
+const MathIcon = React.createClass({
+ propTypes: {
+ math: React.PropTypes.string.isRequired,
+ style: React.PropTypes.any,
+ },
+
+ componentDidMount() {
+ this._renderMath();
+ },
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.math !== this.props.math) {
+ this._renderMath();
+ }
+ },
+
+ _renderMath() {
+ const { math } = this.props;
+ katex.render(math, ReactDOM.findDOMNode(this));
+ },
+
+ render() {
+ const { style } = this.props;
+
+ const containerStyle = [
+ row,
+ centered,
+ styles.size,
+ styles.base,
+ ...(Array.isArray(style) ? style : [style]),
+ ];
+
+ return
;
+ },
+});
+
+const styles = StyleSheet.create({
+ size: {
+ height: iconSizeHeightPx,
+ width: iconSizeWidthPx,
+ },
+
+ base: {
+ fontSize: 25,
+ },
+});
+
+module.exports = MathIcon;
diff --git a/src/components/math-input/components/multi-symbol-grid.js b/src/components/math-input/components/multi-symbol-grid.js
new file mode 100644
index 0000000..3dbf41b
--- /dev/null
+++ b/src/components/math-input/components/multi-symbol-grid.js
@@ -0,0 +1,155 @@
+/**
+ * A grid of symbols, rendered as text and positioned based on the number of
+ * symbols provided. Up to four symbols will be shown.
+ */
+
+const React = require('react');
+const { StyleSheet } = require('aphrodite');
+
+const { View } = require('../fake-react-native-web');
+const Icon = require('./icon');
+const { IconTypes } = require('../consts');
+const { iconPropType } = require('./prop-types');
+const { row, column, centered, fullWidth } = require('./styles');
+const { iconSizeHeightPx, iconSizeWidthPx } = require('./common-style');
+
+const MultiSymbolGrid = React.createClass({
+ propTypes: {
+ focused: React.PropTypes.bool,
+ icons: React.PropTypes.arrayOf(iconPropType).isRequired,
+ },
+
+ render() {
+ const { focused, icons } = this.props;
+
+ // Validate that we only received math-based icons. Right now, this
+ // component only supports math icons (and it should only be passed
+ // variables and Greek letters, which are always rendered as math).
+ // Supporting other types of icons is possible but would require
+ // some styles coercion and doesn't seem worthwhile right now.
+ icons.forEach(icon => {
+ if (icon.type !== IconTypes.MATH) {
+ throw new Error(`Received invalid icon: type=${icon.type}, ` +
+ `data=${icon.data}`);
+ }
+ });
+
+ if (icons.length === 1) {
+ return
;
+ } else {
+ const primaryIconStyle = styles.base;
+ const secondaryIconStyle = [
+ styles.base,
+ styles.secondary,
+ ];
+
+ if (icons.length === 2) {
+ return
+
+
+
+
+
+
+ ;
+ } else if (icons.length >= 3) {
+ return
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {icons[3] && }
+
+
+ ;
+ }
+ }
+
+ throw new Error("Invalid number of icons:", icons.length);
+ },
+});
+
+const verticalInsetPx = 2;
+const horizontalInsetPx = 4;
+
+const styles = StyleSheet.create({
+ size: {
+ height: iconSizeHeightPx,
+ width: iconSizeWidthPx,
+ },
+
+ // For the three- and four-icon layouts.
+ bottomLeft: {
+ marginBottom: verticalInsetPx,
+ marginLeft: horizontalInsetPx,
+ },
+ topLeft: {
+ marginTop: verticalInsetPx,
+ marginLeft: horizontalInsetPx,
+ },
+ topRight: {
+ marginTop: verticalInsetPx,
+ marginRight: horizontalInsetPx,
+ },
+ bottomRight: {
+ marginBottom: verticalInsetPx,
+ marginRight: horizontalInsetPx,
+ },
+
+ // For the two-icon layout.
+ middleLeft: {
+ marginLeft: horizontalInsetPx,
+ },
+ middleRight: {
+ marginRight: horizontalInsetPx,
+ },
+
+ base: {
+ fontSize: 18,
+ },
+
+ secondary: {
+ opacity: 0.3,
+ },
+});
+
+module.exports = MultiSymbolGrid;
diff --git a/src/components/math-input/components/multi-symbol-popover.js b/src/components/math-input/components/multi-symbol-popover.js
new file mode 100644
index 0000000..50a0b4b
--- /dev/null
+++ b/src/components/math-input/components/multi-symbol-popover.js
@@ -0,0 +1,52 @@
+/**
+ * A popover that renders a set of keys floating above the page.
+ */
+
+const React = require('react');
+const { StyleSheet } = require('aphrodite');
+
+const { View } = require('../fake-react-native-web');
+const { keyConfigPropType } = require('./prop-types');
+const { BorderStyles } = require('../consts');
+const zIndexes = require('./z-indexes');
+
+const MultiSymbolPopover = React.createClass({
+ propTypes: {
+ keys: React.PropTypes.arrayOf(keyConfigPropType),
+ },
+
+ render() {
+ const { keys } = this.props;
+
+ // TODO(charlie): We have to require this lazily because of a cyclic
+ // dependence in our components.
+ const TouchableKeypadButton = require('./touchable-keypad-button');
+ return
+ {keys.map(key => {
+ return ;
+ })}
+ ;
+ },
+});
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'column-reverse',
+ position: 'relative',
+ width: '100%',
+ borderRadius: 2,
+ boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)',
+ zIndex: zIndexes.popover,
+ },
+
+ popoverButton: {
+ backgroundColor: '#FFF',
+ borderWidth: 0,
+ },
+});
+
+module.exports = MultiSymbolPopover;
diff --git a/src/components/math-input/components/navigation-pad.js b/src/components/math-input/components/navigation-pad.js
new file mode 100644
index 0000000..c6ce4ec
--- /dev/null
+++ b/src/components/math-input/components/navigation-pad.js
@@ -0,0 +1,132 @@
+/**
+ * A component that renders a navigation pad, which consists of an arrow for
+ * each possible direction.
+ */
+const React = require('react');
+
+const { StyleSheet } = require('aphrodite');
+const { View } = require('../fake-react-native-web');
+const TouchableKeypadButton = require('./touchable-keypad-button');
+const { row, column, centered, stretch, roundedTopLeft } = require('./styles');
+const {
+ navigationPadWidthPx,
+ controlGrey,
+ valueGrey,
+ gray85,
+} = require('./common-style');
+const { BorderStyles } = require('../consts');
+const KeyConfigs = require('../data/key-configs');
+
+const NavigationPad = React.createClass({
+ propTypes: {
+ roundTopLeft: React.PropTypes.bool,
+ style: React.PropTypes.any,
+ },
+
+ render() {
+ // TODO(charlie): Disable the navigational arrows depending on the
+ // cursor context.
+ const { roundTopLeft, style } = this.props;
+
+ const containerStyle = [
+ column,
+ centered,
+ styles.container,
+ roundTopLeft && roundedTopLeft,
+ ...(Array.isArray(style) ? style : [style]),
+ ];
+
+ return
+
+
+
+
+
+
+
+
+
+
+
+ ;
+ },
+});
+
+const buttonSizePx = 48;
+const borderRadiusPx = 4;
+const borderWidthPx = 1;
+
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: controlGrey,
+ width: navigationPadWidthPx,
+ },
+
+ navigationKey: {
+ borderColor: gray85,
+ backgroundColor: valueGrey,
+ width: buttonSizePx,
+ height: buttonSizePx,
+
+ // Override the default box-sizing so that our buttons are
+ // `buttonSizePx` exclusive of their borders.
+ boxSizing: 'content-box',
+ },
+
+ topArrow: {
+ borderTopWidth: borderWidthPx,
+ borderLeftWidth: borderWidthPx,
+ borderRightWidth: borderWidthPx,
+ borderTopLeftRadius: borderRadiusPx,
+ borderTopRightRadius: borderRadiusPx,
+ },
+
+ rightArrow: {
+ borderTopWidth: borderWidthPx,
+ borderRightWidth: borderWidthPx,
+ borderBottomWidth: borderWidthPx,
+ borderTopRightRadius: borderRadiusPx,
+ borderBottomRightRadius: borderRadiusPx,
+ },
+
+ bottomArrow: {
+ borderBottomWidth: borderWidthPx,
+ borderLeftWidth: borderWidthPx,
+ borderRightWidth: borderWidthPx,
+ borderBottomLeftRadius: borderRadiusPx,
+ borderBottomRightRadius: borderRadiusPx,
+ },
+
+ leftArrow: {
+ borderTopWidth: borderWidthPx,
+ borderBottomWidth: borderWidthPx,
+ borderLeftWidth: borderWidthPx,
+ borderTopLeftRadius: borderRadiusPx,
+ borderBottomLeftRadius: borderRadiusPx,
+ },
+
+ horizontalSpacer: {
+ background: valueGrey,
+ // No need to set a height -- the spacer will be stretched by its
+ // parent.
+ width: buttonSizePx,
+ },
+});
+
+module.exports = NavigationPad;
diff --git a/src/components/math-input/components/node-manager.js b/src/components/math-input/components/node-manager.js
new file mode 100644
index 0000000..7d24ec1
--- /dev/null
+++ b/src/components/math-input/components/node-manager.js
@@ -0,0 +1,122 @@
+/**
+ * A manager for our node-to-ID system. In particular, this class is
+ * responsible for maintaing a mapping between DOM nodes and node IDs, and
+ * translating touch events from the raw positions at which they occur to the
+ * nodes over which they are occurring. This differs from browser behavior, in
+ * which touch events are only sent to the node in which a touch started.
+ */
+
+class NodeManager {
+ constructor() {
+ // A mapping from IDs to DOM nodes.
+ this._nodesById = {};
+
+ // A mapping from IDs to the borders around the DOM nodes, which can be
+ // useful for layout purposes.
+ this._bordersById = {};
+
+ // An ordered list of IDs, where DOM nodes that are "higher" on the
+ // page come earlier in the list. Note that an ID may be present in
+ // this ordered list but not be registered to a DOM node (i.e., if it
+ // is registered as a child of another DOM node, but hasn't appeared in
+ // the DOM yet).
+ this._orderedIds = [];
+
+ // Cache bounding boxes aggressively, re-computing on page resize. Our
+ // caching here makes the strict assumption that if a node is reasonably
+ // assumed to be on-screen, its bounds won't change. For example, if we
+ // see that a touch occurred within the bounds of a node, we cache those
+ // bounds.
+ // TODO(charlie): It'd be great if we could pre-compute these when the
+ // page is idle and the keypad is visible (i.e., the nodes are in their
+ // proper positions).
+ this._cachedBoundingBoxesById = {};
+ window.addEventListener('resize', () => {
+ this._cachedBoundingBoxesById = {};
+ });
+ }
+
+ /**
+ * Register a DOM node with a given identifier.
+ *
+ * @param {string} id - the identifier of the given node
+ * @param {node} domNode - the DOM node linked to the identifier
+ * @param {object} borders - an opaque object describing the node's borders
+ */
+ registerDOMNode(id, domNode, childIds, borders) {
+ this._nodesById[id] = domNode;
+ this._bordersById[id] = borders;
+
+ // Make sure that any children appear first.
+ // TODO(charlie): This is a very simplistic system that wouldn't
+ // properly handle multiple levels of nesting.
+ const allIds = [...(childIds || []), id, ...this._orderedIds];
+
+ // De-dupe the list of IDs.
+ const orderedIds = [];
+ const seenIds = {};
+ for (const id of allIds) {
+ if (!seenIds[id]) {
+ orderedIds.push(id);
+ seenIds[id] = true;
+ }
+ }
+
+ this._orderedIds = orderedIds;
+ }
+
+ /**
+ * Unregister the DOM node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node to unregister
+ */
+ unregisterDOMNode(id) {
+ delete this._nodesById[id];
+ }
+
+ /**
+ * Return the identifier of the topmost node located at the given
+ * coordinates.
+ *
+ * @param {number} x - the x coordinate at which to search for a node
+ * @param {number} y - the y coordinate at which to search for a node
+ * @returns {null|string} - null or the identifier of the topmost node at
+ * the given coordinates
+ */
+ idForCoords(x, y) {
+ for (const id of this._orderedIds) {
+ const domNode = this._nodesById[id];
+ if (domNode) {
+ const bounds = domNode.getBoundingClientRect();
+ if (bounds.left <= x && bounds.right > x
+ && bounds.top <= y && bounds.bottom > y) {
+ this._cachedBoundingBoxesById[id] = bounds;
+ return id;
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the necessary layout information, including the bounds and border
+ * values, for the node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node for which to return the
+ * layout information
+ * @returns {object} - the bounding client rect for the given node, along
+ * with its borders
+ */
+ layoutPropsForId(id) {
+ if (!this._cachedBoundingBoxesById[id]) {
+ this._cachedBoundingBoxesById[id] =
+ this._nodesById[id].getBoundingClientRect();
+ }
+
+ return {
+ initialBounds: this._cachedBoundingBoxesById[id],
+ borders: this._bordersById[id],
+ };
+ }
+}
+
+module.exports = NodeManager;
diff --git a/src/components/math-input/components/pager-indicator.js b/src/components/math-input/components/pager-indicator.js
new file mode 100644
index 0000000..3b7c820
--- /dev/null
+++ b/src/components/math-input/components/pager-indicator.js
@@ -0,0 +1,94 @@
+/**
+ * A component that renders a view pager indicator, with a circular icon for
+ * each page.
+ */
+
+const React = require('react');
+const { StyleSheet } = require('aphrodite');
+
+const { View } = require('../fake-react-native-web');
+const { pageIndicatorHeightPx, gray68, gray85 } = require('./common-style');
+
+const PagerIcon = React.createClass({
+ propTypes: {
+ active: React.PropTypes.bool,
+ radiusPx: React.PropTypes.number,
+ },
+
+ getDefaultProps() {
+ return {
+ active: false,
+ radiusPx: 4,
+ };
+ },
+
+ render() {
+ const { active, radiusPx } = this.props;
+
+ const fillColor = active ? gray68 : gray85;
+
+ return
;
+ },
+});
+
+const PagerIndicator = React.createClass({
+ propTypes: {
+ currentPage: React.PropTypes.number.isRequired,
+ numPages: React.PropTypes.number.isRequired,
+ },
+
+ render() {
+ const { currentPage, numPages } = this.props;
+
+ const pagerIconRadiusPx = 4;
+
+ // Collect the various indicator circles.
+ const indicators = [];
+ for (let i = 0; i < numPages; i++) {
+ indicators.push(
+
+ );
+ }
+
+ // Size the box that contains the icons to accommodate for proper
+ // spacing, and let Flexbox take care of the details.
+ const totalIconWidthPx = 2 * pagerIconRadiusPx * numPages;
+ const totalSpacingWidthPx = 2 * pagerIconRadiusPx * (numPages - 1);
+ const iconStripSize = {
+ width: totalIconWidthPx + totalSpacingWidthPx,
+ };
+
+ return
+
+ {indicators}
+
+ ;
+ },
+});
+
+const styles = StyleSheet.create({
+ indicatorStrip: {
+ backgroundColor: '#F0F1F2',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: pageIndicatorHeightPx,
+ },
+ iconStrip: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+});
+
+module.exports = PagerIndicator;
diff --git a/src/components/math-input/components/popover-manager.js b/src/components/math-input/components/popover-manager.js
new file mode 100644
index 0000000..b682963
--- /dev/null
+++ b/src/components/math-input/components/popover-manager.js
@@ -0,0 +1,67 @@
+/**
+ * A component that renders and animates the popovers that appear over the
+ * multi-functional keys.
+ */
+
+const React = require('react');
+const ReactCSSTransitionGroup = require('react-addons-css-transition-group');
+
+const KeyConfigs = require('../data/key-configs');
+const MultiSymbolPopover = require('./multi-symbol-popover');
+const {
+ boundingBoxPropType,
+ keyConfigPropType,
+ popoverPropType,
+} = require('./prop-types');
+
+// NOTE(charlie): These must be kept in sync with the transition durations and
+// classnames specified in popover.css.
+const animationTransitionName = 'popover';
+const animationDurationMs = 200;
+
+// A container component used to position a popover absolutely at a specific
+// position.
+const PopoverContainer = React.createClass({
+ propTypes: {
+ bounds: boundingBoxPropType.isRequired,
+ childKeys: React.PropTypes.arrayOf(keyConfigPropType).isRequired,
+ },
+
+ render() {
+ const { bounds, childKeys } = this.props;
+
+ const containerStyle = {
+ position: 'absolute',
+ ...bounds,
+ };
+
+ return
+
+
;
+ },
+});
+
+const PopoverManager = React.createClass({
+ propTypes: {
+ popover: popoverPropType,
+ },
+
+ render() {
+ const { popover } = this.props;
+
+ return
+ {popover && KeyConfigs[id])}
+ />}
+ ;
+ },
+});
+
+module.exports = PopoverManager;
diff --git a/src/components/math-input/components/popover-state-machine.js b/src/components/math-input/components/popover-state-machine.js
new file mode 100644
index 0000000..ff59448
--- /dev/null
+++ b/src/components/math-input/components/popover-state-machine.js
@@ -0,0 +1,173 @@
+/**
+ * A state machine for the popover state. In particular, this class manages the
+ * mapping of parent nodes to their children, and translates touch events that
+ * traverse various nodes to actions that are conditioned on whether a popover
+ * is present.
+ */
+
+class PopoverStateMachine {
+ constructor(handlers) {
+ this.handlers = handlers;
+
+ this.activePopover = null;
+ this.popovers = {};
+ }
+
+ /**
+ * Register a popover container as containing a set of children.
+ *
+ * @param {string} id - the identifier of the popover container
+ * @param {string[]} childIds - the identifiers of the nodes contained in
+ * the popover container
+ */
+ registerPopover(id, childIds) {
+ this.popovers[id] = childIds;
+ }
+
+ /**
+ * Unregister a popover container.
+ *
+ * @param {string} id - the identifier of the popover container to
+ * unregister
+ */
+ unregisterPopover(id) {
+ delete this.popovers[id];
+ }
+
+ /**
+ * @returns {boolean} - whether a popover is active and visible
+ */
+ isPopoverVisible() {
+ return this.activePopover != null;
+ }
+
+ /**
+ * Blur the active nodes.
+ */
+ onBlur() {
+ this.activePopover = null;
+ this.handlers.onActiveNodesChanged({
+ popover: null,
+ focus: null,
+ });
+ }
+
+ /**
+ * Handle a focus event on the node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node that was focused
+ */
+ onFocus(id) {
+ if (this.activePopover) {
+ // If we have a popover that is currently active, we focus this
+ // node if it's in the popover, and remove any highlight otherwise.
+ if (this._isNodeInsidePopover(this.activePopover, id)) {
+ this.handlers.onActiveNodesChanged({
+ popover: {
+ parentId: this.activePopover,
+ childIds: this.popovers[this.activePopover],
+ },
+ focus: id,
+ });
+ } else {
+ this.handlers.onActiveNodesChanged({
+ popover: {
+ parentId: this.activePopover,
+ childIds: this.popovers[this.activePopover],
+ },
+ focus: null,
+ });
+ }
+ } else {
+ this.activePopover = null;
+ this.handlers.onActiveNodesChanged({
+ popover: null,
+ focus: id,
+ });
+ }
+ }
+
+ /**
+ * Handle a long press event on the node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node that was long-pressed
+ */
+ onLongPress(id) {
+ // We only care about long presses if they occur on a popover, and we
+ // don't already have a popover active.
+ if (!this.activePopover && this.popovers[id]) {
+ // NOTE(charlie): There's an assumption here that focusing the
+ // first child is the correct behavior for a newly focused popover.
+ // This relies on the fact that the children are rendered
+ // bottom-up. If that rendering changes, this logic will need to
+ // change as well.
+ this.activePopover = id;
+ this.handlers.onActiveNodesChanged({
+ popover: {
+ parentId: this.activePopover,
+ childIds: this.popovers[this.activePopover],
+ },
+ focus: this._defaultNodeForPopover(this.activePopover),
+ });
+ }
+ }
+
+ /**
+ * Handle the trigger (click or hold) of the node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node that was triggered
+ */
+ onTrigger(id) {
+ this.handlers.onClick(id, id, false);
+ }
+
+ /**
+ * Handle a touch-end event on the node with the given identifier.
+ *
+ * @param {string} id - the identifier of the node over which the touch
+ * ended
+ */
+ onTouchEnd(id) {
+ const inPopover = !!this.activePopover;
+ if (inPopover) {
+ // If we have a popover that is currently active, we trigger a
+ // click on this node if and only if it's in the popover, with the
+ // exception that, if the node passed back _is_ the active popover,
+ // then we trigger its default node. This latter case should only
+ // be triggered if the user were to tap down on a popover-enabled
+ // node, hold for long enough for the popover to appear, and then
+ // release without ever moving their finger, in which case, the
+ // underlying gesture system would have no idea that the popover's
+ // first child node was now focused.
+ if (this._isNodeInsidePopover(this.activePopover, id)) {
+ this.handlers.onClick(id, id, inPopover);
+ } else if (this.activePopover === id) {
+ const keyId = this._defaultNodeForPopover(id);
+ this.handlers.onClick(keyId, keyId, inPopover);
+ }
+ } else if (this.popovers[id]) {
+ // Otherwise, if the node is itself a popover revealer, trigger the
+ // clicking of its default node, but pass back the popover node ID
+ // for layout purposes.
+ const keyId = this._defaultNodeForPopover(id);
+ const domNodeId = id;
+ this.handlers.onClick(keyId, domNodeId, inPopover);
+ } else if (id != null) {
+ // Finally, if we have no active popover, and we touched up over a
+ // valid key, trigger a click.
+ this.onTrigger(id);
+ }
+
+ this.onBlur();
+ }
+
+ _isNodeInsidePopover(popover, id) {
+ return this.popovers[popover].includes(id);
+ }
+
+ _defaultNodeForPopover(popover) {
+ return this.popovers[popover][0];
+ }
+}
+
+module.exports = PopoverStateMachine;
diff --git a/src/components/math-input/components/prop-types.js b/src/components/math-input/components/prop-types.js
new file mode 100644
index 0000000..faa8e6d
--- /dev/null
+++ b/src/components/math-input/components/prop-types.js
@@ -0,0 +1,96 @@
+/**
+ * React PropTypes that may be shared between components.
+ */
+
+const React = require('react');
+
+const KeyConfigs = require('../data/key-configs');
+const CursorContexts = require('./input/cursor-contexts');
+const {
+ BorderDirections,
+ EchoAnimationTypes,
+ IconTypes,
+ KeyTypes,
+ KeypadTypes,
+} = require('../consts');
+
+const iconPropType = React.PropTypes.shape({
+ type: React.PropTypes.oneOf(Object.keys(IconTypes)).isRequired,
+ data: React.PropTypes.string.isRequired,
+});
+
+const keyIdPropType = React.PropTypes.oneOf(Object.keys(KeyConfigs));
+
+const keyConfigPropType = React.PropTypes.shape({
+ ariaLabel: React.PropTypes.string,
+ id: keyIdPropType.isRequired,
+ type: React.PropTypes.oneOf(Object.keys(KeyTypes)).isRequired,
+ childKeyIds: React.PropTypes.arrayOf(keyIdPropType),
+ icon: iconPropType.isRequired,
+});
+
+const keypadConfigurationPropType = React.PropTypes.shape({
+ keypadType: React.PropTypes.oneOf(Object.keys(KeypadTypes)).isRequired,
+ extraKeys: React.PropTypes.arrayOf(keyIdPropType),
+});
+
+// NOTE(charlie): This is a React element.
+const keypadElementPropType = React.PropTypes.shape({
+ activate: React.PropTypes.func.isRequired,
+ dismiss: React.PropTypes.func.isRequired,
+ configure: React.PropTypes.func.isRequired,
+ setCursor: React.PropTypes.func.isRequired,
+ setKeyHandler: React.PropTypes.func.isRequired,
+});
+
+const bordersPropType = React.PropTypes.arrayOf(
+ React.PropTypes.oneOf(Object.keys(BorderDirections))
+);
+
+const boundingBoxPropType = React.PropTypes.shape({
+ height: React.PropTypes.number,
+ width: React.PropTypes.number,
+ top: React.PropTypes.number,
+ right: React.PropTypes.number,
+ bottom: React.PropTypes.number,
+ left: React.PropTypes.number,
+});
+
+const echoPropType = React.PropTypes.shape({
+ animationId: React.PropTypes.string.isRequired,
+ animationType: React.PropTypes.oneOf(
+ Object.keys(EchoAnimationTypes)
+ ).isRequired,
+ borders: bordersPropType,
+ id: keyIdPropType.isRequired,
+ initialBounds: boundingBoxPropType.isRequired,
+});
+
+const cursorContextPropType = React.PropTypes.oneOf(
+ Object.keys(CursorContexts)
+);
+
+const popoverPropType = React.PropTypes.shape({
+ parentId: keyIdPropType.isRequired,
+ bounds: boundingBoxPropType.isRequired,
+ childKeyIds: React.PropTypes.arrayOf(keyIdPropType).isRequired,
+});
+
+const childrenPropType = React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.node),
+ React.PropTypes.node,
+]);
+
+module.exports = {
+ keyConfigPropType,
+ keyIdPropType,
+ keypadConfigurationPropType,
+ keypadElementPropType,
+ bordersPropType,
+ boundingBoxPropType,
+ echoPropType,
+ cursorContextPropType,
+ popoverPropType,
+ iconPropType,
+ childrenPropType,
+};
diff --git a/src/components/math-input/components/provided-keypad.js b/src/components/math-input/components/provided-keypad.js
new file mode 100644
index 0000000..4f5386c
--- /dev/null
+++ b/src/components/math-input/components/provided-keypad.js
@@ -0,0 +1,77 @@
+const React = require('react');
+const { Provider } = require('react-redux');
+
+const KeypadContainer = require('./keypad-container');
+const {
+ activateKeypad,
+ dismissKeypad,
+ configureKeypad,
+ setCursor,
+ setKeyHandler,
+} = require('../actions');
+const createStore = require('../store');
+
+const ProvidedKeypad = React.createClass({
+ propTypes: {
+ onElementMounted: React.PropTypes.func,
+ },
+
+ componentWillMount() {
+ this.store = createStore();
+ },
+
+ activate() {
+ this.store.dispatch(activateKeypad());
+ },
+
+ dismiss() {
+ this.store.dispatch(dismissKeypad());
+ },
+
+ configure(configuration, cb) {
+ this.store.dispatch(configureKeypad(configuration));
+
+ // HACK(charlie): In Perseus, triggering a focus causes the keypad to
+ // animate into view and re-configure. We'd like to provide the option
+ // to re-render the re-configured keypad before animating it into view,
+ // to avoid jank in the animation. As such, we support passing a
+ // callback into `configureKeypad`. However, implementing this properly
+ // would require middleware, etc., so we just hack it on with
+ // `setTimeout` for now.
+ setTimeout(() => cb && cb());
+ },
+
+ setCursor(cursor) {
+ this.store.dispatch(setCursor(cursor));
+ },
+
+ setKeyHandler(keyHandler) {
+ this.store.dispatch(setKeyHandler(keyHandler));
+ },
+
+ render() {
+ const { onElementMounted, ...rest } = this.props;
+
+ return
+ {
+ // Append the dispatch methods that we want to expose
+ // externally to the returned React element.
+ const elementWithDispatchMethods = {
+ ...element,
+ activate: this.activate,
+ dismiss: this.dismiss,
+ configure: this.configure,
+ setCursor: this.setCursor,
+ setKeyHandler: this.setKeyHandler,
+ };
+ onElementMounted &&
+ onElementMounted(elementWithDispatchMethods);
+ }}
+ {...rest}
+ />
+ ;
+ },
+});
+
+module.exports = ProvidedKeypad;
diff --git a/src/components/math-input/components/styles.js b/src/components/math-input/components/styles.js
new file mode 100644
index 0000000..c01f20f
--- /dev/null
+++ b/src/components/math-input/components/styles.js
@@ -0,0 +1,38 @@
+/**
+ * Common styles shared across components.
+ */
+
+const { StyleSheet } = require('aphrodite');
+
+const { compactKeypadBorderRadiusPx } = require('./common-style');
+
+module.exports = StyleSheet.create({
+ row: {
+ flexDirection: 'row',
+ },
+ column: {
+ flexDirection: 'column',
+ },
+ oneColumn: {
+ flexGrow: 1,
+ },
+ fullWidth: {
+ width: '100%',
+ },
+ stretch: {
+ alignItems: 'stretch',
+ },
+ centered: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ centeredText: {
+ textAlign: 'center',
+ },
+ roundedTopLeft: {
+ borderTopLeftRadius: compactKeypadBorderRadiusPx,
+ },
+ roundedTopRight: {
+ borderTopRightRadius: compactKeypadBorderRadiusPx,
+ },
+});
diff --git a/src/components/math-input/components/svg-icon.js b/src/components/math-input/components/svg-icon.js
new file mode 100644
index 0000000..ea9a146
--- /dev/null
+++ b/src/components/math-input/components/svg-icon.js
@@ -0,0 +1,43 @@
+/**
+ * A component that renders a single SVG icon.
+ */
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+
+const Iconography = require('./iconography');
+
+const SvgIcon = React.createClass({
+ propTypes: {
+ color: React.PropTypes.string.isRequired,
+ name: React.PropTypes.string.isRequired,
+ },
+
+ componentDidMount() {
+ this._addFillRule();
+ },
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.name !== this.props.name) {
+ this._addFillRule();
+ }
+ },
+
+ _addFillRule() {
+ // TODO(kevinb) remove this when we upgrade to React 15.
+ const node = ReactDOM.findDOMNode(this);
+ if (node instanceof SVGElement) {
+ const firstGroup = node.querySelector('g');
+ firstGroup.setAttributeNS(null, 'fill-rule', 'evenodd');
+ }
+ },
+
+ render() {
+ const { color, name } = this.props;
+
+ const SvgForName = Iconography[name];
+ return
;
+ },
+});
+
+module.exports = SvgIcon;
diff --git a/src/components/math-input/components/text-icon.js b/src/components/math-input/components/text-icon.js
new file mode 100644
index 0000000..ec57b31
--- /dev/null
+++ b/src/components/math-input/components/text-icon.js
@@ -0,0 +1,48 @@
+/**
+ * A component that renders a text-based icon.
+ */
+
+const React = require('react');
+const { StyleSheet } = require('aphrodite');
+
+const { View, Text } = require('../fake-react-native-web');
+const { row, centered } = require('./styles');
+const { iconSizeHeightPx, iconSizeWidthPx } = require('./common-style');
+
+const TextIcon = React.createClass({
+ propTypes: {
+ character: React.PropTypes.string.isRequired,
+ style: React.PropTypes.any,
+ },
+
+ render() {
+ const { character, style } = this.props;
+
+ const containerStyle = [
+ row,
+ centered,
+ styles.size,
+ styles.base,
+ ...(Array.isArray(style) ? style : [style]),
+ ];
+ return
+
+ {character}
+
+ ;
+ },
+});
+
+const styles = StyleSheet.create({
+ size: {
+ height: iconSizeHeightPx,
+ width: iconSizeWidthPx,
+ },
+
+ base: {
+ fontFamily: 'Proxima Nova',
+ fontSize: 25,
+ },
+});
+
+module.exports = TextIcon;
diff --git a/src/components/math-input/components/touchable-keypad-button.js b/src/components/math-input/components/touchable-keypad-button.js
new file mode 100644
index 0000000..4fef296
--- /dev/null
+++ b/src/components/math-input/components/touchable-keypad-button.js
@@ -0,0 +1,124 @@
+/**
+ * A touchable wrapper around the base KeypadButton component. This button is
+ * responsible for keeping our button ID system (which will be used to handle
+ * touch events globally) opaque to the KeypadButton.
+ */
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+const { connect } = require('react-redux');
+const { StyleSheet } = require('aphrodite');
+
+const KeypadButton = require('./keypad-button');
+const KeyConfigs = require('../data/key-configs');
+const GestureManager = require('./gesture-manager');
+const { bordersPropType, keyIdPropType } = require('./prop-types');
+const { KeyTypes } = require('../consts');
+
+const TouchableKeypadButton = React.createClass({
+ propTypes: {
+ borders: bordersPropType,
+ childKeyIds: React.PropTypes.arrayOf(keyIdPropType),
+ disabled: React.PropTypes.bool,
+ focused: React.PropTypes.bool,
+ gestureManager: React.PropTypes.instanceOf(GestureManager),
+ id: keyIdPropType.isRequired,
+ popoverEnabled: React.PropTypes.bool,
+ style: React.PropTypes.any,
+ type: React.PropTypes.oneOf(Object.keys(KeyTypes)).isRequired,
+ },
+
+ shouldComponentUpdate(newProps) {
+ // We take advantage of a few different properties of our key
+ // configuration system. Namely, we know that the other props flow
+ // directly from the ID, and thus don't need to be checked. If a key has
+ // a custom style, we bail out (this should be rare).
+ return newProps.id !== this.props.id ||
+ newProps.gestureManager !== this.props.gestureManager ||
+ newProps.focused !== this.props.focused ||
+ newProps.disabled !== this.props.disabled ||
+ newProps.popoverEnabled !== this.props.popoverEnabled ||
+ newProps.type !== this.props.type || !!newProps.style;
+ },
+
+ componentWillUnmount() {
+ const { gestureManager, id } = this.props;
+ gestureManager.unregisterDOMNode(id);
+ },
+
+ render() {
+ const {
+ borders, childKeyIds, disabled, gestureManager, id, style, ...rest
+ } = this.props;
+
+ // Only bind the relevant event handlers if the key is enabled.
+ const eventHandlers = disabled ? {
+ onTouchStart: (evt) => evt.preventDefault(),
+ } : {
+ onTouchStart: (evt) => gestureManager.onTouchStart(evt, id),
+ onTouchEnd: (evt) => gestureManager.onTouchEnd(evt),
+ onTouchMove: (evt) => gestureManager.onTouchMove(evt),
+ onTouchCancel: (evt) => gestureManager.onTouchCancel(evt),
+ };
+
+ const styleWithAddons = [
+ ...(Array.isArray(style) ? style : [style]),
+ styles.preventScrolls,
+ ];
+
+ return
gestureManager.registerDOMNode(
+ id, ReactDOM.findDOMNode(node), childKeyIds, borders
+ )}
+ borders={borders}
+ disabled={disabled}
+ style={styleWithAddons}
+ {...eventHandlers}
+ {...rest}
+ />;
+ },
+});
+
+const extractProps = (keyConfig) => {
+ const { ariaLabel, icon, type } = keyConfig;
+ return { ariaLabel, icon, type };
+};
+
+const mapStateToProps = (state, ownProps) => {
+ const { gestures } = state;
+
+ const { keyConfig, ...rest } = ownProps;
+ const { id, childKeyIds, type } = keyConfig;
+
+ const childKeys = childKeyIds && childKeyIds.map(id => KeyConfigs[id]);
+
+ // Override with the default child props, if the key is a multi-symbol key
+ // (but not a many-symbol key, which operates under different rules).
+ const useFirstChildProps = type !== KeyTypes.MANY &&
+ childKeys && childKeys.length > 0;
+
+ return {
+ ...rest,
+ childKeyIds: childKeyIds,
+ gestureManager: gestures.gestureManager,
+ id: id,
+
+ // Add in some gesture state.
+ focused: gestures.focus === id,
+ popoverEnabled: gestures.popover && gestures.popover.parentId === id,
+
+ // Pass down the child keys and any extracted props.
+ childKeys,
+ ...extractProps(useFirstChildProps ? childKeys[0] : keyConfig),
+ };
+};
+
+const styles = StyleSheet.create({
+ preventScrolls: {
+ // Touch events that start in the touchable buttons shouldn't be
+ // allowed to produce page scrolls.
+ touchAction: "none",
+ },
+});
+
+module.exports = connect(mapStateToProps)(TouchableKeypadButton);
diff --git a/src/components/math-input/components/two-page-keypad.js b/src/components/math-input/components/two-page-keypad.js
new file mode 100644
index 0000000..f1e4452
--- /dev/null
+++ b/src/components/math-input/components/two-page-keypad.js
@@ -0,0 +1,83 @@
+/**
+ * A keypad with two pages of keys.
+ */
+
+const React = require('react');
+const { connect } = require('react-redux');
+const { StyleSheet } = require('aphrodite');
+
+const Keypad = require('./keypad');
+const ViewPager = require('./view-pager');
+const PagerIndicator = require('./pager-indicator');
+const { View } = require('../fake-react-native-web');
+const { column, row, fullWidth } = require('./styles');
+const {
+ innerBorderColor, innerBorderStyle, innerBorderWidthPx, gray85,
+} = require('./common-style');
+
+const TwoPageKeypad = React.createClass({
+ propTypes: {
+ currentPage: React.PropTypes.oneOf([0, 1]).isRequired,
+ leftPage: React.PropTypes.node.isRequired,
+ paginationEnabled: React.PropTypes.bool.isRequired,
+ rightPage: React.PropTypes.node.isRequired,
+ },
+
+ render() {
+ const {
+ currentPage,
+ leftPage,
+ paginationEnabled,
+ rightPage,
+ } = this.props;
+
+ if (paginationEnabled) {
+ return
+
+
+
+ {leftPage}
+ {rightPage}
+
+
+ ;
+ } else {
+ return
+
+
+ {leftPage}
+
+
+ {rightPage}
+
+
+ ;
+ }
+ },
+});
+
+const styles = StyleSheet.create({
+ keypad: {
+ // Set the background to light grey, so that when the user drags the
+ // keypad pages past the edges, there's a grey backdrop.
+ backgroundColor: gray85,
+ },
+
+ borderTop: {
+ borderTop: `${innerBorderWidthPx}px ${innerBorderStyle} `
+ + `${innerBorderColor}`,
+ },
+ borderLeft: {
+ borderLeft: `${innerBorderWidthPx}px ${innerBorderStyle} `
+ + `${innerBorderColor}`,
+ boxSizing: 'content-box',
+ },
+});
+
+const mapStateToProps = (state) => {
+ return {
+ paginationEnabled: state.layout.paginationEnabled,
+ };
+};
+
+module.exports = connect(mapStateToProps)(TwoPageKeypad);
diff --git a/src/components/math-input/components/velocity-tracker.js b/src/components/math-input/components/velocity-tracker.js
new file mode 100644
index 0000000..540aa3a
--- /dev/null
+++ b/src/components/math-input/components/velocity-tracker.js
@@ -0,0 +1,76 @@
+/**
+ * A system for tracking gesture velocity in a single dimension.
+ *
+ * Velocity is computed by smoothing linearly over the gestures that have
+ * occurred in the last 100 milliseconds.
+ */
+
+const now = require('performance-now');
+
+class VelocityTracker {
+ constructor(options) {
+ this.options = {
+ velocityTimeout: 100,
+ ...options,
+ };
+ this._events = [];
+ }
+
+ /**
+ * Pushes an event with the given displacement onto the event buffer,
+ * associating it with a timestamp. Note that, as this method computes the
+ * timestamp for the event at calltime, it should be called immediately
+ * after the event occurs.
+ *
+ * @param {number} x - the cumulative displacement of the event
+ */
+ push(x) {
+ this._events.push({
+ x,
+ t: now(),
+ });
+ }
+
+ /**
+ * Compute the velocity with respect to the events that have been tracked
+ * by the system. Velocity is computed by smoothing linearly over recent
+ * displacement values.
+ *
+ * Note that, for performance reasons, a call to `getVelocity` will clear
+ * out the event buffer. As such, repeated calls will not return the same
+ * value (in particular, a second call in quick succession will return 0).
+ *
+ * @returns {number} the velocity associated with the tracker
+ */
+ getVelocity() {
+ const events = this._getEvents();
+
+ if (events.length < 2) {
+ return 0;
+ } else {
+ const current = events[events.length - 1];
+ const first = events[0];
+ const dt = current.t - first.t;
+ return (current.x - first.x) / dt;
+ }
+ }
+
+ /**
+ * Filter the tracked events to exclude any events that occurred too far in
+ * the past, and reset the event buffer.
+ *
+ * @returns {number[]} an array of displacements corresponding to events
+ * that occurred in the past `velocityTimeout`
+ * milliseconds
+ */
+ _getEvents() {
+ const threshold = now() - this.options.velocityTimeout;
+ const recentEvents = this._events.filter((event) => {
+ return event.t > threshold;
+ });
+ this._events = [];
+ return recentEvents;
+ }
+}
+
+module.exports = VelocityTracker;
diff --git a/src/components/math-input/components/view-pager.js b/src/components/math-input/components/view-pager.js
new file mode 100644
index 0000000..f98a7ee
--- /dev/null
+++ b/src/components/math-input/components/view-pager.js
@@ -0,0 +1,124 @@
+/**
+ * A view pager that allows for pagination in the horizontal direction.
+ * Right now, there are a number of limitations built into the system. Namely:
+ * - It only supports pagination in the horizontal direction.
+ * - It supports exactly two pages.
+ */
+
+const React = require('react');
+const { connect } = require('react-redux');
+const { StyleSheet } = require('aphrodite');
+
+const { View } = require('../fake-react-native-web');
+const { row } = require('./styles');
+const { childrenPropType } = require('./prop-types');
+const {
+ innerBorderColor,
+ innerBorderStyle,
+ innerBorderWidthPx,
+} = require('./common-style');
+
+const ViewPager = React.createClass({
+ propTypes: {
+ // Whether the page should animate to its next specified position.
+ animateToPosition: React.PropTypes.bool,
+ children: childrenPropType,
+ pageWidthPx: React.PropTypes.number.isRequired,
+ translateX: React.PropTypes.number.isRequired,
+ },
+
+ getInitialState() {
+ return {
+ animationDurationMs: 0,
+ };
+ },
+
+ componentWillReceiveProps(newProps) {
+ // Compute the appropriate animation length, if the pager should
+ // animate to its next position.
+ let animationDurationMs;
+ if (newProps.animateToPosition) {
+ const finalTranslateX = newProps.translateX;
+ const prevTranslateX = this.props.translateX;
+
+ // We animate at a rate of 1 pixel per millisecond, and thus we can
+ // use the displacement as the animation duration.
+ animationDurationMs = Math.abs(finalTranslateX - prevTranslateX);
+ } else {
+ animationDurationMs = 0;
+ }
+ this.setState({
+ animationDurationMs,
+ });
+ },
+
+ render() {
+ const { children, pageWidthPx, translateX } = this.props;
+ const { animationDurationMs } = this.state;
+
+ const pagerStyle = [row, styles.twoPagePager];
+
+ const transform = {
+ msTransform: `translate3d(${translateX}px, 0, 0)`,
+ WebkitTransform: `translate3d(${translateX}px, 0, 0)`,
+ transform: `translate3d(${translateX}px, 0, 0)`,
+ };
+ const animate = animationDurationMs ? {
+ msTransitionProperty: 'transform',
+ WebkitTransitionProperty: 'transform',
+ transitionProperty: 'transform',
+ msTransitionDuration: `${animationDurationMs}ms`,
+ WebkitTransitionDuration: `${animationDurationMs}ms`,
+ transitionDuration: `${animationDurationMs}ms`,
+ msTransitionTimingFunction: 'ease-out',
+ WebkitTransitionTimingFunction: 'ease-out',
+ transitionTimingFunction: 'ease-out',
+ } : {};
+ const dynamicPagerStyle = {
+ ...transform,
+ ...animate,
+ };
+
+ const dynamicPageStyle = {
+ width: pageWidthPx,
+ };
+
+ return
+
+ {children[0]}
+
+
+ {children[1]}
+
+ ;
+ },
+});
+
+const styles = StyleSheet.create({
+ twoPagePager: {
+ alignSelf: 'flex-start',
+ // Note: By default, sets a `maxWidth` of 100% to fix some
+ // Flexbox bugs. We have to override it to accommodate for our two
+ // pages. The exact value here isn't super important, as long as it's
+ // large enough to accommodate for two pages (so, 200%) and some
+ // separators.
+ maxWidth: '250%',
+ },
+
+ rightPage: {
+ borderLeft: `${innerBorderWidthPx}px ${innerBorderStyle} `
+ + `${innerBorderColor}`,
+ boxSizing: 'content-box',
+ },
+});
+
+const mapStateToProps = (state) => {
+ const { animateToPosition, currentPage, dx, pageWidthPx } = state.pager;
+ return {
+ animateToPosition,
+ pageWidthPx,
+ translateX: -currentPage * (pageWidthPx + innerBorderWidthPx) + dx,
+ };
+};
+
+module.exports = connect(mapStateToProps)(ViewPager);
diff --git a/src/components/math-input/components/z-indexes.js b/src/components/math-input/components/z-indexes.js
new file mode 100644
index 0000000..1079593
--- /dev/null
+++ b/src/components/math-input/components/z-indexes.js
@@ -0,0 +1,10 @@
+/**
+ * This file contains all of the z-index values used throughout the math-input
+ * component and its children.
+ */
+
+module.exports = {
+ popover: 1,
+ echo: 2,
+ keypad: 1060,
+};
diff --git a/src/components/math-input/consts.js b/src/components/math-input/consts.js
new file mode 100644
index 0000000..27f844f
--- /dev/null
+++ b/src/components/math-input/consts.js
@@ -0,0 +1,73 @@
+/**
+ * Constants that are shared between multiple files.
+ */
+
+module.exports = {
+ KeypadTypes: {
+ FRACTION: 'FRACTION',
+ EXPRESSION: 'EXPRESSION',
+ },
+
+ KeyTypes: {
+ EMPTY: 'EMPTY',
+ // For numerals, variables, and any other characters that themselves
+ // compose 'values'.
+ VALUE: 'VALUE',
+ // For buttons that insert or adjust math in an input.
+ OPERATOR: 'OPERATOR',
+ // For buttons that move the cursor in an input (including via
+ // deletion).
+ INPUT_NAVIGATION: 'INPUT_NAVIGATION',
+ // For buttons that modify the broader keypad state (e.g., by changing
+ // the visible pane).
+ KEYPAD_NAVIGATION: 'KEYPAD_NAVIGATION',
+ // For buttons that house multiple buttons and have no action
+ // themselves.
+ MANY: 'MANY',
+ // For the echo animation that appears on press.
+ ECHO: 'ECHO',
+ },
+
+ DeviceOrientations: {
+ LANDSCAPE: 'LANDSCAPE',
+ PORTRAIT: 'PORTRAIT',
+ },
+
+ DeviceTypes: {
+ PHONE: 'PHONE',
+ TABLET: 'TABLET',
+ },
+
+ LayoutModes: {
+ FULLSCREEN: 'FULLSCREEN',
+ COMPACT: 'COMPACT',
+ },
+
+ BorderDirections: {
+ LEFT: 'LEFT',
+ BOTTOM: 'BOTTOM',
+ },
+ BorderStyles: {
+ LEFT: ['LEFT'],
+ BOTTOM: ['BOTTOM'],
+ ALL: ['LEFT', 'BOTTOM'],
+ NONE: [],
+ },
+
+ IconTypes: {
+ MATH: 'MATH',
+ SVG: 'SVG',
+ TEXT: 'TEXT',
+ },
+
+ DecimalSeparators: {
+ COMMA: 'COMMA',
+ PERIOD: 'PERIOD',
+ },
+
+ EchoAnimationTypes: {
+ SLIDE_AND_FADE: 'SLIDE_AND_FADE',
+ FADE_ONLY: 'FADE_ONLY',
+ LONG_FADE_ONLY: 'LONG_FADE_ONLY',
+ },
+};
diff --git a/src/components/math-input/data/key-configs.js b/src/components/math-input/data/key-configs.js
new file mode 100644
index 0000000..57b3954
--- /dev/null
+++ b/src/components/math-input/data/key-configs.js
@@ -0,0 +1,305 @@
+/**
+ * This file contains configuration settings for the buttons in the keypad.
+ */
+
+/* globals i18n */
+
+const Keys = require('../data/keys');
+const { DecimalSeparators, IconTypes, KeyTypes } = require('../consts');
+const { decimalSeparator } = require('../utils');
+const i18n = require('../lib/i18n');
+
+const KeyConfigs = {
+ // Basic math keys.
+ [Keys.PLUS]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a plus sign.
+ ariaLabel: i18n._('Plus'),
+ },
+ [Keys.MINUS]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a minus sign.
+ ariaLabel: i18n._('Minus'),
+ },
+ [Keys.NEGATIVE]: {
+ type: KeyTypes.VALUE,
+ // I18N: A label for a minus sign.
+ ariaLabel: i18n._('Negative'),
+ },
+ [Keys.TIMES]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a multiplication sign (represented with an 'x').
+ ariaLabel: i18n._('Multiply'),
+ },
+ [Keys.DIVIDE]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a division sign.
+ ariaLabel: i18n._('Divide'),
+ },
+ [Keys.DECIMAL]: {
+ type: KeyTypes.VALUE,
+ // I18N: A label for a decimal symbol.
+ ariaLabel: i18n._('Decimal'),
+ icon: decimalSeparator === DecimalSeparators.COMMA ? {
+ // TODO(charlie): Get an SVG icon for the comma, or verify with
+ // design that the text-rendered version is acceptable.
+ type: IconTypes.TEXT,
+ data: ',',
+ } : {
+ type: IconTypes.SVG,
+ data: Keys.PERIOD,
+ },
+ },
+ [Keys.PERCENT]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a percent sign.
+ ariaLabel: i18n._('Percent'),
+ },
+ [Keys.CDOT]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a multiplication sign (represented as a dot).
+ ariaLabel: i18n._('Multiply'),
+ },
+ [Keys.EQUAL]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Equals sign'),
+ },
+ [Keys.NEQ]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Not-equals sign'),
+ },
+ [Keys.GT]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a 'greater than' sign (represented as '>').
+ ariaLabel: i18n._('Greater than sign'),
+ },
+ [Keys.LT]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a 'less than' sign (represented as '<').
+ ariaLabel: i18n._('Less than sign'),
+ },
+ [Keys.GEQ]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Greater than or equal to sign'),
+ },
+ [Keys.LEQ]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Less than or equal to sign'),
+ },
+ [Keys.FRAC_INCLUSIVE]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a button that creates a new fraction and puts the
+ // current expression in the numerator of that fraction.
+ ariaLabel: i18n._('Fraction, with current expression in numerator'),
+ },
+ [Keys.FRAC_EXCLUSIVE]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a button that creates a new fraction next to the
+ // cursor.
+ ariaLabel: i18n._('Fraction, excluding the current expression'),
+ },
+ [Keys.EXP]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a button that will allow the user to input a custom
+ // exponent.
+ ariaLabel: i18n._('Custom exponent'),
+ },
+ [Keys.EXP_2]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a button that will square (take to the second
+ // power) some math.
+ ariaLabel: i18n._('Square'),
+ },
+ [Keys.EXP_3]: {
+ type: KeyTypes.OPERATOR,
+ // I18N: A label for a button that will cube (take to the third power)
+ // some math.
+ ariaLabel: i18n._('Cube'),
+ },
+ [Keys.SQRT]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Square root'),
+ },
+ [Keys.CUBE_ROOT]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Cube root'),
+ },
+ [Keys.RADICAL]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Radical with custom root'),
+ },
+ [Keys.LEFT_PAREN]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Left parenthesis'),
+ },
+ [Keys.RIGHT_PAREN]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Right parenthesis'),
+ },
+ [Keys.LN]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Natural logarithm'),
+ },
+ [Keys.LOG]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Logarithm with base 10'),
+ },
+ [Keys.LOG_N]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Logarithm with custom base'),
+ },
+ [Keys.SIN]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Sine'),
+ },
+ [Keys.COS]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Cosine'),
+ },
+ [Keys.TAN]: {
+ type: KeyTypes.OPERATOR,
+ ariaLabel: i18n._('Tangent'),
+ },
+ [Keys.PI]: {
+ type: KeyTypes.VALUE,
+ ariaLabel: i18n._('Pi'),
+ icon: {
+ type: IconTypes.MATH,
+ data: '\\pi',
+ },
+ },
+ [Keys.THETA]: {
+ type: KeyTypes.VALUE,
+ ariaLabel: i18n._('Theta'),
+ icon: {
+ type: IconTypes.MATH,
+ data: '\\theta',
+ },
+ },
+ [Keys.NOOP]: {
+ type: KeyTypes.EMPTY,
+ },
+
+ // Input navigation keys.
+ [Keys.UP]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Up arrow'),
+ },
+ [Keys.RIGHT]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Right arrow'),
+ },
+ [Keys.DOWN]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Down arrow'),
+ },
+ [Keys.LEFT]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Left arrow'),
+ },
+ [Keys.JUMP_OUT_PARENTHESES]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Navigate right out of a set of parentheses'),
+ },
+ [Keys.JUMP_OUT_EXPONENT]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Navigate right out of an exponent'),
+ },
+ [Keys.JUMP_OUT_BASE]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Navigate right out of a base'),
+ },
+ [Keys.JUMP_INTO_NUMERATOR]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._('Navigate right into the numerator of a fraction'),
+ },
+ [Keys.JUMP_OUT_NUMERATOR]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._(
+ 'Navigate right out of the numerator and into the denominator'),
+ },
+ [Keys.JUMP_OUT_DENOMINATOR]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ ariaLabel: i18n._(
+ 'Navigate right out of the denominator of a fraction'),
+ },
+ [Keys.BACKSPACE]: {
+ type: KeyTypes.INPUT_NAVIGATION,
+ // I18N: A label for a button that will delete some input.
+ ariaLabel: i18n._('Delete'),
+ },
+
+ // Keypad navigation keys.
+ [Keys.DISMISS]: {
+ type: KeyTypes.KEYPAD_NAVIGATION,
+ // I18N: A label for a button that will dismiss/hide a keypad.
+ ariaLabel: i18n._('Dismiss'),
+ },
+};
+
+// Add in any multi-function buttons. By default, these keys will mix in any
+// configuration settings from their default child key (i.e., the first key in
+// the `childKeyIds` array).
+// TODO(charlie): Make the multi-function button's long-press interaction
+// accessible.
+KeyConfigs[Keys.FRAC_MULTI] = {
+ childKeyIds: [Keys.FRAC_INCLUSIVE, Keys.FRAC_EXCLUSIVE],
+};
+
+// TODO(charlie): Use the numeral color for the 'Many' key.
+KeyConfigs[Keys.MANY] = {
+ type: KeyTypes.MANY,
+ // childKeyIds will be configured by the client.
+};
+
+// Add in every numeral.
+const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+for (const num of NUMBERS) {
+ // TODO(charlie): Consider removing the SVG icons that we have for the
+ // numeral keys. They can be rendered just as easily with text (though that
+ // would mean that we'd be using text beyond the variable key).
+ const textRepresentation = `${num}`;
+ KeyConfigs[`NUM_${num}`] = {
+ type: KeyTypes.VALUE,
+ ariaLabel: textRepresentation,
+ icon: {
+ type: IconTypes.TEXT,
+ data: textRepresentation,
+ },
+ };
+}
+
+// Add in every variable.
+const LETTERS = [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+];
+for (const letter of LETTERS) {
+ const lowerCaseVariable = letter.toLowerCase();
+ const upperCaseVariable = letter.toUpperCase();
+
+ for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
+ KeyConfigs[textRepresentation] = {
+ type: KeyTypes.VALUE,
+ ariaLabel: textRepresentation,
+ icon: {
+ type: IconTypes.MATH,
+ data: textRepresentation,
+ },
+ };
+ }
+}
+
+for (const key of Object.keys(KeyConfigs)) {
+ KeyConfigs[key] = {
+ id: key,
+ // Default to an SVG icon indexed by the key name.
+ icon: {
+ type: IconTypes.SVG,
+ data: key,
+ },
+ ...KeyConfigs[key],
+ };
+}
+
+module.exports = KeyConfigs;
diff --git a/src/components/math-input/data/keys.js b/src/components/math-input/data/keys.js
new file mode 100644
index 0000000..d6dbede
--- /dev/null
+++ b/src/components/math-input/data/keys.js
@@ -0,0 +1,70 @@
+/**
+ * This file contains constants for keypad buttons that aren't single
+ * alphanumeric characters.
+ */
+
+// TODO(charlie): There's duplication between this file and key-configs.js.
+// We should clean it up by removing this file and requiring clients to use the
+// `id` field on the key configurations.
+const Keys = {
+ PLUS: 'PLUS',
+ MINUS: 'MINUS',
+ NEGATIVE: 'NEGATIVE',
+ TIMES: 'TIMES',
+ DIVIDE: 'DIVIDE',
+ DECIMAL: 'DECIMAL',
+ PERIOD: 'PERIOD',
+ PERCENT: 'PERCENT',
+ CDOT: 'CDOT',
+ EQUAL: 'EQUAL',
+ NEQ: 'NEQ',
+ GT: 'GT',
+ LT: 'LT',
+ GEQ: 'GEQ',
+ LEQ: 'LEQ',
+ FRAC_INCLUSIVE: 'FRAC_INCLUSIVE',
+ FRAC_EXCLUSIVE: 'FRAC_EXCLUSIVE',
+ EXP: 'EXP',
+ EXP_2: 'EXP_2',
+ EXP_3: 'EXP_3',
+ SQRT: 'SQRT',
+ CUBE_ROOT: 'CUBE_ROOT',
+ RADICAL: 'RADICAL',
+ LEFT_PAREN: 'LEFT_PAREN',
+ RIGHT_PAREN: 'RIGHT_PAREN',
+ LN: 'LN',
+ LOG: 'LOG',
+ LOG_N: 'LOG_N',
+ SIN: 'SIN',
+ COS: 'COS',
+ TAN: 'TAN',
+
+ // TODO(charlie): Add in additional Greek letters.
+ PI: 'PI',
+ THETA: 'THETA',
+
+ UP: 'UP',
+ RIGHT: 'RIGHT',
+ DOWN: 'DOWN',
+ LEFT: 'LEFT',
+ BACKSPACE: 'BACKSPACE',
+ DISMISS: 'DISMISS',
+
+ JUMP_OUT_PARENTHESES: 'JUMP_OUT_PARENTHESES',
+ JUMP_OUT_EXPONENT: 'JUMP_OUT_EXPONENT',
+ JUMP_OUT_BASE: 'JUMP_OUT_BASE',
+ JUMP_INTO_NUMERATOR: 'JUMP_INTO_NUMERATOR',
+ JUMP_OUT_NUMERATOR: 'JUMP_OUT_NUMERATOR',
+ JUMP_OUT_DENOMINATOR: 'JUMP_OUT_DENOMINATOR',
+
+ NOOP: 'NOOP',
+
+ // Multi-functional keys.
+ FRAC_MULTI: 'FRAC_MULTI',
+
+ // A custom key that captures an arbitrary number of symbols but has no
+ // 'default' symbol or action.
+ MANY: 'MANY',
+};
+
+module.exports = Keys;
diff --git a/src/components/math-input/echo.css b/src/components/math-input/echo.css
new file mode 100644
index 0000000..dd83a53
--- /dev/null
+++ b/src/components/math-input/echo.css
@@ -0,0 +1,72 @@
+/**
+* Styles for managing the echo animations. These were generated by Aphrodite's
+* autoprefixer, but some minor tweaks were applied to get them working on mobile
+* Safari. Ideally, we'd be generating these styles with Aphrodite (along with
+* ReactCSSTransitionGroup's support for custom classnames), but the generated
+* styles have issues on mobile Safari.
+* See: https://github.com/Khan/aphrodite/issues/68.
+*
+ * If the animation durations change, the corresponding values in
+ * echo-manager.js must change as well.
+ */
+
+/* Variant A: Slide and fade. */
+
+.echo-slide-and-fade-enter {
+ opacity: 1 !important;
+ transform: translate3d(0, 0, 0) !important;
+ -webkit-transform: translate3d(0, 0, 0) !important;
+ -moz-transform: translate3d(0, 0, 0) !important;
+ -ms-transform: translate3d(0, 0, 0) !important;
+}
+
+.echo-slide-and-fade-enter.echo-slide-and-fade-enter-active {
+ opacity: 0 !important;
+ transform: translate3d(0, -33%, 0) !important;
+ -webkit-transform: translate3d(0, -33%, 0) !important;
+ -moz-transform: translate3d(0, -33%, 0) !important;
+ -ms-transform: translate3d(0, -33%, 0) !important;
+
+ /**
+ * TODO(charlie): These times are intentionally different, which means that
+ * the animation really "ends" after 400ms cubic-bezier(1, 0, 0.9, 1) (since
+ * the opacity goes to 0), even though the transform doesn't complete.
+ * There's probably a way to achieve the same effect by manipulating the
+ * transform's Bezier curve and total displacement.
+ */
+ transition: -webkit-transform 800ms cubic-bezier(0, 1, 0.25, 1), -moz-transform 800ms cubic-bezier(0, 1, 0.25, 1), -ms-transform 800ms cubic-bezier(0, 1, 0.25, 1), transform 800ms cubic-bezier(0, 1, 0.25, 1), opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
+ -webkit-transform: translate3d(0, -33%, 0) !important;
+ -moz-transform: translate3d(0, -33%, 0) !important;
+ -ms-transform: translate3d(0, -33%, 0) !important;
+ -webkit-transition: -webkit-transform 800ms cubic-bezier(0, 1, 0.25, 1), transform 800ms cubic-bezier(0, 1, 0.25, 1), opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
+ -moz-transition: -moz-transform 800ms cubic-bezier(0, 1, 0.25, 1), transform 800ms cubic-bezier(0, 1, 0.25, 1), opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
+ -ms-transition: -ms-transform 800ms cubic-bezier(0, 1, 0.25, 1), transform 800ms cubic-bezier(0, 1, 0.25, 1), opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
+}
+
+/* Variant B: Fade, but don't slide. */
+
+.echo-fade-only-enter {
+ opacity: 1 !important;
+}
+
+.echo-fade-only-enter.echo-fade-only-enter-active {
+ opacity: 0 !important;
+ transition: opacity 300ms cubic-bezier(0.25, 0, 0.75, 1) !important;
+ -webkit-transition: opacity 300ms cubic-bezier(0.25, 0, 0.75, 1) !important;
+ -moz-transition: opacity 300ms cubic-bezier(0.25, 0, 0.75, 1) !important;
+ -ms-transition: opacity 300ms cubic-bezier(0.25, 0, 0.75, 1) !important;
+}
+
+/* Variant C: Fade for a longer duration, but again, don't slide. */
+
+.echo-long-fade-only-enter {
+ opacity: 1 !important;
+}
+
+.echo-long-fade-only-enter.echo-long-fade-only-enter-active {
+ opacity: 0 !important;
+ transition: opacity 400ms cubic-bezier(0.75, 0, 0.75, 1) !important;
+ -webkit-transition: opacity 400ms cubic-bezier(0.75, 0, 0.75, 1) !important;
+ -moz-transition: opacity 400ms cubic-bezier(0.75, 0, 0.75, 1) !important;
+ -ms-transition: opacity 400ms cubic-bezier(0.75, 0, 0.75, 1) !important;
+}
diff --git a/src/components/math-input/fake-react-native-web/index.js b/src/components/math-input/fake-react-native-web/index.js
new file mode 100644
index 0000000..1c9155c
--- /dev/null
+++ b/src/components/math-input/fake-react-native-web/index.js
@@ -0,0 +1,13 @@
+/**
+ * This file exports components View and Text which wrap and
.
+ * We do this so that someday in the future we can use these components with
+ * React Native.
+ *
+ * Inspired by https://github.com/necolas/react-native-web. We use aphrodite
+ * StyleSheets instead.
+ */
+
+module.exports = {
+ Text: require('./text'),
+ View: require('./view'),
+};
diff --git a/src/components/math-input/fake-react-native-web/text.js b/src/components/math-input/fake-react-native-web/text.js
new file mode 100644
index 0000000..2da8ff7
--- /dev/null
+++ b/src/components/math-input/fake-react-native-web/text.js
@@ -0,0 +1,53 @@
+const React = require('react');
+const { StyleSheet, css } = require('aphrodite');
+
+const Text = React.createClass({
+ propTypes: {
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.node),
+ React.PropTypes.node,
+ ]),
+ // The `dynamicStyle` prop is provided for animating dynamic
+ // properties, as creating Aphrodite StyleSheets in animation loops is
+ // expensive. `dynamicStyle` should be a raw style object, rather than
+ // a StyleSheet.
+ dynamicStyle: React.PropTypes.any,
+ numberOfLines: React.PropTypes.number,
+ style: React.PropTypes.any,
+ },
+
+ render() {
+ const { numberOfLines, style } = this.props;
+
+ const className = css(
+ styles.initial,
+ ...(Array.isArray(style) ? style : [style]),
+ numberOfLines === 1 && styles.singleLineStyle
+ );
+
+ return
+ {this.props.children}
+ ;
+ },
+});
+
+// https://github.com/necolas/react-native-web/blob/master/src/components/Text/index.js
+const styles = StyleSheet.create({
+ initial: {
+ color: 'inherit',
+ display: 'inline',
+ font: 'inherit',
+ margin: 0,
+ padding: 0,
+ textDecorationLine: 'none',
+ wordWrap: 'break-word',
+ },
+ singleLineStyle: {
+ maxWidth: '100%',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ },
+});
+
+module.exports = Text;
diff --git a/src/components/math-input/fake-react-native-web/view.js b/src/components/math-input/fake-react-native-web/view.js
new file mode 100644
index 0000000..924ee86
--- /dev/null
+++ b/src/components/math-input/fake-react-native-web/view.js
@@ -0,0 +1,122 @@
+const React = require('react');
+const { StyleSheet, css } = require('aphrodite');
+
+const View = React.createClass({
+ propTypes: {
+ ariaLabel: React.PropTypes.string,
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.node),
+ React.PropTypes.node,
+ ]),
+ // The `dynamicStyle` prop is provided for animating dynamic
+ // properties, as creating Aphrodite StyleSheets in animation loops is
+ // expensive. `dynamicStyle` should be a raw style object, rather than
+ // a StyleSheet.
+ dynamicStyle: React.PropTypes.any,
+ // The `extraClassName` prop should almost never be used. It gives the
+ // client a way to provide an additional CSS class name, to augment
+ // the class name generated by Aphrodite. (Right now, it's only used to
+ // disable some externally-applied CSS that would otherwise be far too
+ // difficult to override with inline styles.)
+ extraClassName: React.PropTypes.string,
+ numberOfLines: React.PropTypes.number,
+ onClick: React.PropTypes.func,
+ onTouchCancel: React.PropTypes.func,
+ onTouchEnd: React.PropTypes.func,
+ onTouchMove: React.PropTypes.func,
+ onTouchStart: React.PropTypes.func,
+ role: React.PropTypes.string,
+ style: React.PropTypes.any,
+ },
+
+ statics: {
+ styles: StyleSheet.create({
+ // From: https://github.com/necolas/react-native-web/blob/master/src/components/View/index.js
+ initial: {
+ alignItems: 'stretch',
+ borderWidth: 0,
+ borderStyle: 'solid',
+ boxSizing: 'border-box',
+ display: 'flex',
+ flexBasis: 'auto',
+ flexDirection: 'column',
+ margin: 0,
+ padding: 0,
+ position: 'relative',
+ // button and anchor reset
+ backgroundColor: 'transparent',
+ color: 'inherit',
+ font: 'inherit',
+ textAlign: 'inherit',
+ textDecorationLine: 'none',
+ // list reset
+ listStyle: 'none',
+ // fix flexbox bugs
+ maxWidth: '100%',
+ minHeight: 0,
+ minWidth: 0,
+ },
+ }),
+ },
+
+ render() {
+ const className = css(
+ View.styles.initial,
+ ...(Array.isArray(this.props.style) ? this.props.style
+ : [this.props.style])
+ ) + (this.props.extraClassName ? ` ${this.props.extraClassName}` : "");
+
+ return {
+ // Touch events have extra properties compared to mouse
+ // events and also have a concept of "pointer lock",
+ // where the element that receives the touchstart event
+ // receives all subsequent events for that same touch,
+ // whereas mouse events change target if the cursor
+ // moves. We take mouse events and pretend they're touch
+ // events.
+ const augmentMouseEvent = (e) => {
+ e.touches = e.changedTouches = [{
+ identifier: 1,
+ clientX: e.clientX,
+ clientY: e.clientY,
+ }];
+ };
+
+ const doc = this._div.ownerDocument;
+ const onMove = (e) => {
+ augmentMouseEvent(e);
+ this.props.onTouchMove && this.props.onTouchMove(e);
+ };
+ const onUp = (e) => {
+ doc.removeEventListener('mousemove', onMove);
+ doc.removeEventListener('mouseup', onUp);
+ augmentMouseEvent(e);
+ this.props.onTouchEnd && this.props.onTouchEnd(e);
+ };
+ doc.addEventListener('mousemove', onMove, false);
+ doc.addEventListener('mouseup', onUp, false);
+
+ // Need to .persist() a React event object before adding
+ // properties to it since it's reused otherwise.
+ e.persist();
+ augmentMouseEvent(e);
+ this.props.onTouchStart && this.props.onTouchStart(e);
+ }}
+ ref={(node) => this._div = node}
+ aria-label={this.props.ariaLabel}
+ role={this.props.role}
+ >
+ {this.props.children}
+
;
+ },
+});
+
+module.exports = View;
diff --git a/src/components/math-input/index.js b/src/components/math-input/index.js
new file mode 100644
index 0000000..72f2c1e
--- /dev/null
+++ b/src/components/math-input/index.js
@@ -0,0 +1,27 @@
+/**
+ * A single entry-point for all of the external-facing functionality.
+ */
+
+import './overrides.css';
+import './echo.css';
+import './popover.css';
+
+const components = {
+ Keypad: require('./components/provided-keypad'),
+ KeypadInput: require('./components/input/math-input'),
+};
+
+const { KeypadTypes } = require('./consts');
+const consts = { KeypadTypes };
+
+const {
+ keypadConfigurationPropType,
+ keypadElementPropType,
+} = require('./components/prop-types');
+const propTypes = { keypadConfigurationPropType, keypadElementPropType };
+
+module.exports = {
+ components,
+ consts,
+ propTypes,
+};
diff --git a/src/components/math-input/lib/i18n.js b/src/components/math-input/lib/i18n.js
new file mode 100644
index 0000000..583fdc3
--- /dev/null
+++ b/src/components/math-input/lib/i18n.js
@@ -0,0 +1,411 @@
+// Running in local mode depends on $_, which is defined here. This was taken
+// from Perseus#826719c5.
+
+// The plural language strings for all the languages we have
+// listed in crowdin. The values here need to match what crowdin
+// uses (sometimes different platforms use different plural forms,
+// for ambiguous languages like Turkish). I got it by running
+// deploy/download_i18n.py -s
+// and looking a the .po files in all.zip. Each .po file has a
+// header line that say something like:
+// "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+// which I copied in here with the following changes:
+// 1) I only take the 'plural=' section, which I wrapped in a function
+// 2) Changed 'or' to '||'
+// These functions return either true or false or a number. We map
+// true to 1 and false to 0 below, to always get a number out of this.
+
+const icu = require('./icu-slim');
+
+/* eslint-disable space-infix-ops, eqeqeq, max-len */
+var likeEnglish = function (n) {
+ return n != 1;
+};
+
+// TODO(csilvers): auto-generate this list from the foo.po files (in dropbox)
+var allPluralForms = {
+ "accents": likeEnglish, // a 'fake' langauge
+ "af": likeEnglish,
+ "ar": function (n) {
+ return n == 0 ? 0 : n == 1 ? 1 : n == 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;
+ },
+ "az": likeEnglish,
+ "bg": likeEnglish,
+ "bn": likeEnglish,
+ "boxes": likeEnglish, // a 'fake' langauge
+ "ca": likeEnglish,
+ "cs": function (n) {
+ return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
+ },
+ "da": likeEnglish,
+ "de": likeEnglish,
+ "el": likeEnglish,
+ "empty": likeEnglish, // a 'fake' langauge
+ "en": likeEnglish,
+ "en-pt": likeEnglish, // a 'fake' language, used by crowdin for JIPT
+ "es": likeEnglish,
+ "fa": function (n) {
+ return 0;
+ },
+ "fa-af": function (n) {
+ return 0;
+ },
+ "fi": likeEnglish,
+ "fr": function (n) {
+ return n > 1;
+ },
+ "he": likeEnglish,
+ "hi": likeEnglish,
+ "hu": likeEnglish,
+ "hy": likeEnglish,
+ "id": function (n) {
+ return 0;
+ },
+ "it": likeEnglish,
+ "ja": function (n) {
+ return 0;
+ },
+ "ko": function (n) {
+ return 0;
+ },
+ "lol": likeEnglish, // a 'fake' langauge
+ "mn": likeEnglish,
+ "ms": function (n) {
+ return 0;
+ },
+ "nb": likeEnglish,
+ "nl": likeEnglish,
+ "pl": function (n) {
+ return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
+ },
+ "pt": likeEnglish,
+ "pt-pt": likeEnglish,
+ "ro": function (n) {
+ return n == 1 ? 0 : n == 0 || n % 100 > 0 && n % 100 < 20 ? 1 : 2;
+ },
+ "ru": function (n) {
+ return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
+ },
+ "si-LK": likeEnglish,
+ "sk": function (n) {
+ return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
+ },
+ "sr": function (n) {
+ return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
+ },
+ "sv-SE": likeEnglish,
+ "sw": likeEnglish,
+ "te": likeEnglish,
+ "th": function (n) {
+ return 0;
+ },
+ "tr": function (n) {
+ return 0;
+ },
+ "uk": function (n) {
+ return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
+ },
+ "ur": likeEnglish,
+ "vi": function (n) {
+ return 0;
+ },
+ "xh": likeEnglish,
+ "zh-hans": function (n) {
+ return 0;
+ },
+ "zh-hant": function (n) {
+ return 0;
+ },
+ "zu": likeEnglish
+};
+
+/* eslint-enable */
+
+var interpolationMarker = /%\(([\w_]+)\)s/g;
+/**
+ * Performs sprintf-like %(name)s replacement on str, and returns a React
+ * fragment of the string interleaved with those replacements. The replacements
+ * can be any valid React node including strings and numbers.
+ *
+ * For example:
+ * interpolateStringToFragment("test", {}) ->
+ * test
+ * interpolateStringToFragment("test %(num)s", {num: 5}) ->
+ * test 5
+ * interpolateStringToFragment("test %(num)s", {num: }) ->
+ * test
+ */
+var interpolateStringToFragment = function (str, options) {
+ options = options || {};
+
+ // Split the string into its language fragments and substitutions
+ var split = str.split(interpolationMarker);
+
+ var result = { "text_0": split[0] };
+
+ // Replace the substitutions with the appropriate option
+ for (var i = 1; i < split.length; i += 2) {
+ var key = split[i];
+ var replaceWith = options[key];
+ if (replaceWith === undefined) {
+ replaceWith = "%(" + key + ")s";
+ }
+
+ // We prefix each substitution key with a number that increments each
+ // time it's used, so "test %(num)s %(fruit)s and %(num)s again" turns
+ // into an object with keys:
+ // [text_0, 0_num, text_2, 0_fruit, text_4, 1_num, text_6]
+ // This is better than just using the array index in the case that we
+ // switch between two translated strings with the same variables.
+ // Admittedly, an edge case.
+ var j = 0;
+ while ("" + j + "_" + key in result) {
+ j++;
+ }
+
+ result["" + j + "_" + key] = replaceWith;
+ // Because the regex has one capturing group, the `split` array always
+ // has an odd number of elements, so this always stays in bounds.
+ result["text_" + (i + 1)] = split[i + 1];
+ }
+
+ return createFragment(result);
+};
+
+/**
+ * Simple i18n method with sprintf-like %(name)s replacement
+ * To be used like so:
+ * i18n._("Some string")
+ * i18n._("Hello %(name)s", {name: "John"})
+ */
+var _ = function (str, options) {
+ // Sometimes we're given an argument that's meant for ngettext(). This
+ // happens if the same string is used in both i18n._() and i18n.ngettext()
+ // (.g. a = i18n._(foo); b = i18n.ngettext("foo", "bar", count);
+ // In such cases, only the plural form ends up in the .po file, and
+ // then it gets sent to us for the i18n._() case too. No problem, though:
+ // we'll just take the singular arg.
+ if (typeof str === "object" && str.messages) {
+ str = str.messages[0];
+ }
+
+ options = options || {};
+
+ return str.replace(interpolationMarker, function (match, key) {
+ var replaceWith = options[key];
+ return replaceWith === undefined ? match : replaceWith;
+ });
+};
+
+/**
+ * A simple i18n react component-like function to allow for string
+ * interpolation destined for the output of a react render() function
+ *
+ * This function understands react components, or other things
+ * renderable by react, passed in as props.
+ *
+ * Examples:
+ * <$_ first="Motoko" last="Kusanagi">
+ * Hello, %(first)s %(last)s!
+ * $_>
+ *
+ * which react/jsx compiles to:
+ * $_({first: "Motoko", last: "Kusanagi"}, "Hello, %(first)s %(last)s!")
+ *
+ *
+ * <$_ textbox={}>
+ * Please enter a number: %(textbox)s
+ * $_>
+ *
+ * which react/jsx compiles to:
+ * $_({textbox: React.DOM.input({type: "text"}),
+ * "Please enter a number: %(textbox)s")
+ *
+ * Note: this is not a full react component to avoid complex handling of
+ * other things added to props, such as this.props.ref and
+ * this.props.children
+ */
+export function $_(options, str) {
+ if (arguments.length !== 2 || typeof str !== "string") {
+ return "<$_> must have exactly one child, which must be a string";
+ }
+
+ return interpolateStringToFragment(str, options);
+};
+
+/**
+ * A simple i18n react component-like function to allow for marking a
+ * string as not needing to be translated.
+ *
+ * Example:
+ *
+ * <$i18nDoNotTranslate>English only text.$i18nDoNotTranslate>
+ *
+ * which react/jsx compiles to:
+ * $i18nDoNotTranslate(null, "English only text.")
+ */
+export function $i18nDoNotTranslate(options, str) {
+ return str;
+};
+
+/**
+ * Simple ngettext method with sprintf-like %(name)s replacement
+ * To be used like so:
+ * i18n.ngettext("Singular", "Plural", 3)
+ * i18n.ngettext("1 Cat", "%(num)s Cats", 3)
+ * i18n.ngettext("1 %(type)s", "%(num)s %(type)s", 3, {type: "Cat"})
+ * This method is also meant to be used when injecting for other
+ * non-English languages, like so (taking an array of plural messages,
+ * which varies based upon the language):
+ * i18n.ngettext({
+ * lang: "ja",
+ * messages: ["%(num)s 猫 %(username)s"]
+ * }, 3, {username: "John"});
+ */
+var ngettext = function (singular, plural, num, options) {
+ // Fall back to the default lang
+ var lang;
+ var messages;
+
+ // If the first argument is an object then we're receiving a plural
+ // configuration object
+ if (typeof singular === "object") {
+ lang = singular.lang;
+ messages = singular.messages;
+ // We only have a messages object no plural string
+ // thus we need to shift all the arguments over by one.
+ options = num;
+ num = plural;
+ } else {
+ lang = "en"; // We're using text written into the source code
+ messages = [singular, plural];
+ }
+
+ // Get the translated string
+ var idx = ngetpos(num, lang);
+ var translation = "";
+ if (idx < messages.length) {// the common (non-error) case
+ translation = messages[idx];
+ }
+
+ // Get the options to substitute into the string.
+ // We automatically add in the 'magic' option-variable 'num'.
+ options = options || {};
+ options.num = options.num || num;
+
+ // Then pass into i18n._ for the actual substitution
+ return _(translation, options);
+};
+
+/*
+ * Return the ngettext position that matches the given number and locale.
+ *
+ * Arguments:
+ * - num: The number upon which to toggle the plural forms.
+ * - lang: The language to use as the basis for the pluralization.
+ */
+var ngetpos = function (num, lang) {
+ var pluralForm = allPluralForms[lang] || allPluralForms["en"];
+ var pos = pluralForm(num);
+ // Map true to 1 and false to 0, keep any numeric return value the same.
+ return pos === true ? 1 : pos ? pos : 0;
+};
+
+/*
+ * A dummy identity function. It's used as a signal to automatic
+ * translation-identification tools that they shouldn't mark this
+ * text up to be translated, even though it looks like
+ * natural-language text. (And likewise, a signal to linters that
+ * they shouldn't complain that this text isn't translated.)
+ * Use it like so: 'tag.author = i18n.i18nDoNotTranslate("Jim");'
+ */
+var i18nDoNotTranslate = _;
+
+/**
+ * Dummy Handlebars _ function. Is a noop.
+ * Should be used as: {{#_}}...{{/_}}
+ * The text is extracted, at compile-time, by server-side scripts.
+ * This is just used for marking up those fragments that need translation.
+ * The translated text is injected at deploy-time.
+ */
+var handlebarsUnderscore = function (options) {
+ return options.fn(this);
+};
+
+/**
+ * Mark text as not needing translation.
+ *
+ * This function is used to let i18nize_templates.py know that
+ * everything within it does not need to be translate.
+ * Should be used as: {{#i18nDoNotTranslate}}...{{/i18nDoNotTranslate}}
+ * It does not need to actually do anything and hence returns the contents
+ * as is.
+ */
+var handlebarsDoNotTranslate = function (options) {
+ return options.fn(this);
+};
+
+/**
+ * Handlebars ngettext function.
+ * Doesn't do any translation, is used for showing the correct string
+ * based upon the specified number and language.
+ * All strings are extracted (at compile-time) and injected (at
+ * deploy-time). By default this should be used as:
+ * {{#ngettext NUM}}singular{{else}}plural{{/ngettext}}
+ * After injecting the translated strings into the page it'll read as:
+ * {{#ngettext NUM "lang" 0}}singular{{else}}plural{{/ngettext}}
+ * (May depend upon the language used and how many different plural
+ * forms the language has.)
+ *
+ * Arguments:
+ * - num: The number upon which to toggle the plural forms.
+ * - lang: The language to use as the basis for the pluralization.
+ * - pos: The expected plural form (depends upon the language)
+ */
+var handlebarsNgettext = function (num, lang, pos, options) {
+ // This method has two signatures:
+ // (num) (the default for when the code is run in dev mode)
+ // (num, lang, pos) (for when the code is run in prod mode)
+ if (typeof lang !== "string") {
+ options = lang;
+ lang = "en";
+ pos = 0;
+ }
+
+ // Add in 'num' as a magic variable.
+ this.num = this.num || num;
+
+ // If the result of the plural form function given the specified
+ // number matches the expected position then we give the first
+ // result, otherwise we give the inverse result.
+ return ngetpos(num) === pos ?
+ options.fn(this) :
+ options.inverse(this);
+};
+
+/**
+ * Rounds num to X places, and uses the proper decimal seperator.
+ * But does *not* insert thousands separators.
+ */
+var localeToFixed = function (num, places) {
+ var decimalSeperator = icu.getDecimalFormatSymbols().decimal_separator;
+ var localeFixed = num.toFixed(places).replace(".", decimalSeperator);
+ if (localeFixed === "-0") {
+ localeFixed = "0";
+ }
+
+ return localeFixed;
+};
+
+// This is necessary for khan-exercises, perseus, and
+// bootstrap-daterangepicker (live-editor also uses the global i18n
+// var, but defines its own version of it.) We export the symbols
+// that they need.
+module.exports = {
+ _: _,
+ ngettext: ngettext,
+ i18nDoNotTranslate: i18nDoNotTranslate,
+ // khan-exercises is the only client of ngetpos (which is emitted
+ // into khan-exercises by kake/translate-exercises.py).
+ ngetpos: ngetpos
+}
diff --git a/src/components/math-input/lib/icu-slim.js b/src/components/math-input/lib/icu-slim.js
new file mode 100644
index 0000000..e675a14
--- /dev/null
+++ b/src/components/math-input/lib/icu-slim.js
@@ -0,0 +1,99 @@
+// This file was automatically generated by Khan/localeplanet/slim.py
+// We only use one function from `localeplanet` on mobile native, so we
+// cut the weight dramatically by generating this slim version.
+// [git hash: 6915111db5c0588b5d5f9af4871fe967a673c19f]
+
+var data = {
+ "configs": [{
+ "grouping_separator": ",", "decimal_separator": ".", "minus": "-"
+ }, { "grouping_separator": "\u00a0", "decimal_separator": ",", "minus": "-" }, {
+ "grouping_separator": "\u00a0", "decimal_separator": ".", "minus": "-"
+ }, { "grouping_separator": "\u066c", "decimal_separator": "\u066b", "minus": "-" }, {
+ "grouping_separator": ".", "decimal_separator": ",", "minus": "-"
+ }, { "grouping_separator": "'", "decimal_separator": ".", "minus": "-" }, {
+ "grouping_separator": "\u2019", "decimal_separator": ".", "minus": "\u2212"
+ }, { "grouping_separator": ".", "decimal_separator": ",", "minus": "\u2212" }, {
+ "grouping_separator": ",", "decimal_separator": ".", "minus": "\u2212"
+ }, { "grouping_separator": "\u00a0", "decimal_separator": ",", "minus": "\u2212" }], "locales": {
+ "gv": 0, "gu": 0, "ku-Arab-SY": 0, "ga": 0, "gl": 4, "ne-NP": 0, "lt-LT": 8, "tt": 0, "tr": 4, "ts": 0,
+ "pa-Guru": 0, "tn": 0, "to": 0, "tl": 0, "th": 0, "ti": 0, "tg": 0, "te": 0, "mn-Cyrl": 0, "nds-DE": 0,
+ "kcg": 0,
+ "en-NA": 0, "en-NZ": 0, "ro-MD": 4, "de-BE": 4, "gu-IN": 0, "mk-MK": 4, "gaa-GH": 0, "lv": 9, "kam-KE": 0,
+ "mn-Mong-CN": 0, "trv": 0, "zh": 0, "oc-FR": 0, "zh-HK": 0, "zu": 1, "zh-CN": 0, "ts-ZA": 0, "se-FI": 0,
+ "ha-Arab": 0, "tt-RU": 0, "uz-Latn-UZ": 0, "ar-LY": 3, "am-ET": 0, "my": 0, "ko-KR": 0, "aa-DJ": 0,
+ "__language__": 0, "ak-GH": 2, "ha-Latn": 0, "id-ID": 4, "mr-IN": 0, "uz-Arab": 3, "ve": 0, "hi-IN": 0,
+ "gl-ES": 4, "ku-Arab-IR": 0, "ku-Arab-IQ": 0, "vi": 4, "ii-CN": 0, "sv-FI": 9, "da-DK": 4, "en-BZ": 0,
+ "zh-SG": 0,
+ "en-BW": 0, "om-ET": 0, "trv-TW": 0, "om": 0, "hu-HU": 1, "en-BE": 4, "ml": 0, "mo": 4, "mn": 0, "mk": 4,
+ "mt": 0,
+ "ms": 0, "mr": 0, "ta": 0, "af-NA": 1, "en-PK": 0, "en-PH": 0, "mn-Cyrl-MN": 0, "zu-ZA": 1, "ss-ZA": 0,
+ "bn-BD": 0, "pl-PL": 1, "sa-IN": 0, "pa-Arab": 3, "sr": 4, "ha-NE": 0, "ha-NG": 0, "sid": 0, "ha-Arab-SD": 0,
+ "fr": 1, "ny-MW": 0, "sr-Latn-YU": 4, "fa": 3, "en-Dsrt-US": 0, "fi": 1, "uz-Cyrl": 0, "fo": 4, "ss": 0,
+ "hy-AM": 4, "sq": 4, "sw": 0, "ar-IQ": 3, "st": 0, "sk": 1, "si": 0, "sh": 4, "fa-AF": 3, "es-VE": 4,
+ "pt-BR": 4,
+ "sa": 0, "he-IL": 0, "sh-CS": 4, "se": 0, "fr-CH": 5, "it-CH": 5, "yo-NG": 0, "fr-CA": 1, "kk-Cyrl": 1,
+ "pa-IN": 0, "nb-NO": 1, "ca-ES": 4, "ss-SZ": 0, "cch-NG": 0, "lo": 0, "sr-YU": 4, "de-CH": 5, "nl-NL": 4,
+ "lt": 8,
+ "tg-Cyrl": 0, "dz-BT": 0, "fil": 0, "en-US-POSIX": 0, "yo": 0, "es-DO": 0, "bn-IN": 0, "ru-RU": 1,
+ "sr-Latn-BA": 4, "ha-GH": 0, "sr-ME": 4, "mn-MN": 0, "ga-IE": 0, "es-CR": 4, "fr-LU": 4, "es-CO": 4, "kpe": 0,
+ "el": 4, "eo": 1, "en": 0, "az-AZ": 4, "ee": 0, "en-TT": 0, "ee-GH": 0, "eu": 4, "et": 1, "es": 4, "cs-CZ": 1,
+ "rw": 4, "uz-UZ": 0, "ti-ET": 0, "ti-ER": 0, "ar-JO": 3, "ro": 4, "ar-DZ": 4, "gv-GB": 0, "mn-CN": 0,
+ "kk-KZ": 1,
+ "fil-PH": 0, "syr-SY": 0, "nn-NO": 9, "ar-MA": 4, "sw-KE": 0, "dv-MV": 0, "xh": 0, "ky-KG": 0, "es-GT": 0,
+ "sr-BA": 4, "mn-Mong": 0, "kfo": 0, "en-CA": 0, "kok": 0, "es-NI": 0, "so-SO": 0, "tr-TR": 4, "zh-Hant-TW": 0,
+ "om-KE": 0, "ar-SY": 3, "my-MM": 0, "xh-ZA": 0, "sr-Cyrl-BA": 4, "zh-Hans-HK": 0, "fi-FI": 1, "ar-SA": 3,
+ "ha-Arab-NG": 0, "en-ZW": 0, "az-Latn-AZ": 4, "zh-Hant-MO": 0, "en-ZA": 1, "so-ET": 0, "si-LK": 0, "sv": 9,
+ "ar-AE": 3, "wo-SN": 0, "ur-PK": 0, "ku-SY": 0, "ha-Latn-GH": 0, "es-UY": 4, "sr-Cyrl-ME": 4, "es-US": 0,
+ "ug-CN": 0, "en-JM": 0, "so-DJ": 0, "so": 0, "hy-AM-REVISED": 4, "az-Latn": 4, "en-HK": 0, "kaj": 0, "sl": 4,
+ "kam": 0, "haw-US": 0, "fur-IT": 0, "fr-FR": 1, "ug-Arab-CN": 0, "te-IN": 0, "byn-ER": 0, "uz-Arab-AF": 3,
+ "ka": 4, "kk": 1, "ko": 0, "kn": 0, "km": 4, "kl": 4, "kw": 0, "ku": 0, "ky": 0, "sr-Latn-CS": 4, "ar-SD": 3,
+ "en-GB": 0, "aa-ER": 0, "ee-TG": 0, "ig-NG": 0, "es-BO": 4, "cy-GB": 0, "sl-SI": 4, "ms-MY": 0, "gez": 0,
+ "de": 4,
+ "da": 4, "eu-ES": 4, "dz": 0, "dv": 0, "ps-AF": 3, "or-IN": 0, "en-Shaw": 0, "kw-GB": 0, "kcg-NG": 0,
+ "en-VI": 0,
+ "th-TH": 0, "ar-EG": 3, "ha-SD": 0, "ku-Latn": 0, "uz-Cyrl-UZ": 0, "ne-IN": 0, "kfo-CI": 0, "sr-Latn": 4,
+ "ku-Latn-TR": 0, "tig-ER": 0, "wo": 0, "bo-IN": 0, "sr-Cyrl-RS": 4, "az-Cyrl": 4, "aa-ER-SAAHO": 0, "fr-BE": 4,
+ "ja": 0, "cop": 0, "ar-LB": 3, "pt-PT": 1, "ln": 4, "uz-Latn": 0, "sq-AL": 4, "wal-ET": 0, "sr-Latn-ME": 4,
+ "ca": 4, "cy": 0, "cs": 1, "bg-BG": 1, "ps": 3, "kl-GL": 4, "pt": 4, "vi-VN": 4, "pa": 0, "ta-IN": 0,
+ "nr-ZA": 0,
+ "ak": 2, "pl": 1, "ar-BH": 3, "am": 0, "en-US": 0, "byn": 0, "en-UM": 0, "lo-LA": 0, "gaa": 0, "ar-KW": 3,
+ "fur": 0, "es-PR": 0, "es-PY": 4, "es-PE": 0, "so-KE": 0, "tg-Cyrl-TJ": 0, "es-PA": 0, "en-IN": 0, "uz-AF": 3,
+ "en-IE": 0, "is": 7, "iu": 0, "it": 4, "iw": 0, "tg-TJ": 0, "ii": 0, "in": 4, "ia": 0, "ja-JP": 0, "id": 4,
+ "ig": 0, "kok-IN": 0, "pa-Guru-IN": 0, "bo-CN": 0, "pa-PK": 3, "sr-Latn-RS": 4, "gsw-CH": 6, "ro-RO": 4,
+ "sr-CS": 4, "ar-YE": 3, "syr": 0, "lv-LV": 9, "zh-MO": 0, "nl-BE": 4, "ku-Arab": 0, "gsw": 6, "sk-SK": 1,
+ "zh-TW": 0, "ml-IN": 0, "es-MX": 0, "de-DE": 4, "cch": 0, "kaj-NG": 0, "el-GR": 4, "zh-Hans": 0, "zh-Hant": 0,
+ "en-Dsrt": 0, "tn-ZA": 0, "ar-TN": 4, "zh-Hans-MO": 0, "ny": 0, "pa-Arab-PK": 3, "af-ZA": 1, "wo-Latn-SN": 0,
+ "fr-SN": 1, "zh-Hans-SG": 0, "es-SV": 0, "haw": 0, "az-Cyrl-AZ": 4, "ve-ZA": 0, "be-BY": 1, "km-KH": 4,
+ "tig": 0,
+ "kk-Cyrl-KZ": 1, "kn-IN": 0, "ar-OM": 3, "en-MP": 0, "en-MT": 0, "se-NO": 0, "ku-TR": 0, "ru-UA": 1, "is-IS": 7,
+ "en-MH": 0, "root": 0, "ka-GE": 4, "es-HN": 0, "wo-Latn": 0, "es-CL": 4, "ln-CG": 4, "ln-CD": 4, "sr-Cyrl": 4,
+ "de-AT": 4, "be": 1, "bg": 1, "zh-Hant-HK": 0, "bn": 0, "bo": 0, "et-EE": 1, "bs": 4, "ku-IR": 0, "ku-IQ": 0,
+ "sr-Cyrl-CS": 4, "ug-Arab": 0, "mt-MT": 0, "es-AR": 4, "oc": 0, "ms-BN": 4, "nds": 0, "or": 0, "nso": 0,
+ "nr": 0,
+ "sid-ET": 0, "bs-BA": 4, "en-GU": 0, "wal": 0, "sh-BA": 4, "ur-IN": 3, "fo-FO": 4, "kpe-LR": 0, "gez-ER": 0,
+ "hy": 4, "gez-ET": 0, "hr": 4, "hu": 1, "el-CY": 4, "to-TO": 0, "hi": 0, "ha": 0, "aa-ET": 0, "he": 0,
+ "hr-HR": 4,
+ "uz": 0, "nso-ZA": 0, "ur": 0, "uk": 1, "ug": 0, "el-POLYTON": 4, "aa": 0, "de-LI": 5, "af": 1, "it-IT": 4,
+ "es-EC": 4, "zh-Hans-CN": 0, "as": 0, "ar": 3, "uk-UA": 1, "sv-SE": 9, "fr-MC": 1, "de-LU": 4, "az": 4,
+ "es-ES": 4, "nl": 4, "nn": 9, "no": 1, "st-ZA": 0, "nb": 1, "ne": 0, "en-AU": 0, "en-AS": 0, "sh-YU": 4,
+ "rw-RW": 4, "sr-Cyrl-YU": 4, "st-LS": 0, "ha-Latn-NG": 0, "ha-Latn-NE": 0, "kpe-GN": 0, "ru": 1, "fa-IR": 3,
+ "en-SG": 0, "as-IN": 0, "sr-RS": 4, "ar-QA": 3, "sw-TZ": 0
+ }
+};
+
+var locale = 'en-US';
+
+module.exports = {
+ getLocale() {
+ return locale;
+ },
+ getLanguage() {
+ return locale.split("-")[0];
+ },
+ setLocale(newLocale) {
+ locale = newLocale;
+ },
+ getDecimalFormatSymbols() {
+ return data.configs[data.locales[locale]] || data.configs[0];
+ }
+};
diff --git a/src/components/math-input/overrides.css b/src/components/math-input/overrides.css
new file mode 100644
index 0000000..e0c84c7
--- /dev/null
+++ b/src/components/math-input/overrides.css
@@ -0,0 +1,108 @@
+@import "https://cdnjs.cloudflare.com/ajax/libs/mathquill/0.10.1/mathquill.min.css";
+@import "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.css";
+
+.keypad-input .mq-editable-field .mq-cursor:not(:only-child),
+.keypad-input .mq-editable-field .mq-root-block.mq-hasCursor > .mq-cursor:only-child {
+ /* HACK(charlie): Magic numbers to properly size and position the vertical
+ cursor, which is visible whenever the cursor is not alone in its parent,
+ with the exception that it's also visible when the entire input is
+ empty. */
+ height: 20px !important;
+ vertical-align: middle !important;
+ margin-top: -5px !important;
+}
+
+.keypad-input .mq-editable-field .mq-cursor {
+ border-color: #78c008;
+
+ border-left: 2px solid #78c008 !important;
+ border-radius: 1px;
+
+ margin-left: -1px !important;
+ margin-right: -1px !important;
+
+ /* Fade the cursor in and out, overriding MathQuill's default behavior. */
+ /* NOTE(charlie): The 500ms animation length perfectly matches MathQuill's
+ own frequency for toggling the application of the .mq-blink class. If we
+ were to change this animation length at all, we'd need to modify
+ MathQuill as well to match. */
+ visibility: visible !important;
+ opacity: 1 !important;
+ transition: opacity 500ms ease-out !important;
+}
+
+.keypad-input .mq-editable-field .mq-cursor.mq-blink {
+ visibility: visible !important;
+ opacity: 0 !important;
+ transition: opacity 500ms ease-in !important;
+}
+
+.keypad-input .mq-editable-field .mq-non-leaf .mq-cursor:only-child {
+ border: 2px solid !important;
+ padding: 0 4px 0 4px;
+
+ border-color: #78c008 !important; /* bright-green color */
+ transition: border-color 500ms ease-out !important;
+ opacity: 1 !important;
+}
+
+.keypad-input .mq-editable-field .mq-non-leaf .mq-cursor.mq-blink:only-child {
+ border-color: #CCC !important; /* grey color */
+ transition: border-color 500ms ease-in !important;
+ opacity: 1 !important;
+}
+
+.keypad-input .mq-empty {
+ background: transparent !important;
+}
+
+/* also adds empty block styling to elements with .mq-hasCursor but without a cursor element (this happens where the cursor is when the math input loses focus) */
+.keypad-input .mq-empty:not(.mq-root-block):after, .keypad-input .mq-hasCursor:empty:not(.mq-root-block):after {
+ visibility: visible !important;
+
+ /* hides the 'c' content added by MathQuill to measure the width */
+ color: transparent;
+
+ display: inline-block;
+ border: 2px solid #ccc;
+ border-radius: 1px;
+ padding: 0 4px 0 4px;
+ margin-left: -1px;
+ margin-right: -1px;
+}
+
+.keypad-input .mq-selection .mq-empty:not(.mq-root-block):after {
+ border-color: #ffffff;
+}
+
+.keypad-input .mq-hasCursor:empty:not(.mq-root-block):after {
+ /* place a c inside for sizing the cursor (for the case explained above); normally, MathQuill already does this for .mq-cursor */
+ content: 'c';
+}
+
+.keypad-input .mq-math-mode .mq-selection .mq-non-leaf,
+.keypad-input .mq-editable-field .mq-selection .mq-non-leaf {
+ background: #78c008 !important;
+ color: white !important;
+ border-color: white !important;
+}
+
+.keypad-input .mq-math-mode .mq-selection .mq-scaled,
+.keypad-input .mq-editable-field .mq-selection .mq-scaled {
+ background: transparent !important;
+ color: white !important;
+ border-color: transparent !important;
+}
+
+.keypad-input .mq-selection {
+ display: inline-block !important;
+ background: #78c008 !important;
+ color: white !important;
+ border-color: white !important;
+}
+
+/*The keypad sets its own color styles for KaTeX elements that are rendered in*/
+/*its keys, so prevent any external styling.*/
+.keypad-container .katex {
+ color: inherit !important;
+}
diff --git a/src/components/math-input/popover.css b/src/components/math-input/popover.css
new file mode 100644
index 0000000..60ae332
--- /dev/null
+++ b/src/components/math-input/popover.css
@@ -0,0 +1,23 @@
+/**
+ * Styles for managing the popover animations. These were generated by
+ * Aphrodite's autoprefixer, but some minor tweaks were applied to get them
+ * working on mobile Safari. Ideally, we'd be generating these styles with
+ * Aphrodite (along with ReactCSSTransitionGroup's support for custom
+ * classnames), but the generated styles have issues on mobile Safari.
+ * See: https://github.com/Khan/aphrodite/issues/68.
+ *
+ * If the animation durations change, the corresponding values in
+ * popover-manager.js must change as well.
+ */
+
+.popover-enter {
+ opacity: 0 !important;
+}
+
+.popover-enter.popover-enter-active {
+ opacity: 1 !important;
+ transition: opacity 200ms ease-out !important;
+ -webkit-transition: opacity 200ms ease-out !important;
+ -moz-transition: opacity 200ms ease-out !important;
+ -ms-transition: opacity 200ms ease-out !important;
+}
diff --git a/src/components/math-input/store/index.js b/src/components/math-input/store/index.js
new file mode 100644
index 0000000..ff3618e
--- /dev/null
+++ b/src/components/math-input/store/index.js
@@ -0,0 +1,493 @@
+const Redux = require('redux');
+
+const { tabletCutoffPx } = require('../components/common-style');
+const computeLayoutParameters = require('../components/compute-layout-parameters');
+const {
+ DeviceOrientations,
+ DeviceTypes,
+ EchoAnimationTypes,
+ KeyTypes,
+ KeypadTypes,
+ LayoutModes,
+} = require('../consts');
+const Keys = require('../data/keys');
+const KeyConfigs = require('../data/key-configs');
+const CursorContexts = require('../components/input/cursor-contexts');
+const GestureManager = require('../components/gesture-manager');
+const VelocityTracker = require('../components/velocity-tracker');
+
+const FractionKeypad = require('../components/fraction-keypad');
+const ExpressionKeypad = require('../components/expression-keypad');
+
+const keypadForType = {
+ [KeypadTypes.FRACTION]: FractionKeypad,
+ [KeypadTypes.EXPRESSION]: ExpressionKeypad,
+};
+
+const createStore = () => {
+ const initialInputState = {
+ keyHandler: null,
+ cursor: {
+ context: CursorContexts.NONE,
+ },
+ };
+
+ const inputReducer = function (state = initialInputState, action) {
+ switch (action.type) {
+ case 'SetKeyHandler':
+ return {
+ ...state,
+ keyHandler: action.keyHandler,
+ };
+
+ case 'PressKey':
+ const keyConfig = KeyConfigs[action.key];
+ if (keyConfig.type !== KeyTypes.KEYPAD_NAVIGATION) {
+ // This is probably an anti-pattern but it works for the
+ // case where we don't actually control the state but we
+ // still want to communicate with the other object
+ return {
+ ...state,
+ cursor: state.keyHandler(keyConfig.id),
+ };
+ }
+
+ // TODO(kevinb) get state from MathQuill and store it?
+ return state;
+
+ case 'SetCursor':
+ return {
+ ...state,
+ cursor: action.cursor,
+ };
+
+ default:
+ return state;
+ }
+ };
+
+ const defaultKeypadType = KeypadTypes.EXPRESSION;
+
+ const initialKeypadState = {
+ extraKeys: ['x', 'y', Keys.THETA, Keys.PI],
+ keypadType: defaultKeypadType,
+ active: false,
+ };
+
+ const keypadReducer = function (state = initialKeypadState, action) {
+ switch (action.type) {
+ case 'DismissKeypad':
+ return {
+ ...state,
+ active: false,
+ };
+
+ case 'ActivateKeypad':
+ return {
+ ...state,
+ active: true,
+ };
+
+ case 'ConfigureKeypad':
+ return {
+ ...state,
+ // Default `extraKeys` to the empty array.
+ extraKeys: [],
+ ...action.configuration,
+ };
+
+ case 'PressKey':
+ const keyConfig = KeyConfigs[action.key];
+ // NOTE(charlie): Our keypad system operates by triggering key
+ // presses with key IDs in a dumb manner, such that the keys
+ // don't know what they can do--instead, the store is
+ // responsible for interpreting key presses and triggering the
+ // right actions when they occur. Hence, we figure off a
+ // dismissal here rather than dispatching a dismiss action in
+ // the first place.
+ if (keyConfig.id === Keys.DISMISS) {
+ return keypadReducer(state, { type: 'DismissKeypad' });
+ }
+ return state;
+
+ default:
+ return state;
+ }
+ };
+
+ // We default to the right-most page. This is done so-as to enforce a
+ // consistent orientation between the view pager layout and the flattened
+ // layout, where our default page appears on the far right.
+ const getDefaultPage = (numPages) => numPages - 1;
+
+ const initialPagerState = {
+ animateToPosition: false,
+ currentPage: getDefaultPage(keypadForType[defaultKeypadType].numPages),
+ // The cumulative differential in the horizontal direction for the
+ // current swipe.
+ dx: 0,
+ numPages: keypadForType[defaultKeypadType].numPages,
+ pageWidthPx: 0,
+ velocityTracker: new VelocityTracker(),
+ };
+
+ const pagerReducer = function (state = initialPagerState, action) {
+ switch (action.type) {
+ case 'ConfigureKeypad':
+ const { keypadType } = action.configuration;
+ const { numPages } = keypadForType[keypadType];
+ return {
+ ...state,
+ numPages,
+ animateToPosition: false,
+ currentPage: getDefaultPage(numPages),
+ dx: 0,
+ };
+
+ case 'SetPageSize':
+ return {
+ ...state,
+ pageWidthPx: action.pageWidthPx,
+ };
+
+ case 'PressKey':
+ const keyConfig = KeyConfigs[action.key];
+
+ // Reset the keypad page if the user performs a math operation.
+ if (keyConfig.type === KeyTypes.VALUE ||
+ keyConfig.type === KeyTypes.OPERATOR) {
+ return pagerReducer(state, { type: 'ResetKeypadPage' });
+ }
+ return state;
+
+ case 'ResetKeypadPage':
+ return {
+ ...state,
+ animateToPosition: true,
+ // We start at the right-most page.
+ currentPage: getDefaultPage(state.numPages),
+ dx: 0,
+ };
+
+ case 'PageKeypadRight':
+ const nextPage = Math.min(
+ state.currentPage + 1,
+ state.numPages - 1
+ );
+ return {
+ ...state,
+ animateToPosition: true,
+ currentPage: nextPage,
+ dx: 0,
+ };
+
+ case 'PageKeypadLeft':
+ const prevPage = Math.max(state.currentPage - 1, 0);
+ return {
+ ...state,
+ animateToPosition: true,
+ currentPage: prevPage,
+ dx: 0,
+ };
+
+ case 'OnSwipeChange':
+ state.velocityTracker.push(action.dx);
+
+ return {
+ ...state,
+ animateToPosition: false,
+ dx: action.dx,
+ };
+
+ case 'OnSwipeEnd':
+ const { pageWidthPx, velocityTracker } = state;
+ const { dx } = action;
+ const velocity = velocityTracker.getVelocity();
+
+ // NOTE(charlie): These will need refinement. The velocity comes
+ // from Framer.
+ const minFlingVelocity = 0.1;
+ const minFlingDistance = 10;
+
+ const shouldPageRight = (dx < -pageWidthPx / 2) ||
+ (velocity < -minFlingVelocity && dx < -minFlingDistance);
+
+ const shouldPageLeft = (dx > pageWidthPx / 2) ||
+ (velocity > minFlingVelocity && dx > minFlingDistance);
+
+ if (shouldPageRight) {
+ return pagerReducer(state, { type: 'PageKeypadRight' });
+ } else if (shouldPageLeft) {
+ return pagerReducer(state, { type: 'PageKeypadLeft' });
+ }
+
+ return {
+ ...state,
+ animateToPosition: true,
+ dx: 0,
+ };
+
+ default:
+ return state;
+ }
+ };
+
+ const createGestureManager = (swipeEnabled) => {
+ return new GestureManager({
+ swipeEnabled,
+ }, {
+ onSwipeChange: (dx) => {
+ store.dispatch({
+ type: 'OnSwipeChange',
+ dx,
+ });
+ },
+ onSwipeEnd: (dx) => {
+ store.dispatch({
+ type: 'OnSwipeEnd',
+ dx,
+ });
+ },
+ onActiveNodesChanged: (activeNodes) => {
+ store.dispatch({
+ type: 'SetActiveNodes',
+ activeNodes,
+ });
+ },
+ onClick: (key, layoutProps, inPopover) => {
+ store.dispatch({
+ type: 'PressKey',
+ key,
+ ...layoutProps,
+ inPopover,
+ });
+ },
+ }, [], [
+ Keys.BACKSPACE,
+ Keys.UP,
+ Keys.RIGHT,
+ Keys.DOWN,
+ Keys.LEFT,
+ ]);
+ };
+
+ const initialGestureState = {
+ popover: null,
+ focus: null,
+ gestureManager: createGestureManager(
+ keypadForType[defaultKeypadType].numPages > 1
+ ),
+ };
+
+ const gestureReducer = function (state = initialGestureState, action) {
+ switch (action.type) {
+ case 'DismissKeypad':
+ // NOTE(charlie): In the past, we enforced the "gesture manager
+ // will not receive any events when the keypad is hidden"
+ // assumption by assuming that the keypad would be hidden when
+ // dismissed and, as such, that none of its managed DOM nodes
+ // would be able to receive touch events. However, on mobile
+ // Safari, we're seeing that some of the keys receive touch
+ // events even when off-screen, inexplicably. So, to guard
+ // against that bug and make the contract explicit, we enable
+ // and disable event tracking on activation and dismissal.
+ state.gestureManager.disableEventTracking();
+ return state;
+
+ case 'ActivateKeypad':
+ state.gestureManager.enableEventTracking();
+ return state;
+
+ case 'SetActiveNodes':
+ return {
+ ...state,
+ ...action.activeNodes,
+ };
+
+ case 'ConfigureKeypad':
+ const { keypadType } = action.configuration;
+ const { numPages } = keypadForType[keypadType];
+ const swipeEnabled = numPages > 1;
+ return {
+ popover: null,
+ focus: null,
+ gestureManager: createGestureManager(swipeEnabled),
+ };
+
+ default:
+ return state;
+ }
+ };
+
+ // Used to generate unique animation IDs for the echo animations. The actual
+ // values are irrelevant as long as they are unique.
+ let _lastAnimationId = 0;
+
+ const initialEchoState = {
+ echoes: [],
+ };
+
+ const echoReducer = function (state = initialEchoState, action) {
+ switch (action.type) {
+ case 'PressKey':
+ const keyConfig = KeyConfigs[action.key];
+
+ // Add in the echo animation if the user performs a math
+ // operation.
+ if (keyConfig.type === KeyTypes.VALUE ||
+ keyConfig.type === KeyTypes.OPERATOR) {
+ return {
+ ...state,
+ echoes: [
+ ...state.echoes,
+ {
+ animationId: "" + _lastAnimationId++,
+ animationType: action.inPopover
+ ? EchoAnimationTypes.LONG_FADE_ONLY
+ : EchoAnimationTypes.FADE_ONLY,
+ borders: action.borders,
+ id: keyConfig.id,
+ initialBounds: action.initialBounds,
+ },
+ ],
+ };
+ }
+ return state;
+
+ case 'RemoveEcho':
+ const remainingEchoes = state.echoes.filter((echo) => {
+ return echo.animationId !== action.animationId;
+ });
+ return {
+ ...state,
+ echoes: remainingEchoes,
+ };
+
+ default:
+ return state;
+ }
+ };
+
+ const initialLayoutState = {
+ gridDimensions: {
+ numRows: keypadForType[defaultKeypadType].rows,
+ numColumns: keypadForType[defaultKeypadType].columns,
+ numMaxVisibleRows: keypadForType[defaultKeypadType].maxVisibleRows,
+ numPages: keypadForType[defaultKeypadType].numPages,
+ },
+ buttonDimensions: {
+ widthPx: 48,
+ heightPx: 48,
+ },
+ pageDimensions: {
+ pageWidthPx: 0,
+ pageHeightPx: 0,
+ },
+ layoutMode: LayoutModes.FULLSCREEN,
+ paginationEnabled: false,
+ navigationPadEnabled: false,
+ };
+
+ /**
+ * Compute the additional layout state based on the provided page and grid
+ * dimensions.
+ */
+ const layoutParametersForDimensions = (pageDimensions, gridDimensions) => {
+ const { pageWidthPx, pageHeightPx } = pageDimensions;
+
+ // Determine the device type and orientation.
+ const deviceOrientation = pageWidthPx > pageHeightPx
+ ? DeviceOrientations.LANDSCAPE
+ : DeviceOrientations.PORTRAIT;
+ const deviceType =
+ Math.min(pageWidthPx, pageHeightPx) > tabletCutoffPx ?
+ DeviceTypes.TABLET : DeviceTypes.PHONE;
+
+ // Using that information, make some decisions (or assumptions)
+ // about the resulting layout.
+ const navigationPadEnabled = deviceType === DeviceTypes.TABLET;
+ const paginationEnabled = deviceType === DeviceTypes.PHONE &&
+ deviceOrientation === DeviceOrientations.PORTRAIT;
+
+ const deviceInfo = { deviceOrientation, deviceType };
+ const layoutOptions = {
+ navigationPadEnabled,
+ paginationEnabled,
+ // HACK(charlie): It's not great that we're making assumptions about
+ // the toolbar (which is rendered by webapp, and should always be
+ // visible and anchored to the bottom of the page for phone and
+ // tablet exercises). But this is primarily a heuristic (the goal is
+ // to preserve a 'good' amount of space between the top of the
+ // keypad and the top of the page) so we afford to have some margin
+ // of error.
+ toolbarEnabled: true,
+ };
+
+ return {
+ ...computeLayoutParameters(
+ gridDimensions,
+ pageDimensions,
+ deviceInfo,
+ layoutOptions
+ ),
+ // Pass along some of the layout information, so that other
+ // components in the heirarchy can adapt appropriately.
+ navigationPadEnabled,
+ paginationEnabled,
+ };
+ };
+
+ const layoutReducer = function (state = initialLayoutState, action) {
+ switch (action.type) {
+ case 'ConfigureKeypad':
+ const { keypadType } = action.configuration;
+ const gridDimensions = {
+ numRows: keypadForType[keypadType].rows,
+ numColumns: keypadForType[keypadType].columns,
+ numMaxVisibleRows: keypadForType[keypadType].maxVisibleRows,
+ numPages: keypadForType[keypadType].numPages,
+ };
+
+ return {
+ ...state,
+ ...layoutParametersForDimensions(
+ state.pageDimensions, gridDimensions
+ ),
+ gridDimensions,
+ };
+
+ case 'SetPageSize':
+ const { pageWidthPx, pageHeightPx } = action;
+ const pageDimensions = { pageWidthPx, pageHeightPx };
+
+ return {
+ ...state,
+ ...layoutParametersForDimensions(
+ pageDimensions, state.gridDimensions
+ ),
+ pageDimensions,
+ };
+
+ default:
+ return state;
+ }
+ };
+
+ const reducer = Redux.combineReducers({
+ input: inputReducer,
+ keypad: keypadReducer,
+ pager: pagerReducer,
+ gestures: gestureReducer,
+ echoes: echoReducer,
+ layout: layoutReducer,
+ });
+
+ // TODO(charlie): This non-inlined return is necessary so as to allow the
+ // gesture manager to dispatch actions on the store in its callbacks. We
+ // should come up with a better pattern to remove the two-way dependency.
+ const store = Redux.createStore(reducer);
+
+ return store;
+};
+
+module.exports = createStore;
diff --git a/src/components/math-input/tools/svg-to-react/convert.py b/src/components/math-input/tools/svg-to-react/convert.py
new file mode 100644
index 0000000..b70082c
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/convert.py
@@ -0,0 +1,110 @@
+import os
+import re
+import sys
+import symbol_map
+
+color = '#3B3E40'
+
+header = '''/**
+ * An autogenerated component that renders the %s iconograpy in SVG.
+ *
+ * Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
+ */
+const React = require('react');
+'''
+
+# A simple template with no PropTypes, for the case in which there are no
+# colors in the component.
+simple_template = header + '''
+const %s = () => {
+ return %s;
+};
+
+module.exports = %s;
+'''
+complex_template = header + '''
+const %s = React.createClass({
+ propTypes: {
+ color: React.PropTypes.string.isRequired,
+ },
+
+ render() {
+ return %s;
+ },
+});
+
+module.exports = %s;
+'''
+
+index_template = '''/**
+ * A directory of autogenerated icon components.
+ */
+
+module.exports = {
+%s
+};
+'''
+
+if __name__ == '__main__':
+ input_dir_name = sys.argv[1]
+ output_dir_name = sys.argv[2]
+
+ filename_map = {}
+
+ for filename in os.listdir(input_dir_name):
+ use_simple = True
+
+ svg_filename = filename.split('/')[-1].split('.')[0]
+
+ prefix = 'math-keypad-icon-'
+ if svg_filename[:len(prefix)] == prefix:
+ svg_filename = svg_filename[len(prefix):]
+ else:
+ continue
+
+ try:
+ symbol_name = symbol_map.filename_to_symbol[svg_filename]
+ except:
+ print 'Skipping: ' + svg_filename
+ continue
+
+ component_name = symbol_name.title().replace('_', '')
+ js_filename = symbol_name.lower().replace('_', '-')
+
+ with open(input_dir_name + '/' + filename, 'r') as f:
+ contents = f.read()
+
+ # Strip out the namespace tag
+ namespace = 'xmlns="http://www.w3.org/2000/svg"'
+ namespace_index = contents.index(namespace)
+ contents = contents[:namespace_index - 1] + contents[namespace_index + len(namespace):]
+
+ # Replace any colors
+ before = contents
+ contents = re.sub('"' + color + '"', '{this.props.color}', contents)
+ if before != contents:
+ use_simple = False
+
+ # Replace the xlink:href tag (special case)
+ contents = contents.replace('xlink:href', 'xlinkHref')
+ # Replace any other tags
+ tags = re.findall(r' (\S+)=', contents)
+ for tag in tags:
+ pieces = tag.split('-')
+ jsx_version = pieces[0] + ''.join(map(lambda x: x.title(), pieces[1:]))
+ contents = contents.replace(tag, jsx_version)
+
+ with open(output_dir_name + '/' + js_filename + '.js', 'w') as f:
+ template = simple_template if use_simple else complex_template
+ f.write(template % (symbol_name, component_name, contents, component_name))
+
+ filename_map[symbol_name] = js_filename
+
+ index_contents = ''
+ for symbol_name in filename_map:
+ if index_contents:
+ index_contents += '\n'
+ index_contents += ' %s: require(\'./%s\'),' % (symbol_name, filename_map[symbol_name])
+
+ with open(output_dir_name + '/index.js', 'w') as f:
+ f.write(index_template % index_contents)
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-0.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-0.svg
new file mode 100644
index 0000000..ce3e5a8
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-0.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-1.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-1.svg
new file mode 100644
index 0000000..3087ca0
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-1.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-2.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-2.svg
new file mode 100644
index 0000000..76a9f78
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-2.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-3.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-3.svg
new file mode 100644
index 0000000..c5f1bfe
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-3.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-4.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-4.svg
new file mode 100644
index 0000000..7519303
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-4.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-5.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-5.svg
new file mode 100644
index 0000000..2304865
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-5.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-6.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-6.svg
new file mode 100644
index 0000000..e95c8e4
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-6.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-7.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-7.svg
new file mode 100644
index 0000000..da2f6e9
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-7.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-8.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-8.svg
new file mode 100644
index 0000000..6bc6400
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-8.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-9.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-9.svg
new file mode 100644
index 0000000..806b30c
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-9.svg
@@ -0,0 +1,37 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-addition.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-addition.svg
new file mode 100644
index 0000000..5158fb4
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-addition.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-cos.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-cos.svg
new file mode 100644
index 0000000..4132feb
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-cos.svg
@@ -0,0 +1,43 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-delete.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-delete.svg
new file mode 100644
index 0000000..df45420
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-delete.svg
@@ -0,0 +1,50 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-dismiss.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-dismiss.svg
new file mode 100644
index 0000000..3f1b517
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-dismiss.svg
@@ -0,0 +1,41 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-division.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-division.svg
new file mode 100644
index 0000000..2abb9a1
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-division.svg
@@ -0,0 +1,44 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals-not.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals-not.svg
new file mode 100644
index 0000000..a7a0858
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals-not.svg
@@ -0,0 +1,62 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals.svg
new file mode 100644
index 0000000..f27bae7
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-equals.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-2.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-2.svg
new file mode 100644
index 0000000..ceecd7a
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-2.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-3.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-3.svg
new file mode 100644
index 0000000..26c5f22
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent-3.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent.svg
new file mode 100644
index 0000000..e79d260
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-exponent.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-fraction.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-fraction.svg
new file mode 100644
index 0000000..14749bf
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-fraction.svg
@@ -0,0 +1,51 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-greater-than.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-greater-than.svg
new file mode 100644
index 0000000..810a9f2
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-greater-than.svg
@@ -0,0 +1,52 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-base.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-base.svg
new file mode 100644
index 0000000..f312b29
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-base.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-denominator.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-denominator.svg
new file mode 100644
index 0000000..2712d40
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-denominator.svg
@@ -0,0 +1,66 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-exponent.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-exponent.svg
new file mode 100644
index 0000000..4b8e2df
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-exponent.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-parentheses.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-parentheses.svg
new file mode 100644
index 0000000..abd6fc0
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-jump-out-parentheses.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-less-than.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-less-than.svg
new file mode 100644
index 0000000..5ca4f64
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-less-than.svg
@@ -0,0 +1,52 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-10.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-10.svg
new file mode 100644
index 0000000..9ec4c52
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-10.svg
@@ -0,0 +1,41 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-e.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-e.svg
new file mode 100644
index 0000000..c49ef99
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log-e.svg
@@ -0,0 +1,41 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log.svg
new file mode 100644
index 0000000..aaed7cc
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-log.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-cross.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-cross.svg
new file mode 100644
index 0000000..e1165ff
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-cross.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-dot.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-dot.svg
new file mode 100644
index 0000000..fc0cd1b
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-multiplication-dot.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-percent.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-percent.svg
new file mode 100644
index 0000000..c487013
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-percent.svg
@@ -0,0 +1,45 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-2.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-2.svg
new file mode 100644
index 0000000..bceb578
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-2.svg
@@ -0,0 +1,40 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-3.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-3.svg
new file mode 100644
index 0000000..b09761b
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical-3.svg
@@ -0,0 +1,46 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical.svg
new file mode 100644
index 0000000..a08fead
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radical.svg
@@ -0,0 +1,46 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radix-character.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radix-character.svg
new file mode 100644
index 0000000..be5a8b6
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-radix-character.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-sin.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-sin.svg
new file mode 100644
index 0000000..248acf9
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-sin.svg
@@ -0,0 +1,43 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-subtraction.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-subtraction.svg
new file mode 100644
index 0000000..d3ece86
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-subtraction.svg
@@ -0,0 +1,38 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-tan.svg b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-tan.svg
new file mode 100644
index 0000000..400eeaf
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/icons/math-keypad-icon-tan.svg
@@ -0,0 +1,43 @@
+
+
diff --git a/src/components/math-input/tools/svg-to-react/symbol_map.py b/src/components/math-input/tools/svg-to-react/symbol_map.py
new file mode 100644
index 0000000..a1db1ef
--- /dev/null
+++ b/src/components/math-input/tools/svg-to-react/symbol_map.py
@@ -0,0 +1,41 @@
+
+filename_to_symbol = {
+ 'addition': 'PLUS',
+ 'subtraction': 'MINUS',
+ 'cos': 'COS',
+ 'sin': 'SIN',
+ 'tan': 'TAN',
+ 'delete': 'BACKSPACE',
+ 'dismiss': 'DISMISS',
+ 'division': 'DIVIDE',
+ 'equals': 'EQUAL',
+ 'equals-not': 'NEQ',
+ 'exponent-2': 'EXP_2',
+ 'exponent-3': 'EXP_3',
+ 'exponent': 'EXP',
+ 'fraction': 'FRAC_INCLUSIVE',
+ 'fraction-mixed-number': 'FRAC_EXCLUSIVE',
+ 'greater-than-not': 'GEQ',
+ 'greater-than': 'GT',
+ 'less-than-not': 'LEQ',
+ 'less-than': 'LT',
+ 'log-10': 'LOG',
+ 'log-e': 'LN',
+ 'log': 'LOG_N',
+ 'move-backward': 'ARROW',
+ 'parenthesis-left': 'LEFT_PAREN',
+ 'parenthesis-right': 'RIGHT_PAREN',
+ 'multiplication-cross': 'TIMES',
+ 'multiplication-dot': 'CDOT',
+ 'percent': 'PERCENT',
+ 'radix-character': 'PERIOD',
+ 'radical': 'RADICAL',
+ 'radical-2': 'SQRT',
+ 'radical-3': 'CUBE_ROOT',
+ 'jump-out-numerator': 'JUMP_OUT_NUMERATOR',
+ 'jump-out-base': 'JUMP_OUT_BASE',
+ 'jump-out-exponent': 'JUMP_OUT_EXPONENT',
+ 'jump-out-mixed-number-integer': 'JUMP_INTO_NUMERATOR',
+ 'jump-out-denominator': 'JUMP_OUT_DENOMINATOR',
+ 'jump-out-parentheses': 'JUMP_OUT_PARENTHESES'
+}
diff --git a/src/components/math-input/utils.js b/src/components/math-input/utils.js
new file mode 100644
index 0000000..6348bcd
--- /dev/null
+++ b/src/components/math-input/utils.js
@@ -0,0 +1,17 @@
+const { DecimalSeparators } = require('./consts');
+const icu = require('./lib/icu-slim');
+
+// We expect `window.icu` to be exposed by the parent. When in doubt, we fall
+// back to a period. We can only depend on a subset of what localeplanet
+// provides, however -- the things in `icu-slim.js` (there's a copy in ../lib/
+// for reference).
+let decimalSeparator;
+if (icu.getDecimalFormatSymbols().decimal_separator === ',') {
+ decimalSeparator = DecimalSeparators.COMMA;
+} else {
+ decimalSeparator = DecimalSeparators.PERIOD;
+}
+
+module.exports = {
+ decimalSeparator,
+};
diff --git a/src/index.js b/src/index.js
index f1881d2..f5d52e4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,4 @@
-import { EditorState, Entity } from 'draft-js';
+import { EditorState } from 'draft-js';
import decorateComponentWithProps from 'decorate-component-with-props';
import TeXBlock from './components/TeXBlock';
import removeTeXBlock from './modifiers/removeTeXBlock';
@@ -6,22 +6,34 @@ import InsertButton from './components/InsertKatexButton';
import styles from './styles.css';
+function noopTranslator(tex) {
+ return tex;
+}
+
export default (config = {}) => {
const theme = Object.assign(styles, config.theme || {});
const insertContent = config.insertContent || 'Ω';
- const doneContent = config.doneContent || { valid: 'Done', invalid: 'Invalid TeX' };
+ const doneContent = config.doneContent || {
+ valid: 'Done',
+ invalid: 'Invalid TeX',
+ };
const removeContent = config.removeContent || 'Remove';
+ const translator = config.translator || noopTranslator;
+ const katex = config.katex;
+
+ if (!katex || !katex.render) {
+ throw new Error('Invalid katex plugin provided!');
+ }
const store = {
getEditorState: undefined,
setEditorState: undefined,
getReadOnly: undefined,
setReadOnly: undefined,
- onChange: undefined
+ onChange: undefined,
};
const liveTeXEdits = new Map();
-
return {
initialize: ({ getEditorState, setEditorState, getReadOnly, setReadOnly }) => {
store.getEditorState = getEditorState;
@@ -30,17 +42,28 @@ export default (config = {}) => {
store.setReadOnly = setReadOnly;
},
- blockRendererFn: (block) => {
+ blockRendererFn: block => {
if (block.getType() === 'atomic') {
- const entity = Entity.get(block.getEntityAt(0));
+ const entity = store
+ .getEditorState()
+ .getCurrentContent()
+ .getEntity(block.getEntityAt(0));
const type = entity.getType();
- if (type === 'kateX') {
+ if (type === 'KateX') {
return {
- component: decorateComponentWithProps(TeXBlock, { theme, store, doneContent, removeContent }),
+ component: decorateComponentWithProps(TeXBlock, {
+ theme,
+ store,
+ doneContent,
+ removeContent,
+ translator,
+ katex,
+ MathInput: config.MathInput,
+ }),
editable: false,
props: {
- onStartEdit: (blockKey) => {
+ onStartEdit: blockKey => {
liveTeXEdits.set(blockKey, true);
store.setReadOnly(liveTeXEdits.size);
},
@@ -51,18 +74,25 @@ export default (config = {}) => {
store.setEditorState(EditorState.forceSelection(newEditorState, newEditorState.getSelection()));
},
- onRemove: (blockKey) => {
+ onRemove: blockKey => {
liveTeXEdits.delete(blockKey);
+ store.setReadOnly(liveTeXEdits.size);
+
const editorState = store.getEditorState();
const newEditorState = removeTeXBlock(editorState, blockKey);
store.setEditorState(newEditorState);
},
- }
+ },
};
}
}
return null;
},
- InsertButton: decorateComponentWithProps(InsertButton, { theme, store, children: insertContent })
+ InsertButton: decorateComponentWithProps(InsertButton, {
+ theme,
+ store,
+ translator,
+ defaultContent: insertContent,
+ }),
};
};
diff --git a/src/katex.js b/src/katex.js
new file mode 100644
index 0000000..49e84c1
--- /dev/null
+++ b/src/katex.js
@@ -0,0 +1,10 @@
+import katex from 'katex';
+
+/**
+ * A simple katex wrapper to enable injecting katex from outside this plugin
+ */
+
+export default {
+ render: katex.render,
+ __parse: katex.__parse,
+};
diff --git a/src/modifiers/insertTeXBlock.js b/src/modifiers/insertTeXBlock.js
index 8a76cea..5e6bc7d 100644
--- a/src/modifiers/insertTeXBlock.js
+++ b/src/modifiers/insertTeXBlock.js
@@ -1,26 +1,17 @@
-import {
- Entity,
- EditorState,
- AtomicBlockUtils
-} from 'draft-js';
+import { EditorState, AtomicBlockUtils } from 'draft-js';
let count = 0;
const examples = [
- '\\int_a^bu\\frac{d^2v}{dx^2}\\,dx\n' +
- '=\\left.u\\frac{dv}{dx}\\right|_a^b\n' +
- '-\\int_a^b\\frac{du}{dx}\\frac{dv}{dx}\\,dx',
+ 'f(x)=\\frac{ax^2}{y}+bx+c',
- 'P(E) = {n \\choose k} p^k (1-p)^{ n-k} ',
-
- '\\tilde f(\\omega)=\\frac{1}{2\\pi}\n' +
- '\\int_{-\\infty}^\\infty f(x)e^{-i\\omega x}\\,dx',
+ 'P(E) = \\binom{n}{k} p^k (1-p)^{ n-k}',
'\\frac{1}{(\\sqrt{\\phi \\sqrt{5}}-\\phi) e^{\\frac25 \\pi}} =\n' +
- '1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}\n' +
- '{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } }',
+ '1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}\n' +
+ '{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } }',
];
-export default function insertTeXBlock(editorState, tex) {
+export default function insertTeXBlock(editorState, translator, tex, displayMode = true) {
let texContent = tex;
if (!texContent) {
const nextFormula = count % examples.length;
@@ -28,11 +19,19 @@ export default function insertTeXBlock(editorState, tex) {
texContent = examples[nextFormula];
}
- const entityKey = Entity.create('kateX', 'IMMUTABLE', { content: texContent });
- const newEditorState = AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ');
+ // maybe insertTeXBlock should have a separate argument for inputvalue.
+ const contentState = editorState.getCurrentContent();
+ const newContentState = contentState.createEntity('KateX', 'IMMUTABLE', {
+ value: translator(texContent),
+ inputValue: texContent,
+ displayMode,
+ });
- return EditorState.forceSelection(
- newEditorState,
- editorState.getCurrentContent().getSelectionAfter()
+ const newEditorState = AtomicBlockUtils.insertAtomicBlock(
+ editorState,
+ newContentState.getLastCreatedEntityKey(),
+ ' '
);
+
+ return EditorState.forceSelection(newEditorState, editorState.getCurrentContent().getSelectionAfter());
}
diff --git a/src/modifiers/removeTeXBlock.js b/src/modifiers/removeTeXBlock.js
index 9e7bf22..72d9c06 100644
--- a/src/modifiers/removeTeXBlock.js
+++ b/src/modifiers/removeTeXBlock.js
@@ -1,53 +1,53 @@
import {
- Modifier,
- EditorState,
- SelectionState
+ Modifier,
+ EditorState,
+ SelectionState
} from 'draft-js';
-export default (editorState, blockKey) => {
- let content = editorState.getCurrentContent();
- const newSelection = new SelectionState({
- anchorKey: blockKey,
- anchorOffset: 0,
- focusKey: blockKey,
- focusOffset: 0,
- });
+export default (editorState: Object, blockKey: String) => {
+ let content = editorState.getCurrentContent();
+ const newSelection = new SelectionState({
+ anchorKey: blockKey,
+ anchorOffset: 0,
+ focusKey: blockKey,
+ focusOffset: 0,
+ });
- const afterKey = content.getKeyAfter(blockKey);
- const afterBlock = content.getBlockForKey(afterKey);
- let targetRange;
+ const afterKey = content.getKeyAfter(blockKey);
+ const afterBlock = content.getBlockForKey(afterKey);
+ let targetRange;
- // Only if the following block the last with no text then the whole block
- // should be removed. Otherwise the block should be reduced to an unstyled block
- // without any characters.
- if (afterBlock &&
- afterBlock.getType() === 'unstyled' &&
- afterBlock.getLength() === 0 &&
- afterBlock === content.getBlockMap().last()) {
- targetRange = new SelectionState({
- anchorKey: blockKey,
- anchorOffset: 0,
- focusKey: afterKey,
- focusOffset: 0,
- });
- } else {
- targetRange = new SelectionState({
- anchorKey: blockKey,
- anchorOffset: 0,
- focusKey: blockKey,
- focusOffset: 1,
- });
- }
+ // Only if the following block the last with no text then the whole block
+ // should be removed. Otherwise the block should be reduced to an unstyled block
+ // without any characters.
+ if (afterBlock &&
+ afterBlock.getType() === 'unstyled' &&
+ afterBlock.getLength() === 0 &&
+ afterBlock === content.getBlockMap().last()) {
+ targetRange = new SelectionState({
+ anchorKey: blockKey,
+ anchorOffset: 0,
+ focusKey: afterKey,
+ focusOffset: 0,
+ });
+ } else {
+ targetRange = new SelectionState({
+ anchorKey: blockKey,
+ anchorOffset: 0,
+ focusKey: blockKey,
+ focusOffset: 1,
+ });
+ }
- // change the blocktype and remove the characterList entry with the sticker
- content = Modifier.setBlockType(
- content,
- targetRange,
- 'unstyled'
- );
- content = Modifier.removeRange(content, targetRange, 'backward');
+ // change the blocktype and remove the characterList entry with the sticker
+ content = Modifier.setBlockType(
+ content,
+ targetRange,
+ 'unstyled'
+ );
+ content = Modifier.removeRange(content, targetRange, 'backward');
- // force to new selection
- const newState = EditorState.push(editorState, content, 'remove-range');
- return EditorState.forceSelection(newState, newSelection);
+ // force to new selection
+ const newState = EditorState.push(editorState, content, 'remove-range');
+ return EditorState.forceSelection(newState, newSelection);
};
diff --git a/src/styles.css b/src/styles.css
index 7056e96..6127a6f 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,99 +1,100 @@
.tex {
- background-color: #fff;
- cursor: pointer;
- margin: 20px auto;
- padding: 20px;
- -webkit-transition: background-color 0.2s fade-in-out;
- user-select: none;
- -webkit-user-select: none;
+ text-align: center;
+ background-color: #fff;
+ cursor: pointer;
+ margin: 20px auto;
+ /*padding: 20px;*/
+ -webkit-transition: background-color 0.2s fade-in-out;
+ user-select: none;
+ -webkit-user-select: none;
}
.activeTeX {
- color: #888;
+ color: #888;
}
.panel {
- font-family: 'Helvetica', sans-serif;
- font-weight: 200;
+ font-family: 'Helvetica', sans-serif;
+ font-weight: 200;
}
.panel .texValue {
- border: 1px solid #e1e1e1;
- display: block;
- font-family: 'Inconsolata', 'Menlo', monospace;
- font-size: 14px;
- height: 110px;
- margin: 20px auto 10px;
- outline: none;
- padding: 14px;
- resize: none;
- -webkit-box-sizing: border-box;
- width: 500px;
+ border: 1px solid #e1e1e1;
+ display: block;
+ font-family: 'Inconsolata', 'Menlo', monospace;
+ font-size: 14px;
+ height: 110px;
+ margin: 20px auto 10px;
+ outline: none;
+ padding: 14px;
+ resize: none;
+ -webkit-box-sizing: border-box;
+ width: 500px;
}
.buttons {
- text-align: center;
+ text-align: center;
}
.saveButton,
.removeButton {
- background-color: #fff;
- border: 1px solid #0a0;
- cursor: pointer;
- font-family: 'Helvetica', 'Arial', sans-serif;
- font-size: 16px;
- font-weight: 200;
- margin: 10px auto;
- padding: 6px;
- -webkit-border-radius: 3px;
- width: 100px;
+ background-color: #fff;
+ border: 1px solid #0a0;
+ cursor: pointer;
+ font-family: 'Helvetica', 'Arial', sans-serif;
+ font-size: 16px;
+ font-weight: 200;
+ margin: 10px auto;
+ padding: 6px;
+ -webkit-border-radius: 3px;
+ width: 100px;
}
.removeButton {
- border-color: #aaa;
- color: #999;
- margin-left: 8px;
+ border-color: #aaa;
+ color: #999;
+ margin-left: 8px;
}
.invalidButton {
- background-color: #eee;
- border-color: #a00;
- color: #666;
+ background-color: #eee;
+ border-color: #a00;
+ color: #666;
}
.insertButton {
- box-sizing: border-box;
- border: 1px solid #ddd;
- height: 1.5em;
- color: #888;
- border-radius: 1.5em;
- line-height: 1.2em;
- cursor: pointer;
- background-color: #fff;
- width: 2.5em;
- font-weight: bold;
- font-size: 1.5em;
- padding: 0;
- margin: 0;
+ box-sizing: border-box;
+ border: 1px solid #ddd;
+ height: 1.5em;
+ color: #888;
+ border-radius: 1.5em;
+ line-height: 1.2em;
+ cursor: pointer;
+ background-color: #fff;
+ width: 2.5em;
+ font-weight: bold;
+ font-size: 1.5em;
+ padding: 0;
+ margin: 0;
}
.insertButton:focus {
- background-color: #eee;
- color: #999;
- outline: 0; /* reset for :focus */
+ background-color: #eee;
+ color: #999;
+ outline: 0; /* reset for :focus */
}
.insertButton:hover {
- background-color: #eee;
- color: #999;
+ background-color: #eee;
+ color: #999;
}
.insertButton:active {
- background-color: #ddd;
- color: #777;
+ background-color: #ddd;
+ color: #777;
}
.insertButton:disabled {
- background-color: #F5F5F5;
- color: #ccc;
+ background-color: #F5F5F5;
+ color: #ccc;
}
diff --git a/stories/ConfiguredEditor.js b/stories/ConfiguredEditor.js
new file mode 100644
index 0000000..d9c1adf
--- /dev/null
+++ b/stories/ConfiguredEditor.js
@@ -0,0 +1,88 @@
+import React, { Component } from 'react';
+import asciimath2latex from 'asciimath-to-latex';
+import { EditorState } from 'draft-js';
+
+import Editor from 'draft-js-plugins-editor';
+
+import MathInput from '../src/components/math-input/components/app';
+import createKaTeXPlugin from '../src/index';
+import '../src/styles.css';
+
+import katex from '../src/katex';
+
+const katexTheme = {
+ saveButton: 'Button Button-small Button-main',
+ removeButton: 'Button Button-small Button-main',
+ invalidButton: 'Button-small Button-alert',
+ buttons: 'ButtonGroup',
+};
+
+function configuredEditor(props) {
+ const kaTeXPlugin = createKaTeXPlugin({
+ // the configs here are mainly to show you that it is possible. Feel free to use w/o config
+ doneContent: { valid: 'Close', invalid: 'Invalid syntax' },
+ katex, // <-- required
+ MathInput: props.withMathInput ? MathInput : null,
+ removeContent: 'Remove',
+ theme: katexTheme,
+ translator: props.withAsciimath ? asciimath2latex : null,
+ });
+
+ const plugins = [kaTeXPlugin];
+
+ const baseEditorProps = Object.assign({
+ plugins,
+ });
+
+ return { baseEditorProps, InsertButton: kaTeXPlugin.InsertButton };
+}
+
+export default class ConfiguredEditor extends Component {
+ static propTypes = {};
+
+ constructor(props) {
+ super(props);
+ const { baseEditorProps, InsertButton } = configuredEditor(props);
+ this.baseEditorProps = baseEditorProps;
+ this.InsertButton = InsertButton;
+ this.state = { editorState: EditorState.createEmpty() };
+ }
+
+ componentDidMount() {
+ this.focus();
+ }
+
+ // use this when triggering a button that only changes editorstate
+ onEditorStateChange = editorState => {
+ this.setState(() => ({ editorState }));
+ };
+
+ focus = () => {
+ this.editor.focus();
+ };
+
+ render() {
+ const { InsertButton } = this;
+
+ return (
+
+
Editor:
+
+
+
+ Insert ascii:
+ Insert ascii math
+
+
{
+ this.editor = element;
+ }}
+ editorState={this.state.editorState}
+ onChange={this.onEditorStateChange}
+ />
+
+
+ );
+ }
+}
diff --git a/stories/Welcome.js b/stories/Welcome.js
new file mode 100644
index 0000000..9eee5cd
--- /dev/null
+++ b/stories/Welcome.js
@@ -0,0 +1,103 @@
+import React from 'react';
+
+const styles = {
+ main: {
+ margin: 15,
+ maxWidth: 600,
+ lineHeight: 1.4,
+ fontFamily: '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif',
+ },
+
+ logo: {
+ width: 200,
+ },
+
+ link: {
+ color: '#1474f3',
+ textDecoration: 'none',
+ borderBottom: '1px solid #1474f3',
+ paddingBottom: 2,
+ },
+
+ code: {
+ fontSize: 15,
+ fontWeight: 600,
+ padding: '2px 5px',
+ border: '1px solid #eae9e9',
+ borderRadius: 4,
+ backgroundColor: '#f3f2f2',
+ color: '#3a3a3a',
+ },
+
+ note: {
+ opacity: 0.5,
+ },
+};
+
+export default class Welcome extends React.Component {
+ showApp(e) {
+ e.preventDefault();
+ if (this.props.showApp) this.props.showApp();
+ }
+
+ render() {
+ return (
+
+
Welcome to STORYBOOK
+
+ This is a UI component dev environment for your app.
+
+
+ We've added some basic stories inside the
+ {' '}
+ src/stories
+ {' '}
+ directory.
+
+ A story is a single state of one or more UI components. You can have as many stories as you want.
+
+ (Basically a story is like a visual test case.)
+
+
+ See these sample
+ {' '}
+ stories
+ {' '}
+ for a component called
+ {' '}
+ Button
+ .
+
+
+ Just like that, you can add your own components as stories.
+
+ You can also edit those components and see changes right away.
+
+ (Try editing the Button
component
+ located at src/stories/Button.js
.)
+
+
+ This is just one thing you can do with Storybook.
+
+ Have a look at the
+ {' '}
+
+ Storybook
+
+ {' '}
+ repo for more information.
+
+
+ NOTE:
+
+ Have a look at the
+ {' '}
+ .storybook/webpack.config.js
+ {' '}
+ to add webpack
+ loaders and plugins you are using in this project.
+
+
+ );
+ }
+}
diff --git a/stories/index.js b/stories/index.js
new file mode 100644
index 0000000..b4d0903
--- /dev/null
+++ b/stories/index.js
@@ -0,0 +1,35 @@
+import React from 'react';
+
+import { storiesOf } from '@storybook/react';
+import { action } from '@storybook/addon-actions';
+import { linkTo } from '@storybook/addon-links';
+
+import Welcome from './Welcome';
+
+import ConfiguredEditor from './ConfiguredEditor';
+import KatexOutput from '../src/components/KatexOutput';
+
+storiesOf('Katex editor', module).add('to Storybook', () => (
+
+));
+
+storiesOf('Katex editor', module)
+ .add('Without mathinput', () => (
+
+
+
+ ))
+ .add('With mathinput', () => )
+ .add('With asciimath', () => (
+
+
+
+ To learn more about asciimath see:{' '}
+ http://asciimath.org/
+
+
+ A custom translator like asciimath in combination with MathInput is not
+ supported.
+
+
+ ));
diff --git a/yarn.lock b/yarn.lock
index 13e7c9c..826e3f9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,10 +2,153 @@
# yarn lockfile v1
+"@hypnosphi/fuse.js@^3.0.9":
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/@hypnosphi/fuse.js/-/fuse.js-3.0.9.tgz#ea99f6121b4a8f065b4c71f85595db2714498807"
+
+"@storybook/addon-actions@^3.2.6":
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.2.6.tgz#d8e476188a288f49f36a8482175bc2c1898dfc28"
+ dependencies:
+ "@storybook/addons" "^3.2.6"
+ deep-equal "^1.0.1"
+ json-stringify-safe "^5.0.1"
+ prop-types "^15.5.10"
+ react-inspector "^2.1.1"
+ uuid "^3.1.0"
+
+"@storybook/addon-links@^3.2.6":
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.2.6.tgz#93029ecee8a1a1939f01381c06ed19327acd746b"
+ dependencies:
+ "@storybook/addons" "^3.2.6"
+
+"@storybook/addons@^3.2.6":
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.2.6.tgz#c7974db36bd1b969d8ca3776f57fd955447dc7ed"
+
+"@storybook/channel-postmessage@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.2.0.tgz#612ff53120bf266660cb9328bac9ad671228a2f7"
+ dependencies:
+ "@storybook/channels" "^3.2.0"
+ global "^4.3.2"
+ json-stringify-safe "^5.0.1"
+
+"@storybook/channels@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.2.0.tgz#d75395212db76b49e3335f50cce5bc763cf0b5c6"
+
+"@storybook/components@^3.2.7":
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.2.7.tgz#7d4c7221851260e4236bbb3ef82a6494b23e5ec9"
+ dependencies:
+ glamor "^2.20.40"
+ glamorous "^4.1.2"
+ prop-types "^15.5.10"
+
+"@storybook/react-fuzzy@^0.4.0":
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/@storybook/react-fuzzy/-/react-fuzzy-0.4.0.tgz#2961e8a1f6c1afcce97e9e9a14d1dfe9d9061087"
+ dependencies:
+ babel-runtime "^6.23.0"
+ classnames "^2.2.5"
+ fuse.js "^3.0.1"
+ prop-types "^15.5.9"
+
+"@storybook/react@^3.2.8":
+ version "3.2.8"
+ resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.2.8.tgz#7d43ef450559b7cf3b3ecc17cc54d5a09d5ea402"
+ dependencies:
+ "@storybook/addon-actions" "^3.2.6"
+ "@storybook/addon-links" "^3.2.6"
+ "@storybook/addons" "^3.2.6"
+ "@storybook/channel-postmessage" "^3.2.0"
+ "@storybook/ui" "^3.2.7"
+ airbnb-js-shims "^1.1.1"
+ autoprefixer "^7.1.1"
+ babel-core "^6.25.0"
+ babel-loader "^7.0.0"
+ babel-plugin-react-docgen "^1.6.0"
+ babel-preset-env "^1.6.0"
+ babel-preset-minify "^0.2.0"
+ babel-preset-react "^6.24.1"
+ babel-preset-react-app "^3.0.0"
+ babel-preset-stage-0 "^6.24.1"
+ babel-runtime "^6.23.0"
+ case-sensitive-paths-webpack-plugin "^2.0.0"
+ chalk "^2.0.1"
+ commander "^2.9.0"
+ common-tags "^1.4.0"
+ configstore "^3.1.0"
+ css-loader "^0.28.1"
+ express "^4.15.3"
+ file-loader "^0.11.1"
+ find-cache-dir "^1.0.0"
+ glamor "^2.20.40"
+ glamorous "^4.1.2"
+ global "^4.3.2"
+ json-loader "^0.5.4"
+ json-stringify-safe "^5.0.1"
+ json5 "^0.5.1"
+ lodash.flattendeep "^4.4.0"
+ lodash.pick "^4.4.0"
+ postcss-flexbugs-fixes "^3.0.0"
+ postcss-loader "^2.0.5"
+ prop-types "^15.5.10"
+ qs "^6.4.0"
+ react-modal "^2.2.4"
+ redux "^3.6.0"
+ request "^2.81.0"
+ serve-favicon "^2.4.3"
+ shelljs "^0.7.8"
+ style-loader "^0.17.0"
+ url-loader "^0.5.8"
+ util-deprecate "^1.0.2"
+ uuid "^3.1.0"
+ webpack "^2.5.1 || ^3.0.0"
+ webpack-dev-middleware "^1.10.2"
+ webpack-hot-middleware "^2.18.0"
+
+"@storybook/ui@^3.2.7":
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.2.7.tgz#c07dd5523e2c83d9f8ac5a7982c305cc59f34e78"
+ dependencies:
+ "@hypnosphi/fuse.js" "^3.0.9"
+ "@storybook/components" "^3.2.7"
+ "@storybook/react-fuzzy" "^0.4.0"
+ babel-runtime "^6.23.0"
+ deep-equal "^1.0.1"
+ events "^1.1.1"
+ global "^4.3.2"
+ json-stringify-safe "^5.0.1"
+ keycode "^2.1.8"
+ lodash.debounce "^4.0.8"
+ lodash.pick "^4.4.0"
+ lodash.sortby "^4.7.0"
+ mantra-core "^1.7.0"
+ podda "^1.2.2"
+ prop-types "^15.5.10"
+ qs "^6.4.0"
+ react-icons "^2.2.5"
+ react-inspector "^2.1.1"
+ react-komposer "^2.0.0"
+ react-modal "^2.2.4"
+ react-split-pane "^0.1.65"
+ react-treebeard "^2.0.3"
+ redux "^3.6.0"
+
abbrev@1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+accepts@~1.3.3:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f"
+ dependencies:
+ mime-types "~2.1.16"
+ negotiator "0.6.1"
+
acorn-dynamic-import@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
@@ -26,10 +169,33 @@ acorn@^3.0.4:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+acorn@^5.0.0:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7"
+
+airbnb-js-shims@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.3.0.tgz#aac46d80057fb0b414f70e06d07e362fd99ee2fa"
+ dependencies:
+ array-includes "^3.0.3"
+ es5-shim "^4.5.9"
+ es6-shim "^0.35.3"
+ function.prototype.name "^1.0.3"
+ object.entries "^1.0.4"
+ object.getownpropertydescriptors "^2.0.3"
+ object.values "^1.0.4"
+ promise.prototype.finally "^3.0.0"
+ string.prototype.padend "^3.0.0"
+ string.prototype.padstart "^3.0.0"
+
ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+ajv-keywords@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0"
+
ajv@^4.11.2, ajv@^4.7.0, ajv@^4.9.1:
version "4.11.5"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
@@ -37,6 +203,15 @@ ajv@^4.11.2, ajv@^4.7.0, ajv@^4.9.1:
co "^4.6.0"
json-stable-stringify "^1.0.1"
+ajv@^5.0.0, ajv@^5.1.5:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39"
+ dependencies:
+ co "^4.6.0"
+ fast-deep-equal "^1.0.0"
+ json-schema-traverse "^0.3.0"
+ json-stable-stringify "^1.0.1"
+
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@@ -53,6 +228,10 @@ ansi-escapes@^1.0.0, ansi-escapes@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+ansi-html@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
+
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@@ -61,6 +240,12 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ansi-styles@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
+ dependencies:
+ color-convert "^1.9.0"
+
anymatch@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
@@ -68,6 +253,14 @@ anymatch@^1.3.0:
arrify "^1.0.0"
micromatch "^2.1.5"
+aphrodite@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-1.2.3.tgz#4b161e9eef319b1f90a889501f985d7b5e70b285"
+ dependencies:
+ asap "^2.0.3"
+ inline-style-prefixer "^3.0.1"
+ string-hash "^1.1.3"
+
app-root-path@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46"
@@ -105,6 +298,21 @@ arr-flatten@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+array-find@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+
+array-includes@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.7.0"
+
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -126,14 +334,22 @@ array.prototype.find@^2.0.1:
define-properties "^1.1.2"
es-abstract "^1.7.0"
-arrify@^1.0.0, arrify@^1.0.1:
+arrify@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+asap@^2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+
asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+asciimath-to-latex@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/asciimath-to-latex/-/asciimath-to-latex-0.3.2.tgz#1f6e6b36ccc11e3de0ceeffa3dce16483ec28b4e"
+
asn1.js@^4.0.0:
version "4.9.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
@@ -164,6 +380,10 @@ ast-types-flow@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
+ast-types@0.9.11:
+ version "0.9.11"
+ resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.11.tgz#371177bb59232ff5ceaa1d09ee5cad705b1a5aa9"
+
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -174,6 +394,12 @@ async@^2.1.2:
dependencies:
lodash "^4.14.0"
+async@^2.1.4:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d"
+ dependencies:
+ lodash "^4.14.0"
+
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -189,6 +415,17 @@ autoprefixer@^6.3.1, autoprefixer@^6.7.7:
postcss "^5.2.16"
postcss-value-parser "^3.2.3"
+autoprefixer@^7.1.1:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.4.tgz#960847dbaa4016bc8e8e52ec891cbf8f1257a748"
+ dependencies:
+ browserslist "^2.4.0"
+ caniuse-lite "^1.0.30000726"
+ normalize-range "^0.1.2"
+ num2fraction "^1.2.2"
+ postcss "^6.0.11"
+ postcss-value-parser "^3.2.3"
+
aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
@@ -226,7 +463,15 @@ babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
esutils "^2.0.2"
js-tokens "^3.0.0"
-babel-core@^6.0.0, babel-core@^6.14.0, babel-core@^6.24.0:
+babel-code-frame@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+ dependencies:
+ chalk "^1.1.3"
+ esutils "^2.0.2"
+ js-tokens "^3.0.2"
+
+babel-core@^6.14.0, babel-core@^6.24.0:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
dependencies:
@@ -250,6 +495,30 @@ babel-core@^6.0.0, babel-core@^6.14.0, babel-core@^6.24.0:
slash "^1.0.0"
source-map "^0.5.0"
+babel-core@^6.25.0, babel-core@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-generator "^6.26.0"
+ babel-helpers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ convert-source-map "^1.5.0"
+ debug "^2.6.8"
+ json5 "^0.5.1"
+ lodash "^4.17.4"
+ minimatch "^3.0.4"
+ path-is-absolute "^1.0.1"
+ private "^0.1.7"
+ slash "^1.0.0"
+ source-map "^0.5.6"
+
babel-eslint@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2"
@@ -260,7 +529,7 @@ babel-eslint@^7.1.1:
babylon "^6.13.0"
lodash.pickby "^4.6.0"
-babel-generator@^6.18.0, babel-generator@^6.24.0:
+babel-generator@^6.24.0:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
dependencies:
@@ -273,6 +542,19 @@ babel-generator@^6.18.0, babel-generator@^6.24.0:
source-map "^0.5.0"
trim-right "^1.0.1"
+babel-generator@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5"
+ dependencies:
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ detect-indent "^4.0.0"
+ jsesc "^1.3.0"
+ lodash "^4.17.4"
+ source-map "^0.5.6"
+ trim-right "^1.0.1"
+
babel-helper-bindify-decorators@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.22.0.tgz#d7f5bc261275941ac62acfc4e20dacfb8a3fe952"
@@ -281,6 +563,14 @@ babel-helper-bindify-decorators@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
+babel-helper-bindify-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-builder-binary-assignment-operator-visitor@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd"
@@ -289,6 +579,14 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
+babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
+ dependencies:
+ babel-helper-explode-assignable-expression "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
babel-helper-builder-react-jsx@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.23.0.tgz#d53fc8c996e0bc56d0de0fc4cc55a7138395ea4b"
@@ -298,6 +596,14 @@ babel-helper-builder-react-jsx@^6.23.0:
esutils "^2.0.0"
lodash "^4.2.0"
+babel-helper-builder-react-jsx@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ esutils "^2.0.2"
+
babel-helper-call-delegate@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef"
@@ -307,6 +613,15 @@ babel-helper-call-delegate@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
+babel-helper-call-delegate@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-define-map@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7"
@@ -316,6 +631,19 @@ babel-helper-define-map@^6.23.0:
babel-types "^6.23.0"
lodash "^4.2.0"
+babel-helper-define-map@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-helper-evaluate-path@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz#0bb2eb01996c0cef53c5e8405e999fe4a0244c08"
+
babel-helper-explode-assignable-expression@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478"
@@ -324,6 +652,14 @@ babel-helper-explode-assignable-expression@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
+babel-helper-explode-assignable-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-explode-class@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.22.0.tgz#646304924aa6388a516843ba7f1855ef8dfeb69b"
@@ -333,6 +669,19 @@ babel-helper-explode-class@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
+babel-helper-explode-class@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb"
+ dependencies:
+ babel-helper-bindify-decorators "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-flip-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz#160d2090a3d9f9c64a750905321a0bc218f884ec"
+
babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6"
@@ -343,6 +692,16 @@ babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0:
babel-traverse "^6.23.0"
babel-types "^6.23.0"
+babel-helper-function-name@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
+ dependencies:
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-get-function-arity@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce"
@@ -350,6 +709,13 @@ babel-helper-get-function-arity@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
+babel-helper-get-function-arity@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
babel-helper-hoist-variables@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72"
@@ -357,6 +723,25 @@ babel-helper-hoist-variables@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
+babel-helper-hoist-variables@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-is-nodes-equiv@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
+
+babel-helper-is-void-0@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz#6ed0ada8a9b1c5b6e88af6b47c1b3b5c080860eb"
+
+babel-helper-mark-eval-scopes@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz#7648aaf2ec92aae9b09a20ad91e8df5e1fcc94b2"
+
babel-helper-optimise-call-expression@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5"
@@ -364,6 +749,13 @@ babel-helper-optimise-call-expression@^6.23.0:
babel-runtime "^6.22.0"
babel-types "^6.23.0"
+babel-helper-optimise-call-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
babel-helper-regex@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d"
@@ -382,6 +774,20 @@ babel-helper-remap-async-to-generator@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
+babel-helper-remap-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-remove-or-void@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz#8e46ad5b30560d57d7510b3fd93f332ee7c67386"
+
babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd"
@@ -393,6 +799,21 @@ babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0:
babel-traverse "^6.23.0"
babel-types "^6.23.0"
+babel-helper-replace-supers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
+ dependencies:
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-to-multiple-sequence-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz#d1a419634c6cb301f27858c659167cfee0a9d318"
+
babel-helpers@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
@@ -400,13 +821,12 @@ babel-helpers@^6.23.0:
babel-runtime "^6.22.0"
babel-template "^6.23.0"
-babel-jest@^19.0.0:
- version "19.0.0"
- resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+babel-helpers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
dependencies:
- babel-core "^6.0.0"
- babel-plugin-istanbul "^4.0.0"
- babel-preset-jest "^19.0.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
babel-loader@^6.2.5:
version "6.4.0"
@@ -417,6 +837,14 @@ babel-loader@^6.2.5:
mkdirp "^0.5.1"
object-assign "^4.0.1"
+babel-loader@^7.0.0:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126"
+ dependencies:
+ find-cache-dir "^1.0.0"
+ loader-utils "^1.0.2"
+ mkdirp "^0.5.1"
+
babel-messages@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
@@ -429,23 +857,86 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-istanbul@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.0.0.tgz#36bde8fbef4837e5ff0366531a2beabd7b1ffa10"
+babel-plugin-dynamic-import-node@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.0.2.tgz#adb5bc8f48a89311540395ae9f0cc3ed4b10bb2e"
dependencies:
- find-up "^2.1.0"
- istanbul-lib-instrument "^1.4.2"
- test-exclude "^4.0.0"
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ babel-template "^6.24.1"
+ babel-types "^6.24.1"
-babel-plugin-jest-hoist@^19.0.0:
- version "19.0.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+babel-plugin-minify-builtins@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz#317f824b0907210b6348671bb040ca072e2e0c82"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
-babel-plugin-react-transform@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.2.tgz#515bbfa996893981142d90b1f9b1635de2995109"
+babel-plugin-minify-constant-folding@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz#8c70b528b2eb7c13e94d95c8789077d4cdbc3970"
dependencies:
- lodash "^4.6.1"
+ babel-helper-evaluate-path "^0.2.0"
+
+babel-plugin-minify-dead-code-elimination@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz#e8025ee10a1e5e4f202633a6928ce892c33747e3"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+ babel-helper-mark-eval-scopes "^0.2.0"
+ babel-helper-remove-or-void "^0.2.0"
+ lodash.some "^4.6.0"
+
+babel-plugin-minify-flip-comparisons@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz#0c9c8e93155c8f09dedad8118b634c259f709ef5"
+ dependencies:
+ babel-helper-is-void-0 "^0.2.0"
+
+babel-plugin-minify-guarded-expressions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz#8a8c950040fce3e258a12e6eb21eab94ad7235ab"
+ dependencies:
+ babel-helper-flip-expressions "^0.2.0"
+
+babel-plugin-minify-infinity@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz#30960c615ddbc657c045bb00a1d8eb4af257cf03"
+
+babel-plugin-minify-mangle-names@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz#719892297ff0106a6ec1a4b0fc062f1f8b6a8529"
+ dependencies:
+ babel-helper-mark-eval-scopes "^0.2.0"
+
+babel-plugin-minify-numeric-literals@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz#5746e851700167a380c05e93f289a7070459a0d1"
+
+babel-plugin-minify-replace@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz#3c1f06bc4e6d3e301eacb763edc1be611efc39b0"
+
+babel-plugin-minify-simplify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz#21ceec4857100c5476d7cef121f351156e5c9bc0"
+ dependencies:
+ babel-helper-flip-expressions "^0.2.0"
+ babel-helper-is-nodes-equiv "^0.0.1"
+ babel-helper-to-multiple-sequence-expressions "^0.2.0"
+
+babel-plugin-minify-type-constructors@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz#7f3b6458be0863cfd59e9985bed6d134aa7a2e17"
+ dependencies:
+ babel-helper-is-void-0 "^0.2.0"
+
+babel-plugin-react-docgen@^1.6.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-1.7.0.tgz#87e72d3d54b182a30706b740bb4d116f59aadc80"
+ dependencies:
+ babel-types "^6.24.1"
+ lodash "4.x.x"
+ react-docgen "^2.15.0"
babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
@@ -471,7 +962,7 @@ babel-plugin-syntax-do-expressions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d"
-babel-plugin-syntax-dynamic-import@^6.18.0:
+babel-plugin-syntax-dynamic-import@6.18.0, babel-plugin-syntax-dynamic-import@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
@@ -511,6 +1002,14 @@ babel-plugin-transform-async-generator-functions@^6.22.0:
babel-plugin-syntax-async-generators "^6.5.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-async-generator-functions@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-generators "^6.5.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-async-to-generator@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e"
@@ -519,6 +1018,14 @@ babel-plugin-transform-async-to-generator@^6.22.0:
babel-plugin-syntax-async-functions "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-functions "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-class-constructor-call@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.22.0.tgz#11a4d2216abb5b0eef298b493748f4f2f4869120"
@@ -527,6 +1034,23 @@ babel-plugin-transform-class-constructor-call@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
+babel-plugin-transform-class-constructor-call@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9"
+ dependencies:
+ babel-plugin-syntax-class-constructor-call "^6.18.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-class-properties@6.24.1, babel-plugin-transform-class-properties@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-plugin-syntax-class-properties "^6.8.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
babel-plugin-transform-class-properties@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b"
@@ -546,6 +1070,16 @@ babel-plugin-transform-decorators@^6.22.0:
babel-template "^6.22.0"
babel-types "^6.22.0"
+babel-plugin-transform-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d"
+ dependencies:
+ babel-helper-explode-class "^6.24.1"
+ babel-plugin-syntax-decorators "^6.13.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-types "^6.24.1"
+
babel-plugin-transform-do-expressions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb"
@@ -575,6 +1109,16 @@ babel-plugin-transform-es2015-block-scoping@^6.22.0:
babel-types "^6.23.0"
lodash "^4.2.0"
+babel-plugin-transform-es2015-block-scoping@^6.23.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
babel-plugin-transform-es2015-classes@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1"
@@ -589,6 +1133,20 @@ babel-plugin-transform-es2015-classes@^6.22.0:
babel-traverse "^6.23.0"
babel-types "^6.23.0"
+babel-plugin-transform-es2015-classes@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
+ dependencies:
+ babel-helper-define-map "^6.24.1"
+ babel-helper-function-name "^6.24.1"
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-helper-replace-supers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-plugin-transform-es2015-computed-properties@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7"
@@ -596,7 +1154,7 @@ babel-plugin-transform-es2015-computed-properties@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
-babel-plugin-transform-es2015-destructuring@^6.22.0:
+babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
dependencies:
@@ -609,7 +1167,7 @@ babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
-babel-plugin-transform-es2015-for-of@^6.22.0:
+babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
dependencies:
@@ -629,6 +1187,14 @@ babel-plugin-transform-es2015-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
+babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
+ dependencies:
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
babel-plugin-transform-es2015-modules-amd@^6.24.0:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e"
@@ -637,6 +1203,15 @@ babel-plugin-transform-es2015-modules-amd@^6.24.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
+babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a"
+ dependencies:
+ babel-plugin-transform-strict-mode "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-types "^6.26.0"
+
babel-plugin-transform-es2015-modules-commonjs@^6.24.0:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f"
@@ -654,6 +1229,22 @@ babel-plugin-transform-es2015-modules-systemjs@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.23.0"
+babel-plugin-transform-es2015-modules-systemjs@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-modules-umd@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
+ dependencies:
+ babel-plugin-transform-es2015-modules-amd "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
babel-plugin-transform-es2015-modules-umd@^6.24.0:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450"
@@ -680,6 +1271,17 @@ babel-plugin-transform-es2015-parameters@^6.22.0:
babel-traverse "^6.23.0"
babel-types "^6.23.0"
+babel-plugin-transform-es2015-parameters@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
+ dependencies:
+ babel-helper-call-delegate "^6.24.1"
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-plugin-transform-es2015-shorthand-properties@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723"
@@ -707,7 +1309,7 @@ babel-plugin-transform-es2015-template-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
+babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
dependencies:
@@ -729,6 +1331,14 @@ babel-plugin-transform-exponentiation-operator@^6.22.0:
babel-plugin-syntax-exponentiation-operator "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-exponentiation-operator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
+ dependencies:
+ babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
+ babel-plugin-syntax-exponentiation-operator "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-export-extensions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653"
@@ -750,33 +1360,69 @@ babel-plugin-transform-function-bind@^6.22.0:
babel-plugin-syntax-function-bind "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-object-rest-spread@^6.22.0:
+babel-plugin-transform-inline-consecutive-adds@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz#15dae78921057f4004f8eafd79e15ddc5f12f426"
+
+babel-plugin-transform-member-expression-literals@^6.8.5:
+ version "6.8.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz#e06ae305cf48d819822e93a70d79269f04d89eec"
+
+babel-plugin-transform-merge-sibling-variables@^6.8.6:
+ version "6.8.6"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz#6d21efa5ee4981f71657fae716f9594bb2622aef"
+
+babel-plugin-transform-minify-booleans@^6.8.3:
+ version "6.8.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz#5906ed776d3718250519abf1bace44b0b613ddf9"
+
+babel-plugin-transform-object-rest-spread@6.23.0, babel-plugin-transform-object-rest-spread@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-property-literals@^6.8.5:
+ version "6.8.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz#67ed5930b34805443452c8b9690c7ebe1e206c40"
+ dependencies:
+ esutils "^2.0.2"
+
+babel-plugin-transform-react-constant-elements@6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.23.0.tgz#2f119bf4d2cdd45eb9baaae574053c604f6147dd"
+ dependencies:
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-react-display-name@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37"
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx-self@^6.22.0:
+babel-plugin-transform-react-jsx-self@6.22.0, babel-plugin-transform-react-jsx-self@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx-source@^6.22.0:
+babel-plugin-transform-react-jsx-source@6.22.0, babel-plugin-transform-react-jsx-source@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-react-jsx@6.24.1, babel-plugin-transform-react-jsx@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
+ dependencies:
+ babel-helper-builder-react-jsx "^6.24.1"
+ babel-plugin-syntax-jsx "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-react-jsx@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.23.0.tgz#23e892f7f2e759678eb5e4446a8f8e94e81b3470"
@@ -785,12 +1431,46 @@ babel-plugin-transform-react-jsx@^6.23.0:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-regenerator@6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418"
+ dependencies:
+ regenerator-transform "0.9.11"
+
babel-plugin-transform-regenerator@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6"
dependencies:
regenerator-transform "0.9.8"
+babel-plugin-transform-regexp-constructors@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz#6aa5dd0acc515db4be929bbcec4ed4c946c534a3"
+
+babel-plugin-transform-remove-console@^6.8.5:
+ version "6.8.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz#fde9d2d3d725530b0fadd8d31078402410386810"
+
+babel-plugin-transform-remove-debugger@^6.8.5:
+ version "6.8.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz#809584d412bf918f071fdf41e1fdb15ea89cdcd5"
+
+babel-plugin-transform-remove-undefined@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz#94f052062054c707e8d094acefe79416b63452b1"
+ dependencies:
+ babel-helper-evaluate-path "^0.2.0"
+
+babel-plugin-transform-runtime@6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-simplify-comparison-operators@^6.8.5:
+ version "6.8.5"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz#a838786baf40cc33a93b95ae09e05591227e43bf"
+
babel-plugin-transform-strict-mode@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c"
@@ -798,6 +1478,17 @@ babel-plugin-transform-strict-mode@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
+babel-plugin-transform-strict-mode@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-undefined-to-void@^6.8.3:
+ version "6.8.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz#fc52707f6ee1ddc71bb91b0d314fbefdeef9beb4"
+
babel-plugin-webpack-loaders@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/babel-plugin-webpack-loaders/-/babel-plugin-webpack-loaders-0.9.0.tgz#686ec1cab9db348958f990a95f57090f7e16b743"
@@ -821,6 +1512,76 @@ babel-polyfill@^6.13.0, babel-polyfill@^6.23.0:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
+babel-preset-env@1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.5.2.tgz#cd4ae90a6e94b709f97374b33e5f8b983556adef"
+ dependencies:
+ babel-plugin-check-es2015-constants "^6.22.0"
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-to-generator "^6.22.0"
+ babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoping "^6.23.0"
+ babel-plugin-transform-es2015-classes "^6.23.0"
+ babel-plugin-transform-es2015-computed-properties "^6.22.0"
+ babel-plugin-transform-es2015-destructuring "^6.23.0"
+ babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
+ babel-plugin-transform-es2015-for-of "^6.23.0"
+ babel-plugin-transform-es2015-function-name "^6.22.0"
+ babel-plugin-transform-es2015-literals "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.22.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-umd "^6.23.0"
+ babel-plugin-transform-es2015-object-super "^6.22.0"
+ babel-plugin-transform-es2015-parameters "^6.23.0"
+ babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
+ babel-plugin-transform-es2015-spread "^6.22.0"
+ babel-plugin-transform-es2015-sticky-regex "^6.22.0"
+ babel-plugin-transform-es2015-template-literals "^6.22.0"
+ babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
+ babel-plugin-transform-es2015-unicode-regex "^6.22.0"
+ babel-plugin-transform-exponentiation-operator "^6.22.0"
+ babel-plugin-transform-regenerator "^6.22.0"
+ browserslist "^2.1.2"
+ invariant "^2.2.2"
+ semver "^5.3.0"
+
+babel-preset-env@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4"
+ dependencies:
+ babel-plugin-check-es2015-constants "^6.22.0"
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-to-generator "^6.22.0"
+ babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoping "^6.23.0"
+ babel-plugin-transform-es2015-classes "^6.23.0"
+ babel-plugin-transform-es2015-computed-properties "^6.22.0"
+ babel-plugin-transform-es2015-destructuring "^6.23.0"
+ babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
+ babel-plugin-transform-es2015-for-of "^6.23.0"
+ babel-plugin-transform-es2015-function-name "^6.22.0"
+ babel-plugin-transform-es2015-literals "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.22.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-umd "^6.23.0"
+ babel-plugin-transform-es2015-object-super "^6.22.0"
+ babel-plugin-transform-es2015-parameters "^6.23.0"
+ babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
+ babel-plugin-transform-es2015-spread "^6.22.0"
+ babel-plugin-transform-es2015-sticky-regex "^6.22.0"
+ babel-plugin-transform-es2015-template-literals "^6.22.0"
+ babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
+ babel-plugin-transform-es2015-unicode-regex "^6.22.0"
+ babel-plugin-transform-exponentiation-operator "^6.22.0"
+ babel-plugin-transform-regenerator "^6.22.0"
+ browserslist "^2.1.2"
+ invariant "^2.2.2"
+ semver "^5.3.0"
+
babel-preset-es2015@^6.14.0, babel-preset-es2015@^6.3.13:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.0.tgz#c162d68b1932696e036cd3110dc1ccd303d2673a"
@@ -856,20 +1617,61 @@ babel-preset-flow@^6.23.0:
dependencies:
babel-plugin-transform-flow-strip-types "^6.22.0"
-babel-preset-jest@^19.0.0:
- version "19.0.0"
- resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
- dependencies:
- babel-plugin-jest-hoist "^19.0.0"
-
-babel-preset-react-hmre@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/babel-preset-react-hmre/-/babel-preset-react-hmre-1.1.1.tgz#d216e60cb5b8d4c873e19ed0f54eaff1437bc492"
+babel-preset-minify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz#006566552d9b83834472273f306c0131062a0acc"
+ dependencies:
+ babel-plugin-minify-builtins "^0.2.0"
+ babel-plugin-minify-constant-folding "^0.2.0"
+ babel-plugin-minify-dead-code-elimination "^0.2.0"
+ babel-plugin-minify-flip-comparisons "^0.2.0"
+ babel-plugin-minify-guarded-expressions "^0.2.0"
+ babel-plugin-minify-infinity "^0.2.0"
+ babel-plugin-minify-mangle-names "^0.2.0"
+ babel-plugin-minify-numeric-literals "^0.2.0"
+ babel-plugin-minify-replace "^0.2.0"
+ babel-plugin-minify-simplify "^0.2.0"
+ babel-plugin-minify-type-constructors "^0.2.0"
+ babel-plugin-transform-inline-consecutive-adds "^0.2.0"
+ babel-plugin-transform-member-expression-literals "^6.8.5"
+ babel-plugin-transform-merge-sibling-variables "^6.8.6"
+ babel-plugin-transform-minify-booleans "^6.8.3"
+ babel-plugin-transform-property-literals "^6.8.5"
+ babel-plugin-transform-regexp-constructors "^0.2.0"
+ babel-plugin-transform-remove-console "^6.8.5"
+ babel-plugin-transform-remove-debugger "^6.8.5"
+ babel-plugin-transform-remove-undefined "^0.2.0"
+ babel-plugin-transform-simplify-comparison-operators "^6.8.5"
+ babel-plugin-transform-undefined-to-void "^6.8.3"
+ lodash.isplainobject "^4.0.6"
+
+babel-preset-react-app@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-3.0.2.tgz#d062fca5dce68ed9c2615f2fecbc08861720f8e5"
+ dependencies:
+ babel-plugin-dynamic-import-node "1.0.2"
+ babel-plugin-syntax-dynamic-import "6.18.0"
+ babel-plugin-transform-class-properties "6.24.1"
+ babel-plugin-transform-object-rest-spread "6.23.0"
+ babel-plugin-transform-react-constant-elements "6.23.0"
+ babel-plugin-transform-react-jsx "6.24.1"
+ babel-plugin-transform-react-jsx-self "6.22.0"
+ babel-plugin-transform-react-jsx-source "6.22.0"
+ babel-plugin-transform-regenerator "6.24.1"
+ babel-plugin-transform-runtime "6.23.0"
+ babel-preset-env "1.5.2"
+ babel-preset-react "6.24.1"
+
+babel-preset-react@6.24.1, babel-preset-react@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
dependencies:
- babel-plugin-react-transform "^2.0.2"
- react-transform-catch-errors "^1.0.2"
- react-transform-hmr "^1.0.3"
- redbox-react "^1.2.2"
+ babel-plugin-syntax-jsx "^6.3.13"
+ babel-plugin-transform-react-display-name "^6.23.0"
+ babel-plugin-transform-react-jsx "^6.24.1"
+ babel-plugin-transform-react-jsx-self "^6.22.0"
+ babel-plugin-transform-react-jsx-source "^6.22.0"
+ babel-preset-flow "^6.23.0"
babel-preset-react@^6.11.1:
version "6.23.0"
@@ -882,6 +1684,14 @@ babel-preset-react@^6.11.1:
babel-plugin-transform-react-jsx-source "^6.22.0"
babel-preset-flow "^6.23.0"
+babel-preset-stage-0@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz#5642d15042f91384d7e5af8bc88b1db95b039e6a"
+ dependencies:
+ babel-plugin-transform-do-expressions "^6.22.0"
+ babel-plugin-transform-function-bind "^6.22.0"
+ babel-preset-stage-1 "^6.24.1"
+
babel-preset-stage-0@^6.5.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz#707eeb5b415da769eff9c42f4547f644f9296ef9"
@@ -898,6 +1708,14 @@ babel-preset-stage-1@^6.22.0:
babel-plugin-transform-export-extensions "^6.22.0"
babel-preset-stage-2 "^6.22.0"
+babel-preset-stage-1@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0"
+ dependencies:
+ babel-plugin-transform-class-constructor-call "^6.24.1"
+ babel-plugin-transform-export-extensions "^6.22.0"
+ babel-preset-stage-2 "^6.24.1"
+
babel-preset-stage-2@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07"
@@ -907,6 +1725,15 @@ babel-preset-stage-2@^6.22.0:
babel-plugin-transform-decorators "^6.22.0"
babel-preset-stage-3 "^6.22.0"
+babel-preset-stage-2@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1"
+ dependencies:
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ babel-plugin-transform-class-properties "^6.24.1"
+ babel-plugin-transform-decorators "^6.24.1"
+ babel-preset-stage-3 "^6.24.1"
+
babel-preset-stage-3@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.22.0.tgz#a4e92bbace7456fafdf651d7a7657ee0bbca9c2e"
@@ -917,6 +1744,16 @@ babel-preset-stage-3@^6.22.0:
babel-plugin-transform-exponentiation-operator "^6.22.0"
babel-plugin-transform-object-rest-spread "^6.22.0"
+babel-preset-stage-3@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395"
+ dependencies:
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-generator-functions "^6.24.1"
+ babel-plugin-transform-async-to-generator "^6.24.1"
+ babel-plugin-transform-exponentiation-operator "^6.24.1"
+ babel-plugin-transform-object-rest-spread "^6.22.0"
+
babel-register@^6.24.0, babel-register@^6.4.3:
version "6.24.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
@@ -929,6 +1766,25 @@ babel-register@^6.24.0, babel-register@^6.4.3:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
+babel-register@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
+ dependencies:
+ babel-core "^6.26.0"
+ babel-runtime "^6.26.0"
+ core-js "^2.5.0"
+ home-or-tmp "^2.0.0"
+ lodash "^4.17.4"
+ mkdirp "^0.5.1"
+ source-map-support "^0.4.15"
+
+babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.5.0, babel-runtime@^6.9.2:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+ dependencies:
+ core-js "^2.4.0"
+ regenerator-runtime "^0.11.0"
+
babel-runtime@^6.18.0, babel-runtime@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
@@ -936,7 +1792,7 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
-babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0:
+babel-template@^6.22.0, babel-template@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
dependencies:
@@ -946,7 +1802,17 @@ babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0:
babylon "^6.11.0"
lodash "^4.2.0"
-babel-traverse@^6.15.0, babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1, babel-traverse@^6.3.26:
+babel-template@^6.24.1, babel-template@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ lodash "^4.17.4"
+
+babel-traverse@^6.15.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1, babel-traverse@^6.3.26:
version "6.23.1"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
dependencies:
@@ -960,7 +1826,21 @@ babel-traverse@^6.15.0, babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-tr
invariant "^2.2.0"
lodash "^4.2.0"
-babel-types@^6.15.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0, babel-types@^6.3.24:
+babel-traverse@^6.24.1, babel-traverse@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ debug "^2.6.8"
+ globals "^9.18.0"
+ invariant "^2.2.2"
+ lodash "^4.17.4"
+
+babel-types@^6.15.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0, babel-types@^6.3.24:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
dependencies:
@@ -969,14 +1849,35 @@ babel-types@^6.15.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22
lodash "^4.2.0"
to-fast-properties "^1.0.1"
+babel-types@^6.24.1, babel-types@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+ dependencies:
+ babel-runtime "^6.26.0"
+ esutils "^2.0.2"
+ lodash "^4.17.4"
+ to-fast-properties "^1.0.3"
+
babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0, babylon@^6.3.26:
version "6.16.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+babylon@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+
+babylon@~5.8.3:
+ version "5.8.38"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
+
balanced-match@^0.4.1, balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
@@ -1011,6 +1912,10 @@ boom@2.x.x:
dependencies:
hoek "2.x.x"
+bowser@^1.0.0, bowser@^1.6.0, bowser@^1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.3.tgz#504bdb43118ca8db9cbbadf28fd60f265af96e4f"
+
brace-expansion@^1.0.0:
version "1.1.6"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
@@ -1018,6 +1923,13 @@ brace-expansion@^1.0.0:
balanced-match "^0.4.1"
concat-map "0.0.1"
+brace-expansion@^1.1.7:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
braces@^1.8.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
@@ -1026,6 +1938,10 @@ braces@^1.8.2:
preserve "^0.2.0"
repeat-element "^1.1.2"
+brcast@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd"
+
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -1088,6 +2004,13 @@ browserslist@^1.0.1, browserslist@^1.5.2, browserslist@^1.7.6:
caniuse-db "^1.0.30000631"
electron-to-chromium "^1.2.5"
+browserslist@^2.1.2, browserslist@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.4.0.tgz#693ee93d01e66468a6348da5498e011f578f87f8"
+ dependencies:
+ caniuse-lite "^1.0.30000718"
+ electron-to-chromium "^1.3.18"
+
buffer-shims@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
@@ -1130,6 +2053,10 @@ camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+camelcase@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+
caniuse-api@^1.5.2:
version "1.5.3"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.3.tgz#5018e674b51c393e4d50614275dc017e27c4a2a2"
@@ -1143,6 +2070,14 @@ caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000631, caniuse-db@^1.0.30000634:
version "1.0.30000634"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000634.tgz#439f4b95e715b1fd105196d40c681edd7122e622"
+caniuse-lite@^1.0.30000718, caniuse-lite@^1.0.30000726:
+ version "1.0.30000733"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000733.tgz#ebfc48254117cc0c66197a4536cb4397a6cfbccd"
+
+case-sensitive-paths-webpack-plugin@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909"
+
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
@@ -1154,6 +2089,10 @@ center-align@^0.1.1:
align-text "^0.1.3"
lazy-cache "^1.0.3"
+chain-function@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
+
chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@@ -1164,6 +2103,14 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
+chalk@^2.0.1, chalk@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
+ dependencies:
+ ansi-styles "^3.1.0"
+ escape-string-regexp "^1.0.5"
+ supports-color "^4.0.0"
+
chokidar@^1.4.3, chokidar@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
@@ -1179,6 +2126,21 @@ chokidar@^1.4.3, chokidar@^1.6.1:
optionalDependencies:
fsevents "^1.0.0"
+chokidar@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+ dependencies:
+ anymatch "^1.3.0"
+ async-each "^1.0.0"
+ glob-parent "^2.0.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^2.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ optionalDependencies:
+ fsevents "^1.0.0"
+
cipher-base@^1.0.0, cipher-base@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
@@ -1195,6 +2157,10 @@ clap@^1.0.9:
dependencies:
chalk "^1.1.3"
+classnames@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
+
cli-cursor@^1.0.1, cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -1250,7 +2216,7 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
-color-convert@^1.3.0:
+color-convert@^1.3.0, color-convert@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
@@ -1298,6 +2264,12 @@ commander@^2.8.1, commander@^2.9.0:
dependencies:
graceful-readlink ">= 1.0.0"
+common-tags@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0"
+ dependencies:
+ babel-runtime "^6.18.0"
+
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -1314,6 +2286,17 @@ concat-stream@^1.4.6:
readable-stream "^2.2.2"
typedarray "^0.0.6"
+configstore@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90"
+ dependencies:
+ dot-prop "^4.1.0"
+ graceful-fs "^4.1.2"
+ make-dir "^1.0.0"
+ unique-string "^1.0.0"
+ write-file-atomic "^2.0.0"
+ xdg-basedir "^3.0.0"
+
console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
@@ -1332,10 +2315,30 @@ contains-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
+content-disposition@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
+
+content-type@~1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+
convert-source-map@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3"
+convert-source-map@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+
+cookie@0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
@@ -1344,6 +2347,10 @@ core-js@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+core-js@^2.4.1, core-js@^2.5.0:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
+
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -1424,17 +2431,51 @@ crypto-browserify@^3.11.0:
public-encrypt "^4.0.0"
randombytes "^2.0.0"
+crypto-random-string@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
+
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
-css-loader@^0.27.2:
- version "0.27.3"
- resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.27.3.tgz#69ab6f47b69bfb1b5acee61bac2aab14302ff0dc"
+css-in-js-utils@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz#9ac7e02f763cf85d94017666565ed68a5b5f3215"
+ dependencies:
+ hyphenate-style-name "^1.0.2"
+
+css-in-js-utils@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz#5af1dd70f4b06b331f48d22a3d86e0786c0b9435"
+ dependencies:
+ hyphenate-style-name "^1.0.2"
+
+css-loader@^0.27.2:
+ version "0.27.3"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.27.3.tgz#69ab6f47b69bfb1b5acee61bac2aab14302ff0dc"
+ dependencies:
+ babel-code-frame "^6.11.0"
+ css-selector-tokenizer "^0.7.0"
+ cssnano ">=2.6.1 <4"
+ loader-utils "^1.0.2"
+ lodash.camelcase "^4.3.0"
+ object-assign "^4.0.1"
+ postcss "^5.0.6"
+ postcss-modules-extract-imports "^1.0.0"
+ postcss-modules-local-by-default "^1.0.1"
+ postcss-modules-scope "^1.0.0"
+ postcss-modules-values "^1.1.0"
+ source-list-map "^0.1.7"
+
+css-loader@^0.28.1:
+ version "0.28.7"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
dependencies:
babel-code-frame "^6.11.0"
css-selector-tokenizer "^0.7.0"
cssnano ">=2.6.1 <4"
+ icss-utils "^2.1.0"
loader-utils "^1.0.2"
lodash.camelcase "^4.3.0"
object-assign "^4.0.1"
@@ -1443,7 +2484,8 @@ css-loader@^0.27.2:
postcss-modules-local-by-default "^1.0.1"
postcss-modules-scope "^1.0.0"
postcss-modules-values "^1.1.0"
- source-list-map "^0.1.7"
+ postcss-value-parser "^3.3.0"
+ source-list-map "^2.0.0"
css-selector-tokenizer@^0.6.0:
version "0.6.0"
@@ -1539,6 +2581,12 @@ debug@2.2.0, debug@~2.2.0:
dependencies:
ms "0.7.1"
+debug@2.6.8, debug@^2.6.8:
+ version "2.6.8"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
+ dependencies:
+ ms "2.0.0"
+
debug@^2.1.1, debug@^2.2.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.2.tgz#dfa96a861ee9b8c2f29349b3bcc41aa599a71e0f"
@@ -1553,6 +2601,10 @@ decorate-component-with-props@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/decorate-component-with-props/-/decorate-component-with-props-1.0.2.tgz#5764d3cf6a58685a522201bad31bff0cb531e5fe"
+deep-equal@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
+
deep-extend@~0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
@@ -1592,6 +2644,10 @@ delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+depd@1.1.1, depd@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
+
des.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
@@ -1599,6 +2655,10 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
+destroy@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+
detect-indent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
@@ -1620,6 +2680,17 @@ doctrine@1.5.0, doctrine@^1.2.2:
esutils "^2.0.2"
isarray "^1.0.0"
+doctrine@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
+ dependencies:
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
+dom-helpers@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
+
dom-walk@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
@@ -1628,6 +2699,22 @@ domain-browser@^1.1.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+dot-prop@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+ dependencies:
+ is-obj "^1.0.0"
+
+draft-js-plugins-editor@2.0.0-rc7:
+ version "2.0.0-rc7"
+ resolved "https://registry.yarnpkg.com/draft-js-plugins-editor/-/draft-js-plugins-editor-2.0.0-rc7.tgz#21900097476cda6eb5db392143b959eb877d481c"
+ dependencies:
+ decorate-component-with-props "^1.0.2"
+ find-with-regex "^1.0.2"
+ immutable "^3.7.4"
+ prop-types "^15.5.8"
+ union-class-names "^1.0.0"
+
draft-js@>=0.9.1:
version "0.10.0"
resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.0.tgz#29d16191012b932fdab28a9b37ec1538f421abf6"
@@ -1642,10 +2729,18 @@ ecc-jsbn@~0.1.1:
dependencies:
jsbn "~0.1.0"
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+
electron-to-chromium@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.6.tgz#f38ad51d1919b06bc07275c62629db803ddca05a"
+electron-to-chromium@^1.3.18:
+ version "1.3.21"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz#a967ebdcfe8ed0083fc244d1894022a8e8113ea2"
+
elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
@@ -1670,6 +2765,10 @@ emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+encodeurl@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
+
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
@@ -1694,6 +2793,15 @@ enhanced-resolve@^3.0.0:
object-assign "^4.0.1"
tapable "^0.2.5"
+enhanced-resolve@^3.4.0:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
+ dependencies:
+ graceful-fs "^4.1.2"
+ memory-fs "^0.4.0"
+ object-assign "^4.0.1"
+ tapable "^0.2.7"
+
errno@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
@@ -1706,11 +2814,15 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
-error-stack-parser@^1.3.6:
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-1.3.6.tgz#e0e73b93e417138d1cd7c0b746b1a4a14854c292"
+es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.8.2:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.2.tgz#25103263dc4decbda60e0c737ca32313518027ee"
dependencies:
- stackframe "^0.3.1"
+ es-to-primitive "^1.1.1"
+ function-bind "^1.1.1"
+ has "^1.0.1"
+ is-callable "^1.1.3"
+ is-regex "^1.0.4"
es-abstract@^1.7.0:
version "1.7.0"
@@ -1736,6 +2848,10 @@ es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.
es6-iterator "2"
es6-symbol "~3.1"
+es5-shim@^4.5.9:
+ version "4.5.9"
+ resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.5.9.tgz#2a1e2b9e583ff5fed0c20a3ee2cbf3f75230a5c0"
+
es6-iterator@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac"
@@ -1765,6 +2881,10 @@ es6-set@~0.1.3:
es6-symbol "3"
event-emitter "~0.3.4"
+es6-shim@^0.35.3:
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26"
+
es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
@@ -1781,6 +2901,10 @@ es6-weak-map@^2.0.1:
es6-iterator "2"
es6-symbol "3"
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -1915,6 +3039,10 @@ esprima@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+esprima@~4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
+
esrecurse@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
@@ -1934,6 +3062,10 @@ esutils@^2.0.0, esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+etag@~1.8.0:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+
event-emitter@~0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5"
@@ -1941,7 +3073,7 @@ event-emitter@~0.3.4:
d "~0.1.1"
es5-ext "~0.10.7"
-events@^1.0.0:
+events@^1.0.0, events@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
@@ -1963,6 +3095,22 @@ execa@^0.6.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+exenv@^1.2.0, exenv@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
+
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
@@ -1979,6 +3127,39 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
+express@^4.15.3:
+ version "4.15.4"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1"
+ dependencies:
+ accepts "~1.3.3"
+ array-flatten "1.1.1"
+ content-disposition "0.5.2"
+ content-type "~1.0.2"
+ cookie "0.3.1"
+ cookie-signature "1.0.6"
+ debug "2.6.8"
+ depd "~1.1.1"
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ etag "~1.8.0"
+ finalhandler "~1.0.4"
+ fresh "0.5.0"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "~2.3.0"
+ parseurl "~1.3.1"
+ path-to-regexp "0.1.7"
+ proxy-addr "~1.1.5"
+ qs "6.5.0"
+ range-parser "~1.2.0"
+ send "0.15.4"
+ serve-static "1.12.4"
+ setprototypeof "1.0.3"
+ statuses "~1.3.1"
+ type-is "~1.6.15"
+ utils-merge "1.0.0"
+ vary "~1.1.1"
+
extend@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
@@ -2002,10 +3183,18 @@ extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+fast-deep-equal@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
+
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+fast-memoize@^2.2.7:
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.2.8.tgz#d7f899f31d037b12d9db4281912f9018575720b1"
+
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
@@ -2022,6 +3211,18 @@ fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.7:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
+fbjs@^0.8.12, fbjs@^0.8.9:
+ version "0.8.15"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.15.tgz#4f0695fdfcc16c37c0b07facec8cb4c4091685b9"
+ dependencies:
+ core-js "^1.0.0"
+ isomorphic-fetch "^2.1.1"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.9"
+
figures@^1.3.5, figures@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -2036,6 +3237,12 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1"
object-assign "^4.0.1"
+file-loader@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
+ dependencies:
+ loader-utils "^1.0.2"
+
filename-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
@@ -2050,6 +3257,18 @@ fill-range@^2.1.0:
repeat-element "^1.1.2"
repeat-string "^1.5.2"
+finalhandler@~1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.5.tgz#a701303d257a1bc82fea547a33e5ae89531723df"
+ dependencies:
+ debug "2.6.8"
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.2"
+ statuses "~1.3.1"
+ unpipe "~1.0.0"
+
find-cache-dir@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9"
@@ -2058,6 +3277,14 @@ find-cache-dir@^0.1.1:
mkdirp "^0.5.1"
pkg-dir "^1.0.0"
+find-cache-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
+ dependencies:
+ commondir "^1.0.1"
+ make-dir "^1.0.0"
+ pkg-dir "^2.0.0"
+
find-up@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@@ -2065,12 +3292,16 @@ find-up@^1.0.0:
path-exists "^2.0.0"
pinkie-promise "^2.0.0"
-find-up@^2.1.0:
+find-up@^2.0.0, find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
dependencies:
locate-path "^2.0.0"
+find-with-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/find-with-regex/-/find-with-regex-1.0.2.tgz#d3b36286539f14c527e31f194159c6d251651a45"
+
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
@@ -2114,6 +3345,18 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
+forwarded@~0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+
+fresh@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
+
+fresh@0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.1.tgz#c3a08bcec0fcdcc223edf3b23eb327f1f9fcbf5c"
+
fs-readdir-recursive@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560"
@@ -2150,6 +3393,22 @@ function-bind@^1.0.2, function-bind@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+
+function.prototype.name@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.3.tgz#0099ae5572e9dd6f03c97d023fd92bcc5e639eac"
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.0"
+ is-callable "^1.1.3"
+
+fuse.js@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.1.0.tgz#9062146c471552189b0f678b4f5a155731ae3b3c"
+
gauge@~2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09"
@@ -2187,6 +3446,28 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
+glamor@^2.20.40:
+ version "2.20.40"
+ resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.40.tgz#f606660357b7cf18dface731ad1a2cfa93817f05"
+ dependencies:
+ fbjs "^0.8.12"
+ inline-style-prefixer "^3.0.6"
+ object-assign "^4.1.1"
+ prop-types "^15.5.10"
+ through "^2.3.8"
+
+glamorous@^4.1.2:
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/glamorous/-/glamorous-4.9.2.tgz#858c035633f53dfce3899110b79b8bf61794c0df"
+ dependencies:
+ brcast "^3.0.0"
+ fast-memoize "^2.2.7"
+ html-tag-names "^1.1.1"
+ is-function "^1.0.1"
+ is-plain-object "^2.0.4"
+ react-html-attributes "^1.3.0"
+ svg-tag-names "^1.1.0"
+
glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
@@ -2211,9 +3492,9 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
once "^1.3.0"
path-is-absolute "^1.0.0"
-global@^4.3.0:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
+global@^4.3.2:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
dependencies:
min-document "^2.19.0"
process "~0.5.1"
@@ -2222,6 +3503,10 @@ globals@^9.0.0, globals@^9.14.0:
version "9.16.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80"
+globals@^9.18.0:
+ version "9.18.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+
globby@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
@@ -2233,7 +3518,7 @@ globby@^5.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
-graceful-fs@^4.1.2, graceful-fs@^4.1.4:
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@@ -2262,6 +3547,10 @@ has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+has-flag@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
+
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -2299,6 +3588,14 @@ hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+hoist-non-react-statics@1.x.x, hoist-non-react-statics@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
+
+hoist-non-react-statics@^2.2.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
+
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@@ -2314,6 +3611,27 @@ html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
+html-element-attributes@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/html-element-attributes/-/html-element-attributes-1.3.0.tgz#f06ebdfce22de979db82020265cac541fb17d4fc"
+
+html-entities@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
+
+html-tag-names@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/html-tag-names/-/html-tag-names-1.1.2.tgz#f65168964c5a9c82675efda882875dcb2a875c22"
+
+http-errors@~1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
+ dependencies:
+ depd "1.1.1"
+ inherits "2.0.3"
+ setprototypeof "1.0.3"
+ statuses ">= 1.3.1 < 2"
+
http-signature@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
@@ -2326,6 +3644,10 @@ https-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+hyphenate-style-name@^1.0.1, hyphenate-style-name@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
+
iconv-lite@~0.4.13:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
@@ -2334,6 +3656,12 @@ icss-replace-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
+icss-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
+ dependencies:
+ postcss "^6.0.1"
+
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
@@ -2342,6 +3670,10 @@ ignore@^3.2.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8"
+immutable@^3.7.4, immutable@^3.8.1:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2"
+
immutable@~3.7.4:
version "3.7.6"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
@@ -2375,7 +3707,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@@ -2387,6 +3719,27 @@ ini@~1.3.0:
version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+inline-style-prefixer@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
+ dependencies:
+ bowser "^1.0.0"
+ hyphenate-style-name "^1.0.1"
+
+inline-style-prefixer@^3.0.1:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.7.tgz#0ccc92e5902fe6e0d28d975c4258443f880615f8"
+ dependencies:
+ bowser "^1.6.0"
+ css-in-js-utils "^1.0.3"
+
+inline-style-prefixer@^3.0.6:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz#8551b8e5b4d573244e66a34b04f7d32076a2b534"
+ dependencies:
+ bowser "^1.7.3"
+ css-in-js-utils "^2.0.0"
+
inquirer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
@@ -2409,7 +3762,7 @@ interpret@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
-invariant@^2.2.0:
+invariant@2.x.x, invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
dependencies:
@@ -2419,6 +3772,10 @@ invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ipaddr.js@1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
+
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
@@ -2451,6 +3808,10 @@ is-date-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
+is-dom@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d"
+
is-dotfile@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
@@ -2485,6 +3846,10 @@ is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+is-function@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
+
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
@@ -2506,6 +3871,10 @@ is-number@^2.0.2, is-number@^2.1.0:
dependencies:
kind-of "^3.0.2"
+is-obj@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -2526,6 +3895,12 @@ is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ dependencies:
+ isobject "^3.0.1"
+
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
@@ -2542,7 +3917,7 @@ is-property@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
-is-regex@^1.0.3:
+is-regex@^1.0.3, is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
dependencies:
@@ -2590,6 +3965,10 @@ isobject@^2.0.0:
dependencies:
isarray "1.0.0"
+isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
@@ -2601,28 +3980,16 @@ isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
-istanbul-lib-coverage@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz#f263efb519c051c5f1f3343034fc40e7b43ff212"
-
-istanbul-lib-instrument@^1.4.2:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.4.2.tgz#0e2fdfac93c1dabf2e31578637dc78a19089f43e"
- dependencies:
- babel-generator "^6.18.0"
- babel-template "^6.16.0"
- babel-traverse "^6.18.0"
- babel-types "^6.18.0"
- babylon "^6.13.0"
- istanbul-lib-coverage "^1.0.0"
- semver "^5.3.0"
-
jodid25519@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
dependencies:
jsbn "~0.1.0"
+jquery@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787"
+
js-base64@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
@@ -2631,6 +3998,10 @@ js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+js-tokens@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+
js-yaml@^3.4.3, js-yaml@^3.5.1:
version "3.8.2"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721"
@@ -2661,6 +4032,10 @@ json-loader@^0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+json-schema-traverse@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@@ -2671,11 +4046,11 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
dependencies:
jsonify "~0.0.0"
-json-stringify-safe@~5.0.1:
+json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
-json5@^0.5.0:
+json5@^0.5.0, json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
@@ -2701,12 +4076,16 @@ jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4:
dependencies:
object-assign "^4.1.0"
-katex@^0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/katex/-/katex-0.7.1.tgz#06bb5298efad05e1e7228035ba8e1591f3061b8f"
+katex@^0.8.3:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/katex/-/katex-0.8.3.tgz#909d99864baf964c3ccae39c4a99a8e0fb9a1bd0"
dependencies:
match-at "^0.1.0"
+keycode@^2.1.8:
+ version "2.1.9"
+ resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa"
+
kind-of@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
@@ -2798,6 +4177,15 @@ load-json-file@^1.0.0:
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
+load-json-file@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ strip-bom "^3.0.0"
+
loader-runner@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
@@ -2819,6 +4207,14 @@ loader-utils@^1.0.2:
emojis-list "^2.0.0"
json5 "^0.5.0"
+loader-utils@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
+ dependencies:
+ big.js "^3.1.3"
+ emojis-list "^2.0.0"
+ json5 "^0.5.0"
+
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -2826,6 +4222,14 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
+lodash-es@^4.2.0, lodash-es@^4.2.1:
+ version "4.17.4"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
+
+lodash._getnative@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -2834,22 +4238,66 @@ lodash.cond@^4.3.0:
version "4.5.2"
resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+
+lodash.flattendeep@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+
+lodash.isarguments@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+
+lodash.isarray@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+
+lodash.isplainobject@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+
+lodash.keys@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+ dependencies:
+ lodash._getnative "^3.0.0"
+ lodash.isarguments "^3.0.0"
+ lodash.isarray "^3.0.0"
+
lodash.memoize@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+lodash.pick@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
+
lodash.pickby@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
+lodash.some@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
+
+lodash.sortby@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+
lodash.uniq@^4.3.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
-lodash@^4.0.0, lodash@^4.14.0, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1:
+lodash@4.x.x, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+lodash@^3.10.1:
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+
log-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
@@ -2867,7 +4315,7 @@ longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-loose-envify@^1.0.0, loose-envify@^1.1.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@@ -2884,6 +4332,20 @@ macaddress@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
+make-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978"
+ dependencies:
+ pify "^2.3.0"
+
+mantra-core@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/mantra-core/-/mantra-core-1.7.0.tgz#a8c83e8cee83ef6a7383131519fe8031ad546386"
+ dependencies:
+ babel-runtime "6.x.x"
+ react-komposer "^1.9.0"
+ react-simple-di "^1.2.0"
+
match-at@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/match-at/-/match-at-0.1.0.tgz#f561e7709ff9a105b85cc62c6b8ee7c15bf24f31"
@@ -2892,6 +4354,16 @@ math-expression-evaluator@^1.2.14:
version "1.2.16"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9"
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+
+mem@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
+ dependencies:
+ mimic-fn "^1.0.0"
+
memory-fs@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20"
@@ -2906,7 +4378,15 @@ memory-fs@^0.4.0, memory-fs@~0.4.1:
errno "^0.1.3"
readable-stream "^2.0.1"
-micromatch@^2.1.5, micromatch@^2.3.11:
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+
+micromatch@^2.1.5:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
@@ -2935,12 +4415,38 @@ mime-db@~1.26.0:
version "1.26.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff"
+mime-db@~1.30.0:
+ version "1.30.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
+
mime-types@^2.1.12, mime-types@~2.1.7:
version "2.1.14"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee"
dependencies:
mime-db "~1.26.0"
+mime-types@~2.1.15, mime-types@~2.1.16:
+ version "2.1.17"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
+ dependencies:
+ mime-db "~1.30.0"
+
+mime@1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
+
+mime@1.3.x:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0"
+
+mime@^1.3.4:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343"
+
+mimic-fn@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
+
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
@@ -2961,6 +4467,12 @@ minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
dependencies:
brace-expansion "^1.0.0"
+minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ dependencies:
+ brace-expansion "^1.1.7"
+
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
@@ -2975,6 +4487,10 @@ minimist@^1.2.0:
dependencies:
minimist "0.0.8"
+mobx@^2.3.4:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mobx/-/mobx-2.7.0.tgz#cf3d82d18c0ca7f458d8f2a240817b3dc7e54a01"
+
ms@0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
@@ -2983,6 +4499,10 @@ ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+
mute-stream@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
@@ -2995,6 +4515,16 @@ natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+negotiator@0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
+
+node-dir@^0.1.10:
+ version "0.1.17"
+ resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
+ dependencies:
+ minimatch "^3.0.2"
+
node-fetch@^1.0.1:
version "1.6.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
@@ -3133,12 +4663,43 @@ object.assign@^4.0.4:
function-bind "^1.1.0"
object-keys "^1.0.10"
+object.entries@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.6.1"
+ function-bind "^1.1.0"
+ has "^1.0.1"
+
+object.getownpropertydescriptors@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.5.1"
+
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
dependencies:
- for-own "^0.1.4"
- is-extendable "^0.1.1"
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
+object.values@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.6.1"
+ function-bind "^1.1.0"
+ has "^1.0.1"
+
+on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ dependencies:
+ ee-first "1.1.1"
once@^1.3.0:
version "1.4.0"
@@ -3190,6 +4751,14 @@ os-locale@^1.4.0:
dependencies:
lcid "^1.0.0"
+os-locale@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
+ dependencies:
+ execa "^0.7.0"
+ lcid "^1.0.0"
+ mem "^1.1.0"
+
os-tmpdir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -3245,6 +4814,10 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
+parseurl@~1.3.1, parseurl@~1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
+
path-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
@@ -3259,7 +4832,7 @@ path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
-path-is-absolute@^1.0.0:
+path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -3275,6 +4848,10 @@ path-parse@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@@ -3283,6 +4860,12 @@ path-type@^1.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+path-type@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+ dependencies:
+ pify "^2.0.0"
+
pbkdf2@^3.0.3:
version "3.0.9"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693"
@@ -3293,7 +4876,7 @@ performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
-pify@^2.0.0:
+pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -3313,6 +4896,12 @@ pkg-dir@^1.0.0:
dependencies:
find-up "^1.0.0"
+pkg-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ dependencies:
+ find-up "^2.1.0"
+
pkg-up@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26"
@@ -3323,6 +4912,13 @@ pluralize@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
+podda@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/podda/-/podda-1.2.2.tgz#15b0edbd334ade145813343f5ecf9c10a71cf500"
+ dependencies:
+ babel-runtime "^6.11.6"
+ immutable "^3.8.1"
+
postcss-calc@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
@@ -3384,6 +4980,12 @@ postcss-filter-plugins@^2.0.0:
postcss "^5.0.4"
uniqid "^4.0.0"
+postcss-flexbugs-fixes@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-3.2.0.tgz#9b8b932c53f9cf13ba0f61875303e447c33dcc51"
+ dependencies:
+ postcss "^6.0.1"
+
postcss-load-config@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a"
@@ -3416,6 +5018,15 @@ postcss-loader@^1.3.3:
postcss "^5.2.15"
postcss-load-config "^1.2.0"
+postcss-loader@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.6.tgz#8c7e0055a3df1889abc6bad52dd45b2f41bbc6fc"
+ dependencies:
+ loader-utils "^1.1.0"
+ postcss "^6.0.2"
+ postcss-load-config "^1.2.0"
+ schema-utils "^0.3.0"
+
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
@@ -3593,6 +5204,14 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"
+postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.2:
+ version "6.0.11"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.11.tgz#f48db210b1d37a7f7ab6499b7a54982997ab6f72"
+ dependencies:
+ chalk "^2.1.0"
+ source-map "^0.5.7"
+ supports-color "^4.4.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -3605,7 +5224,7 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
-private@^0.1.6:
+private@^0.1.6, private@^0.1.7, private@~0.1.5:
version "0.1.7"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
@@ -3625,12 +5244,40 @@ progress@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
+promise.prototype.finally@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.0.1.tgz#51ba2fa0a4cba5cbca54da818a8da8f24fc68f39"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.8.2"
+ function-bind "^1.1.1"
+
promise@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
dependencies:
asap "~2.0.3"
+prop-types@15.5.8:
+ version "15.5.8"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394"
+ dependencies:
+ fbjs "^0.8.9"
+
+prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.5.9:
+ version "15.5.10"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+ dependencies:
+ fbjs "^0.8.9"
+ loose-envify "^1.3.1"
+
+proxy-addr@~1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
+ dependencies:
+ forwarded "~0.1.0"
+ ipaddr.js "1.4.0"
+
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
@@ -3661,6 +5308,14 @@ q@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
+qs@6.5.0:
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49"
+
+qs@^6.4.0:
+ version "6.5.1"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
+
qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
@@ -3676,10 +5331,19 @@ querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
-querystring@0.2.0:
+querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+radium@^0.19.0:
+ version "0.19.4"
+ resolved "https://registry.yarnpkg.com/radium/-/radium-0.19.4.tgz#56aa49fde6181d2f5e1fa57b4710ffd0c23de820"
+ dependencies:
+ array-find "^1.0.0"
+ exenv "^1.2.1"
+ inline-style-prefixer "^2.0.5"
+ prop-types "^15.5.8"
+
ramda@^0.22.1:
version "0.22.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.22.1.tgz#031da0c3df417c5b33c96234757eb37033f36a0e"
@@ -3695,6 +5359,10 @@ randombytes@^2.0.0, randombytes@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
+range-parser@^1.0.3, range-parser@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
+
rc@~1.1.6:
version "1.1.7"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.7.tgz#c5ea564bb07aff9fd3a5b32e906c1d3a65940fea"
@@ -3704,9 +5372,34 @@ rc@~1.1.6:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-deep-force-update@^1.0.0:
+react-addons-css-transition-group@^15.6.0:
+ version "15.6.0"
+ resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.6.0.tgz#69887cf6e4874d25cd66e22a699e29f0d648aba0"
+ dependencies:
+ react-transition-group "^1.2.0"
+
+react-addons-pure-render-mixin@^15.6.0:
+ version "15.6.0"
+ resolved "https://registry.yarnpkg.com/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.0.tgz#84ba028630cdf89239d16f1bb4d98fe865651813"
+ dependencies:
+ fbjs "^0.8.4"
+ object-assign "^4.1.0"
+
+react-docgen@^2.15.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-2.18.0.tgz#fe6c57bd10fe2f3ecb32ab800a2db0fb43a93a35"
+ dependencies:
+ async "^2.1.4"
+ babel-runtime "^6.9.2"
+ babylon "~5.8.3"
+ commander "^2.9.0"
+ doctrine "^2.0.0"
+ node-dir "^0.1.10"
+ recast "^0.12.6"
+
+react-dom-factories@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz#f911b5be1d2a6fe387507dd6e9a767aa2924b4c7"
+ resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.1.tgz#c50692ac5ff1adb39d86dfe6dbe3485dacf58455"
react-dom@^15.4.2:
version "15.4.2"
@@ -3716,23 +5409,117 @@ react-dom@^15.4.2:
loose-envify "^1.1.0"
object-assign "^4.1.0"
-react-proxy@^1.1.7:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"
+react-html-attributes@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/react-html-attributes/-/react-html-attributes-1.4.1.tgz#97b5ec710da68833598c8be6f89ac436216840a5"
dependencies:
- lodash "^4.6.1"
- react-deep-force-update "^1.0.0"
+ html-element-attributes "^1.0.0"
-react-transform-catch-errors@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/react-transform-catch-errors/-/react-transform-catch-errors-1.0.2.tgz#1b4d4a76e97271896fc16fe3086c793ec88a9eeb"
+react-icon-base@2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.0.7.tgz#0bd18736bd6ce79ca6d69ce8387a07fb8d4ceffe"
+ dependencies:
+ prop-types "15.5.8"
-react-transform-hmr@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/react-transform-hmr/-/react-transform-hmr-1.0.4.tgz#e1a40bd0aaefc72e8dfd7a7cda09af85066397bb"
+react-icons@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-2.2.5.tgz#f942501c21a4cc0456ce2bbee5032c93f6051dcf"
dependencies:
- global "^4.3.0"
- react-proxy "^1.1.7"
+ react-icon-base "2.0.7"
+
+react-inspector@^2.1.1:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-2.1.4.tgz#2123fab74f68ae3136fbd02392fadb764326d04d"
+ dependencies:
+ babel-runtime "^6.23.0"
+ is-dom "^1.0.9"
+
+react-komposer@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/react-komposer/-/react-komposer-1.13.1.tgz#4b8ac4bcc71323bd7413dcab95c831197f50eed0"
+ dependencies:
+ babel-runtime "6.x.x"
+ hoist-non-react-statics "1.x.x"
+ invariant "2.x.x"
+ mobx "^2.3.4"
+ shallowequal "0.2.x"
+
+react-komposer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/react-komposer/-/react-komposer-2.0.0.tgz#b964738014a9b4aee494a83c0b5b833d66072a90"
+ dependencies:
+ babel-runtime "^6.11.6"
+ hoist-non-react-statics "^1.2.0"
+ lodash.pick "^4.4.0"
+ react-stubber "^1.0.0"
+ shallowequal "^0.2.2"
+
+react-modal@^2.2.4:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-2.3.2.tgz#af9d625da218461de3e87551609dfca12d8d4946"
+ dependencies:
+ exenv "^1.2.0"
+ prop-types "^15.5.10"
+ react-dom-factories "^1.0.0"
+
+react-redux@^5.0.6:
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946"
+ dependencies:
+ hoist-non-react-statics "^2.2.1"
+ invariant "^2.0.0"
+ lodash "^4.2.0"
+ lodash-es "^4.2.0"
+ loose-envify "^1.1.0"
+ prop-types "^15.5.10"
+
+react-simple-di@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/react-simple-di/-/react-simple-di-1.2.0.tgz#dde0e5bf689f391ef2ab02c9043b213fe239c6d0"
+ dependencies:
+ babel-runtime "6.x.x"
+ hoist-non-react-statics "1.x.x"
+
+react-split-pane@^0.1.65:
+ version "0.1.66"
+ resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.66.tgz#369085dd07ec1237bda123e73813dcc7dc6502c1"
+ dependencies:
+ inline-style-prefixer "^3.0.6"
+ prop-types "^15.5.10"
+ react-style-proptype "^3.0.0"
+
+react-stubber@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/react-stubber/-/react-stubber-1.0.0.tgz#41ee2cac72d4d4fd70a63896da98e13739b84628"
+ dependencies:
+ babel-runtime "^6.5.0"
+
+react-style-proptype@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/react-style-proptype/-/react-style-proptype-3.0.0.tgz#89e0b646f266c656abb0f0dd8202dbd5036c31e6"
+ dependencies:
+ prop-types "^15.5.4"
+
+react-transition-group@^1.1.2, react-transition-group@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
+ dependencies:
+ chain-function "^1.0.0"
+ dom-helpers "^3.2.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.5.6"
+ warning "^3.0.0"
+
+react-treebeard@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/react-treebeard/-/react-treebeard-2.0.3.tgz#cd644209c1be2fe2be3ae4bca8350ed6abf293d6"
+ dependencies:
+ babel-runtime "^6.23.0"
+ deep-equal "^1.0.1"
+ prop-types "^15.5.8"
+ radium "^0.19.0"
+ shallowequal "^0.2.2"
+ velocity-react "^1.3.1"
react@^15.4.2:
version "15.4.2"
@@ -3749,6 +5536,13 @@ read-pkg-up@^1.0.1:
find-up "^1.0.0"
read-pkg "^1.0.0"
+read-pkg-up@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
+ dependencies:
+ find-up "^2.0.0"
+ read-pkg "^2.0.0"
+
read-pkg@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
@@ -3757,6 +5551,14 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
+read-pkg@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+ dependencies:
+ load-json-file "^2.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^2.0.0"
+
"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729"
@@ -3798,19 +5600,22 @@ readline2@^1.0.1:
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"
+recast@^0.12.6:
+ version "0.12.6"
+ resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.6.tgz#4b0fb82feb1d10b3bd62d34943426d9b3ed30d4c"
+ dependencies:
+ ast-types "0.9.11"
+ core-js "^2.4.1"
+ esprima "~4.0.0"
+ private "~0.1.5"
+ source-map "~0.5.0"
+
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
dependencies:
resolve "^1.1.6"
-redbox-react@^1.2.2:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/redbox-react/-/redbox-react-1.3.4.tgz#3d882bb62cc7c8f6256279d12f05c6a5a96d24c6"
- dependencies:
- error-stack-parser "^1.3.6"
- object-assign "^4.0.1"
-
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
@@ -3825,6 +5630,15 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
+redux@^3.6.0, redux@^3.7.2:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
+ dependencies:
+ lodash "^4.2.1"
+ lodash-es "^4.2.1"
+ loose-envify "^1.1.0"
+ symbol-observable "^1.0.3"
+
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
@@ -3833,6 +5647,18 @@ regenerator-runtime@^0.10.0:
version "0.10.3"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+regenerator-runtime@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
+
+regenerator-transform@0.9.11:
+ version "0.9.11"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283"
+ dependencies:
+ babel-runtime "^6.18.0"
+ babel-types "^6.19.0"
+ private "^0.1.6"
+
regenerator-transform@0.9.8:
version "0.9.8"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c"
@@ -3888,7 +5714,7 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
-request@^2.79.0:
+request@^2.79.0, request@^2.81.0:
version "2.81.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
dependencies:
@@ -3989,6 +5815,10 @@ rxjs@^5.0.0-beta.11:
dependencies:
symbol-observable "^1.0.1"
+safe-buffer@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
+
safe-buffer@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
@@ -3997,10 +5827,57 @@ sax@~1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0:
+schema-utils@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
+ dependencies:
+ ajv "^5.0.0"
+
+"semver@2 || 3 || 4 || 5", semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+semver@^5.3.0:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
+
+send@0.15.4:
+ version "0.15.4"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9"
+ dependencies:
+ debug "2.6.8"
+ depd "~1.1.1"
+ destroy "~1.0.4"
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ etag "~1.8.0"
+ fresh "0.5.0"
+ http-errors "~1.6.2"
+ mime "1.3.4"
+ ms "2.0.0"
+ on-finished "~2.3.0"
+ range-parser "~1.2.0"
+ statuses "~1.3.1"
+
+serve-favicon@^2.4.3:
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.4.tgz#412ddd74965151c9f74c0828f35d50c5250210de"
+ dependencies:
+ etag "~1.8.0"
+ fresh "0.5.1"
+ ms "2.0.0"
+ parseurl "~1.3.2"
+ safe-buffer "5.1.1"
+
+serve-static@1.12.4:
+ version "1.12.4"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961"
+ dependencies:
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ parseurl "~1.3.1"
+ send "0.15.4"
+
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -4013,12 +5890,22 @@ setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+setprototypeof@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
+
sha.js@^2.3.6:
version "2.4.8"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
dependencies:
inherits "^2.0.1"
+shallowequal@0.2.x, shallowequal@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
+ dependencies:
+ lodash.keys "^3.1.2"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -4037,7 +5924,15 @@ shelljs@^0.7.5:
interpret "^1.0.0"
rechoir "^0.6.2"
-signal-exit@^3.0.0:
+shelljs@^0.7.8:
+ version "0.7.8"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -4065,6 +5960,16 @@ source-list-map@^0.1.7, source-list-map@~0.1.7:
version "0.1.8"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
+source-list-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
+
+source-map-support@^0.4.15:
+ version "0.4.18"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
+ dependencies:
+ source-map "^0.5.6"
+
source-map-support@^0.4.2:
version "0.4.11"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322"
@@ -4075,6 +5980,10 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, sour
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+source-map@^0.5.7, source-map@~0.5.0:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
@@ -4108,14 +6017,14 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"
-stackframe@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4"
-
staged-git-files@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35"
+"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
+
stream-browserify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
@@ -4141,6 +6050,10 @@ strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
+string-hash@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
+
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -4156,6 +6069,22 @@ string-width@^2.0.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^3.0.0"
+string.prototype.padend@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.4.3"
+ function-bind "^1.0.2"
+
+string.prototype.padstart@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.0.0.tgz#5bcfad39f4649bb2d031292e19bcf0b510d4b242"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.4.3"
+ function-bind "^1.0.2"
+
string_decoder@^0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@@ -4194,6 +6123,12 @@ style-loader@^0.13.2:
dependencies:
loader-utils "^1.0.2"
+style-loader@^0.17.0:
+ version "0.17.0"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310"
+ dependencies:
+ loader-utils "^1.0.2"
+
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -4204,6 +6139,16 @@ supports-color@^3.1.0, supports-color@^3.2.3:
dependencies:
has-flag "^1.0.0"
+supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
+ dependencies:
+ has-flag "^2.0.0"
+
+svg-tag-names@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a"
+
svgo@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
@@ -4216,7 +6161,7 @@ svgo@^0.7.0:
sax "~1.2.1"
whet.extend "~0.9.9"
-symbol-observable@^1.0.1:
+symbol-observable@^1.0.1, symbol-observable@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
@@ -4235,6 +6180,10 @@ tapable@^0.2.3, tapable@^0.2.5, tapable@~0.2.5:
version "0.2.6"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+tapable@^0.2.7:
+ version "0.2.8"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
+
tar-pack@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae"
@@ -4256,24 +6205,18 @@ tar@~2.2.1:
fstream "^1.0.2"
inherits "2"
-test-exclude@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.0.tgz#0ddc0100b8ae7e88b34eb4fd98a907e961991900"
- dependencies:
- arrify "^1.0.1"
- micromatch "^2.3.11"
- object-assign "^4.1.0"
- read-pkg-up "^1.0.1"
- require-main-filename "^1.0.1"
-
text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
-through@^2.3.6:
+through@^2.3.6, through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+time-stamp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357"
+
timers-browserify@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
@@ -4288,6 +6231,10 @@ to-fast-properties@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+to-fast-properties@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+
tough-cookie@~2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
@@ -4322,6 +6269,13 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
+type-is@~1.6.15:
+ version "1.6.15"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.15"
+
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -4338,10 +6292,27 @@ uglify-js@^2.7.5:
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
+uglify-js@^2.8.29:
+ version "2.8.29"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+ dependencies:
+ source-map "~0.5.1"
+ yargs "~3.10.0"
+ optionalDependencies:
+ uglify-to-browserify "~1.0.0"
+
uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+uglifyjs-webpack-plugin@^0.4.6:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309"
+ dependencies:
+ source-map "^0.5.6"
+ uglify-js "^2.8.29"
+ webpack-sources "^1.0.1"
+
uid-number@~0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
@@ -4364,6 +6335,23 @@ uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
+unique-string@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+ dependencies:
+ crypto-random-string "^1.0.0"
+
+unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+
+url-loader@^0.5.8:
+ version "0.5.9"
+ resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295"
+ dependencies:
+ loader-utils "^1.0.2"
+ mime "1.3.x"
+
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -4381,7 +6369,7 @@ user-home@^2.0.0:
dependencies:
os-homedir "^1.0.0"
-util-deprecate@~1.0.1:
+util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -4391,10 +6379,18 @@ util@0.10.3, util@^0.10.3:
dependencies:
inherits "2.0.1"
+utils-merge@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
+
uuid@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+uuid@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
+
v8flags@^2.0.10:
version "2.0.11"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
@@ -4408,6 +6404,23 @@ validate-npm-package-license@^3.0.1:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
+vary@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
+
+velocity-animate@^1.4.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/velocity-animate/-/velocity-animate-1.5.0.tgz#fc8771d8dfe1136ff02a707e10fbb0957c4b030f"
+
+velocity-react@^1.3.1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/velocity-react/-/velocity-react-1.3.3.tgz#d6d47276cfc8be2a75623879b20140ac58c1b82b"
+ dependencies:
+ lodash "^3.10.1"
+ prop-types "^15.5.8"
+ react-transition-group "^1.1.2"
+ velocity-animate "^1.4.0"
+
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
@@ -4424,6 +6437,12 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
+warning@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
+ dependencies:
+ loose-envify "^1.0.0"
+
watchpack@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
@@ -4432,6 +6451,33 @@ watchpack@^1.2.0:
chokidar "^1.4.3"
graceful-fs "^4.1.2"
+watchpack@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"
+ dependencies:
+ async "^2.1.2"
+ chokidar "^1.7.0"
+ graceful-fs "^4.1.2"
+
+webpack-dev-middleware@^1.10.2:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709"
+ dependencies:
+ memory-fs "~0.4.1"
+ mime "^1.3.4"
+ path-is-absolute "^1.0.0"
+ range-parser "^1.0.3"
+ time-stamp "^2.0.0"
+
+webpack-hot-middleware@^2.18.0:
+ version "2.19.1"
+ resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.19.1.tgz#5db32c31c955c1ead114d37c7519ea554da0d405"
+ dependencies:
+ ansi-html "0.0.7"
+ html-entities "^1.2.0"
+ querystring "^0.2.0"
+ strip-ansi "^3.0.0"
+
webpack-sources@^0.1.0, webpack-sources@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.5.tgz#aa1f3abf0f0d74db7111c40e500b84f966640750"
@@ -4439,6 +6485,13 @@ webpack-sources@^0.1.0, webpack-sources@^0.1.4:
source-list-map "~0.1.7"
source-map "~0.5.3"
+webpack-sources@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.5.3"
+
webpack@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.2.1.tgz#7bb1d72ae2087dd1a4af526afec15eed17dda475"
@@ -4464,6 +6517,33 @@ webpack@^2.2.1:
webpack-sources "^0.1.4"
yargs "^6.0.0"
+"webpack@^2.5.1 || ^3.0.0":
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.6.0.tgz#a89a929fbee205d35a4fa2cc487be9cbec8898bc"
+ dependencies:
+ acorn "^5.0.0"
+ acorn-dynamic-import "^2.0.0"
+ ajv "^5.1.5"
+ ajv-keywords "^2.0.0"
+ async "^2.1.2"
+ enhanced-resolve "^3.4.0"
+ escope "^3.6.0"
+ interpret "^1.0.0"
+ json-loader "^0.5.4"
+ json5 "^0.5.1"
+ loader-runner "^2.3.0"
+ loader-utils "^1.1.0"
+ memory-fs "~0.4.1"
+ mkdirp "~0.5.0"
+ node-libs-browser "^2.0.0"
+ source-map "^0.5.3"
+ supports-color "^4.2.1"
+ tapable "^0.2.7"
+ uglifyjs-webpack-plugin "^0.4.6"
+ watchpack "^1.4.0"
+ webpack-sources "^1.0.1"
+ yargs "^8.0.2"
+
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
@@ -4476,6 +6556,10 @@ which-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+which-module@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+
which@^1.2.10, which@^1.2.9:
version "1.2.12"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192"
@@ -4511,12 +6595,24 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+write-file-atomic@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab"
+ dependencies:
+ graceful-fs "^4.1.11"
+ imurmurhash "^0.1.4"
+ signal-exit "^3.0.2"
+
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
dependencies:
mkdirp "^0.5.1"
+xdg-basedir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+
xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@@ -4535,6 +6631,12 @@ yargs-parser@^4.2.0:
dependencies:
camelcase "^3.0.0"
+yargs-parser@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
+ dependencies:
+ camelcase "^4.1.0"
+
yargs@^6.0.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
@@ -4553,6 +6655,24 @@ yargs@^6.0.0:
y18n "^3.2.1"
yargs-parser "^4.2.0"
+yargs@^8.0.2:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360"
+ dependencies:
+ camelcase "^4.1.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^2.0.0"
+ read-pkg-up "^2.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^7.0.0"
+
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"