def22b37605314b81b1b189062ba1aadea67bf74.svn-base
4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
"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 => {
if (node.childNodes.length === 0) {
return '';
} // If parent container is `<Box>`, text nodes will be treated as separate nodes in
// the tree and will have their own coordinates in the layout.
// To ensure text nodes are aligned correctly, take X and Y of the first text node
// and use them as offset for the rest of the nodes
// Only first node is taken into account, because other text nodes can't have margin or padding,
// so their coordinates will be relative to the first node anyway
const offsetX = node.childNodes[0].yogaNode.getComputedLeft();
const offsetY = node.childNodes[0].yogaNode.getComputedTop();
let text = '\n'.repeat(offsetY) + ' '.repeat(offsetX);
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;