Files
30-seconds-of-code/node_modules/ink/build/render-node-to-output.js
2019-08-20 15:52:05 +02:00

157 lines
4.3 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _widestLine = _interopRequireDefault(require("widest-line"));
var _wrapText = _interopRequireDefault(require("./wrap-text"));
var _getMaxWidth = _interopRequireDefault(require("./get-max-width"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const isAllTextNodes = node => {
if (node.nodeName === '#text') {
return true;
}
if (node.nodeName === 'SPAN') {
if (node.textContent) {
return true;
}
if (Array.isArray(node.childNodes)) {
return node.childNodes.every(isAllTextNodes);
}
}
return false;
}; // Squashing text nodes allows to combine multiple text nodes into one and write
// to `Output` instance only once. For example, <Text>hello{' '}world</Text>
// is actually 3 text nodes, which would result 3 writes to `Output`.
//
// Also, this is necessary for libraries like ink-link (https://github.com/sindresorhus/ink-link),
// which need to wrap all children at once, instead of wrapping 3 text nodes separately.
const squashTextNodes = node => {
let text = '';
for (const childNode of node.childNodes) {
let nodeText;
if (childNode.nodeName === '#text') {
nodeText = childNode.nodeValue;
}
if (childNode.nodeName === 'SPAN') {
nodeText = childNode.textContent || squashTextNodes(childNode);
} // Since these text nodes are being concatenated, `Output` instance won't be able to
// apply children transform, so we have to do it manually here for each text node
if (childNode.unstable__transformChildren) {
nodeText = childNode.unstable__transformChildren(nodeText);
}
text += nodeText;
}
return text;
}; // After nodes are laid out, render each to output object, which later gets rendered to terminal
const renderNodeToOutput = (node, output, {
offsetX = 0,
offsetY = 0,
transformers = [],
skipStaticElements
}) => {
if (node.unstable__static && skipStaticElements) {
return;
}
const {
yogaNode
} = node; // Left and top positions in Yoga are relative to their parent node
const x = offsetX + yogaNode.getComputedLeft();
const y = offsetY + yogaNode.getComputedTop(); // Transformers are functions that transform final text output of each component
// See Output class for logic that applies transformers
let newTransformers = transformers;
if (node.unstable__transformChildren) {
newTransformers = [node.unstable__transformChildren, ...transformers];
} // Nodes with only text inside
if (node.textContent) {
let text = node.textContent; // Since text nodes are always wrapped in an additional node, parent node
// is where we should look for attributes
if (node.parentNode.style.textWrap) {
const currentWidth = (0, _widestLine.default)(text);
const maxWidth = (0, _getMaxWidth.default)(node.parentNode.yogaNode);
if (currentWidth > maxWidth) {
text = (0, _wrapText.default)(text, maxWidth, {
textWrap: node.parentNode.style.textWrap
});
}
}
output.write(x, y, text, {
transformers: newTransformers
});
return;
} // Text nodes
if (node.nodeName === '#text') {
output.write(x, y, node.nodeValue, {
transformers: newTransformers
});
return;
} // Nodes that have other nodes as children
if (Array.isArray(node.childNodes) && node.childNodes.length > 0) {
const isFlexDirectionRow = node.style.flexDirection === 'row';
if (isFlexDirectionRow && node.childNodes.every(isAllTextNodes)) {
let text = squashTextNodes(node);
if (node.style.textWrap) {
const currentWidth = (0, _widestLine.default)(text);
const maxWidth = (0, _getMaxWidth.default)(yogaNode);
if (currentWidth > maxWidth) {
text = (0, _wrapText.default)(text, maxWidth, {
textWrap: node.style.textWrap
});
}
}
output.write(x, y, text, {
transformers: newTransformers
});
return;
}
for (const childNode of node.childNodes) {
renderNodeToOutput(childNode, output, {
offsetX: x,
offsetY: y,
transformers: newTransformers,
skipStaticElements
});
}
}
};
var _default = renderNodeToOutput;
exports.default = _default;