cjkspace
Version:
Add space between CJK character and western character
161 lines (133 loc) • 4.02 kB
JavaScript
;
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;