@alchemy.run/sigil 0.0.0-alpha.1 → 0.0.0-alpha.2
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/README.md +299 -299
- package/dist/ansi.d.ts +223 -0
- package/dist/ansi.js +2 -0
- package/dist/{devtools-QpCMm9JH.mjs → devtools-BhYGjb7h.js} +1 -1
- package/dist/index-DDVME65c.d.ts +919 -0
- package/dist/index.d.ts +1657 -0
- package/dist/index.js +4643 -0
- package/dist/sgr-CMfEpjSk.d.ts +91 -0
- package/dist/truncate-CBiyyZzw.js +2156 -0
- package/dist/yoga-5jKhYCJC.js +3465 -0
- package/dist/yoga.d.ts +2 -0
- package/dist/yoga.js +2 -0
- package/package.json +37 -17
- package/src/ansi/chalk.ts +179 -0
- package/src/ansi/cursor.ts +48 -0
- package/src/ansi/east-asian-width.ts +215 -0
- package/src/ansi/escapes.ts +128 -0
- package/src/ansi/index.ts +27 -0
- package/src/ansi/sgr.ts +237 -0
- package/src/ansi/slice.ts +43 -0
- package/src/ansi/string-width.ts +236 -0
- package/src/ansi/strip.ts +33 -0
- package/src/ansi/supports-color.ts +213 -0
- package/src/ansi/tokenize.ts +453 -0
- package/src/ansi/truncate.ts +194 -0
- package/src/ansi/widest-line.ts +12 -0
- package/src/ansi/wrap.ts +766 -0
- package/src/ansi-tokenizer.ts +510 -0
- package/src/auto-bind.ts +41 -0
- package/src/boxes.ts +100 -0
- package/src/code-excerpt.ts +39 -0
- package/src/colorize.ts +60 -0
- package/src/components/AccessibilityContext.ts +5 -0
- package/src/components/AnimationContext.ts +24 -0
- package/src/components/App.tsx +781 -0
- package/src/components/AppContext.ts +111 -0
- package/src/components/BackgroundContext.ts +8 -0
- package/src/components/Box.tsx +116 -0
- package/src/components/CursorContext.ts +19 -0
- package/src/components/ErrorBoundary.tsx +38 -0
- package/src/components/ErrorOverview.tsx +133 -0
- package/src/components/FocusContext.ts +30 -0
- package/src/components/Newline.tsx +15 -0
- package/src/components/Spacer.tsx +10 -0
- package/src/components/Static.tsx +59 -0
- package/src/components/StderrContext.ts +26 -0
- package/src/components/StdinContext.ts +49 -0
- package/src/components/StdoutContext.ts +28 -0
- package/src/components/Text.tsx +144 -0
- package/src/components/Transform.tsx +37 -0
- package/src/cursor-position.ts +103 -0
- package/src/devtools-window-polyfill.ts +73 -0
- package/src/devtools.ts +43 -0
- package/src/dom.ts +292 -0
- package/src/get-max-width.ts +11 -0
- package/src/global.d.ts +36 -0
- package/src/hooks/use-animation.ts +142 -0
- package/src/hooks/use-app.ts +8 -0
- package/src/hooks/use-box-metrics.ts +134 -0
- package/src/hooks/use-cursor.ts +33 -0
- package/src/hooks/use-focus-manager.ts +62 -0
- package/src/hooks/use-focus.ts +83 -0
- package/src/hooks/use-input.ts +267 -0
- package/src/hooks/use-is-screen-reader-enabled.ts +12 -0
- package/src/hooks/use-paste.ts +78 -0
- package/src/hooks/use-stderr.ts +8 -0
- package/src/hooks/use-stdin.ts +10 -0
- package/src/hooks/use-stdout.ts +8 -0
- package/src/hooks/use-window-size.ts +41 -0
- package/src/indent-string.ts +16 -0
- package/src/index.ts +44 -0
- package/src/ink.tsx +1506 -0
- package/src/input-parser.ts +283 -0
- package/src/instances.ts +9 -0
- package/src/is-in-ci.ts +7 -0
- package/src/kitty-keyboard.ts +57 -0
- package/src/log-update.ts +370 -0
- package/src/measure-element.ts +62 -0
- package/src/measure-text.ts +31 -0
- package/src/output.ts +308 -0
- package/src/parse-keypress.ts +516 -0
- package/src/parse-stack-line.ts +139 -0
- package/src/patch-console.ts +62 -0
- package/src/quick-lru.ts +85 -0
- package/src/reconciler.ts +451 -0
- package/src/render-background.ts +38 -0
- package/src/render-border.ts +134 -0
- package/src/render-node-to-output.ts +191 -0
- package/src/render-to-string.ts +131 -0
- package/src/render.ts +276 -0
- package/src/renderer.ts +73 -0
- package/src/sanitize-ansi.ts +33 -0
- package/src/signal-exit.ts +107 -0
- package/src/squash-text-nodes.ts +40 -0
- package/src/stream.ts +30 -0
- package/src/styles.ts +748 -0
- package/src/terminal-size.ts +57 -0
- package/src/throttle.ts +73 -0
- package/src/types.ts +15 -0
- package/src/utils.ts +40 -0
- package/src/wrap-text.ts +50 -0
- package/src/write-synchronized.ts +9 -0
- package/src/yoga/config.ts +57 -0
- package/src/yoga/core/absoluteLayout.ts +626 -0
- package/src/yoga/core/baseline.ts +66 -0
- package/src/yoga/core/cache.ts +136 -0
- package/src/yoga/core/calculateLayout.ts +2920 -0
- package/src/yoga/core/config.ts +104 -0
- package/src/yoga/core/flexLine.ts +177 -0
- package/src/yoga/core/helpers.ts +293 -0
- package/src/yoga/core/layoutResults.ts +167 -0
- package/src/yoga/core/node.ts +611 -0
- package/src/yoga/core/numeric.ts +44 -0
- package/src/yoga/core/pixelGrid.ts +151 -0
- package/src/yoga/core/style.ts +887 -0
- package/src/yoga/core/types.ts +224 -0
- package/src/yoga/generated/YGEnums.ts +263 -0
- package/src/yoga/index.ts +19 -0
- package/src/yoga/node.ts +1140 -0
- package/dist/index.d.mts +0 -2379
- package/dist/index.mjs +0 -10072
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Derived from Yoga. See THIRD_PARTY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
// Port of yoga/node/Node.h and yoga/node/Node.cpp, including the
|
|
5
|
+
// LayoutableChildren traversal from yoga/node/LayoutableChildren.h.
|
|
6
|
+
//
|
|
7
|
+
// The persistence/cloning machinery (owners distinct from parents, clone
|
|
8
|
+
// callbacks) is not exposed through the JS binding, so children are always
|
|
9
|
+
// uniquely owned and cloneChildrenIfNeeded is a no-op.
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
Align,
|
|
13
|
+
BoxSizing,
|
|
14
|
+
Dimension,
|
|
15
|
+
Direction,
|
|
16
|
+
Display,
|
|
17
|
+
FlexDirection,
|
|
18
|
+
MeasureMode,
|
|
19
|
+
NodeType,
|
|
20
|
+
PositionType,
|
|
21
|
+
} from "../generated/YGEnums.ts";
|
|
22
|
+
import { Config, configUpdateInvalidatesLayout, getDefaultConfig } from "./config.ts";
|
|
23
|
+
import {
|
|
24
|
+
PhysicalEdge,
|
|
25
|
+
dimension,
|
|
26
|
+
inlineStartEdge,
|
|
27
|
+
inlineEndEdge,
|
|
28
|
+
isRow,
|
|
29
|
+
resolveCrossDirection,
|
|
30
|
+
resolveDirection,
|
|
31
|
+
} from "./helpers.ts";
|
|
32
|
+
import { LayoutResults } from "./layoutResults.ts";
|
|
33
|
+
import { isDefined, isUndefined, maxOrDefined } from "./numeric.ts";
|
|
34
|
+
import { Style } from "./style.ts";
|
|
35
|
+
import type { Size, StyleSizeLength } from "./types.ts";
|
|
36
|
+
import { StyleSizeLength as SizeLength } from "./types.ts";
|
|
37
|
+
|
|
38
|
+
export type MeasureFunc = (
|
|
39
|
+
width: number,
|
|
40
|
+
widthMode: MeasureMode,
|
|
41
|
+
height: number,
|
|
42
|
+
heightMode: MeasureMode,
|
|
43
|
+
) => Size;
|
|
44
|
+
|
|
45
|
+
export type BaselineFunc = (width: number, height: number) => number;
|
|
46
|
+
|
|
47
|
+
export type DirtiedFunc = () => void;
|
|
48
|
+
|
|
49
|
+
export class Node {
|
|
50
|
+
hasNewLayout_ = true;
|
|
51
|
+
isReferenceBaseline_ = false;
|
|
52
|
+
private isDirty_ = true;
|
|
53
|
+
alwaysFormsContainingBlock = false;
|
|
54
|
+
nodeType: NodeType = NodeType.Default;
|
|
55
|
+
private measureFunc_: MeasureFunc | null = null;
|
|
56
|
+
private measureResult_: Size | null = null;
|
|
57
|
+
private baselineFunc_: BaselineFunc | null = null;
|
|
58
|
+
private dirtiedFunc_: DirtiedFunc | null = null;
|
|
59
|
+
style: Style = new Style();
|
|
60
|
+
layout: LayoutResults = new LayoutResults();
|
|
61
|
+
lineIndex = 0;
|
|
62
|
+
private contentsChildrenCount_ = 0;
|
|
63
|
+
owner: Node | null = null;
|
|
64
|
+
children: Node[] = [];
|
|
65
|
+
config: Config;
|
|
66
|
+
private processedDimensionWidth_: StyleSizeLength = SizeLength.undefined();
|
|
67
|
+
private processedDimensionHeight_: StyleSizeLength = SizeLength.undefined();
|
|
68
|
+
private dimensionsDirty_ = true;
|
|
69
|
+
|
|
70
|
+
constructor(config: Config = getDefaultConfig()) {
|
|
71
|
+
this.config = config;
|
|
72
|
+
if (config.useWebDefaults()) {
|
|
73
|
+
this.style.setFlexDirection(FlexDirection.Row);
|
|
74
|
+
this.style.setAlignContent(Align.Stretch);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
hasMeasureFunc(): boolean {
|
|
79
|
+
return this.measureFunc_ !== null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
measure(
|
|
83
|
+
availableWidth: number,
|
|
84
|
+
widthMode: MeasureMode,
|
|
85
|
+
availableHeight: number,
|
|
86
|
+
heightMode: MeasureMode,
|
|
87
|
+
): Size {
|
|
88
|
+
const size = this.measureFunc_!(availableWidth, widthMode, availableHeight, heightMode);
|
|
89
|
+
|
|
90
|
+
const width = size.width === undefined || size.width === null ? NaN : size.width;
|
|
91
|
+
const height = size.height === undefined || size.height === null ? NaN : size.height;
|
|
92
|
+
|
|
93
|
+
const result = (this.measureResult_ ??= { width: 0, height: 0 });
|
|
94
|
+
|
|
95
|
+
if (isUndefined(height) || height < 0 || isUndefined(width) || width < 0) {
|
|
96
|
+
result.width = maxOrDefined(0, width);
|
|
97
|
+
result.height = maxOrDefined(0, height);
|
|
98
|
+
} else {
|
|
99
|
+
result.width = width;
|
|
100
|
+
result.height = height;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
hasBaselineFunc(): boolean {
|
|
107
|
+
return this.baselineFunc_ !== null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
baseline(width: number, height: number): number {
|
|
111
|
+
return this.baselineFunc_!(width, height);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getDirtiedFunc(): DirtiedFunc | null {
|
|
115
|
+
return this.dirtiedFunc_;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
dimensionWithMargin(axis: FlexDirection, widthSize: number): number {
|
|
119
|
+
return (
|
|
120
|
+
this.layout.measuredDimension(dimension(axis)) +
|
|
121
|
+
this.style.computeMarginForAxis(axis, widthSize)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
isLayoutDimensionDefined(axis: FlexDirection): boolean {
|
|
126
|
+
const value = this.layout.measuredDimension(dimension(axis));
|
|
127
|
+
return isDefined(value) && value >= 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Whether the node has a "definite length" along the given axis.
|
|
132
|
+
* https://www.w3.org/TR/css-sizing-3/#definite
|
|
133
|
+
*/
|
|
134
|
+
hasDefiniteLength(dim: Dimension, ownerSize: number): boolean {
|
|
135
|
+
const usedValue = this.getProcessedDimension(dim).resolve(ownerSize);
|
|
136
|
+
return isDefined(usedValue) && usedValue >= 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
hasErrata(errata: number): boolean {
|
|
140
|
+
return this.config.hasErrata(errata);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
hasContentsChildren(): boolean {
|
|
144
|
+
return this.contentsChildrenCount_ !== 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
getChildCount(): number {
|
|
148
|
+
return this.children.length;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
getChild(index: number): Node {
|
|
152
|
+
return this.children[index]!;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Children for layout purposes: skips display: contents nodes, splicing
|
|
157
|
+
* their children in place. Returns the raw children array when nothing
|
|
158
|
+
* needs splicing — do not mutate the result.
|
|
159
|
+
*/
|
|
160
|
+
getLayoutChildren(): readonly Node[] {
|
|
161
|
+
if (this.contentsChildrenCount_ === 0) {
|
|
162
|
+
return this.children;
|
|
163
|
+
}
|
|
164
|
+
const result: Node[] = [];
|
|
165
|
+
appendLayoutChildren(this, result);
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
getLayoutChildCount(): number {
|
|
170
|
+
if (this.contentsChildrenCount_ === 0) {
|
|
171
|
+
return this.children.length;
|
|
172
|
+
}
|
|
173
|
+
return this.getLayoutChildren().length;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
isDirty(): boolean {
|
|
177
|
+
return this.isDirty_;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getProcessedDimension(dim: Dimension): StyleSizeLength {
|
|
181
|
+
return dim === Dimension.Width ? this.processedDimensionWidth_ : this.processedDimensionHeight_;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getResolvedDimension(
|
|
185
|
+
direction: Direction,
|
|
186
|
+
dim: Dimension,
|
|
187
|
+
referenceLength: number,
|
|
188
|
+
ownerWidth: number,
|
|
189
|
+
): number {
|
|
190
|
+
const value = this.getProcessedDimension(dim).resolve(referenceLength);
|
|
191
|
+
if (this.style.boxSizing() === BoxSizing.BorderBox) {
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const dimensionPaddingAndBorder = this.style.computePaddingAndBorderForDimension(
|
|
196
|
+
direction,
|
|
197
|
+
dim,
|
|
198
|
+
ownerWidth,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return value + (isDefined(dimensionPaddingAndBorder) ? dimensionPaddingAndBorder : 0);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Setters
|
|
205
|
+
|
|
206
|
+
setMeasureFunc(measureFunc: MeasureFunc | null): void {
|
|
207
|
+
if (measureFunc === null) {
|
|
208
|
+
this.nodeType = NodeType.Default;
|
|
209
|
+
} else {
|
|
210
|
+
if (this.children.length !== 0) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
"Cannot set measure function: Nodes with measure functions cannot have children.",
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
this.nodeType = NodeType.Text;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.measureFunc_ = measureFunc;
|
|
219
|
+
// nodeType selects text rounding behavior, which is a pixel-grid input.
|
|
220
|
+
this.markLayoutWritten();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
setBaselineFunc(baselineFunc: BaselineFunc | null): void {
|
|
224
|
+
this.baselineFunc_ = baselineFunc;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
setCoreDirtiedFunc(dirtiedFunc: DirtiedFunc | null): void {
|
|
228
|
+
this.dirtiedFunc_ = dirtiedFunc;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
insertChild(child: Node, index: number): void {
|
|
232
|
+
if (child.style.display() === Display.Contents) {
|
|
233
|
+
this.contentsChildrenCount_++;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (index === this.children.length) {
|
|
237
|
+
this.children.push(child);
|
|
238
|
+
} else {
|
|
239
|
+
this.children.splice(index, 0, child);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
setConfig(config: Config): void {
|
|
244
|
+
if (config.useWebDefaults() !== this.config.useWebDefaults()) {
|
|
245
|
+
throw new Error("UseWebDefaults may not be changed after constructing a Node");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (configUpdateInvalidatesLayout(this.config, config)) {
|
|
249
|
+
this.markDirtyAndPropagate();
|
|
250
|
+
this.layout.configVersion = 0;
|
|
251
|
+
} else {
|
|
252
|
+
// If the config is functionally the same, then align the configVersion
|
|
253
|
+
// so that we can reuse the layout cache
|
|
254
|
+
this.layout.configVersion = config.getVersion();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.config = config;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
setDirty(isDirty: boolean): void {
|
|
261
|
+
if (isDirty === this.isDirty_) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.isDirty_ = isDirty;
|
|
265
|
+
if (isDirty && this.dirtiedFunc_ !== null) {
|
|
266
|
+
this.dirtiedFunc_();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
setChildren(children: Node[]): void {
|
|
271
|
+
this.children = children.slice();
|
|
272
|
+
|
|
273
|
+
this.contentsChildrenCount_ = 0;
|
|
274
|
+
for (const child of children) {
|
|
275
|
+
if (child.style.display() === Display.Contents) {
|
|
276
|
+
this.contentsChildrenCount_++;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
removeChild(child: Node): boolean {
|
|
282
|
+
const index = this.children.indexOf(child);
|
|
283
|
+
if (index >= 0) {
|
|
284
|
+
if (child.style.display() === Display.Contents) {
|
|
285
|
+
this.contentsChildrenCount_--;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this.children.splice(index, 1);
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
removeChildAtIndex(index: number): void {
|
|
295
|
+
if (this.children[index]!.style.display() === Display.Contents) {
|
|
296
|
+
this.contentsChildrenCount_--;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.children.splice(index, 1);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
clearChildren(): void {
|
|
303
|
+
this.children = [];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Called by the public wrapper when a child's display changes between
|
|
307
|
+
// Contents and something else while attached.
|
|
308
|
+
syncContentsChildrenCount(): void {
|
|
309
|
+
this.contentsChildrenCount_ = 0;
|
|
310
|
+
for (const child of this.children) {
|
|
311
|
+
if (child.style.display() === Display.Contents) {
|
|
312
|
+
this.contentsChildrenCount_++;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
setLayoutDirection(direction: Direction): void {
|
|
318
|
+
this.layout.setDirection(direction);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
setLayoutMargin(margin: number, edge: PhysicalEdge): void {
|
|
322
|
+
this.layout.setMargin(edge, margin);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
setLayoutBorder(border: number, edge: PhysicalEdge): void {
|
|
326
|
+
this.layout.setBorder(edge, border);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
setLayoutPadding(padding: number, edge: PhysicalEdge): void {
|
|
330
|
+
this.layout.setPadding(edge, padding);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
setLayoutLastOwnerDirection(direction: Direction): void {
|
|
334
|
+
this.layout.lastOwnerDirection = direction;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
setLayoutComputedFlexBasis(computedFlexBasis: number): void {
|
|
338
|
+
this.layout.computedFlexBasis = computedFlexBasis;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Marks this node's rounding state (and its ancestors') dirty. Ancestors
|
|
342
|
+
// are marked together with descendants, so an already-set flag means the
|
|
343
|
+
// whole ancestor chain is set.
|
|
344
|
+
markLayoutWritten(): void {
|
|
345
|
+
if (this.layout.roundingDirty) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
this.layout.roundingDirty = true;
|
|
349
|
+
let node = this.owner;
|
|
350
|
+
while (node !== null && !node.layout.roundingDirty) {
|
|
351
|
+
node.layout.roundingDirty = true;
|
|
352
|
+
node = node.owner;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
setLayoutPosition(position: number, edge: PhysicalEdge): void {
|
|
357
|
+
// Only value-changing writes dirty the pixel-grid state — rewriting an
|
|
358
|
+
// identical value leaves every rounding input unchanged. Object.is treats
|
|
359
|
+
// NaN as equal to itself (and only over-marks on -0 vs 0).
|
|
360
|
+
const value = position;
|
|
361
|
+
if (!Object.is(this.layout.position(edge), value)) {
|
|
362
|
+
this.layout.setPosition(edge, value);
|
|
363
|
+
this.markLayoutWritten();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
setLayoutComputedFlexBasisGeneration(computedFlexBasisGeneration: number): void {
|
|
368
|
+
this.layout.computedFlexBasisGeneration = computedFlexBasisGeneration;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
setLayoutMeasuredDimension(measuredDimension: number, dim: Dimension): void {
|
|
372
|
+
this.layout.setMeasuredDimension(dim, measuredDimension);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
setLayoutHadOverflow(hadOverflow: boolean): void {
|
|
376
|
+
this.layout.setHadOverflow(hadOverflow);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
setLayoutDimension(lengthValue: number, dim: Dimension): void {
|
|
380
|
+
const value = lengthValue;
|
|
381
|
+
if (
|
|
382
|
+
!Object.is(this.layout.dimension(dim), value) ||
|
|
383
|
+
!Object.is(this.layout.rawDimension(dim), value)
|
|
384
|
+
) {
|
|
385
|
+
this.layout.setDimension(dim, value);
|
|
386
|
+
this.layout.setRawDimension(dim, value);
|
|
387
|
+
this.markLayoutWritten();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// If both left and right are defined, then use left. Otherwise return +left
|
|
392
|
+
// or -right depending on which is defined. Ignore statically positioned
|
|
393
|
+
// nodes as insets do not apply to them.
|
|
394
|
+
relativePosition(axis: FlexDirection, direction: Direction, axisSize: number): number {
|
|
395
|
+
if (this.style.positionType() === PositionType.Static) {
|
|
396
|
+
return 0;
|
|
397
|
+
}
|
|
398
|
+
if (
|
|
399
|
+
this.style.isInlineStartPositionDefined(axis, direction) &&
|
|
400
|
+
!this.style.isInlineStartPositionAuto(axis, direction)
|
|
401
|
+
) {
|
|
402
|
+
return this.style.computeInlineStartPosition(axis, direction, axisSize);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return -1 * this.style.computeInlineEndPosition(axis, direction, axisSize);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
setPositionFromStyle(direction: Direction, ownerWidth: number, ownerHeight: number): void {
|
|
409
|
+
if (!this.style.hasPositionOrMargin()) {
|
|
410
|
+
this.setLayoutPosition(0, PhysicalEdge.Left);
|
|
411
|
+
this.setLayoutPosition(0, PhysicalEdge.Top);
|
|
412
|
+
this.setLayoutPosition(0, PhysicalEdge.Right);
|
|
413
|
+
this.setLayoutPosition(0, PhysicalEdge.Bottom);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
/* Root nodes should be always layouted as LTR, so we don't return negative
|
|
417
|
+
* values. */
|
|
418
|
+
const directionRespectingRoot = this.owner !== null ? direction : Direction.LTR;
|
|
419
|
+
const mainAxis = resolveDirection(this.style.flexDirection(), directionRespectingRoot);
|
|
420
|
+
const crossAxis = resolveCrossDirection(mainAxis, directionRespectingRoot);
|
|
421
|
+
|
|
422
|
+
// In the case of position static these are just 0. See:
|
|
423
|
+
// https://www.w3.org/TR/css-position-3/#valdef-position-static
|
|
424
|
+
const relativePositionMain = this.relativePosition(
|
|
425
|
+
mainAxis,
|
|
426
|
+
directionRespectingRoot,
|
|
427
|
+
isRow(mainAxis) ? ownerWidth : ownerHeight,
|
|
428
|
+
);
|
|
429
|
+
const relativePositionCross = this.relativePosition(
|
|
430
|
+
crossAxis,
|
|
431
|
+
directionRespectingRoot,
|
|
432
|
+
isRow(mainAxis) ? ownerHeight : ownerWidth,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
const mainAxisLeadingEdge = inlineStartEdge(mainAxis, direction);
|
|
436
|
+
const mainAxisTrailingEdge = inlineEndEdge(mainAxis, direction);
|
|
437
|
+
const crossAxisLeadingEdge = inlineStartEdge(crossAxis, direction);
|
|
438
|
+
const crossAxisTrailingEdge = inlineEndEdge(crossAxis, direction);
|
|
439
|
+
|
|
440
|
+
this.setLayoutPosition(
|
|
441
|
+
this.style.computeInlineStartMargin(mainAxis, direction, ownerWidth) + relativePositionMain,
|
|
442
|
+
mainAxisLeadingEdge,
|
|
443
|
+
);
|
|
444
|
+
this.setLayoutPosition(
|
|
445
|
+
this.style.computeInlineEndMargin(mainAxis, direction, ownerWidth) + relativePositionMain,
|
|
446
|
+
mainAxisTrailingEdge,
|
|
447
|
+
);
|
|
448
|
+
this.setLayoutPosition(
|
|
449
|
+
this.style.computeInlineStartMargin(crossAxis, direction, ownerWidth) + relativePositionCross,
|
|
450
|
+
crossAxisLeadingEdge,
|
|
451
|
+
);
|
|
452
|
+
this.setLayoutPosition(
|
|
453
|
+
this.style.computeInlineEndMargin(crossAxis, direction, ownerWidth) + relativePositionCross,
|
|
454
|
+
crossAxisTrailingEdge,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
processFlexBasis(): StyleSizeLength {
|
|
459
|
+
const flexBasis = this.style.flexBasis();
|
|
460
|
+
if (!flexBasis.isAuto() && !flexBasis.isUndefined()) {
|
|
461
|
+
return flexBasis;
|
|
462
|
+
}
|
|
463
|
+
if (isDefined(this.style.flex()) && this.style.flex() > 0) {
|
|
464
|
+
return this.config.useWebDefaults() ? SizeLength.ofAuto() : SizeLength.points(0);
|
|
465
|
+
}
|
|
466
|
+
return SizeLength.ofAuto();
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
resolveFlexBasis(
|
|
470
|
+
direction: Direction,
|
|
471
|
+
flexDirection: FlexDirection,
|
|
472
|
+
referenceLength: number,
|
|
473
|
+
ownerWidth: number,
|
|
474
|
+
): number {
|
|
475
|
+
const value = this.processFlexBasis().resolve(referenceLength);
|
|
476
|
+
if (this.style.boxSizing() === BoxSizing.BorderBox) {
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const dim = dimension(flexDirection);
|
|
481
|
+
const dimensionPaddingAndBorder = this.style.computePaddingAndBorderForDimension(
|
|
482
|
+
direction,
|
|
483
|
+
dim,
|
|
484
|
+
ownerWidth,
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
return value + (isDefined(dimensionPaddingAndBorder) ? dimensionPaddingAndBorder : 0);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
processDimensions(): void {
|
|
491
|
+
if (!this.dimensionsDirty_) {
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
for (let dim = Dimension.Width; dim <= Dimension.Height; dim++) {
|
|
495
|
+
const maxDimension = this.style.maxDimension(dim);
|
|
496
|
+
const processed =
|
|
497
|
+
maxDimension.isDefined() && maxDimension.inexactEquals(this.style.minDimension(dim))
|
|
498
|
+
? maxDimension
|
|
499
|
+
: this.style.dimension(dim);
|
|
500
|
+
if (dim === Dimension.Width) {
|
|
501
|
+
this.processedDimensionWidth_ = processed;
|
|
502
|
+
} else {
|
|
503
|
+
this.processedDimensionHeight_ = processed;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
this.dimensionsDirty_ = false;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
invalidateProcessedDimensions(): void {
|
|
510
|
+
this.dimensionsDirty_ = true;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
resolveDirection(ownerDirection: Direction): Direction {
|
|
514
|
+
if (this.style.direction() === Direction.Inherit) {
|
|
515
|
+
return ownerDirection !== Direction.Inherit ? ownerDirection : Direction.LTR;
|
|
516
|
+
} else {
|
|
517
|
+
return this.style.direction();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
cloneChildrenIfNeeded(): void {
|
|
522
|
+
// No-op: the JS binding does not support shared subtrees, so children are
|
|
523
|
+
// always uniquely owned by their parent.
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
cloneContentsChildrenIfNeeded(): void {
|
|
527
|
+
// No-op: see cloneChildrenIfNeeded.
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
markDirtyAndPropagate(): void {
|
|
531
|
+
if (!this.isDirty_) {
|
|
532
|
+
this.setDirty(true);
|
|
533
|
+
this.setLayoutComputedFlexBasis(NaN);
|
|
534
|
+
if (this.owner !== null) {
|
|
535
|
+
this.owner.markDirtyAndPropagate();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
resolveFlexGrow(): number {
|
|
541
|
+
// Root nodes flexGrow should always be 0
|
|
542
|
+
if (this.owner === null) {
|
|
543
|
+
return 0;
|
|
544
|
+
}
|
|
545
|
+
if (isDefined(this.style.flexGrow())) {
|
|
546
|
+
return this.style.flexGrow();
|
|
547
|
+
}
|
|
548
|
+
if (isDefined(this.style.flex()) && this.style.flex() > 0) {
|
|
549
|
+
return this.style.flex();
|
|
550
|
+
}
|
|
551
|
+
return Style.DefaultFlexGrow;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
resolveFlexShrink(): number {
|
|
555
|
+
if (this.owner === null) {
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
if (isDefined(this.style.flexShrink())) {
|
|
559
|
+
return this.style.flexShrink();
|
|
560
|
+
}
|
|
561
|
+
if (!this.config.useWebDefaults() && isDefined(this.style.flex()) && this.style.flex() < 0) {
|
|
562
|
+
return -this.style.flex();
|
|
563
|
+
}
|
|
564
|
+
return this.config.useWebDefaults() ? Style.WebDefaultFlexShrink : Style.DefaultFlexShrink;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
isNodeFlexible(): boolean {
|
|
568
|
+
return (
|
|
569
|
+
this.style.positionType() !== PositionType.Absolute &&
|
|
570
|
+
(this.resolveFlexGrow() !== 0 || this.resolveFlexShrink() !== 0)
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
reset(): void {
|
|
575
|
+
if (this.children.length !== 0) {
|
|
576
|
+
throw new Error("Cannot reset a node which still has children attached");
|
|
577
|
+
}
|
|
578
|
+
if (this.owner !== null) {
|
|
579
|
+
throw new Error("Cannot reset a node still attached to a owner");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const fresh = new Node(this.config);
|
|
583
|
+
this.hasNewLayout_ = fresh.hasNewLayout_;
|
|
584
|
+
this.isReferenceBaseline_ = fresh.isReferenceBaseline_;
|
|
585
|
+
this.isDirty_ = true;
|
|
586
|
+
this.alwaysFormsContainingBlock = fresh.alwaysFormsContainingBlock;
|
|
587
|
+
this.nodeType = fresh.nodeType;
|
|
588
|
+
this.measureFunc_ = null;
|
|
589
|
+
this.measureResult_ = null;
|
|
590
|
+
this.baselineFunc_ = null;
|
|
591
|
+
this.dirtiedFunc_ = null;
|
|
592
|
+
this.style = fresh.style;
|
|
593
|
+
this.layout = fresh.layout;
|
|
594
|
+
this.lineIndex = 0;
|
|
595
|
+
this.contentsChildrenCount_ = 0;
|
|
596
|
+
this.children = [];
|
|
597
|
+
this.processedDimensionWidth_ = SizeLength.undefined();
|
|
598
|
+
this.processedDimensionHeight_ = SizeLength.undefined();
|
|
599
|
+
this.dimensionsDirty_ = true;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function appendLayoutChildren(node: Node, out: Node[]): void {
|
|
604
|
+
for (const child of node.children) {
|
|
605
|
+
if (child.style.display() === Display.Contents) {
|
|
606
|
+
appendLayoutChildren(child, out);
|
|
607
|
+
} else {
|
|
608
|
+
out.push(child);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Derived from Yoga. See THIRD_PARTY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
// Port of yoga/numeric/Comparison.h and yoga/numeric/FloatOptional.h.
|
|
5
|
+
//
|
|
6
|
+
// C++ FloatOptional wraps a float where NaN means "undefined". In this port an
|
|
7
|
+
// optional float is just a `number` with NaN as the undefined sentinel, and
|
|
8
|
+
// these helpers reproduce the C++ comparison semantics while calculations
|
|
9
|
+
// themselves use JavaScript's native double-precision numbers.
|
|
10
|
+
|
|
11
|
+
export function isUndefined(value: number): boolean {
|
|
12
|
+
return Number.isNaN(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isDefined(value: number): boolean {
|
|
16
|
+
return !Number.isNaN(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function maxOrDefined(a: number, b: number): number {
|
|
20
|
+
if (isDefined(a) && isDefined(b)) {
|
|
21
|
+
return Math.max(a, b);
|
|
22
|
+
}
|
|
23
|
+
return isUndefined(a) ? b : a;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function minOrDefined(a: number, b: number): number {
|
|
27
|
+
if (isDefined(a) && isDefined(b)) {
|
|
28
|
+
return Math.min(a, b);
|
|
29
|
+
}
|
|
30
|
+
return isUndefined(a) ? b : a;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Custom equality using a hardcoded epsilon of 0.0001, or true if both are NaN.
|
|
34
|
+
export function inexactEquals(a: number, b: number): boolean {
|
|
35
|
+
if (isDefined(a) && isDefined(b)) {
|
|
36
|
+
return Math.abs(a - b) < 0.0001;
|
|
37
|
+
}
|
|
38
|
+
return isUndefined(a) && isUndefined(b);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// FloatOptional::operator== — exact equality, or both undefined.
|
|
42
|
+
export function optionalEquals(a: number, b: number): boolean {
|
|
43
|
+
return a === b || (isUndefined(a) && isUndefined(b));
|
|
44
|
+
}
|