UNPKG

cjkspace

Version:

Add space between CJK character and western character

161 lines (133 loc) 4.02 kB
"use strict"; var React = require('react'); var shouldSpace = require('./shouldSpace'); // https://github.com/facebook/react/blob/master/packages/shared/ReactTypes.js var NodeTypes = { Element: 'element', Text: 'text', Empty: 'empty', Fragment: 'fragment' }; var isTextNode = function isTextNode(node) { return typeof node === 'string' || typeof node === 'number'; }; var isEmptyNode = function isEmptyNode(node) { return node == null || typeof node === 'boolean'; }; var getNodeType = function getNodeType(node) { if (React.isValidElement(node)) { return NodeTypes.Element; } else if (isTextNode(node)) { return NodeTypes.Text; } else if (isEmptyNode(node)) { return NodeTypes.Empty; } else if (Array.isArray(node)) { return NodeTypes.Fragment; } }; var transformToXTree = function transformToXTree(root, visit) { var walk = function walk(xnode) { var reactNode = xnode.node; xnode.type = getNodeType(reactNode); if (xnode.type === NodeTypes.Element) { xnode.children = React.Children.map(reactNode.props.children, function (child) { return walk({ node: child, parent: xnode }, visit); }); } else if (xnode.type === NodeTypes.Fragment) { xnode.children = React.Children.map(reactNode, function (child) { return walk({ node: child, parent: xnode }, visit); }); } visit(xnode); return xnode; }; return walk({ node: root, parent: null }, visit); }; var unfold = function unfold(obj, fn) { return [obj].concat(function (v, next) { return v == null ? [] : next(v); }(fn(obj), function (v) { return unfold(v, fn); })); }; var findCommonAncestor = function findCommonAncestor(a, b) { var pathA = unfold(a, function (n) { return n.parent; }); var pathB = unfold(b, function (n) { return n.parent; }); var index = pathA.findIndex(function (n) { return pathB.includes(n); }); // 将在 CA 下插入,在靠近 a 的一侧祖先元素之后 return [pathA[index], pathA[index - 1]]; }; var insertSpaceAfter = function insertSpaceAfter(parent, child) { parent.children.splice(parent.children.indexOf(child) + 1, 0, { node: ' ' }); }; var insertSpacesBetween = function insertSpacesBetween(textNodes) { var inserted = false; textNodes.reduce(function (prev, next) { if (prev && next && shouldSpace(String(prev.node), String(next.node))) { var _findCommonAncestor = findCommonAncestor(prev, next), caNode = _findCommonAncestor[0], refNode = _findCommonAncestor[1]; insertSpaceAfter(caNode, refNode); inserted = true; } return next; }); return inserted; }; var transformToReactTree = function transformToReactTree(xnode) { if (Array.isArray(xnode.children)) { if (xnode.type === NodeTypes.Fragment) { return React.Children.map(xnode.children.map(transformToReactTree), function (child) { return child; }); } return React.createElement(xnode.node.type, xnode.node.props, React.Children.map(xnode.children.map(transformToReactTree), function (child) { return child; })); } return xnode.node; }; // React tree => X tree => spacing => React tree var process = function process(tree) { if (!tree) { // empty fragment return null; } var textNodes = []; var xtree = transformToXTree(tree, function (xnode) { if (xnode.type === NodeTypes.Text && xnode.node !== '') { // non-empty text nodes textNodes.push(xnode); } }); if (textNodes.length && insertSpacesBetween(textNodes)) { return transformToReactTree(xtree); } return tree; }; var CJKSpace = function CJKSpace(_ref) { var component = _ref.component, children = _ref.children; return React.createElement(component, { children: process(children) }); }; CJKSpace.defaultProps = { // React 16 || 15 component: React.Fragment || 'span' }; exports.CJKSpace = CJKSpace;