@flowtty/core 1.0.0-alpha.1 → 1.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend-CT8SGLO5.d.ts +103 -0
- package/dist/cells-C-GthybI.d.ts +43 -0
- package/dist/host/index.d.ts +6 -8
- package/dist/host/index.js +338 -312
- package/dist/host-C98WW3Ai.d.ts +184 -0
- package/dist/index.d.ts +104 -54
- package/dist/index.js +699 -360
- package/dist/keys-Ck-RALk_.js +40 -0
- package/dist/testing/index.d.ts +39 -31
- package/dist/testing/index.js +140 -65
- package/dist/wrap-D5f0P1iA.js +180 -0
- package/package.json +3 -3
- package/dist/backend-BcB7VR87.d.ts +0 -74
- package/dist/cells-CaXEx4lH.d.ts +0 -31
- package/dist/chunk-D6HW2BNM.js +0 -106
- package/dist/host-DttBG-OZ.d.ts +0 -151
package/dist/host/index.js
CHANGED
|
@@ -1,357 +1,383 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var yogaPromise = null;
|
|
1
|
+
import { a as Buffer, n as BORDER_CHARS, t as wrapText } from "../wrap-D5f0P1iA.js";
|
|
2
|
+
import { Align, Display, Edge, FlexDirection, Gutter, Justify, MeasureMode, PositionType, Wrap, loadYoga } from "yoga-layout/load";
|
|
3
|
+
//#region src/host/yoga.ts
|
|
4
|
+
let yogaPromise = null;
|
|
6
5
|
function getYoga() {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
yogaPromise ??= loadYoga();
|
|
7
|
+
return yogaPromise;
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/host/host.ts
|
|
12
11
|
function createInstance(type, props, Yoga) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
const inst = {
|
|
13
|
+
type: "box",
|
|
14
|
+
props,
|
|
15
|
+
yogaNode: Yoga.Node.create(),
|
|
16
|
+
children: []
|
|
17
|
+
};
|
|
18
|
+
applyProps(inst, props, Yoga);
|
|
19
|
+
return inst;
|
|
17
20
|
}
|
|
18
21
|
function createTextInstance(text, _Yoga) {
|
|
19
|
-
|
|
22
|
+
return {
|
|
23
|
+
type: "text",
|
|
24
|
+
text
|
|
25
|
+
};
|
|
20
26
|
}
|
|
21
27
|
function applyProps(inst, props, _Yoga) {
|
|
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
|
-
n.setMaxHeight(props.maxHeight);
|
|
78
|
-
n.setAspectRatio(props.aspectRatio);
|
|
79
|
-
n.setDisplay(props.display === "none" ? Display.None : Display.Flex);
|
|
80
|
-
n.setFlexWrap(wrapMap(props.flexWrap));
|
|
81
|
-
n.setAlignContent(acMap(props.alignContent));
|
|
82
|
-
n.setJustifyContent(jcMap(props.justifyContent));
|
|
83
|
-
n.setAlignItems(aiMap(props.alignItems));
|
|
28
|
+
inst.props = props;
|
|
29
|
+
const n = inst.yogaNode;
|
|
30
|
+
if (typeof props.width === "number") n.setWidth(props.width);
|
|
31
|
+
else if (typeof props.width === "string" && props.width.endsWith("%")) n.setWidthPercent(parseFloat(props.width));
|
|
32
|
+
else n.setWidthAuto();
|
|
33
|
+
if (typeof props.height === "number") n.setHeight(props.height);
|
|
34
|
+
else if (typeof props.height === "string" && props.height.endsWith("%")) n.setHeightPercent(parseFloat(props.height));
|
|
35
|
+
else n.setHeightAuto();
|
|
36
|
+
n.setFlexDirection(props.flexDirection === "row" ? FlexDirection.Row : FlexDirection.Column);
|
|
37
|
+
const isViewport = props.scrollTop !== void 0 || props.scrollBottom !== void 0;
|
|
38
|
+
n.setPositionType(props.position === "absolute" ? PositionType.Absolute : isViewport ? PositionType.Relative : PositionType.Static);
|
|
39
|
+
if (props.top !== void 0) n.setPosition(Edge.Top, props.top);
|
|
40
|
+
if (props.left !== void 0) n.setPosition(Edge.Left, props.left);
|
|
41
|
+
if (props.right !== void 0) n.setPosition(Edge.Right, props.right);
|
|
42
|
+
if (props.bottom !== void 0) n.setPosition(Edge.Bottom, props.bottom);
|
|
43
|
+
const borderWidth = props.border ? 1 : 0;
|
|
44
|
+
n.setBorder(Edge.Top, borderWidth);
|
|
45
|
+
n.setBorder(Edge.Right, borderWidth);
|
|
46
|
+
n.setBorder(Edge.Bottom, borderWidth);
|
|
47
|
+
n.setBorder(Edge.Left, borderWidth);
|
|
48
|
+
const padTop = props.paddingTop ?? props.paddingY ?? props.padding ?? 0;
|
|
49
|
+
const padRight = props.paddingRight ?? props.paddingX ?? props.padding ?? 0;
|
|
50
|
+
const padBottom = props.paddingBottom ?? props.paddingY ?? props.padding ?? 0;
|
|
51
|
+
const padLeft = props.paddingLeft ?? props.paddingX ?? props.padding ?? 0;
|
|
52
|
+
n.setPadding(Edge.Top, padTop);
|
|
53
|
+
n.setPadding(Edge.Right, padRight);
|
|
54
|
+
n.setPadding(Edge.Bottom, padBottom);
|
|
55
|
+
n.setPadding(Edge.Left, padLeft);
|
|
56
|
+
const marTop = props.marginTop ?? props.marginY ?? props.margin ?? 0;
|
|
57
|
+
const marRight = props.marginRight ?? props.marginX ?? props.margin ?? 0;
|
|
58
|
+
const marBottom = props.marginBottom ?? props.marginY ?? props.margin ?? 0;
|
|
59
|
+
const marLeft = props.marginLeft ?? props.marginX ?? props.margin ?? 0;
|
|
60
|
+
n.setMargin(Edge.Top, marTop);
|
|
61
|
+
n.setMargin(Edge.Right, marRight);
|
|
62
|
+
n.setMargin(Edge.Bottom, marBottom);
|
|
63
|
+
n.setMargin(Edge.Left, marLeft);
|
|
64
|
+
const rGap = props.rowGap ?? props.gap ?? 0;
|
|
65
|
+
const cGap = props.columnGap ?? props.gap ?? 0;
|
|
66
|
+
n.setGap(Gutter.Row, rGap);
|
|
67
|
+
n.setGap(Gutter.Column, cGap);
|
|
68
|
+
n.setFlexGrow(props.flexGrow ?? 0);
|
|
69
|
+
n.setFlexShrink(props.flexShrink ?? 0);
|
|
70
|
+
if (typeof props.flexBasis === "number") n.setFlexBasis(props.flexBasis);
|
|
71
|
+
else if (typeof props.flexBasis === "string" && props.flexBasis.endsWith("%")) n.setFlexBasisPercent(parseFloat(props.flexBasis));
|
|
72
|
+
else n.setFlexBasisAuto();
|
|
73
|
+
n.setMinWidth(props.minWidth);
|
|
74
|
+
n.setMaxWidth(props.maxWidth);
|
|
75
|
+
n.setMinHeight(props.minHeight);
|
|
76
|
+
n.setMaxHeight(props.maxHeight);
|
|
77
|
+
n.setAspectRatio(props.aspectRatio);
|
|
78
|
+
n.setDisplay(props.display === "none" ? Display.None : Display.Flex);
|
|
79
|
+
n.setFlexWrap(wrapMap(props.flexWrap));
|
|
80
|
+
n.setAlignContent(acMap(props.alignContent));
|
|
81
|
+
n.setJustifyContent(jcMap(props.justifyContent));
|
|
82
|
+
n.setAlignItems(aiMap(props.alignItems));
|
|
84
83
|
}
|
|
85
84
|
function wrapMap(v) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
default:
|
|
92
|
-
return Wrap.NoWrap;
|
|
93
|
-
}
|
|
85
|
+
switch (v) {
|
|
86
|
+
case "wrap": return Wrap.Wrap;
|
|
87
|
+
case "wrap-reverse": return Wrap.WrapReverse;
|
|
88
|
+
default: return Wrap.NoWrap;
|
|
89
|
+
}
|
|
94
90
|
}
|
|
95
91
|
function jcMap(v) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return Justify.SpaceAround;
|
|
105
|
-
case "space-evenly":
|
|
106
|
-
return Justify.SpaceEvenly;
|
|
107
|
-
default:
|
|
108
|
-
return Justify.FlexStart;
|
|
109
|
-
}
|
|
92
|
+
switch (v) {
|
|
93
|
+
case "center": return Justify.Center;
|
|
94
|
+
case "flex-end": return Justify.FlexEnd;
|
|
95
|
+
case "space-between": return Justify.SpaceBetween;
|
|
96
|
+
case "space-around": return Justify.SpaceAround;
|
|
97
|
+
case "space-evenly": return Justify.SpaceEvenly;
|
|
98
|
+
default: return Justify.FlexStart;
|
|
99
|
+
}
|
|
110
100
|
}
|
|
111
101
|
function aiMap(v) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return Align.FlexStart;
|
|
119
|
-
// Default 'stretch' (matches React Native; deviates from CSS flex-start).
|
|
120
|
-
// Rationale: most TUI use cases want children to fill cross-axis (e.g. a
|
|
121
|
-
// column dialog wants its TextInput/buttons to span the dialog width); CSS's
|
|
122
|
-
// flex-start default forces content-sizing which causes percentage children
|
|
123
|
-
// to collapse and onLayout-driven scroll to misreport viewport widths.
|
|
124
|
-
default:
|
|
125
|
-
return Align.Stretch;
|
|
126
|
-
}
|
|
102
|
+
switch (v) {
|
|
103
|
+
case "center": return Align.Center;
|
|
104
|
+
case "flex-end": return Align.FlexEnd;
|
|
105
|
+
case "flex-start": return Align.FlexStart;
|
|
106
|
+
default: return Align.Stretch;
|
|
107
|
+
}
|
|
127
108
|
}
|
|
128
109
|
function acMap(v) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
case "space-evenly":
|
|
139
|
-
return Align.SpaceEvenly;
|
|
140
|
-
case "stretch":
|
|
141
|
-
return Align.Stretch;
|
|
142
|
-
default:
|
|
143
|
-
return Align.FlexStart;
|
|
144
|
-
}
|
|
110
|
+
switch (v) {
|
|
111
|
+
case "flex-end": return Align.FlexEnd;
|
|
112
|
+
case "center": return Align.Center;
|
|
113
|
+
case "space-between": return Align.SpaceBetween;
|
|
114
|
+
case "space-around": return Align.SpaceAround;
|
|
115
|
+
case "space-evenly": return Align.SpaceEvenly;
|
|
116
|
+
case "stretch": return Align.Stretch;
|
|
117
|
+
default: return Align.FlexStart;
|
|
118
|
+
}
|
|
145
119
|
}
|
|
146
120
|
function measureText(text) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
121
|
+
const lines = text.split("\n");
|
|
122
|
+
return {
|
|
123
|
+
width: lines.reduce((m, l) => Math.max(m, [...l].length), 0),
|
|
124
|
+
height: lines.length
|
|
125
|
+
};
|
|
150
126
|
}
|
|
151
127
|
function ownText(inst) {
|
|
152
|
-
|
|
128
|
+
return inst.children.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
153
129
|
}
|
|
154
130
|
function refreshMeasure(inst, _Yoga) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
131
|
+
const hasText = inst.children.some((c) => c.type === "text");
|
|
132
|
+
const hasBox = inst.children.some((c) => c.type === "box");
|
|
133
|
+
if (hasText && !hasBox) {
|
|
134
|
+
const text = ownText(inst);
|
|
135
|
+
const mode = inst.props.wrap ?? "none";
|
|
136
|
+
inst.yogaNode.setMeasureFunc((width, widthMode) => {
|
|
137
|
+
if (mode !== "none" && (widthMode === MeasureMode.Exactly || widthMode === MeasureMode.AtMost) && Number.isFinite(width)) {
|
|
138
|
+
const lines = wrapText(text, Math.max(0, Math.floor(width)), mode);
|
|
139
|
+
return {
|
|
140
|
+
width: lines.reduce((m, l) => Math.max(m, [...l].length), 0),
|
|
141
|
+
height: lines.length
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return measureText(text);
|
|
145
|
+
});
|
|
146
|
+
inst.yogaNode.markDirty();
|
|
147
|
+
} else inst.yogaNode.setMeasureFunc(null);
|
|
148
|
+
}
|
|
149
|
+
function detachForMove(parent, child) {
|
|
150
|
+
const i = parent.children.indexOf(child);
|
|
151
|
+
if (i < 0) return;
|
|
152
|
+
parent.children.splice(i, 1);
|
|
153
|
+
if (child.type === "box") parent.yogaNode.removeChild(child.yogaNode);
|
|
173
154
|
}
|
|
174
155
|
function appendChild(parent, child, Yoga) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
refreshMeasure(parent);
|
|
156
|
+
detachForMove(parent, child);
|
|
157
|
+
parent.children.push(child);
|
|
158
|
+
if (child.type === "box") {
|
|
159
|
+
parent.yogaNode.setMeasureFunc(null);
|
|
160
|
+
parent.yogaNode.insertChild(child.yogaNode, parent.yogaNode.getChildCount());
|
|
161
|
+
} else child.parent = parent;
|
|
162
|
+
refreshMeasure(parent, Yoga);
|
|
183
163
|
}
|
|
184
164
|
function removeChild(parent, child, Yoga) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
refreshMeasure(parent);
|
|
165
|
+
const i = parent.children.indexOf(child);
|
|
166
|
+
if (i >= 0) parent.children.splice(i, 1);
|
|
167
|
+
if (child.type === "box") {
|
|
168
|
+
parent.yogaNode.removeChild(child.yogaNode);
|
|
169
|
+
child.yogaNode.freeRecursive();
|
|
170
|
+
} else child.parent = void 0;
|
|
171
|
+
refreshMeasure(parent, Yoga);
|
|
194
172
|
}
|
|
195
173
|
function insertBefore(parent, child, before, Yoga) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
refreshMeasure(parent);
|
|
174
|
+
detachForMove(parent, child);
|
|
175
|
+
const i = parent.children.indexOf(before);
|
|
176
|
+
parent.children.splice(i < 0 ? parent.children.length : i, 0, child);
|
|
177
|
+
if (child.type === "box") {
|
|
178
|
+
const boxIndex = parent.children.filter((c) => c.type === "box").indexOf(child);
|
|
179
|
+
parent.yogaNode.setMeasureFunc(null);
|
|
180
|
+
parent.yogaNode.insertChild(child.yogaNode, boxIndex);
|
|
181
|
+
} else child.parent = parent;
|
|
182
|
+
refreshMeasure(parent, Yoga);
|
|
206
183
|
}
|
|
207
|
-
|
|
208
|
-
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/host/layout.ts
|
|
209
186
|
function computeLayout(container, width, height) {
|
|
210
|
-
|
|
211
|
-
root.yogaNode.calculateLayout(width, height);
|
|
212
|
-
}
|
|
187
|
+
for (const root of container.children) root.yogaNode.calculateLayout(width, height);
|
|
213
188
|
}
|
|
214
189
|
function layoutOf(inst, offsetX = 0, offsetY = 0) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
190
|
+
const n = inst.yogaNode;
|
|
191
|
+
return {
|
|
192
|
+
left: offsetX + n.getComputedLeft(),
|
|
193
|
+
top: offsetY + n.getComputedTop(),
|
|
194
|
+
width: n.getComputedWidth(),
|
|
195
|
+
height: n.getComputedHeight()
|
|
196
|
+
};
|
|
222
197
|
}
|
|
223
|
-
|
|
224
|
-
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/host/paint.ts
|
|
225
200
|
function paint(container, width, height) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
201
|
+
const buffer = new Buffer(width, height);
|
|
202
|
+
for (const root of container.children) paintInstance(root, buffer, 0, 0);
|
|
203
|
+
return buffer;
|
|
229
204
|
}
|
|
230
205
|
function textStyleOf(inst) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
206
|
+
const p = inst.props;
|
|
207
|
+
const style = {};
|
|
208
|
+
if (p.color !== void 0) style.fg = p.color;
|
|
209
|
+
if (p.bold) style.bold = true;
|
|
210
|
+
if (p.dim) style.dim = true;
|
|
211
|
+
if (p.underline) style.underline = true;
|
|
212
|
+
if (p.inverse) style.inverse = true;
|
|
213
|
+
if (p.strikethrough) style.strikethrough = true;
|
|
214
|
+
if (p.link !== void 0) style.link = p.link;
|
|
215
|
+
if (p.backgroundColor !== void 0) style.bg = p.backgroundColor;
|
|
216
|
+
return style;
|
|
242
217
|
}
|
|
243
218
|
function setClipped(buffer, x, y, char, style, clip) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
219
|
+
if (clip !== null) {
|
|
220
|
+
if (x < clip.left || y < clip.top || x >= clip.left + clip.width || y >= clip.top + clip.height) return;
|
|
221
|
+
}
|
|
222
|
+
buffer.set(x, y, char, style);
|
|
248
223
|
}
|
|
249
224
|
function intersectRects(a, b) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
225
|
+
if (a === null) return b;
|
|
226
|
+
const left = Math.max(a.left, b.left);
|
|
227
|
+
const top = Math.max(a.top, b.top);
|
|
228
|
+
const right = Math.min(a.left + a.width, b.left + b.width);
|
|
229
|
+
const bottom = Math.min(a.top + a.height, b.top + b.height);
|
|
230
|
+
if (right <= left || bottom <= top) return {
|
|
231
|
+
left,
|
|
232
|
+
top,
|
|
233
|
+
width: 0,
|
|
234
|
+
height: 0
|
|
235
|
+
};
|
|
236
|
+
return {
|
|
237
|
+
left,
|
|
238
|
+
top,
|
|
239
|
+
width: right - left,
|
|
240
|
+
height: bottom - top
|
|
241
|
+
};
|
|
257
242
|
}
|
|
258
|
-
function paintBorder(inst, buffer, box, clip) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
243
|
+
function paintBorder(inst, buffer, box, clip, effectiveBg) {
|
|
244
|
+
const style = inst.props.border;
|
|
245
|
+
if (!style) return;
|
|
246
|
+
if (box.width < 2 || box.height < 2) return;
|
|
247
|
+
const chars = BORDER_CHARS[style];
|
|
248
|
+
const cellStyle = {};
|
|
249
|
+
if (inst.props.borderColor !== void 0) cellStyle.fg = inst.props.borderColor;
|
|
250
|
+
const bg = inst.props.borderBackgroundColor ?? effectiveBg;
|
|
251
|
+
if (bg !== void 0 && bg !== "default") cellStyle.bg = bg;
|
|
252
|
+
const x0 = box.left;
|
|
253
|
+
const y0 = box.top;
|
|
254
|
+
const x1 = box.left + box.width - 1;
|
|
255
|
+
const y1 = box.top + box.height - 1;
|
|
256
|
+
setClipped(buffer, x0, y0, chars.tl, cellStyle, clip);
|
|
257
|
+
setClipped(buffer, x1, y0, chars.tr, cellStyle, clip);
|
|
258
|
+
setClipped(buffer, x0, y1, chars.bl, cellStyle, clip);
|
|
259
|
+
setClipped(buffer, x1, y1, chars.br, cellStyle, clip);
|
|
260
|
+
for (let x = x0 + 1; x < x1; x++) {
|
|
261
|
+
setClipped(buffer, x, y0, chars.h, cellStyle, clip);
|
|
262
|
+
setClipped(buffer, x, y1, chars.h, cellStyle, clip);
|
|
263
|
+
}
|
|
264
|
+
for (let y = y0 + 1; y < y1; y++) {
|
|
265
|
+
setClipped(buffer, x0, y, chars.v, cellStyle, clip);
|
|
266
|
+
setClipped(buffer, x1, y, chars.v, cellStyle, clip);
|
|
267
|
+
}
|
|
268
|
+
const title = inst.props.borderTitle;
|
|
269
|
+
if (title && title !== "") {
|
|
270
|
+
const avail = box.width - 4;
|
|
271
|
+
if (avail >= 1) {
|
|
272
|
+
const titleChars = [...` ${title} `];
|
|
273
|
+
const drawN = Math.min(titleChars.length, avail);
|
|
274
|
+
for (let i = 0; i < drawN; i++) {
|
|
275
|
+
const ch = i === drawN - 1 && titleChars.length > avail ? "…" : titleChars[i];
|
|
276
|
+
setClipped(buffer, x0 + 2 + i, y0, ch, cellStyle, clip);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
294
280
|
}
|
|
295
281
|
function contentRectOf(inst, box) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
282
|
+
const n = inst.yogaNode;
|
|
283
|
+
const padT = n.getComputedPadding(Edge.Top) + n.getComputedBorder(Edge.Top);
|
|
284
|
+
const padR = n.getComputedPadding(Edge.Right) + n.getComputedBorder(Edge.Right);
|
|
285
|
+
const padB = n.getComputedPadding(Edge.Bottom) + n.getComputedBorder(Edge.Bottom);
|
|
286
|
+
const padL = n.getComputedPadding(Edge.Left) + n.getComputedBorder(Edge.Left);
|
|
287
|
+
return {
|
|
288
|
+
left: box.left + padL,
|
|
289
|
+
top: box.top + padT,
|
|
290
|
+
width: Math.max(0, box.width - padL - padR),
|
|
291
|
+
height: Math.max(0, box.height - padT - padB)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function paddingRectOf(inst, box) {
|
|
295
|
+
const n = inst.yogaNode;
|
|
296
|
+
const t = n.getComputedBorder(Edge.Top);
|
|
297
|
+
const r = n.getComputedBorder(Edge.Right);
|
|
298
|
+
const b = n.getComputedBorder(Edge.Bottom);
|
|
299
|
+
const l = n.getComputedBorder(Edge.Left);
|
|
300
|
+
return {
|
|
301
|
+
left: box.left + l,
|
|
302
|
+
top: box.top + t,
|
|
303
|
+
width: Math.max(0, box.width - l - r),
|
|
304
|
+
height: Math.max(0, box.height - t - b)
|
|
305
|
+
};
|
|
307
306
|
}
|
|
308
307
|
function paintInstance(inst, buffer, offsetX, offsetY, inheritedBg = void 0, clip = null) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
308
|
+
if (inst.props.display === "none") return;
|
|
309
|
+
const box = layoutOf(inst, offsetX, offsetY);
|
|
310
|
+
inst.props.onLayout?.(box);
|
|
311
|
+
const ownBg = inst.props.backgroundColor;
|
|
312
|
+
const effectiveBg = ownBg ?? inheritedBg;
|
|
313
|
+
const offscreen = clip !== null && (box.left >= clip.left + clip.width || box.left + box.width <= clip.left || box.top >= clip.top + clip.height || box.top + box.height <= clip.top);
|
|
314
|
+
if (!offscreen && inst.props.backdrop === "dim") for (let y = box.top; y < box.top + box.height; y++) for (let x = box.left; x < box.left + box.width; x++) {
|
|
315
|
+
if (x < 0 || y < 0 || x >= buffer.width || y >= buffer.height) continue;
|
|
316
|
+
const under = buffer.get(x, y);
|
|
317
|
+
if (under.style.dim && !under.style.bold) continue;
|
|
318
|
+
const { bold: _bold, ...rest } = under.style;
|
|
319
|
+
setClipped(buffer, x, y, under.char, {
|
|
320
|
+
...rest,
|
|
321
|
+
dim: true
|
|
322
|
+
}, clip);
|
|
323
|
+
}
|
|
324
|
+
if (!offscreen && ownBg !== void 0) {
|
|
325
|
+
const fillStyle = ownBg === "default" ? {} : { bg: ownBg };
|
|
326
|
+
for (let y = box.top; y < box.top + box.height; y++) for (let x = box.left; x < box.left + box.width; x++) setClipped(buffer, x, y, " ", fillStyle, clip);
|
|
327
|
+
}
|
|
328
|
+
if (!offscreen) paintBorder(inst, buffer, box, clip, effectiveBg);
|
|
329
|
+
const text = offscreen ? "" : ownText(inst);
|
|
330
|
+
if (text) {
|
|
331
|
+
const content = contentRectOf(inst, box);
|
|
332
|
+
const mode = inst.props.wrap ?? "none";
|
|
333
|
+
const lines = mode === "none" ? text.split("\n") : wrapText(text, content.width, mode);
|
|
334
|
+
const textStyle = textStyleOf(inst);
|
|
335
|
+
if (textStyle.bg === void 0 && effectiveBg !== void 0) textStyle.bg = effectiveBg;
|
|
336
|
+
for (let row = 0; row < lines.length; row++) {
|
|
337
|
+
if (row >= content.height) break;
|
|
338
|
+
const chars = [...lines[row] ?? ""];
|
|
339
|
+
for (let col = 0; col < chars.length; col++) {
|
|
340
|
+
if (col >= content.width) break;
|
|
341
|
+
const ch = chars[col];
|
|
342
|
+
const safe = ch.charCodeAt(0) < 32 ? " " : ch;
|
|
343
|
+
setClipped(buffer, content.left + col, content.top + row, safe, textStyle, clip);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const scrolls = inst.props.scrollTop !== void 0 || inst.props.scrollBottom !== void 0;
|
|
348
|
+
let scrollTop = 0;
|
|
349
|
+
if (scrolls || inst.props.onScrollMetrics) {
|
|
350
|
+
const viewport = contentRectOf(inst, box);
|
|
351
|
+
let contentBottom = 0;
|
|
352
|
+
for (const child of inst.children) {
|
|
353
|
+
if (child.type !== "box" || child.props.position === "absolute" || child.props.display === "none") continue;
|
|
354
|
+
const n = child.yogaNode;
|
|
355
|
+
contentBottom = Math.max(contentBottom, n.getComputedTop() + n.getComputedHeight() + n.getComputedMargin(Edge.Bottom));
|
|
356
|
+
}
|
|
357
|
+
const contentHeight = Math.max(0, contentBottom - (viewport.top - box.top));
|
|
358
|
+
const maxScrollTop = Math.max(0, contentHeight - viewport.height);
|
|
359
|
+
const wanted = inst.props.scrollBottom !== void 0 ? maxScrollTop - inst.props.scrollBottom : inst.props.scrollTop ?? 0;
|
|
360
|
+
scrollTop = Math.max(0, Math.min(maxScrollTop, Math.round(wanted)));
|
|
361
|
+
inst.props.onScrollMetrics?.({
|
|
362
|
+
contentHeight,
|
|
363
|
+
viewportHeight: viewport.height,
|
|
364
|
+
scrollTop,
|
|
365
|
+
maxScrollTop
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
const childClip = inst.props.overflow === "hidden" || scrolls ? intersectRects(clip, contentRectOf(inst, box)) : clip;
|
|
369
|
+
const stackFlow = [];
|
|
370
|
+
const absolutes = [];
|
|
371
|
+
for (const child of inst.children) {
|
|
372
|
+
if (child.type !== "box") continue;
|
|
373
|
+
(child.props.position === "absolute" ? absolutes : stackFlow).push(child);
|
|
374
|
+
}
|
|
375
|
+
const byZ = (a, b) => (a.props.zIndex ?? 0) - (b.props.zIndex ?? 0);
|
|
376
|
+
stackFlow.sort(byZ);
|
|
377
|
+
absolutes.sort(byZ);
|
|
378
|
+
for (const child of stackFlow) paintInstance(child, buffer, box.left, box.top - scrollTop, effectiveBg, childClip);
|
|
379
|
+
const overlayClip = scrolls ? intersectRects(clip, paddingRectOf(inst, box)) : childClip;
|
|
380
|
+
for (const child of absolutes) paintInstance(child, buffer, box.left, box.top, effectiveBg, overlayClip);
|
|
355
381
|
}
|
|
356
|
-
|
|
357
|
-
export { appendChild, applyProps, computeLayout, createInstance, createTextInstance, getYoga, insertBefore, layoutOf, measureText, ownText, paint, refreshMeasure, removeChild };
|
|
382
|
+
//#endregion
|
|
383
|
+
export { BORDER_CHARS, appendChild, applyProps, computeLayout, createInstance, createTextInstance, getYoga, insertBefore, layoutOf, measureText, ownText, paint, refreshMeasure, removeChild };
|