@silvery/examples 0.17.3 → 0.17.4

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.
Files changed (112) hide show
  1. package/dist/UPNG-Cy7ViL8f.mjs +5074 -0
  2. package/dist/__vite-browser-external-2447137e-BML7CYau.mjs +4 -0
  3. package/dist/_banner-DLPxCqVy.mjs +44 -0
  4. package/dist/ansi-CCE2pVS0.mjs +16397 -0
  5. package/dist/apng-HhhBjRGt.mjs +68 -0
  6. package/dist/apng-mwUQbTTF.mjs +3 -0
  7. package/dist/apps/aichat/index.mjs +1299 -0
  8. package/dist/apps/app-todo.mjs +139 -0
  9. package/dist/apps/async-data.mjs +204 -0
  10. package/dist/apps/cli-wizard.mjs +339 -0
  11. package/dist/apps/clipboard.mjs +198 -0
  12. package/dist/apps/components.mjs +864 -0
  13. package/dist/apps/data-explorer.mjs +483 -0
  14. package/dist/apps/dev-tools.mjs +397 -0
  15. package/dist/apps/explorer.mjs +698 -0
  16. package/dist/apps/gallery.mjs +766 -0
  17. package/dist/apps/inline-bench.mjs +115 -0
  18. package/dist/apps/kanban.mjs +280 -0
  19. package/dist/apps/layout-ref.mjs +187 -0
  20. package/dist/apps/outline.mjs +203 -0
  21. package/dist/apps/paste-demo.mjs +189 -0
  22. package/dist/apps/scroll.mjs +86 -0
  23. package/dist/apps/search-filter.mjs +287 -0
  24. package/dist/apps/selection.mjs +355 -0
  25. package/dist/apps/spatial-focus-demo.mjs +388 -0
  26. package/dist/apps/task-list.mjs +258 -0
  27. package/dist/apps/terminal-caps-demo.mjs +315 -0
  28. package/dist/apps/terminal.mjs +872 -0
  29. package/dist/apps/text-selection-demo.mjs +254 -0
  30. package/dist/apps/textarea.mjs +178 -0
  31. package/dist/apps/theme.mjs +661 -0
  32. package/dist/apps/transform.mjs +215 -0
  33. package/dist/apps/virtual-10k.mjs +422 -0
  34. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  35. package/dist/backends-Bahh9mKN.mjs +1179 -0
  36. package/dist/backends-CCtCDQ94.mjs +3 -0
  37. package/dist/{cli.mjs → bin/cli.mjs} +15 -19
  38. package/dist/chunk-BSw8zbkd.mjs +37 -0
  39. package/dist/components/counter.mjs +48 -0
  40. package/dist/components/hello.mjs +31 -0
  41. package/dist/components/progress-bar.mjs +59 -0
  42. package/dist/components/select-list.mjs +85 -0
  43. package/dist/components/spinner.mjs +57 -0
  44. package/dist/components/text-input.mjs +62 -0
  45. package/dist/components/virtual-list.mjs +51 -0
  46. package/dist/flexily-zero-adapter-UB-ra8fR.mjs +3374 -0
  47. package/dist/gif-BZaqPPVX.mjs +3 -0
  48. package/dist/gif-BtnXuxLF.mjs +71 -0
  49. package/dist/gifenc-CLRW41dk.mjs +728 -0
  50. package/dist/jsx-runtime-dMs_8fNu.mjs +241 -0
  51. package/dist/key-mapping-5oYQdAQE.mjs +3 -0
  52. package/dist/key-mapping-D4LR1go6.mjs +130 -0
  53. package/dist/layout/dashboard.mjs +1204 -0
  54. package/dist/layout/live-resize.mjs +303 -0
  55. package/dist/layout/overflow.mjs +70 -0
  56. package/dist/layout/text-layout.mjs +335 -0
  57. package/dist/node-NuJ94BWl.mjs +1083 -0
  58. package/dist/plugins-D1KtkT4a.mjs +3057 -0
  59. package/dist/resvg-js-C_8Wps1F.mjs +201 -0
  60. package/dist/src-BTEVGpd9.mjs +23538 -0
  61. package/dist/src-CUUOuRH6.mjs +5322 -0
  62. package/dist/src-CzfRafCQ.mjs +814 -0
  63. package/dist/usingCtx-CsEf0xO3.mjs +57 -0
  64. package/dist/yoga-adapter-BVtQ5OJR.mjs +237 -0
  65. package/package.json +18 -13
  66. package/_banner.tsx +0 -60
  67. package/apps/aichat/components.tsx +0 -469
  68. package/apps/aichat/index.tsx +0 -220
  69. package/apps/aichat/script.ts +0 -460
  70. package/apps/aichat/state.ts +0 -325
  71. package/apps/aichat/types.ts +0 -19
  72. package/apps/app-todo.tsx +0 -201
  73. package/apps/async-data.tsx +0 -196
  74. package/apps/cli-wizard.tsx +0 -332
  75. package/apps/clipboard.tsx +0 -183
  76. package/apps/components.tsx +0 -658
  77. package/apps/data-explorer.tsx +0 -490
  78. package/apps/dev-tools.tsx +0 -395
  79. package/apps/explorer.tsx +0 -731
  80. package/apps/gallery.tsx +0 -653
  81. package/apps/inline-bench.tsx +0 -138
  82. package/apps/kanban.tsx +0 -265
  83. package/apps/layout-ref.tsx +0 -173
  84. package/apps/outline.tsx +0 -160
  85. package/apps/panes/index.tsx +0 -203
  86. package/apps/paste-demo.tsx +0 -185
  87. package/apps/scroll.tsx +0 -80
  88. package/apps/search-filter.tsx +0 -240
  89. package/apps/selection.tsx +0 -346
  90. package/apps/spatial-focus-demo.tsx +0 -372
  91. package/apps/task-list.tsx +0 -271
  92. package/apps/terminal-caps-demo.tsx +0 -317
  93. package/apps/terminal.tsx +0 -784
  94. package/apps/text-selection-demo.tsx +0 -193
  95. package/apps/textarea.tsx +0 -155
  96. package/apps/theme.tsx +0 -515
  97. package/apps/transform.tsx +0 -229
  98. package/apps/virtual-10k.tsx +0 -405
  99. package/apps/vterm-demo/index.tsx +0 -216
  100. package/components/counter.tsx +0 -49
  101. package/components/hello.tsx +0 -38
  102. package/components/progress-bar.tsx +0 -52
  103. package/components/select-list.tsx +0 -54
  104. package/components/spinner.tsx +0 -44
  105. package/components/text-input.tsx +0 -61
  106. package/components/virtual-list.tsx +0 -56
  107. package/dist/cli.d.mts +0 -1
  108. package/dist/cli.mjs.map +0 -1
  109. package/layout/dashboard.tsx +0 -953
  110. package/layout/live-resize.tsx +0 -282
  111. package/layout/overflow.tsx +0 -51
  112. package/layout/text-layout.tsx +0 -283
@@ -0,0 +1,3374 @@
1
+ import { o as __toESM } from "./chunk-BSw8zbkd.mjs";
2
+ //#region ../../flexily/src/utils.ts
3
+ /**
4
+ * Flexily Utility Functions
5
+ *
6
+ * Helper functions for edge value manipulation and value resolution.
7
+ */
8
+ /**
9
+ * Shared traversal stack for iterative tree operations.
10
+ * Avoids recursion (prevents stack overflow on deep trees) and avoids
11
+ * allocation during layout passes.
12
+ */
13
+ const traversalStack = [];
14
+ /**
15
+ * Set a value on an edge array (supports all edge types including logical START/END).
16
+ */
17
+ function setEdgeValue(arr, edge, value, unit) {
18
+ const v = {
19
+ value,
20
+ unit
21
+ };
22
+ switch (edge) {
23
+ case 0:
24
+ arr[0] = v;
25
+ break;
26
+ case 1:
27
+ arr[1] = v;
28
+ break;
29
+ case 2:
30
+ arr[2] = v;
31
+ break;
32
+ case 3:
33
+ arr[3] = v;
34
+ break;
35
+ case 6:
36
+ arr[0] = v;
37
+ arr[2] = v;
38
+ break;
39
+ case 7:
40
+ arr[1] = v;
41
+ arr[3] = v;
42
+ break;
43
+ case 8:
44
+ arr[0] = v;
45
+ arr[1] = v;
46
+ arr[2] = v;
47
+ arr[3] = v;
48
+ break;
49
+ case 4:
50
+ arr[4] = v;
51
+ break;
52
+ case 5:
53
+ arr[5] = v;
54
+ break;
55
+ }
56
+ }
57
+ /**
58
+ * Set a border value on an edge array.
59
+ */
60
+ function setEdgeBorder(arr, edge, value) {
61
+ switch (edge) {
62
+ case 0:
63
+ arr[0] = value;
64
+ break;
65
+ case 1:
66
+ arr[1] = value;
67
+ break;
68
+ case 2:
69
+ arr[2] = value;
70
+ break;
71
+ case 3:
72
+ arr[3] = value;
73
+ break;
74
+ case 6:
75
+ arr[0] = value;
76
+ arr[2] = value;
77
+ break;
78
+ case 7:
79
+ arr[1] = value;
80
+ arr[3] = value;
81
+ break;
82
+ case 8:
83
+ arr[0] = value;
84
+ arr[1] = value;
85
+ arr[2] = value;
86
+ arr[3] = value;
87
+ break;
88
+ case 4:
89
+ arr[4] = value;
90
+ break;
91
+ case 5:
92
+ arr[5] = value;
93
+ break;
94
+ }
95
+ }
96
+ /**
97
+ * Get a value from an edge array.
98
+ */
99
+ function getEdgeValue(arr, edge) {
100
+ switch (edge) {
101
+ case 0: return arr[0];
102
+ case 1: return arr[1];
103
+ case 2: return arr[2];
104
+ case 3: return arr[3];
105
+ case 4: return arr[4];
106
+ case 5: return arr[5];
107
+ default: return arr[0];
108
+ }
109
+ }
110
+ /**
111
+ * Get a border value from an edge array.
112
+ */
113
+ function getEdgeBorderValue(arr, edge) {
114
+ switch (edge) {
115
+ case 0: return arr[0];
116
+ case 1: return arr[1];
117
+ case 2: return arr[2];
118
+ case 3: return arr[3];
119
+ case 4: return arr[4];
120
+ case 5: return arr[5];
121
+ default: return arr[0];
122
+ }
123
+ }
124
+ /**
125
+ * Resolve a value (point or percent) to an absolute number.
126
+ */
127
+ function resolveValue(value, availableSize) {
128
+ switch (value.unit) {
129
+ case 1: return value.value;
130
+ case 2:
131
+ if (Number.isNaN(availableSize)) return 0;
132
+ return availableSize * (value.value / 100);
133
+ default: return 0;
134
+ }
135
+ }
136
+ /**
137
+ * Apply min/max constraints to a size.
138
+ *
139
+ * CSS behavior:
140
+ * - min: Floor constraint. Does NOT affect children's layout — the container expands
141
+ * after shrink-wrap. When size is NaN (auto-sized), min is NOT applied here;
142
+ * the post-shrink-wrap applyMinMax call (Phase 9) handles it.
143
+ * - max: Ceiling constraint. DOES affect children's layout — content wraps/clips
144
+ * within the max. When size is NaN (auto-sized), max constrains the container
145
+ * so children are laid out within the max bound.
146
+ *
147
+ * Percent constraints that can't resolve (available is NaN) are skipped entirely,
148
+ * since resolveValue returns 0 for percent-against-NaN, which would incorrectly
149
+ * clamp sizes to 0.
150
+ */
151
+ function applyMinMax(size, min, max, available) {
152
+ let result = size;
153
+ if (max.unit !== 0) if (max.unit === 2 && Number.isNaN(available)) {} else {
154
+ const maxValue = resolveValue(max, available);
155
+ if (!Number.isNaN(maxValue)) if (Number.isNaN(result)) {
156
+ if (maxValue !== Infinity) result = maxValue;
157
+ } else result = Math.min(result, maxValue);
158
+ }
159
+ if (min.unit !== 0) if (min.unit === 2 && Number.isNaN(available)) {} else {
160
+ const minValue = resolveValue(min, available);
161
+ if (!Number.isNaN(minValue)) {
162
+ if (!Number.isNaN(result)) result = Math.max(result, minValue);
163
+ }
164
+ }
165
+ return result;
166
+ }
167
+ //#endregion
168
+ //#region ../../flexily/src/logger.ts
169
+ let _logger = null;
170
+ async function createFallbackLogger(namespace) {
171
+ try {
172
+ const { default: createDebug } = await import("./src-CzfRafCQ.mjs").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
173
+ const debug = createDebug(namespace);
174
+ return { debug: debug.enabled ? debug : void 0 };
175
+ } catch {
176
+ return { debug: void 0 };
177
+ }
178
+ }
179
+ async function detectLogger(namespace) {
180
+ try {
181
+ const { createLogger } = await import("loggily");
182
+ const logger = createLogger(namespace);
183
+ if (logger.debug) {
184
+ const originalDebug = logger.debug;
185
+ return { debug: (msg, ...args) => {
186
+ let i = 0;
187
+ originalDebug(msg.replace(/%[sdOo]/g, () => {
188
+ const arg = args[i++];
189
+ if (arg === void 0) return "";
190
+ if (arg === null) return "null";
191
+ if (typeof arg === "object") return JSON.stringify(arg);
192
+ return String(arg);
193
+ }));
194
+ } };
195
+ }
196
+ return { debug: void 0 };
197
+ } catch {
198
+ return createFallbackLogger(namespace);
199
+ }
200
+ }
201
+ _logger = await detectLogger("flexily:layout");
202
+ /** Logger instance - use with optional chaining: `log.debug?.('message')` */
203
+ const log = { get debug() {
204
+ return _logger?.debug;
205
+ } };
206
+ //#endregion
207
+ //#region ../../flexily/src/trace.ts
208
+ let _trace = null;
209
+ /** Get the current trace recorder (null when tracing is disabled). */
210
+ function getTrace() {
211
+ return _trace;
212
+ }
213
+ //#endregion
214
+ //#region ../../flexily/src/layout-helpers.ts
215
+ /**
216
+ * Layout Helper Functions
217
+ *
218
+ * Edge resolution helpers for margins, padding, borders.
219
+ * These are pure functions with no state — safe to extract.
220
+ */
221
+ /**
222
+ * Check if flex direction is row-oriented (horizontal main axis).
223
+ */
224
+ function isRowDirection(flexDirection) {
225
+ return flexDirection === 2 || flexDirection === 3;
226
+ }
227
+ /**
228
+ * Check if flex direction is reversed.
229
+ */
230
+ function isReverseDirection(flexDirection) {
231
+ return flexDirection === 3 || flexDirection === 1;
232
+ }
233
+ /**
234
+ * Get the logical edge value (START/END) for a given physical index.
235
+ * Returns undefined if no logical value applies to this physical edge.
236
+ *
237
+ * EDGE_START/EDGE_END always resolve along the inline (horizontal) axis,
238
+ * regardless of flex direction. Direction (LTR/RTL) determines the mapping:
239
+ * - LTR: START->left, END->right
240
+ * - RTL: START->right, END->left
241
+ */
242
+ function getLogicalEdgeValue(arr, physicalIndex, _flexDirection, direction = 1) {
243
+ const isRTL = direction === 2;
244
+ if (physicalIndex === 0) return isRTL ? arr[5] : arr[4];
245
+ else if (physicalIndex === 2) return isRTL ? arr[4] : arr[5];
246
+ }
247
+ /**
248
+ * Resolve logical (START/END) margins/padding to physical values.
249
+ * EDGE_START/EDGE_END always resolve along the inline (horizontal) axis:
250
+ * - LTR: START->left, END->right
251
+ * - RTL: START->right, END->left
252
+ *
253
+ * Physical edges (LEFT/RIGHT/TOP/BOTTOM) are used directly.
254
+ * When both physical and logical are set, logical takes precedence.
255
+ */
256
+ function resolveEdgeValue(arr, physicalIndex, flexDirection, availableSize, direction = 1) {
257
+ const logicalValue = getLogicalEdgeValue(arr, physicalIndex, flexDirection, direction);
258
+ if (logicalValue && logicalValue.unit !== 0) return resolveValue(logicalValue, availableSize);
259
+ return resolveValue(arr[physicalIndex], availableSize);
260
+ }
261
+ /**
262
+ * Check if a logical edge margin is set to auto.
263
+ */
264
+ function isEdgeAuto(arr, physicalIndex, flexDirection, direction = 1) {
265
+ const logicalValue = getLogicalEdgeValue(arr, physicalIndex, flexDirection, direction);
266
+ if (logicalValue && logicalValue.unit !== 0) return logicalValue.unit === 3;
267
+ return arr[physicalIndex].unit === 3;
268
+ }
269
+ /**
270
+ * Resolve logical (START/END) border widths to physical values.
271
+ * Border values are plain numbers (always points), so resolution is simpler
272
+ * than for margin/padding. Uses NaN as the "not set" sentinel for logical slots.
273
+ * When both physical and logical are set, logical takes precedence.
274
+ *
275
+ * EDGE_START/EDGE_END always resolve along the inline (horizontal) axis,
276
+ * regardless of flex direction. Direction (LTR/RTL) determines the mapping:
277
+ * - LTR: START->left, END->right
278
+ * - RTL: START->right, END->left
279
+ */
280
+ /**
281
+ * Resolve logical (START/END) position edges to physical values.
282
+ * Returns the resolved Value for a physical position index, considering
283
+ * logical EDGE_START/EDGE_END. Logical takes precedence over physical.
284
+ *
285
+ * EDGE_START/EDGE_END always resolve along the inline (horizontal) axis:
286
+ * - LTR: START->left, END->right
287
+ * - RTL: START->right, END->left
288
+ */
289
+ function resolvePositionEdge(arr, physicalIndex, direction = 1) {
290
+ const logicalValue = getLogicalEdgeValue(arr, physicalIndex, 0, direction);
291
+ if (logicalValue && logicalValue.unit !== 0) return logicalValue;
292
+ return arr[physicalIndex];
293
+ }
294
+ function resolveEdgeBorderValue(arr, physicalIndex, _flexDirection, direction = 1) {
295
+ const isRTL = direction === 2;
296
+ let logicalSlot;
297
+ if (physicalIndex === 0) logicalSlot = isRTL ? 5 : 4;
298
+ else if (physicalIndex === 2) logicalSlot = isRTL ? 4 : 5;
299
+ if (logicalSlot !== void 0 && !Number.isNaN(arr[logicalSlot])) return arr[logicalSlot];
300
+ return arr[physicalIndex];
301
+ }
302
+ //#endregion
303
+ //#region ../../flexily/src/layout-traversal.ts
304
+ /**
305
+ * Mark subtree as having new layout and clear dirty flags (iterative to avoid stack overflow).
306
+ * This is called after layout completes to reset dirty tracking for all nodes.
307
+ */
308
+ function markSubtreeLayoutSeen(node) {
309
+ traversalStack.length = 0;
310
+ traversalStack.push(node);
311
+ while (traversalStack.length > 0) {
312
+ const current = traversalStack.pop();
313
+ current["_isDirty"] = false;
314
+ current["_hasNewLayout"] = true;
315
+ for (const child of current.children) traversalStack.push(child);
316
+ }
317
+ }
318
+ /**
319
+ * Count total nodes in tree (iterative to avoid stack overflow).
320
+ */
321
+ function countNodes(node) {
322
+ let count = 0;
323
+ traversalStack.length = 0;
324
+ traversalStack.push(node);
325
+ while (traversalStack.length > 0) {
326
+ const current = traversalStack.pop();
327
+ count++;
328
+ for (const child of current.children) traversalStack.push(child);
329
+ }
330
+ return count;
331
+ }
332
+ /**
333
+ * Propagate position delta to all descendants (iterative to avoid stack overflow).
334
+ * Used when parent position changes but layout is cached.
335
+ *
336
+ * Only updates the constraint fingerprint's lastOffset values, NOT layout.top/left.
337
+ * layout.top/left store RELATIVE positions (relative to parent's border box),
338
+ * so they don't change when an ancestor moves — only the absolute offset
339
+ * (tracked via lastOffsetX/Y) changes.
340
+ */
341
+ function propagatePositionDelta(node, deltaX, deltaY) {
342
+ traversalStack.length = 0;
343
+ for (const child of node.children) traversalStack.push(child);
344
+ while (traversalStack.length > 0) {
345
+ const current = traversalStack.pop();
346
+ current.flex.lastOffsetX += deltaX;
347
+ current.flex.lastOffsetY += deltaY;
348
+ for (const child of current.children) traversalStack.push(child);
349
+ }
350
+ }
351
+ //#endregion
352
+ //#region ../../flexily/src/layout-stats.ts
353
+ /**
354
+ * Layout Statistics Counters
355
+ *
356
+ * Mutable counters for debugging and benchmarking.
357
+ * Separated to avoid circular dependencies between layout modules.
358
+ */
359
+ let layoutNodeCalls = 0;
360
+ let measureNodeCalls = 0;
361
+ let layoutSizingCalls = 0;
362
+ let layoutPositioningCalls = 0;
363
+ let layoutCacheHits = 0;
364
+ function resetLayoutStats() {
365
+ layoutNodeCalls = 0;
366
+ measureNodeCalls = 0;
367
+ layoutSizingCalls = 0;
368
+ layoutPositioningCalls = 0;
369
+ layoutCacheHits = 0;
370
+ }
371
+ function incLayoutNodeCalls() {
372
+ layoutNodeCalls++;
373
+ }
374
+ function incMeasureNodeCalls() {
375
+ measureNodeCalls++;
376
+ }
377
+ function incLayoutSizingCalls() {
378
+ layoutSizingCalls++;
379
+ }
380
+ function incLayoutPositioningCalls() {
381
+ layoutPositioningCalls++;
382
+ }
383
+ function incLayoutCacheHits() {
384
+ layoutCacheHits++;
385
+ }
386
+ //#endregion
387
+ //#region ../../flexily/src/layout-measure.ts
388
+ /**
389
+ * Node Measurement (Intrinsic Sizing)
390
+ *
391
+ * measureNode() computes a node's width and height without calculating positions.
392
+ * It's a lightweight alternative to layoutNode() used during Phase 5 for
393
+ * intrinsic sizing of auto-sized container children.
394
+ *
395
+ * IMPORTANT: measureNode() overwrites layout.width/layout.height as a side effect.
396
+ * Callers MUST save/restore these fields around calls to avoid corrupting
397
+ * the fingerprint cache (see "Bug 1: measureNode corruption" in CLAUDE.md).
398
+ */
399
+ /**
400
+ * Measure a node to get its intrinsic size without computing positions.
401
+ * This is a lightweight alternative to layoutNode for sizing-only passes.
402
+ *
403
+ * Sets layout.width and layout.height but NOT layout.left/top.
404
+ *
405
+ * @param node - The node to measure
406
+ * @param availableWidth - Available width (NaN for unconstrained)
407
+ * @param availableHeight - Available height (NaN for unconstrained)
408
+ * @param direction - Layout direction (LTR or RTL)
409
+ */
410
+ function measureNode(node, availableWidth, availableHeight, direction = 1) {
411
+ incMeasureNodeCalls();
412
+ const style = node.style;
413
+ const layout = node.layout;
414
+ if (style.display === 1) {
415
+ layout.width = 0;
416
+ layout.height = 0;
417
+ return;
418
+ }
419
+ const marginLeft = resolveEdgeValue(style.margin, 0, style.flexDirection, availableWidth, direction);
420
+ const marginTop = resolveEdgeValue(style.margin, 1, style.flexDirection, availableWidth, direction);
421
+ const marginRight = resolveEdgeValue(style.margin, 2, style.flexDirection, availableWidth, direction);
422
+ const marginBottom = resolveEdgeValue(style.margin, 3, style.flexDirection, availableWidth, direction);
423
+ const paddingLeft = resolveEdgeValue(style.padding, 0, style.flexDirection, availableWidth, direction);
424
+ const paddingTop = resolveEdgeValue(style.padding, 1, style.flexDirection, availableWidth, direction);
425
+ const paddingRight = resolveEdgeValue(style.padding, 2, style.flexDirection, availableWidth, direction);
426
+ const paddingBottom = resolveEdgeValue(style.padding, 3, style.flexDirection, availableWidth, direction);
427
+ const borderLeft = resolveEdgeBorderValue(style.border, 0, style.flexDirection, direction);
428
+ const borderTop = resolveEdgeBorderValue(style.border, 1, style.flexDirection, direction);
429
+ const borderRight = resolveEdgeBorderValue(style.border, 2, style.flexDirection, direction);
430
+ const borderBottom = resolveEdgeBorderValue(style.border, 3, style.flexDirection, direction);
431
+ let nodeWidth;
432
+ if (style.width.unit === 1) nodeWidth = style.width.value;
433
+ else if (style.width.unit === 2) nodeWidth = resolveValue(style.width, availableWidth);
434
+ else if (Number.isNaN(availableWidth)) nodeWidth = NaN;
435
+ else nodeWidth = availableWidth - marginLeft - marginRight;
436
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
437
+ let nodeHeight;
438
+ if (style.height.unit === 1) nodeHeight = style.height.value;
439
+ else if (style.height.unit === 2) nodeHeight = resolveValue(style.height, availableHeight);
440
+ else if (Number.isNaN(availableHeight)) nodeHeight = NaN;
441
+ else nodeHeight = availableHeight - marginTop - marginBottom;
442
+ const aspectRatio = style.aspectRatio;
443
+ if (!Number.isNaN(aspectRatio) && aspectRatio > 0) {
444
+ const widthIsAuto = Number.isNaN(nodeWidth) || style.width.unit === 3;
445
+ const heightIsAuto = Number.isNaN(nodeHeight) || style.height.unit === 3;
446
+ if (widthIsAuto && !heightIsAuto && !Number.isNaN(nodeHeight)) {
447
+ nodeWidth = nodeHeight * aspectRatio;
448
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
449
+ } else if (heightIsAuto && !widthIsAuto && !Number.isNaN(nodeWidth)) nodeHeight = nodeWidth / aspectRatio;
450
+ }
451
+ nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
452
+ const innerLeft = borderLeft + paddingLeft;
453
+ const innerTop = borderTop + paddingTop;
454
+ const innerRight = borderRight + paddingRight;
455
+ const innerBottom = borderBottom + paddingBottom;
456
+ const minInnerWidth = innerLeft + innerRight;
457
+ const minInnerHeight = innerTop + innerBottom;
458
+ if (!Number.isNaN(nodeWidth) && nodeWidth < minInnerWidth) nodeWidth = minInnerWidth;
459
+ if (!Number.isNaN(nodeHeight) && nodeHeight < minInnerHeight) nodeHeight = minInnerHeight;
460
+ const contentWidth = Number.isNaN(nodeWidth) ? NaN : Math.max(0, nodeWidth - innerLeft - innerRight);
461
+ const contentHeight = Number.isNaN(nodeHeight) ? NaN : Math.max(0, nodeHeight - innerTop - innerBottom);
462
+ if (node.hasMeasureFunc() && node.children.length === 0) {
463
+ const widthIsAuto = style.width.unit === 3 || style.width.unit === 0 || Number.isNaN(nodeWidth);
464
+ const heightIsAuto = style.height.unit === 3 || style.height.unit === 0 || Number.isNaN(nodeHeight);
465
+ const widthMode = widthIsAuto ? 2 : 1;
466
+ const heightMode = heightIsAuto ? 0 : 1;
467
+ const measureWidth = Number.isNaN(contentWidth) ? Infinity : contentWidth;
468
+ const measureHeight = Number.isNaN(contentHeight) ? Infinity : contentHeight;
469
+ const measured = node.cachedMeasure(measureWidth, widthMode, measureHeight, heightMode);
470
+ if (widthIsAuto) nodeWidth = measured.width + innerLeft + innerRight;
471
+ if (heightIsAuto) nodeHeight = measured.height + innerTop + innerBottom;
472
+ layout.width = Math.round(nodeWidth);
473
+ layout.height = Math.round(nodeHeight);
474
+ return;
475
+ }
476
+ if (node.children.length === 0) {
477
+ if (Number.isNaN(nodeWidth)) nodeWidth = innerLeft + innerRight;
478
+ if (Number.isNaN(nodeHeight)) nodeHeight = innerTop + innerBottom;
479
+ layout.width = Math.round(nodeWidth);
480
+ layout.height = Math.round(nodeHeight);
481
+ return;
482
+ }
483
+ let relativeChildCount = 0;
484
+ for (const c of node.children) {
485
+ if (c.style.display === 1) continue;
486
+ if (c.style.positionType !== 2) relativeChildCount++;
487
+ }
488
+ if (relativeChildCount === 0) {
489
+ if (Number.isNaN(nodeWidth)) nodeWidth = minInnerWidth;
490
+ if (Number.isNaN(nodeHeight)) nodeHeight = minInnerHeight;
491
+ layout.width = Math.round(nodeWidth);
492
+ layout.height = Math.round(nodeHeight);
493
+ return;
494
+ }
495
+ const isRow = isRowDirection(style.flexDirection);
496
+ const crossAxisSize = isRow ? contentHeight : contentWidth;
497
+ const mainGap = isRow ? style.gap[0] : style.gap[1];
498
+ let totalMainSize = 0;
499
+ let maxCrossSize = 0;
500
+ let itemCount = 0;
501
+ for (const child of node.children) {
502
+ if (child.style.display === 1) continue;
503
+ if (child.style.positionType === 2) continue;
504
+ const childStyle = child.style;
505
+ const childMarginMain = isRow ? resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction);
506
+ const childMarginCross = isRow ? resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction);
507
+ const childAvailW = isRow ? NaN : crossAxisSize;
508
+ const childAvailH = isRow ? crossAxisSize : NaN;
509
+ let measuredW = 0;
510
+ let measuredH = 0;
511
+ const cached = child.getCachedLayout(childAvailW, childAvailH);
512
+ if (cached) incLayoutCacheHits();
513
+ else {
514
+ const savedW = child.layout.width;
515
+ const savedH = child.layout.height;
516
+ measureNode(child, childAvailW, childAvailH, direction);
517
+ measuredW = child.layout.width;
518
+ measuredH = child.layout.height;
519
+ child.layout.width = savedW;
520
+ child.layout.height = savedH;
521
+ child.setCachedLayout(childAvailW, childAvailH, measuredW, measuredH);
522
+ }
523
+ const childMainSize = cached ? isRow ? cached.width : cached.height : isRow ? measuredW : measuredH;
524
+ const childCrossSize = cached ? isRow ? cached.height : cached.width : isRow ? measuredH : measuredW;
525
+ totalMainSize += childMainSize + childMarginMain;
526
+ maxCrossSize = Math.max(maxCrossSize, childCrossSize + childMarginCross);
527
+ itemCount++;
528
+ }
529
+ if (itemCount > 1) totalMainSize += mainGap * (itemCount - 1);
530
+ if (Number.isNaN(nodeWidth)) nodeWidth = (isRow ? totalMainSize : maxCrossSize) + innerLeft + innerRight;
531
+ if (Number.isNaN(nodeHeight)) nodeHeight = (isRow ? maxCrossSize : totalMainSize) + innerTop + innerBottom;
532
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
533
+ nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
534
+ layout.width = Math.round(nodeWidth);
535
+ layout.height = Math.round(nodeHeight);
536
+ }
537
+ //#endregion
538
+ //#region ../../flexily/src/layout-flex-lines.ts
539
+ /**
540
+ * Flex Line Breaking and Space Distribution
541
+ *
542
+ * Pre-allocated arrays for zero-allocation flex-wrap layout,
543
+ * plus the line-breaking and flex-distribution algorithms.
544
+ *
545
+ * Re-entrancy: A user measureFunc or baselineFunc may synchronously call
546
+ * calculateLayout() on a separate tree. saveLineState/restoreLineState
547
+ * bracket such nested calls to protect the outer pass's scratch arrays.
548
+ */
549
+ /**
550
+ * Maximum number of flex lines supported without dynamic allocation.
551
+ * If a layout exceeds this, arrays grow automatically (rare edge case).
552
+ * 32 lines covers virtually all real-world layouts while using minimal memory.
553
+ */
554
+ let MAX_FLEX_LINES = 32;
555
+ /**
556
+ * Pre-allocated array for line cross sizes (reused across layout passes).
557
+ * Stores the computed cross-axis size of each flex line.
558
+ */
559
+ let _lineCrossSizes = new Float64Array(MAX_FLEX_LINES);
560
+ /**
561
+ * Pre-allocated array for line cross offsets (reused across layout passes).
562
+ * Stores the cross-axis position offset for each flex line.
563
+ */
564
+ let _lineCrossOffsets = new Float64Array(MAX_FLEX_LINES);
565
+ /**
566
+ * Pre-allocated array for line lengths (number of children per line).
567
+ * Uint16 supports up to 65535 children per line (more than sufficient).
568
+ */
569
+ let _lineLengths = new Uint16Array(MAX_FLEX_LINES);
570
+ /**
571
+ * Pre-allocated 2D array for children per line.
572
+ * Avoids O(n*m) iteration when processing multi-line flex layouts.
573
+ * Each slot holds array of Node references for that line.
574
+ */
575
+ let _lineChildren = Array.from({ length: MAX_FLEX_LINES }, () => []);
576
+ /**
577
+ * Pre-allocated array for per-line justify-content start offsets.
578
+ * Stores the main-axis starting position for each flex line.
579
+ */
580
+ let _lineJustifyStarts = new Float64Array(MAX_FLEX_LINES);
581
+ /**
582
+ * Pre-allocated array for per-line item spacing (justify-content gaps).
583
+ * Stores the spacing between items for each flex line.
584
+ */
585
+ let _lineItemSpacings = new Float64Array(MAX_FLEX_LINES);
586
+ /**
587
+ * Grow pre-allocated line arrays if needed.
588
+ * Called when a layout has more lines than current capacity.
589
+ * This is rare (>32 lines) and acceptable as a one-time allocation.
590
+ */
591
+ function growLineArrays(needed) {
592
+ const newSize = Math.max(needed, MAX_FLEX_LINES * 2);
593
+ MAX_FLEX_LINES = newSize;
594
+ _lineCrossSizes = new Float64Array(newSize);
595
+ _lineCrossOffsets = new Float64Array(newSize);
596
+ _lineLengths = new Uint16Array(newSize);
597
+ _lineJustifyStarts = new Float64Array(newSize);
598
+ _lineItemSpacings = new Float64Array(newSize);
599
+ while (_lineChildren.length < newSize) _lineChildren.push([]);
600
+ }
601
+ /** Current re-entrancy depth. 0 = outermost (no save needed). */
602
+ let _layoutDepth = 0;
603
+ /**
604
+ * Enter a layout pass. If re-entrant (depth > 0), saves current line state.
605
+ * @returns The saved state (to pass to restoreLineState), or null at depth 0.
606
+ */
607
+ function enterLayout() {
608
+ if (_layoutDepth++ === 0) return null;
609
+ return {
610
+ crossSizes: _lineCrossSizes.slice(),
611
+ crossOffsets: _lineCrossOffsets.slice(),
612
+ lengths: _lineLengths.slice(),
613
+ justifyStarts: _lineJustifyStarts.slice(),
614
+ itemSpacings: _lineItemSpacings.slice(),
615
+ children: _lineChildren.map((arr) => arr.slice()),
616
+ maxLines: MAX_FLEX_LINES
617
+ };
618
+ }
619
+ /**
620
+ * Exit a layout pass. If re-entrant, restores saved line state.
621
+ * @param saved - The state returned by enterLayout (null at depth 0).
622
+ */
623
+ function exitLayout(saved) {
624
+ _layoutDepth--;
625
+ if (!saved) return;
626
+ MAX_FLEX_LINES = saved.maxLines;
627
+ _lineCrossSizes = saved.crossSizes;
628
+ _lineCrossOffsets = saved.crossOffsets;
629
+ _lineLengths = saved.lengths;
630
+ _lineJustifyStarts = saved.justifyStarts;
631
+ _lineItemSpacings = saved.itemSpacings;
632
+ _lineChildren = saved.children;
633
+ }
634
+ /**
635
+ * Epsilon value for floating point comparisons in flex distribution.
636
+ * Used to determine when remaining space is negligible and iteration should stop.
637
+ */
638
+ const EPSILON_FLOAT = .001;
639
+ /**
640
+ * Break children into flex lines based on available main-axis space.
641
+ * Zero-allocation: Sets child.flex.lineIndex directly, uses pre-allocated _lineStarts/_lineLengths.
642
+ *
643
+ * @param parent - Parent node whose children to wrap
644
+ * @param relativeCount - Number of relative children (those with flex.relativeIndex >= 0)
645
+ * @param mainAxisSize - Available main-axis space (NaN for unconstrained)
646
+ * @param mainGap - Gap between items on main axis
647
+ * @param wrap - Wrap mode (WRAP_NO_WRAP, WRAP_WRAP, WRAP_WRAP_REVERSE)
648
+ * @returns Number of lines created
649
+ */
650
+ function breakIntoLines(parent, relativeCount, mainAxisSize, mainGap, wrap) {
651
+ if (wrap === 0 || Number.isNaN(mainAxisSize) || relativeCount === 0) {
652
+ const lineArr = _lineChildren[0];
653
+ let idx = 0;
654
+ for (const child of parent.children) if (child.flex.relativeIndex >= 0) {
655
+ child.flex.lineIndex = 0;
656
+ lineArr[idx++] = child;
657
+ }
658
+ lineArr.length = idx;
659
+ _lineLengths[0] = relativeCount;
660
+ _lineCrossSizes[0] = 0;
661
+ _lineCrossOffsets[0] = 0;
662
+ return 1;
663
+ }
664
+ let lineIndex = 0;
665
+ let lineMainSize = 0;
666
+ let lineChildCount = 0;
667
+ let lineChildIdx = 0;
668
+ for (const child of parent.children) {
669
+ if (child.flex.relativeIndex < 0) continue;
670
+ const flex = child.flex;
671
+ const childMainSize = Math.max(flex.minMain, Math.min(flex.maxMain, flex.baseSize)) + flex.mainMargin;
672
+ const gapIfNotFirst = lineChildCount > 0 ? mainGap : 0;
673
+ if (lineChildCount > 0 && lineMainSize + gapIfNotFirst + childMainSize > mainAxisSize) {
674
+ _lineChildren[lineIndex].length = lineChildIdx;
675
+ _lineLengths[lineIndex] = lineChildCount;
676
+ lineIndex++;
677
+ if (lineIndex >= MAX_FLEX_LINES) growLineArrays(lineIndex + 16);
678
+ lineChildIdx = 0;
679
+ lineMainSize = childMainSize;
680
+ lineChildCount = 1;
681
+ } else {
682
+ lineMainSize += gapIfNotFirst + childMainSize;
683
+ lineChildCount++;
684
+ }
685
+ flex.lineIndex = lineIndex;
686
+ _lineChildren[lineIndex][lineChildIdx++] = child;
687
+ }
688
+ if (lineChildCount > 0) {
689
+ _lineChildren[lineIndex].length = lineChildIdx;
690
+ _lineLengths[lineIndex] = lineChildCount;
691
+ lineIndex++;
692
+ }
693
+ const numLines = lineIndex;
694
+ for (let i = 0; i < numLines; i++) {
695
+ _lineCrossSizes[i] = 0;
696
+ _lineCrossOffsets[i] = 0;
697
+ }
698
+ if (wrap === 2 && numLines > 1) {
699
+ for (let i = 0; i < Math.floor(numLines / 2); i++) {
700
+ const j = numLines - 1 - i;
701
+ const lineI = _lineChildren[i];
702
+ const lineJ = _lineChildren[j];
703
+ const lenI = lineI.length;
704
+ const lenJ = lineJ.length;
705
+ const maxLen = Math.max(lenI, lenJ);
706
+ for (let k = 0; k < maxLen; k++) {
707
+ const hasI = k < lenI;
708
+ const hasJ = k < lenJ;
709
+ const tmpI = hasI ? lineI[k] : null;
710
+ const tmpJ = hasJ ? lineJ[k] : null;
711
+ if (hasJ) lineI[k] = tmpJ;
712
+ if (hasI) lineJ[k] = tmpI;
713
+ }
714
+ lineI.length = lenJ;
715
+ lineJ.length = lenI;
716
+ }
717
+ for (let i = 0; i < numLines; i++) {
718
+ const lc = _lineChildren[i];
719
+ for (let c = 0; c < lc.length; c++) lc[c].flex.lineIndex = i;
720
+ }
721
+ }
722
+ return numLines;
723
+ }
724
+ /**
725
+ * Distribute flex space for a single line of children.
726
+ * Implements CSS Flexbox section 9.7: Resolving Flexible Lengths.
727
+ *
728
+ * Takes pre-collected children array to avoid O(n*m) iteration pattern.
729
+ * Previously iterated through ALL parent.children 8 times per line.
730
+ *
731
+ * @param lineChildren - Pre-collected children for this line (from _lineChildren)
732
+ * @param initialFreeSpace - Free space to distribute (positive=grow, negative=shrink)
733
+ */
734
+ function distributeFlexSpaceForLine(lineChildren, initialFreeSpace) {
735
+ const isGrowing = initialFreeSpace > 0;
736
+ if (initialFreeSpace === 0) return;
737
+ const childCount = lineChildren.length;
738
+ if (childCount === 0) return;
739
+ if (childCount === 1) {
740
+ const flex = lineChildren[0].flex;
741
+ if (isGrowing ? flex.flexGrow > 0 : flex.flexShrink > 0) {
742
+ const target = flex.baseSize + initialFreeSpace;
743
+ flex.mainSize = Math.max(flex.minMain, Math.min(flex.maxMain, target));
744
+ }
745
+ return;
746
+ }
747
+ let totalBase = 0;
748
+ for (let i = 0; i < childCount; i++) totalBase += lineChildren[i].flex.baseSize;
749
+ const containerInner = initialFreeSpace + totalBase;
750
+ for (let i = 0; i < childCount; i++) lineChildren[i].flex.frozen = false;
751
+ let freeSpace = initialFreeSpace;
752
+ let iterations = 0;
753
+ const maxIterations = childCount + 1;
754
+ while (iterations++ < maxIterations) {
755
+ let totalFlex = 0;
756
+ for (let i = 0; i < childCount; i++) {
757
+ const flex = lineChildren[i].flex;
758
+ if (flex.frozen) continue;
759
+ if (isGrowing) totalFlex += flex.flexGrow;
760
+ else totalFlex += flex.flexShrink * flex.baseSize;
761
+ }
762
+ if (totalFlex === 0) break;
763
+ let effectiveFreeSpace = freeSpace;
764
+ if (isGrowing && totalFlex < 1) effectiveFreeSpace = freeSpace * totalFlex;
765
+ let totalViolation = 0;
766
+ for (let i = 0; i < childCount; i++) {
767
+ const flex = lineChildren[i].flex;
768
+ if (flex.frozen) continue;
769
+ const flexFactor = isGrowing ? flex.flexGrow : flex.flexShrink * flex.baseSize;
770
+ const ratio = totalFlex > 0 ? flexFactor / totalFlex : 0;
771
+ const target = flex.baseSize + effectiveFreeSpace * ratio;
772
+ const clamped = Math.max(flex.minMain, Math.min(flex.maxMain, target));
773
+ totalViolation += clamped - target;
774
+ flex.mainSize = clamped;
775
+ }
776
+ let anyFrozen = false;
777
+ if (Math.abs(totalViolation) < EPSILON_FLOAT) {
778
+ for (let i = 0; i < childCount; i++) lineChildren[i].flex.frozen = true;
779
+ break;
780
+ } else if (totalViolation > 0) for (let i = 0; i < childCount; i++) {
781
+ const flex = lineChildren[i].flex;
782
+ if (flex.frozen) continue;
783
+ const target = flex.baseSize + (isGrowing ? flex.flexGrow : flex.flexShrink * flex.baseSize) / totalFlex * effectiveFreeSpace;
784
+ if (flex.mainSize > target + EPSILON_FLOAT) {
785
+ flex.frozen = true;
786
+ anyFrozen = true;
787
+ }
788
+ }
789
+ else for (let i = 0; i < childCount; i++) {
790
+ const flex = lineChildren[i].flex;
791
+ if (flex.frozen) continue;
792
+ const flexFactor = isGrowing ? flex.flexGrow : flex.flexShrink * flex.baseSize;
793
+ const target = flex.baseSize + flexFactor / totalFlex * effectiveFreeSpace;
794
+ if (flex.mainSize < target - EPSILON_FLOAT) {
795
+ flex.frozen = true;
796
+ anyFrozen = true;
797
+ }
798
+ }
799
+ if (!anyFrozen) break;
800
+ let frozenSpace = 0;
801
+ let unfrozenBase = 0;
802
+ for (let i = 0; i < childCount; i++) {
803
+ const flex = lineChildren[i].flex;
804
+ if (flex.frozen) frozenSpace += flex.mainSize;
805
+ else unfrozenBase += flex.baseSize;
806
+ }
807
+ freeSpace = containerInner - frozenSpace - unfrozenBase;
808
+ }
809
+ }
810
+ //#endregion
811
+ //#region ../../flexily/src/layout-zero.ts
812
+ /**
813
+ * Flexily Layout Algorithm — Main Entry Point
814
+ *
815
+ * Core flexbox layout computation. This file contains:
816
+ * - computeLayout(): top-level entry point
817
+ * - layoutNode(): recursive layout algorithm (11 phases)
818
+ *
819
+ * Helper modules (split for maintainability, zero-allocation preserved):
820
+ * - layout-helpers.ts: Edge resolution (margins, padding, borders)
821
+ * - layout-traversal.ts: Tree traversal (markSubtreeLayoutSeen, countNodes)
822
+ * - layout-flex-lines.ts: Pre-allocated arrays, line breaking, flex distribution
823
+ * - layout-measure.ts: Intrinsic sizing (measureNode)
824
+ * - layout-stats.ts: Debug/benchmark counters
825
+ *
826
+ * Based on Planning-nl/flexbox.js reference implementation.
827
+ */
828
+ /**
829
+ * Compute layout for a node tree.
830
+ */
831
+ function computeLayout(root, availableWidth, availableHeight, direction = 1) {
832
+ const saved = enterLayout();
833
+ try {
834
+ resetLayoutStats();
835
+ getTrace()?.resetCounter();
836
+ root.resetLayoutCache();
837
+ layoutNode(root, availableWidth, availableHeight, 0, 0, 0, 0, direction);
838
+ } finally {
839
+ exitLayout(saved);
840
+ }
841
+ }
842
+ /**
843
+ * Layout a node and its children.
844
+ *
845
+ * @param absX - Absolute X position from document root (for Yoga-compatible edge rounding)
846
+ * @param absY - Absolute Y position from document root (for Yoga-compatible edge rounding)
847
+ */
848
+ function layoutNode(node, availableWidth, availableHeight, offsetX, offsetY, absX, absY, direction = 1) {
849
+ incLayoutNodeCalls();
850
+ if (offsetX === 0 && offsetY === 0 && absX === 0 && absY === 0 && node.children.length > 0) incLayoutSizingCalls();
851
+ else incLayoutPositioningCalls();
852
+ log.debug?.("layoutNode called: availW=%d, availH=%d, offsetX=%d, offsetY=%d, absX=%d, absY=%d, children=%d", availableWidth, availableHeight, offsetX, offsetY, absX, absY, node.children.length);
853
+ const _t = getTrace();
854
+ const _tn = _t?.nextNode() ?? 0;
855
+ _t?.layoutEnter(_tn, availableWidth, availableHeight, node.isDirty(), node.children.length);
856
+ const style = node.style;
857
+ const layout = node.layout;
858
+ if (style.display === 1) {
859
+ layout.left = 0;
860
+ layout.top = 0;
861
+ layout.width = 0;
862
+ layout.height = 0;
863
+ return;
864
+ }
865
+ const flex = node.flex;
866
+ if (flex.layoutValid && !node.isDirty() && Object.is(flex.lastAvailW, availableWidth) && Object.is(flex.lastAvailH, availableHeight) && flex.lastDir === direction && flex.lastAbsX === absX && flex.lastAbsY === absY) {
867
+ _t?.fingerprintHit(_tn, availableWidth, availableHeight);
868
+ const deltaX = offsetX - flex.lastOffsetX;
869
+ const deltaY = offsetY - flex.lastOffsetY;
870
+ if (deltaX !== 0 || deltaY !== 0) {
871
+ layout.left += deltaX;
872
+ layout.top += deltaY;
873
+ flex.lastOffsetX = offsetX;
874
+ flex.lastOffsetY = offsetY;
875
+ propagatePositionDelta(node, deltaX, deltaY);
876
+ }
877
+ return;
878
+ }
879
+ _t?.fingerprintMiss(_tn, availableWidth, availableHeight, {
880
+ layoutValid: flex.layoutValid,
881
+ isDirty: node.isDirty(),
882
+ sameW: Object.is(flex.lastAvailW, availableWidth),
883
+ sameH: Object.is(flex.lastAvailH, availableHeight),
884
+ sameDir: flex.lastDir === direction,
885
+ sameAbsX: flex.lastAbsX === absX,
886
+ sameAbsY: flex.lastAbsY === absY
887
+ });
888
+ const marginLeft = resolveEdgeValue(style.margin, 0, style.flexDirection, availableWidth, direction);
889
+ const marginTop = resolveEdgeValue(style.margin, 1, style.flexDirection, availableWidth, direction);
890
+ const marginRight = resolveEdgeValue(style.margin, 2, style.flexDirection, availableWidth, direction);
891
+ const marginBottom = resolveEdgeValue(style.margin, 3, style.flexDirection, availableWidth, direction);
892
+ const paddingLeft = resolveEdgeValue(style.padding, 0, style.flexDirection, availableWidth, direction);
893
+ const paddingTop = resolveEdgeValue(style.padding, 1, style.flexDirection, availableWidth, direction);
894
+ const paddingRight = resolveEdgeValue(style.padding, 2, style.flexDirection, availableWidth, direction);
895
+ const paddingBottom = resolveEdgeValue(style.padding, 3, style.flexDirection, availableWidth, direction);
896
+ const borderLeft = resolveEdgeBorderValue(style.border, 0, style.flexDirection, direction);
897
+ const borderTop = resolveEdgeBorderValue(style.border, 1, style.flexDirection, direction);
898
+ const borderRight = resolveEdgeBorderValue(style.border, 2, style.flexDirection, direction);
899
+ const borderBottom = resolveEdgeBorderValue(style.border, 3, style.flexDirection, direction);
900
+ let nodeWidth;
901
+ if (style.width.unit === 1) nodeWidth = style.width.value;
902
+ else if (style.width.unit === 2) nodeWidth = resolveValue(style.width, availableWidth);
903
+ else if (Number.isNaN(availableWidth)) nodeWidth = NaN;
904
+ else nodeWidth = availableWidth - marginLeft - marginRight;
905
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
906
+ let nodeHeight;
907
+ if (style.height.unit === 1) nodeHeight = style.height.value;
908
+ else if (style.height.unit === 2) nodeHeight = resolveValue(style.height, availableHeight);
909
+ else if (Number.isNaN(availableHeight)) nodeHeight = NaN;
910
+ else nodeHeight = availableHeight - marginTop - marginBottom;
911
+ const aspectRatio = style.aspectRatio;
912
+ if (!Number.isNaN(aspectRatio) && aspectRatio > 0) {
913
+ const widthIsAuto = Number.isNaN(nodeWidth) || style.width.unit === 3;
914
+ const heightIsAuto = Number.isNaN(nodeHeight) || style.height.unit === 3;
915
+ if (widthIsAuto && !heightIsAuto && !Number.isNaN(nodeHeight)) {
916
+ nodeWidth = nodeHeight * aspectRatio;
917
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
918
+ } else if (heightIsAuto && !widthIsAuto && !Number.isNaN(nodeWidth)) nodeHeight = nodeWidth / aspectRatio;
919
+ }
920
+ nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
921
+ const innerLeft = borderLeft + paddingLeft;
922
+ const innerTop = borderTop + paddingTop;
923
+ const innerRight = borderRight + paddingRight;
924
+ const innerBottom = borderBottom + paddingBottom;
925
+ const minInnerWidth = innerLeft + innerRight;
926
+ const minInnerHeight = innerTop + innerBottom;
927
+ if (!Number.isNaN(nodeWidth) && nodeWidth < minInnerWidth) nodeWidth = minInnerWidth;
928
+ if (!Number.isNaN(nodeHeight) && nodeHeight < minInnerHeight) nodeHeight = minInnerHeight;
929
+ const contentWidth = Number.isNaN(nodeWidth) ? NaN : Math.max(0, nodeWidth - innerLeft - innerRight);
930
+ const contentHeight = Number.isNaN(nodeHeight) ? NaN : Math.max(0, nodeHeight - innerTop - innerBottom);
931
+ let parentPosOffsetX = 0;
932
+ let parentPosOffsetY = 0;
933
+ if (style.positionType === 1) {
934
+ const leftPos = resolvePositionEdge(style.position, 0, direction);
935
+ const topPos = style.position[1];
936
+ const rightPos = resolvePositionEdge(style.position, 2, direction);
937
+ const bottomPos = style.position[3];
938
+ if (leftPos.unit !== 0) parentPosOffsetX = resolveValue(leftPos, availableWidth);
939
+ else if (rightPos.unit !== 0) parentPosOffsetX = -resolveValue(rightPos, availableWidth);
940
+ if (topPos.unit !== 0) parentPosOffsetY = resolveValue(topPos, availableHeight);
941
+ else if (bottomPos.unit !== 0) parentPosOffsetY = -resolveValue(bottomPos, availableHeight);
942
+ }
943
+ if (node.hasMeasureFunc() && node.children.length === 0) {
944
+ const widthIsAuto = style.width.unit === 3 || style.width.unit === 0 || Number.isNaN(nodeWidth);
945
+ const heightIsAuto = style.height.unit === 3 || style.height.unit === 0 || Number.isNaN(nodeHeight);
946
+ const widthMode = widthIsAuto ? 2 : 1;
947
+ const heightMode = heightIsAuto ? 0 : 1;
948
+ const measureWidth = Number.isNaN(contentWidth) ? Infinity : contentWidth;
949
+ const measureHeight = Number.isNaN(contentHeight) ? Infinity : contentHeight;
950
+ const measured = node.cachedMeasure(measureWidth, widthMode, measureHeight, heightMode);
951
+ if (widthIsAuto) nodeWidth = measured.width + innerLeft + innerRight;
952
+ if (heightIsAuto) nodeHeight = measured.height + innerTop + innerBottom;
953
+ layout.width = Math.round(nodeWidth);
954
+ layout.height = Math.round(nodeHeight);
955
+ layout.left = Math.round(offsetX + marginLeft);
956
+ layout.top = Math.round(offsetY + marginTop);
957
+ return;
958
+ }
959
+ if (node.children.length === 0) {
960
+ if (Number.isNaN(nodeWidth)) nodeWidth = innerLeft + innerRight;
961
+ if (Number.isNaN(nodeHeight)) nodeHeight = innerTop + innerBottom;
962
+ layout.width = Math.round(nodeWidth);
963
+ layout.height = Math.round(nodeHeight);
964
+ layout.left = Math.round(offsetX + marginLeft);
965
+ layout.top = Math.round(offsetY + marginTop);
966
+ return;
967
+ }
968
+ const isRow = isRowDirection(style.flexDirection);
969
+ const isReverse = isReverseDirection(style.flexDirection);
970
+ const effectiveReverse = isRow ? direction === 2 !== isReverse : isReverse;
971
+ const mainAxisSize = isRow ? contentWidth : contentHeight;
972
+ const crossAxisSize = isRow ? contentHeight : contentWidth;
973
+ const mainGap = isRow ? style.gap[0] : style.gap[1];
974
+ let totalBaseMain = 0;
975
+ let relativeCount = 0;
976
+ let totalAutoMargins = 0;
977
+ let hasBaselineAlignment = style.alignItems === 5;
978
+ for (const child of node.children) {
979
+ if (child.style.display === 1 || child.style.positionType === 2) {
980
+ child.flex.relativeIndex = -1;
981
+ continue;
982
+ }
983
+ child.flex.relativeIndex = relativeCount++;
984
+ const childStyle = child.style;
985
+ const cflex = child.flex;
986
+ const mainStartIndex = isRow ? effectiveReverse ? 2 : 0 : isReverse ? 3 : 1;
987
+ const mainEndIndex = isRow ? effectiveReverse ? 0 : 2 : isReverse ? 1 : 3;
988
+ cflex.mainStartMarginAuto = isEdgeAuto(childStyle.margin, mainStartIndex, style.flexDirection, direction);
989
+ cflex.mainEndMarginAuto = isEdgeAuto(childStyle.margin, mainEndIndex, style.flexDirection, direction);
990
+ cflex.marginL = resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction);
991
+ cflex.marginT = resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction);
992
+ cflex.marginR = resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction);
993
+ cflex.marginB = resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction);
994
+ cflex.mainStartMarginValue = cflex.mainStartMarginAuto ? 0 : isRow ? effectiveReverse ? cflex.marginR : cflex.marginL : isReverse ? cflex.marginB : cflex.marginT;
995
+ cflex.mainEndMarginValue = cflex.mainEndMarginAuto ? 0 : isRow ? effectiveReverse ? cflex.marginL : cflex.marginR : isReverse ? cflex.marginT : cflex.marginB;
996
+ cflex.mainMargin = cflex.mainStartMarginValue + cflex.mainEndMarginValue;
997
+ let baseSize = 0;
998
+ if (childStyle.flexBasis.unit === 1) baseSize = childStyle.flexBasis.value;
999
+ else if (childStyle.flexBasis.unit === 2) baseSize = Number.isNaN(mainAxisSize) ? 0 : mainAxisSize * (childStyle.flexBasis.value / 100);
1000
+ else {
1001
+ const sizeVal = isRow ? childStyle.width : childStyle.height;
1002
+ if (sizeVal.unit === 1) baseSize = sizeVal.value;
1003
+ else if (sizeVal.unit === 2) baseSize = Number.isNaN(mainAxisSize) ? 0 : mainAxisSize * (sizeVal.value / 100);
1004
+ else if (child.hasMeasureFunc()) {
1005
+ const availCross = crossAxisSize - (isRow ? cflex.marginT + cflex.marginB : cflex.marginL + cflex.marginR);
1006
+ const wantMaxContent = childStyle.flexGrow > 0;
1007
+ const mW = isRow ? wantMaxContent ? Infinity : Number.isNaN(mainAxisSize) ? Infinity : mainAxisSize : Number.isNaN(availCross) ? Infinity : availCross;
1008
+ const mH = isRow ? Number.isNaN(availCross) ? Infinity : availCross : wantMaxContent ? Infinity : Number.isNaN(mainAxisSize) ? Infinity : mainAxisSize;
1009
+ const mWMode = isRow ? wantMaxContent ? 0 : 2 : Number.isNaN(availCross) ? 0 : 2;
1010
+ const mHMode = isRow ? 0 : wantMaxContent ? 0 : 2;
1011
+ const measured = child.cachedMeasure(mW, mWMode, mH, mHMode);
1012
+ baseSize = isRow ? measured.width : measured.height;
1013
+ } else if (child.children.length > 0) {
1014
+ const sizingW = isRow ? NaN : crossAxisSize;
1015
+ const sizingH = isRow ? crossAxisSize : NaN;
1016
+ const cached = child.getCachedLayout(sizingW, sizingH);
1017
+ if (cached) {
1018
+ incLayoutCacheHits();
1019
+ _t?.cacheHit(_tn, sizingW, sizingH, cached.width, cached.height);
1020
+ baseSize = isRow ? cached.width : cached.height;
1021
+ } else {
1022
+ _t?.cacheMiss(_tn, sizingW, sizingH);
1023
+ const savedW = child.layout.width;
1024
+ const savedH = child.layout.height;
1025
+ measureNode(child, sizingW, sizingH, direction);
1026
+ const measuredW = child.layout.width;
1027
+ const measuredH = child.layout.height;
1028
+ child.layout.width = savedW;
1029
+ child.layout.height = savedH;
1030
+ _t?.measureSaveRestore(_tn, savedW, savedH, measuredW, measuredH);
1031
+ baseSize = isRow ? measuredW : measuredH;
1032
+ child.setCachedLayout(sizingW, sizingH, measuredW, measuredH);
1033
+ }
1034
+ } else {
1035
+ const parentWidth = isRow ? mainAxisSize : crossAxisSize;
1036
+ baseSize = (isRow ? resolveEdgeValue(childStyle.padding, 0, childStyle.flexDirection, parentWidth, direction) + resolveEdgeValue(childStyle.padding, 2, childStyle.flexDirection, parentWidth, direction) : resolveEdgeValue(childStyle.padding, 1, childStyle.flexDirection, parentWidth, direction) + resolveEdgeValue(childStyle.padding, 3, childStyle.flexDirection, parentWidth, direction)) + (isRow ? resolveEdgeBorderValue(childStyle.border, 0, childStyle.flexDirection, direction) + resolveEdgeBorderValue(childStyle.border, 2, childStyle.flexDirection, direction) : resolveEdgeBorderValue(childStyle.border, 1, childStyle.flexDirection, direction) + resolveEdgeBorderValue(childStyle.border, 3, childStyle.flexDirection, direction));
1037
+ }
1038
+ }
1039
+ const minVal = isRow ? childStyle.minWidth : childStyle.minHeight;
1040
+ const maxVal = isRow ? childStyle.maxWidth : childStyle.maxHeight;
1041
+ cflex.minMain = minVal.unit !== 0 ? resolveValue(minVal, mainAxisSize) : 0;
1042
+ cflex.maxMain = maxVal.unit !== 0 ? resolveValue(maxVal, mainAxisSize) : Infinity;
1043
+ cflex.flexGrow = childStyle.flexGrow;
1044
+ let shrink = childStyle.flexShrink;
1045
+ if (childStyle.overflow !== 0) shrink = Math.max(shrink, 1);
1046
+ if (child.hasMeasureFunc() && childStyle.flexGrow > 0) shrink = Math.max(shrink, 1);
1047
+ cflex.flexShrink = shrink;
1048
+ cflex.baseSize = baseSize;
1049
+ cflex.mainSize = baseSize;
1050
+ cflex.frozen = false;
1051
+ totalBaseMain += baseSize + cflex.mainMargin;
1052
+ if (cflex.mainStartMarginAuto) totalAutoMargins++;
1053
+ if (cflex.mainEndMarginAuto) totalAutoMargins++;
1054
+ if (!hasBaselineAlignment && childStyle.alignSelf === 5) hasBaselineAlignment = true;
1055
+ }
1056
+ log.debug?.("layoutNode: node.children=%d, relativeCount=%d", node.children.length, relativeCount);
1057
+ if (relativeCount > 0) {
1058
+ const numLines = breakIntoLines(node, relativeCount, mainAxisSize, mainGap, style.flexWrap);
1059
+ const crossGap = isRow ? style.gap[1] : style.gap[0];
1060
+ for (let lineIdx = 0; lineIdx < numLines; lineIdx++) {
1061
+ const lineChildren = _lineChildren[lineIdx];
1062
+ const lineLength = lineChildren.length;
1063
+ if (lineLength === 0) continue;
1064
+ let lineTotalBaseMain = 0;
1065
+ for (let i = 0; i < lineLength; i++) {
1066
+ const c = lineChildren[i];
1067
+ lineTotalBaseMain += c.flex.baseSize + c.flex.mainMargin;
1068
+ }
1069
+ const lineTotalGaps = lineLength > 1 ? mainGap * (lineLength - 1) : 0;
1070
+ let effectiveMainSize = mainAxisSize;
1071
+ if (Number.isNaN(mainAxisSize)) {
1072
+ const maxMainVal = isRow ? style.maxWidth : style.maxHeight;
1073
+ if (maxMainVal.unit !== 0) {
1074
+ const maxMain = resolveValue(maxMainVal, isRow ? availableWidth : availableHeight);
1075
+ if (!Number.isNaN(maxMain) && lineTotalBaseMain + lineTotalGaps > maxMain) effectiveMainSize = maxMain - (isRow ? innerLeft + innerRight : innerTop + innerBottom);
1076
+ }
1077
+ }
1078
+ if (!Number.isNaN(effectiveMainSize)) distributeFlexSpaceForLine(lineChildren, effectiveMainSize - lineTotalBaseMain - lineTotalGaps);
1079
+ for (let i = 0; i < lineLength; i++) {
1080
+ const f = lineChildren[i].flex;
1081
+ f.mainSize = Math.max(f.minMain, Math.min(f.maxMain, f.mainSize));
1082
+ }
1083
+ }
1084
+ for (let lineIdx = 0; lineIdx < numLines; lineIdx++) {
1085
+ const lineChildren = _lineChildren[lineIdx];
1086
+ const lineLength = lineChildren.length;
1087
+ if (lineLength === 0) {
1088
+ _lineJustifyStarts[lineIdx] = 0;
1089
+ _lineItemSpacings[lineIdx] = mainGap;
1090
+ continue;
1091
+ }
1092
+ let lineUsedMain = 0;
1093
+ let lineAutoMargins = 0;
1094
+ for (let i = 0; i < lineLength; i++) {
1095
+ const c = lineChildren[i];
1096
+ lineUsedMain += c.flex.mainSize + c.flex.mainMargin;
1097
+ if (c.flex.mainStartMarginAuto) lineAutoMargins++;
1098
+ if (c.flex.mainEndMarginAuto) lineAutoMargins++;
1099
+ }
1100
+ const lineGaps = lineLength > 1 ? mainGap * (lineLength - 1) : 0;
1101
+ lineUsedMain += lineGaps;
1102
+ const lineRemainingSpace = Number.isNaN(mainAxisSize) ? 0 : mainAxisSize - lineUsedMain;
1103
+ const lineHasAutoMargins = lineAutoMargins > 0;
1104
+ if (lineHasAutoMargins) {
1105
+ const autoMarginValue = Math.max(0, lineRemainingSpace) / lineAutoMargins;
1106
+ for (let i = 0; i < lineLength; i++) {
1107
+ const child = lineChildren[i];
1108
+ if (child.flex.mainStartMarginAuto) child.flex.mainStartMarginValue = autoMarginValue;
1109
+ if (child.flex.mainEndMarginAuto) child.flex.mainEndMarginValue = autoMarginValue;
1110
+ }
1111
+ }
1112
+ let lineStartOffset = 0;
1113
+ let lineItemSpacing = mainGap;
1114
+ if (!lineHasAutoMargins) switch (style.justifyContent) {
1115
+ case 2:
1116
+ lineStartOffset = lineRemainingSpace;
1117
+ break;
1118
+ case 1:
1119
+ lineStartOffset = lineRemainingSpace / 2;
1120
+ break;
1121
+ case 3:
1122
+ if (lineLength > 1 && lineRemainingSpace > 0) lineItemSpacing = mainGap + lineRemainingSpace / (lineLength - 1);
1123
+ break;
1124
+ case 4:
1125
+ if (lineLength > 0 && lineRemainingSpace > 0) {
1126
+ const extraSpace = lineRemainingSpace / lineLength;
1127
+ lineStartOffset = extraSpace / 2;
1128
+ lineItemSpacing = mainGap + extraSpace;
1129
+ }
1130
+ break;
1131
+ case 5:
1132
+ if (lineLength > 0 && lineRemainingSpace > 0) {
1133
+ const extraSpace = lineRemainingSpace / (lineLength + 1);
1134
+ lineStartOffset = extraSpace;
1135
+ lineItemSpacing = mainGap + extraSpace;
1136
+ }
1137
+ break;
1138
+ }
1139
+ _lineJustifyStarts[lineIdx] = lineStartOffset;
1140
+ _lineItemSpacings[lineIdx] = lineItemSpacing;
1141
+ }
1142
+ const startOffset = _lineJustifyStarts[0];
1143
+ const itemSpacing = _lineItemSpacings[0];
1144
+ let maxBaseline = 0;
1145
+ let baselineZoneHeight = 0;
1146
+ const alignItemsIsBaseline = style.alignItems === 5;
1147
+ if (hasBaselineAlignment && isRow) {
1148
+ let maxChildHeight = 0;
1149
+ for (const child of node.children) {
1150
+ if (child.flex.relativeIndex < 0) continue;
1151
+ const childStyle = child.style;
1152
+ const topMargin = child.flex.marginT;
1153
+ let childWidth;
1154
+ let childHeight;
1155
+ const widthDim = childStyle.width;
1156
+ const heightDim = childStyle.height;
1157
+ if (widthDim.unit === 1) childWidth = widthDim.value;
1158
+ else if (widthDim.unit === 2 && !Number.isNaN(mainAxisSize)) childWidth = mainAxisSize * (widthDim.value / 100);
1159
+ else childWidth = child.flex.mainSize;
1160
+ if (heightDim.unit === 1) childHeight = heightDim.value;
1161
+ else if (heightDim.unit === 2 && !Number.isNaN(crossAxisSize)) childHeight = crossAxisSize * (heightDim.value / 100);
1162
+ else {
1163
+ const cached = child.getCachedLayout(child.flex.mainSize, NaN);
1164
+ if (cached) {
1165
+ incLayoutCacheHits();
1166
+ _t?.cacheHit(_tn, child.flex.mainSize, NaN, cached.width, cached.height);
1167
+ childWidth = cached.width;
1168
+ childHeight = cached.height;
1169
+ } else {
1170
+ _t?.cacheMiss(_tn, child.flex.mainSize, NaN);
1171
+ const savedW = child.layout.width;
1172
+ const savedH = child.layout.height;
1173
+ measureNode(child, child.flex.mainSize, NaN, direction);
1174
+ childWidth = child.layout.width;
1175
+ childHeight = child.layout.height;
1176
+ child.layout.width = savedW;
1177
+ child.layout.height = savedH;
1178
+ _t?.measureSaveRestore(_tn, savedW, savedH, childWidth, childHeight);
1179
+ child.setCachedLayout(child.flex.mainSize, NaN, childWidth, childHeight);
1180
+ }
1181
+ }
1182
+ if (child.baselineFunc !== null) child.flex.baseline = topMargin + child.baselineFunc(childWidth, childHeight);
1183
+ else child.flex.baseline = topMargin + childHeight;
1184
+ maxChildHeight = Math.max(maxChildHeight, topMargin + childHeight + child.flex.marginB);
1185
+ if (alignItemsIsBaseline || childStyle.alignSelf === 5) maxBaseline = Math.max(maxBaseline, child.flex.baseline);
1186
+ }
1187
+ baselineZoneHeight = Math.max(maxBaseline, maxChildHeight);
1188
+ }
1189
+ let cumulativeCrossOffset = 0;
1190
+ const isWrapReverse = style.flexWrap === 2;
1191
+ for (let lineIdx = 0; lineIdx < numLines; lineIdx++) {
1192
+ _lineCrossOffsets[lineIdx] = cumulativeCrossOffset;
1193
+ const lineChildren = _lineChildren[lineIdx];
1194
+ const lineLength = lineChildren.length;
1195
+ let maxLineCross = 0;
1196
+ for (let i = 0; i < lineLength; i++) {
1197
+ const child = lineChildren[i];
1198
+ const childStyle = child.style;
1199
+ const crossDim = isRow ? childStyle.height : childStyle.width;
1200
+ const crossMarginStart = isRow ? child.flex.marginT : child.flex.marginL;
1201
+ const crossMarginEnd = isRow ? child.flex.marginB : child.flex.marginR;
1202
+ let childCross = 0;
1203
+ if (crossDim.unit === 1) childCross = crossDim.value;
1204
+ else if (crossDim.unit === 2 && !Number.isNaN(crossAxisSize)) childCross = crossAxisSize * (crossDim.value / 100);
1205
+ else if (child.hasMeasureFunc()) {
1206
+ const crossMargin = crossMarginStart + crossMarginEnd;
1207
+ const availCross = Number.isNaN(crossAxisSize) ? Infinity : crossAxisSize - crossMargin;
1208
+ const childMainSize = child.flex.mainSize;
1209
+ const mW = isRow ? childMainSize : availCross;
1210
+ const mH = isRow ? availCross : childMainSize;
1211
+ const mWMode = Number.isNaN(mW) ? 0 : 2;
1212
+ const mHMode = Number.isNaN(mH) ? 0 : 2;
1213
+ const measured = child.cachedMeasure(Number.isNaN(mW) ? Infinity : mW, mWMode, Number.isNaN(mH) ? Infinity : mH, mHMode);
1214
+ if (measured) childCross = isRow ? measured.height : measured.width;
1215
+ } else if (child.children.length > 0) {
1216
+ const savedW = child.layout.width;
1217
+ const savedH = child.layout.height;
1218
+ measureNode(child, NaN, NaN, direction);
1219
+ childCross = isRow ? child.layout.height : child.layout.width;
1220
+ child.layout.width = savedW;
1221
+ child.layout.height = savedH;
1222
+ }
1223
+ maxLineCross = Math.max(maxLineCross, childCross + crossMarginStart + crossMarginEnd);
1224
+ }
1225
+ const lineCrossSize = maxLineCross;
1226
+ _lineCrossSizes[lineIdx] = lineCrossSize;
1227
+ cumulativeCrossOffset += lineCrossSize + crossGap;
1228
+ }
1229
+ if (!Number.isNaN(crossAxisSize) && numLines > 0) {
1230
+ const freeSpace = crossAxisSize - (cumulativeCrossOffset - crossGap);
1231
+ switch (style.alignContent) {
1232
+ case 3:
1233
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += freeSpace;
1234
+ break;
1235
+ case 2:
1236
+ {
1237
+ const centerOffset = freeSpace / 2;
1238
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += centerOffset;
1239
+ }
1240
+ break;
1241
+ case 6:
1242
+ if (freeSpace > 0 && numLines > 1) {
1243
+ const gap = freeSpace / (numLines - 1);
1244
+ for (let i = 1; i < numLines; i++) _lineCrossOffsets[i] += gap * i;
1245
+ }
1246
+ break;
1247
+ case 7:
1248
+ if (freeSpace > 0) {
1249
+ const halfGap = freeSpace / (numLines * 2);
1250
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += halfGap + halfGap * 2 * i;
1251
+ } else {
1252
+ const centerOffset = freeSpace / 2;
1253
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += centerOffset;
1254
+ }
1255
+ break;
1256
+ case 8:
1257
+ if (freeSpace > 0 && numLines > 0) {
1258
+ const gap = freeSpace / (numLines + 1);
1259
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += gap * (i + 1);
1260
+ } else if (freeSpace < 0) {
1261
+ const centerOffset = freeSpace / 2;
1262
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += centerOffset;
1263
+ }
1264
+ break;
1265
+ case 4:
1266
+ if (freeSpace > 0 && numLines > 0) {
1267
+ const extraPerLine = freeSpace / numLines;
1268
+ for (let i = 0; i < numLines; i++) {
1269
+ _lineCrossSizes[i] += extraPerLine;
1270
+ if (i > 0) _lineCrossOffsets[i] = _lineCrossOffsets[i - 1] + _lineCrossSizes[i - 1] + crossGap;
1271
+ }
1272
+ }
1273
+ break;
1274
+ }
1275
+ if (isWrapReverse) {
1276
+ let totalLineCrossSize = 0;
1277
+ for (let i = 0; i < numLines; i++) totalLineCrossSize += _lineCrossSizes[i];
1278
+ totalLineCrossSize += crossGap * (numLines - 1);
1279
+ const crossStartOffset = crossAxisSize - totalLineCrossSize;
1280
+ for (let i = 0; i < numLines; i++) _lineCrossOffsets[i] += crossStartOffset;
1281
+ }
1282
+ }
1283
+ let savedLineCrossSizes = null;
1284
+ let savedLineCrossOffsets = null;
1285
+ let savedLineJustifyStarts = null;
1286
+ let savedLineItemSpacings = null;
1287
+ if (numLines > 1) {
1288
+ savedLineCrossSizes = new Float64Array(numLines);
1289
+ savedLineCrossOffsets = new Float64Array(numLines);
1290
+ savedLineJustifyStarts = new Float64Array(numLines);
1291
+ savedLineItemSpacings = new Float64Array(numLines);
1292
+ for (let i = 0; i < numLines; i++) {
1293
+ savedLineCrossSizes[i] = _lineCrossSizes[i];
1294
+ savedLineCrossOffsets[i] = _lineCrossOffsets[i];
1295
+ savedLineJustifyStarts[i] = _lineJustifyStarts[i];
1296
+ savedLineItemSpacings[i] = _lineItemSpacings[i];
1297
+ }
1298
+ }
1299
+ let effectiveMainAxisSize = mainAxisSize;
1300
+ const mainIsAuto = isRow ? style.width.unit !== 1 && style.width.unit !== 2 : style.height.unit !== 1 && style.height.unit !== 2;
1301
+ const totalGaps = relativeCount > 1 ? mainGap * (relativeCount - 1) : 0;
1302
+ if (effectiveReverse && mainIsAuto) {
1303
+ let totalContent = 0;
1304
+ for (const child of node.children) {
1305
+ if (child.flex.relativeIndex < 0) continue;
1306
+ totalContent += child.flex.mainSize + child.flex.mainStartMarginValue + child.flex.mainEndMarginValue;
1307
+ }
1308
+ totalContent += totalGaps;
1309
+ effectiveMainAxisSize = totalContent;
1310
+ }
1311
+ let mainPos = effectiveReverse ? effectiveMainAxisSize - startOffset : startOffset;
1312
+ let currentLineIdx = -1;
1313
+ let relIdx = 0;
1314
+ let lineChildIdx = 0;
1315
+ let currentLineLength = 0;
1316
+ let currentItemSpacing = itemSpacing;
1317
+ log.debug?.("positioning children: isRow=%s, startOffset=%d, relativeCount=%d, effectiveReverse=%s, numLines=%d", isRow, startOffset, relativeCount, effectiveReverse, numLines);
1318
+ for (const child of node.children) {
1319
+ if (child.flex.relativeIndex < 0) continue;
1320
+ const cflex = child.flex;
1321
+ const childStyle = child.style;
1322
+ const childLineIdx = cflex.lineIndex;
1323
+ if (childLineIdx !== currentLineIdx) {
1324
+ currentLineIdx = childLineIdx;
1325
+ lineChildIdx = 0;
1326
+ currentLineLength = _lineChildren[childLineIdx].length;
1327
+ const lineOffset = savedLineJustifyStarts ? savedLineJustifyStarts[childLineIdx] : _lineJustifyStarts[childLineIdx];
1328
+ currentItemSpacing = savedLineItemSpacings ? savedLineItemSpacings[childLineIdx] : _lineItemSpacings[childLineIdx];
1329
+ mainPos = effectiveReverse ? effectiveMainAxisSize - lineOffset : lineOffset;
1330
+ }
1331
+ const lineCrossOffset = savedLineCrossOffsets ? savedLineCrossOffsets[childLineIdx] : childLineIdx < MAX_FLEX_LINES ? _lineCrossOffsets[childLineIdx] : 0;
1332
+ let childMarginLeft;
1333
+ let childMarginTop;
1334
+ let childMarginRight;
1335
+ let childMarginBottom;
1336
+ if (isRow) {
1337
+ childMarginLeft = cflex.mainStartMarginAuto && !effectiveReverse ? cflex.mainStartMarginValue : cflex.mainEndMarginAuto && effectiveReverse ? cflex.mainEndMarginValue : cflex.marginL;
1338
+ childMarginRight = cflex.mainEndMarginAuto && !effectiveReverse ? cflex.mainEndMarginValue : cflex.mainStartMarginAuto && effectiveReverse ? cflex.mainStartMarginValue : cflex.marginR;
1339
+ childMarginTop = cflex.marginT;
1340
+ childMarginBottom = cflex.marginB;
1341
+ } else {
1342
+ childMarginTop = cflex.mainStartMarginAuto && !isReverse ? cflex.mainStartMarginValue : cflex.mainEndMarginAuto && isReverse ? cflex.mainEndMarginValue : cflex.marginT;
1343
+ childMarginBottom = cflex.mainEndMarginAuto && !isReverse ? cflex.mainEndMarginValue : cflex.mainStartMarginAuto && isReverse ? cflex.mainStartMarginValue : cflex.marginB;
1344
+ childMarginLeft = cflex.marginL;
1345
+ childMarginRight = cflex.marginR;
1346
+ }
1347
+ const childMainSize = cflex.mainSize;
1348
+ let alignment = style.alignItems;
1349
+ if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
1350
+ const childCrossDimForAR = isRow ? childStyle.height : childStyle.width;
1351
+ const childCrossIsAutoForAR = childCrossDimForAR.unit === 3 || childCrossDimForAR.unit === 0;
1352
+ if (alignment === 4 && childStyle.alignSelf === 0 && !Number.isNaN(childStyle.aspectRatio) && childStyle.aspectRatio > 0 && childCrossIsAutoForAR) alignment = 1;
1353
+ let childCrossSize;
1354
+ const crossDim = isRow ? childStyle.height : childStyle.width;
1355
+ const crossMargin = isRow ? childMarginTop + childMarginBottom : childMarginLeft + childMarginRight;
1356
+ const parentCrossDim = isRow ? style.height : style.width;
1357
+ const parentHasDefiniteCross = parentCrossDim.unit === 1 || parentCrossDim.unit === 2 || !Number.isNaN(crossAxisSize);
1358
+ if (crossDim.unit === 1) childCrossSize = crossDim.value;
1359
+ else if (crossDim.unit === 2) childCrossSize = resolveValue(crossDim, crossAxisSize);
1360
+ else if (parentHasDefiniteCross && alignment === 4) childCrossSize = (numLines > 1 ? savedLineCrossSizes ? savedLineCrossSizes[childLineIdx] : _lineCrossSizes[childLineIdx] : crossAxisSize) - crossMargin;
1361
+ else childCrossSize = NaN;
1362
+ const crossMinVal = isRow ? childStyle.minHeight : childStyle.minWidth;
1363
+ const crossMaxVal = isRow ? childStyle.maxHeight : childStyle.maxWidth;
1364
+ const crossMin = crossMinVal.unit !== 0 ? resolveValue(crossMinVal, crossAxisSize) : 0;
1365
+ const crossMax = crossMaxVal.unit !== 0 ? resolveValue(crossMaxVal, crossAxisSize) : Infinity;
1366
+ if (Number.isNaN(childCrossSize)) {
1367
+ if (crossMin > 0) childCrossSize = crossMin;
1368
+ } else childCrossSize = Math.max(crossMin, Math.min(crossMax, childCrossSize));
1369
+ const mainDim = isRow ? childStyle.width : childStyle.height;
1370
+ const hasDefiniteFlexBasis = childStyle.flexBasis.unit === 1 || childStyle.flexBasis.unit === 2;
1371
+ const mainIsAutoChild = (mainDim.unit === 3 || mainDim.unit === 0) && !hasDefiniteFlexBasis;
1372
+ const hasFlexGrow = cflex.flexGrow > 0;
1373
+ const effectiveMainSize = childMainSize;
1374
+ let childWidth = isRow ? effectiveMainSize : childCrossSize;
1375
+ let childHeight = isRow ? childCrossSize : effectiveMainSize;
1376
+ const shouldMeasure = child.hasMeasureFunc() && child.children.length === 0 && !hasFlexGrow;
1377
+ if (shouldMeasure) {
1378
+ const widthAuto = childStyle.width.unit === 3 || childStyle.width.unit === 0;
1379
+ const heightAuto = childStyle.height.unit === 3 || childStyle.height.unit === 0;
1380
+ if (widthAuto || heightAuto) {
1381
+ const widthMode = widthAuto ? 2 : 1;
1382
+ const heightMode = heightAuto ? 0 : 1;
1383
+ const rawAvailW = widthAuto ? isRow ? mainAxisSize - mainPos : crossAxisSize - crossMargin : childStyle.width.value;
1384
+ const rawAvailH = heightAuto ? isRow ? crossAxisSize - crossMargin : mainAxisSize - mainPos : childStyle.height.value;
1385
+ const availW = Number.isNaN(rawAvailW) ? Infinity : rawAvailW;
1386
+ const availH = Number.isNaN(rawAvailH) ? Infinity : rawAvailH;
1387
+ const measured = child.cachedMeasure(availW, widthMode, availH, heightMode);
1388
+ if (widthAuto) childWidth = measured.width;
1389
+ if (heightAuto) childHeight = measured.height;
1390
+ }
1391
+ }
1392
+ let childX;
1393
+ let childY;
1394
+ if (effectiveReverse) if (isRow) {
1395
+ childX = mainPos - childMainSize - childMarginRight;
1396
+ childY = lineCrossOffset + childMarginTop;
1397
+ } else {
1398
+ childX = lineCrossOffset + childMarginLeft;
1399
+ childY = mainPos - childMainSize - childMarginTop;
1400
+ }
1401
+ else {
1402
+ childX = isRow ? mainPos + childMarginLeft : lineCrossOffset + childMarginLeft;
1403
+ childY = isRow ? lineCrossOffset + childMarginTop : mainPos + childMarginTop;
1404
+ }
1405
+ const fractionalLeft = innerLeft + childX;
1406
+ const fractionalTop = innerTop + childY;
1407
+ let posOffsetX = 0;
1408
+ let posOffsetY = 0;
1409
+ if (childStyle.positionType === 1) {
1410
+ const relLeftPos = resolvePositionEdge(childStyle.position, 0, direction);
1411
+ const relTopPos = childStyle.position[1];
1412
+ const relRightPos = resolvePositionEdge(childStyle.position, 2, direction);
1413
+ const relBottomPos = childStyle.position[3];
1414
+ if (relLeftPos.unit !== 0) posOffsetX = resolveValue(relLeftPos, contentWidth);
1415
+ else if (relRightPos.unit !== 0) posOffsetX = -resolveValue(relRightPos, contentWidth);
1416
+ if (relTopPos.unit !== 0) posOffsetY = resolveValue(relTopPos, contentHeight);
1417
+ else if (relBottomPos.unit !== 0) posOffsetY = -resolveValue(relBottomPos, contentHeight);
1418
+ }
1419
+ const absChildLeft = absX + marginLeft + parentPosOffsetX + fractionalLeft + posOffsetX;
1420
+ const absChildTop = absY + marginTop + parentPosOffsetY + fractionalTop + posOffsetY;
1421
+ let roundedAbsMainStart;
1422
+ let roundedAbsMainEnd;
1423
+ let edgeBasedMainSize;
1424
+ const useEdgeBasedRounding = childMainSize > 0;
1425
+ const childPaddingL = resolveEdgeValue(childStyle.padding, 0, childStyle.flexDirection, contentWidth, direction);
1426
+ const childPaddingT = resolveEdgeValue(childStyle.padding, 1, childStyle.flexDirection, contentWidth, direction);
1427
+ const childPaddingR = resolveEdgeValue(childStyle.padding, 2, childStyle.flexDirection, contentWidth, direction);
1428
+ const childPaddingB = resolveEdgeValue(childStyle.padding, 3, childStyle.flexDirection, contentWidth, direction);
1429
+ const childBorderL = resolveEdgeBorderValue(childStyle.border, 0, childStyle.flexDirection, direction);
1430
+ const childBorderT = resolveEdgeBorderValue(childStyle.border, 1, childStyle.flexDirection, direction);
1431
+ const childBorderR = resolveEdgeBorderValue(childStyle.border, 2, childStyle.flexDirection, direction);
1432
+ const childBorderB = resolveEdgeBorderValue(childStyle.border, 3, childStyle.flexDirection, direction);
1433
+ const childMinW = childPaddingL + childPaddingR + childBorderL + childBorderR;
1434
+ const childMinH = childPaddingT + childPaddingB + childBorderT + childBorderB;
1435
+ const childMinMain = isRow ? childMinW : childMinH;
1436
+ const constrainedMainSize = Math.max(childMainSize, childMinMain);
1437
+ if (useEdgeBasedRounding) if (isRow) {
1438
+ roundedAbsMainStart = Math.round(absChildLeft);
1439
+ roundedAbsMainEnd = Math.round(absChildLeft + constrainedMainSize);
1440
+ edgeBasedMainSize = roundedAbsMainEnd - roundedAbsMainStart;
1441
+ } else {
1442
+ roundedAbsMainStart = Math.round(absChildTop);
1443
+ roundedAbsMainEnd = Math.round(absChildTop + constrainedMainSize);
1444
+ edgeBasedMainSize = roundedAbsMainEnd - roundedAbsMainStart;
1445
+ }
1446
+ else {
1447
+ roundedAbsMainStart = isRow ? Math.round(absChildLeft) : Math.round(absChildTop);
1448
+ edgeBasedMainSize = childMinMain;
1449
+ }
1450
+ const posRound = shouldMeasure ? Math.floor : Math.round;
1451
+ const childLeft = posRound(fractionalLeft + posOffsetX);
1452
+ const childTop = posRound(fractionalTop + posOffsetY);
1453
+ const crossDimForLayoutCall = isRow ? childStyle.height : childStyle.width;
1454
+ const crossIsAutoForLayoutCall = crossDimForLayoutCall.unit === 3 || crossDimForLayoutCall.unit === 0;
1455
+ const mainIsPercentForLayoutCall = (isRow ? childStyle.width : childStyle.height).unit === 2;
1456
+ const crossIsPercentForLayoutCall = crossDimForLayoutCall.unit === 2;
1457
+ const flexDistChanged = child.flex.mainSize !== child.flex.baseSize;
1458
+ const hasMeasureLeaf = child.hasMeasureFunc() && child.children.length === 0;
1459
+ layoutNode(child, isRow && mainIsAutoChild && !hasFlexGrow && !flexDistChanged && !hasMeasureLeaf ? NaN : !isRow && crossIsAutoForLayoutCall && !parentHasDefiniteCross ? NaN : isRow && mainIsPercentForLayoutCall ? mainAxisSize : !isRow && crossIsPercentForLayoutCall ? crossAxisSize : childWidth, !isRow && mainIsAutoChild && !hasFlexGrow && !flexDistChanged && !hasMeasureLeaf ? NaN : isRow && crossIsAutoForLayoutCall && !parentHasDefiniteCross ? NaN : !isRow && mainIsPercentForLayoutCall ? mainAxisSize : isRow && crossIsPercentForLayoutCall ? crossAxisSize : childHeight, childLeft, childTop, absChildLeft - childMarginLeft, absChildTop - childMarginTop, direction);
1460
+ if (childWidth < childMinW) childWidth = childMinW;
1461
+ if (childHeight < childMinH) childHeight = childMinH;
1462
+ const hasMeasure = child.hasMeasureFunc() && child.children.length === 0;
1463
+ const flexDistributionChangedSize = child.flex.mainSize !== child.flex.baseSize;
1464
+ if (!mainIsAuto && !mainIsAutoChild || hasFlexGrow || hasMeasure || flexDistributionChangedSize) if (isRow) {
1465
+ _t?.parentOverride(_tn, "main", child.layout.width, edgeBasedMainSize);
1466
+ child.layout.width = edgeBasedMainSize;
1467
+ } else {
1468
+ _t?.parentOverride(_tn, "main", child.layout.height, edgeBasedMainSize);
1469
+ child.layout.height = edgeBasedMainSize;
1470
+ }
1471
+ const crossDimForCheck = isRow ? childStyle.height : childStyle.width;
1472
+ const crossIsAuto = crossDimForCheck.unit === 3 || crossDimForCheck.unit === 0;
1473
+ const parentCrossIsAuto = !parentHasDefiniteCross;
1474
+ const hasCrossMinMax = crossMinVal.unit !== 0 || crossMaxVal.unit !== 0;
1475
+ if (!crossIsAuto || !parentCrossIsAuto && alignment === 4 || hasCrossMinMax && !Number.isNaN(childCrossSize)) if (isRow) child.layout.height = Math.round(childHeight);
1476
+ else child.layout.width = Math.round(childWidth);
1477
+ child.layout.left = childLeft;
1478
+ child.layout.top = childTop;
1479
+ childWidth = child.layout.width;
1480
+ childHeight = child.layout.height;
1481
+ const finalCrossSize = isRow ? child.layout.height : child.layout.width;
1482
+ let crossOffset = 0;
1483
+ const crossStartIndex = isRow ? 1 : 0;
1484
+ const crossEndIndex = isRow ? 3 : 2;
1485
+ const hasAutoStartMargin = isEdgeAuto(childStyle.margin, crossStartIndex, style.flexDirection, direction);
1486
+ const hasAutoEndMargin = isEdgeAuto(childStyle.margin, crossEndIndex, style.flexDirection, direction);
1487
+ const availableCrossSpace = (hasBaselineAlignment && isRow && !alignItemsIsBaseline && alignment !== 5 && baselineZoneHeight > 0 ? baselineZoneHeight : crossAxisSize) - finalCrossSize - crossMargin;
1488
+ if (hasAutoStartMargin && hasAutoEndMargin) crossOffset = Math.max(0, availableCrossSpace) / 2;
1489
+ else if (hasAutoStartMargin) crossOffset = Math.max(0, availableCrossSpace);
1490
+ else if (hasAutoEndMargin) crossOffset = 0;
1491
+ else switch (alignment) {
1492
+ case 3:
1493
+ crossOffset = availableCrossSpace;
1494
+ break;
1495
+ case 2:
1496
+ crossOffset = availableCrossSpace / 2;
1497
+ break;
1498
+ case 5:
1499
+ if (isRow && hasBaselineAlignment) crossOffset = maxBaseline - child.flex.baseline;
1500
+ break;
1501
+ }
1502
+ if (crossOffset !== 0) {
1503
+ const crossRound = shouldMeasure ? Math.floor : Math.round;
1504
+ if (isRow) child.layout.top += crossRound(crossOffset);
1505
+ else child.layout.left += crossRound(crossOffset);
1506
+ }
1507
+ const fractionalMainSize = !mainIsAuto && !mainIsAutoChild || hasFlexGrow || hasMeasure || flexDistributionChangedSize ? constrainedMainSize : isRow ? child.layout.width : child.layout.height;
1508
+ const totalMainMargin = cflex.mainStartMarginValue + cflex.mainEndMarginValue;
1509
+ log.debug?.(" child %d: mainPos=%d -> top=%d (fractionalMainSize=%d, totalMainMargin=%d)", relIdx, mainPos, child.layout.top, fractionalMainSize, totalMainMargin);
1510
+ if (effectiveReverse) {
1511
+ mainPos -= fractionalMainSize + totalMainMargin;
1512
+ if (lineChildIdx < currentLineLength - 1) mainPos -= currentItemSpacing;
1513
+ } else {
1514
+ mainPos += fractionalMainSize + totalMainMargin;
1515
+ if (lineChildIdx < currentLineLength - 1) mainPos += currentItemSpacing;
1516
+ }
1517
+ relIdx++;
1518
+ lineChildIdx++;
1519
+ }
1520
+ let actualUsedMain = 0;
1521
+ for (const child of node.children) {
1522
+ if (child.flex.relativeIndex < 0) continue;
1523
+ const childMainSize = isRow ? child.layout.width : child.layout.height;
1524
+ const totalMainMargin = child.flex.mainStartMarginValue + child.flex.mainEndMarginValue;
1525
+ actualUsedMain += childMainSize + totalMainMargin;
1526
+ }
1527
+ actualUsedMain += totalGaps;
1528
+ const hasAR = !Number.isNaN(aspectRatio) && aspectRatio > 0;
1529
+ if (isRow && style.width.unit !== 1 && style.width.unit !== 2 && !hasAR) nodeWidth = actualUsedMain + innerLeft + innerRight;
1530
+ if (!isRow && style.height.unit !== 1 && style.height.unit !== 2 && !hasAR) nodeHeight = actualUsedMain + innerTop + innerBottom;
1531
+ let totalCrossSize = 0;
1532
+ if (numLines > 1) {
1533
+ for (let i = 0; i < numLines; i++) totalCrossSize += savedLineCrossSizes ? savedLineCrossSizes[i] : _lineCrossSizes[i];
1534
+ totalCrossSize += crossGap * (numLines - 1);
1535
+ } else for (const child of node.children) {
1536
+ if (child.flex.relativeIndex < 0) continue;
1537
+ const childCross = isRow ? child.layout.height : child.layout.width;
1538
+ const childMargin = isRow ? resolveEdgeValue(child.style.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(child.style.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(child.style.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(child.style.margin, 2, style.flexDirection, contentWidth, direction);
1539
+ totalCrossSize = Math.max(totalCrossSize, childCross + childMargin);
1540
+ }
1541
+ if (isRow && style.height.unit !== 1 && style.height.unit !== 2 && Number.isNaN(availableHeight) && !hasAR) nodeHeight = totalCrossSize + innerTop + innerBottom;
1542
+ if (!isRow && style.width.unit !== 1 && style.width.unit !== 2 && Number.isNaN(availableWidth) && !hasAR) nodeWidth = totalCrossSize + innerLeft + innerRight;
1543
+ }
1544
+ nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
1545
+ nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
1546
+ if (!Number.isNaN(nodeWidth) && nodeWidth < minInnerWidth) nodeWidth = minInnerWidth;
1547
+ if (!Number.isNaN(nodeHeight) && nodeHeight < minInnerHeight) nodeHeight = minInnerHeight;
1548
+ if (Number.isNaN(crossAxisSize) && relativeCount > 0) {
1549
+ const finalCross = isRow ? nodeHeight - innerTop - innerBottom : nodeWidth - innerLeft - innerRight;
1550
+ if (!Number.isNaN(finalCross) && finalCross > 0) {
1551
+ for (const child of node.children) {
1552
+ if (child.flex.relativeIndex < 0) continue;
1553
+ const cstyle = child.style;
1554
+ let childAlign = style.alignItems;
1555
+ if (cstyle.alignSelf !== 0) childAlign = cstyle.alignSelf;
1556
+ const cCrossDim = isRow ? cstyle.height : cstyle.width;
1557
+ const cCrossIsAuto = cCrossDim.unit === 3 || cCrossDim.unit === 0;
1558
+ if (childAlign === 4 && cstyle.alignSelf === 0 && !Number.isNaN(cstyle.aspectRatio) && cstyle.aspectRatio > 0 && cCrossIsAuto) childAlign = 1;
1559
+ if (childAlign !== 4) continue;
1560
+ if (!cCrossIsAuto) continue;
1561
+ const stretchedCross = finalCross - (isRow ? resolveEdgeValue(cstyle.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(cstyle.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(cstyle.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(cstyle.margin, 2, style.flexDirection, contentWidth, direction));
1562
+ const currentCross = isRow ? child.layout.height : child.layout.width;
1563
+ if (Math.round(stretchedCross) <= currentCross) continue;
1564
+ const savedLeft = child.layout.left;
1565
+ const savedTop = child.layout.top;
1566
+ const cMarginL = resolveEdgeValue(cstyle.margin, 0, style.flexDirection, contentWidth, direction);
1567
+ const cMarginT = resolveEdgeValue(cstyle.margin, 1, style.flexDirection, contentWidth, direction);
1568
+ const cAbsX = absX + innerLeft + savedLeft - cMarginL;
1569
+ const cAbsY = absY + innerTop + savedTop - cMarginT;
1570
+ layoutNode(child, isRow ? child.layout.width : stretchedCross, isRow ? stretchedCross : child.layout.height, savedLeft, savedTop, cAbsX, cAbsY, direction);
1571
+ child.layout.left = savedLeft;
1572
+ child.layout.top = savedTop;
1573
+ if (isRow) child.layout.height = Math.round(stretchedCross);
1574
+ else child.layout.width = Math.round(stretchedCross);
1575
+ }
1576
+ if (Number.isNaN(crossAxisSize) && relativeCount > 0) {
1577
+ const finalCross9c = isRow ? nodeHeight - innerTop - innerBottom : nodeWidth - innerLeft - innerRight;
1578
+ if (!Number.isNaN(finalCross9c) && finalCross9c > 0) for (const child of node.children) {
1579
+ if (child.flex.relativeIndex < 0) continue;
1580
+ const cstyle = child.style;
1581
+ let childAlign = style.alignItems;
1582
+ if (cstyle.alignSelf !== 0) childAlign = cstyle.alignSelf;
1583
+ const cCrossDim = isRow ? cstyle.height : cstyle.width;
1584
+ const cCrossIsAuto = cCrossDim.unit === 3 || cCrossDim.unit === 0;
1585
+ if (childAlign === 4 && cstyle.alignSelf === 0 && !Number.isNaN(cstyle.aspectRatio) && cstyle.aspectRatio > 0 && cCrossIsAuto) childAlign = 1;
1586
+ const crossStartIdx = isRow ? 1 : 0;
1587
+ const crossEndIdx = isRow ? 3 : 2;
1588
+ const hasAutoStart = isEdgeAuto(cstyle.margin, crossStartIdx, style.flexDirection, direction);
1589
+ const hasAutoEnd = isEdgeAuto(cstyle.margin, crossEndIdx, style.flexDirection, direction);
1590
+ if (!(hasAutoStart || hasAutoEnd || childAlign === 2 || childAlign === 3)) continue;
1591
+ const childCrossSize = isRow ? child.layout.height : child.layout.width;
1592
+ const cCrossMargin = isRow ? resolveEdgeValue(cstyle.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(cstyle.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(cstyle.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(cstyle.margin, 2, style.flexDirection, contentWidth, direction);
1593
+ const availSpace = finalCross9c - childCrossSize - cCrossMargin;
1594
+ let crossOffset = 0;
1595
+ if (hasAutoStart && hasAutoEnd) crossOffset = Math.max(0, availSpace) / 2;
1596
+ else if (hasAutoStart) crossOffset = Math.max(0, availSpace);
1597
+ else if (hasAutoEnd) crossOffset = 0;
1598
+ else switch (childAlign) {
1599
+ case 3:
1600
+ crossOffset = availSpace;
1601
+ break;
1602
+ case 2:
1603
+ crossOffset = availSpace / 2;
1604
+ break;
1605
+ }
1606
+ if (isRow) {
1607
+ if (Number.isNaN(child.layout.top)) {
1608
+ const cMarginT = resolveEdgeValue(cstyle.margin, 1, style.flexDirection, contentWidth, direction);
1609
+ child.layout.top = Math.round(cMarginT + crossOffset);
1610
+ } else if (crossOffset !== 0) child.layout.top += Math.round(crossOffset);
1611
+ } else if (Number.isNaN(child.layout.left)) {
1612
+ const cMarginL = resolveEdgeValue(cstyle.margin, 0, style.flexDirection, contentWidth, direction);
1613
+ child.layout.left = Math.round(cMarginL + crossOffset);
1614
+ } else if (crossOffset !== 0) child.layout.left += Math.round(crossOffset);
1615
+ }
1616
+ }
1617
+ }
1618
+ }
1619
+ const absNodeLeft = absX + marginLeft + parentPosOffsetX;
1620
+ const absNodeTop = absY + marginTop + parentPosOffsetY;
1621
+ const absNodeRight = absNodeLeft + nodeWidth;
1622
+ const absNodeBottom = absNodeTop + nodeHeight;
1623
+ const roundedAbsLeft = Math.round(absNodeLeft);
1624
+ const roundedAbsTop = Math.round(absNodeTop);
1625
+ const roundedAbsRight = Math.round(absNodeRight);
1626
+ const roundedAbsBottom = Math.round(absNodeBottom);
1627
+ layout.width = roundedAbsRight - roundedAbsLeft;
1628
+ layout.height = roundedAbsBottom - roundedAbsTop;
1629
+ const roundedAbsParentLeft = Math.round(absX);
1630
+ const roundedAbsParentTop = Math.round(absY);
1631
+ layout.left = roundedAbsLeft - roundedAbsParentLeft;
1632
+ layout.top = roundedAbsTop - roundedAbsParentTop;
1633
+ const absInnerLeft = borderLeft;
1634
+ const absInnerTop = borderTop;
1635
+ const absInnerRight = borderRight;
1636
+ const absInnerBottom = borderBottom;
1637
+ const absPaddingBoxW = nodeWidth - absInnerLeft - absInnerRight;
1638
+ const absPaddingBoxH = nodeHeight - absInnerTop - absInnerBottom;
1639
+ const absContentBoxW = absPaddingBoxW - paddingLeft - paddingRight;
1640
+ const absContentBoxH = absPaddingBoxH - paddingTop - paddingBottom;
1641
+ for (const child of node.children) {
1642
+ if (child.style.display === 1) continue;
1643
+ if (child.style.positionType !== 2) continue;
1644
+ const childStyle = child.style;
1645
+ const childMarginLeft = resolveEdgeValue(childStyle.margin, 0, style.flexDirection, nodeWidth, direction);
1646
+ const childMarginTop = resolveEdgeValue(childStyle.margin, 1, style.flexDirection, nodeWidth, direction);
1647
+ const childMarginRight = resolveEdgeValue(childStyle.margin, 2, style.flexDirection, nodeWidth, direction);
1648
+ const childMarginBottom = resolveEdgeValue(childStyle.margin, 3, style.flexDirection, nodeWidth, direction);
1649
+ const hasAutoMarginLeft = isEdgeAuto(childStyle.margin, 0, style.flexDirection, direction);
1650
+ const hasAutoMarginRight = isEdgeAuto(childStyle.margin, 2, style.flexDirection, direction);
1651
+ const hasAutoMarginTop = isEdgeAuto(childStyle.margin, 1, style.flexDirection, direction);
1652
+ const hasAutoMarginBottom = isEdgeAuto(childStyle.margin, 3, style.flexDirection, direction);
1653
+ const leftPos = resolvePositionEdge(childStyle.position, 0, direction);
1654
+ const topPos = childStyle.position[1];
1655
+ const rightPos = resolvePositionEdge(childStyle.position, 2, direction);
1656
+ const bottomPos = childStyle.position[3];
1657
+ const hasLeft = leftPos.unit !== 0;
1658
+ const hasRight = rightPos.unit !== 0;
1659
+ const hasTop = topPos.unit !== 0;
1660
+ const hasBottom = bottomPos.unit !== 0;
1661
+ const leftOffset = resolveValue(leftPos, absContentBoxW);
1662
+ const topOffset = resolveValue(topPos, absContentBoxH);
1663
+ const rightOffset = resolveValue(rightPos, absContentBoxW);
1664
+ const bottomOffset = resolveValue(bottomPos, absContentBoxH);
1665
+ const contentW = absPaddingBoxW;
1666
+ const contentH = absPaddingBoxH;
1667
+ let childAvailWidth;
1668
+ const widthIsAuto = childStyle.width.unit === 3 || childStyle.width.unit === 0;
1669
+ const widthIsPercent = childStyle.width.unit === 2;
1670
+ if (widthIsAuto && hasLeft && hasRight) childAvailWidth = contentW - leftOffset - rightOffset - childMarginLeft - childMarginRight;
1671
+ else if (widthIsAuto) childAvailWidth = NaN;
1672
+ else if (widthIsPercent) childAvailWidth = absContentBoxW;
1673
+ else childAvailWidth = contentW;
1674
+ let childAvailHeight;
1675
+ const heightIsAuto = childStyle.height.unit === 3 || childStyle.height.unit === 0;
1676
+ const heightIsPercent = childStyle.height.unit === 2;
1677
+ if (heightIsAuto && hasTop && hasBottom) childAvailHeight = contentH - topOffset - bottomOffset - childMarginTop - childMarginBottom;
1678
+ else if (heightIsAuto) childAvailHeight = NaN;
1679
+ else if (heightIsPercent) childAvailHeight = absContentBoxH;
1680
+ else childAvailHeight = contentH;
1681
+ let childX = childMarginLeft + leftOffset;
1682
+ let childY = childMarginTop + topOffset;
1683
+ const childAbsX = absX + marginLeft + absInnerLeft + leftOffset;
1684
+ const childAbsY = absY + marginTop + absInnerTop + topOffset;
1685
+ const clampIfNumber = (v) => Number.isNaN(v) ? NaN : Math.max(0, v);
1686
+ layoutNode(child, clampIfNumber(childAvailWidth), clampIfNumber(childAvailHeight), layout.left + absInnerLeft + childX, layout.top + absInnerTop + childY, childAbsX, childAbsY, direction);
1687
+ const childWidth = child.layout.width;
1688
+ const childHeight = child.layout.height;
1689
+ if (!hasLeft && !hasRight) if (isRow) {
1690
+ const freeSpaceX = contentW - childWidth - childMarginLeft - childMarginRight;
1691
+ switch (style.justifyContent) {
1692
+ case 1:
1693
+ childX = childMarginLeft + freeSpaceX / 2;
1694
+ break;
1695
+ case 2:
1696
+ childX = childMarginLeft + freeSpaceX;
1697
+ break;
1698
+ default:
1699
+ childX = childMarginLeft;
1700
+ break;
1701
+ }
1702
+ } else {
1703
+ let alignment = style.alignItems;
1704
+ if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
1705
+ const freeSpaceX = contentW - childWidth - childMarginLeft - childMarginRight;
1706
+ switch (alignment) {
1707
+ case 2:
1708
+ childX = childMarginLeft + freeSpaceX / 2;
1709
+ break;
1710
+ case 3:
1711
+ childX = childMarginLeft + freeSpaceX;
1712
+ break;
1713
+ case 4: break;
1714
+ default:
1715
+ childX = childMarginLeft;
1716
+ break;
1717
+ }
1718
+ }
1719
+ else if (!hasLeft && hasRight) childX = contentW - rightOffset - childMarginRight - childWidth;
1720
+ else if (hasLeft && hasRight) {
1721
+ if (widthIsAuto) child.layout.width = Math.round(childAvailWidth);
1722
+ else if (hasAutoMarginLeft || hasAutoMarginRight) {
1723
+ const freeSpace = Math.max(0, contentW - leftOffset - rightOffset - childWidth);
1724
+ if (hasAutoMarginLeft && hasAutoMarginRight) childX = leftOffset + freeSpace / 2;
1725
+ else if (hasAutoMarginLeft) childX = leftOffset + freeSpace;
1726
+ }
1727
+ }
1728
+ if (!hasTop && !hasBottom) if (isRow) {
1729
+ let alignment = style.alignItems;
1730
+ if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
1731
+ const freeSpaceY = contentH - childHeight - childMarginTop - childMarginBottom;
1732
+ switch (alignment) {
1733
+ case 2:
1734
+ childY = childMarginTop + freeSpaceY / 2;
1735
+ break;
1736
+ case 3:
1737
+ childY = childMarginTop + freeSpaceY;
1738
+ break;
1739
+ case 4: break;
1740
+ default:
1741
+ childY = childMarginTop;
1742
+ break;
1743
+ }
1744
+ } else {
1745
+ const freeSpaceY = contentH - childHeight - childMarginTop - childMarginBottom;
1746
+ switch (style.justifyContent) {
1747
+ case 1:
1748
+ childY = childMarginTop + freeSpaceY / 2;
1749
+ break;
1750
+ case 2:
1751
+ childY = childMarginTop + freeSpaceY;
1752
+ break;
1753
+ default:
1754
+ childY = childMarginTop;
1755
+ break;
1756
+ }
1757
+ }
1758
+ else if (!hasTop && hasBottom) childY = contentH - bottomOffset - childMarginBottom - childHeight;
1759
+ else if (hasTop && hasBottom) {
1760
+ if (heightIsAuto) child.layout.height = Math.round(childAvailHeight);
1761
+ else if (hasAutoMarginTop || hasAutoMarginBottom) {
1762
+ const freeSpace = Math.max(0, contentH - topOffset - bottomOffset - childHeight);
1763
+ if (hasAutoMarginTop && hasAutoMarginBottom) childY = topOffset + freeSpace / 2;
1764
+ else if (hasAutoMarginTop) childY = topOffset + freeSpace;
1765
+ }
1766
+ }
1767
+ child.layout.left = Math.round(absInnerLeft + childX);
1768
+ child.layout.top = Math.round(absInnerTop + childY);
1769
+ }
1770
+ flex.lastAvailW = availableWidth;
1771
+ flex.lastAvailH = availableHeight;
1772
+ flex.lastOffsetX = offsetX;
1773
+ flex.lastOffsetY = offsetY;
1774
+ flex.lastAbsX = absX;
1775
+ flex.lastAbsY = absY;
1776
+ flex.lastDir = direction;
1777
+ flex.layoutValid = true;
1778
+ _t?.layoutExit(_tn, layout.width, layout.height);
1779
+ }
1780
+ //#endregion
1781
+ //#region ../../flexily/src/types.ts
1782
+ /**
1783
+ * Create a default Value (undefined).
1784
+ */
1785
+ function createValue(value = 0, unit = 0) {
1786
+ return {
1787
+ value,
1788
+ unit
1789
+ };
1790
+ }
1791
+ /**
1792
+ * Create default style.
1793
+ *
1794
+ * Comments indicate where Yoga and CSS defaults differ.
1795
+ * Flexily follows Yoga defaults for API compatibility.
1796
+ */
1797
+ function createDefaultStyle() {
1798
+ return {
1799
+ display: 0,
1800
+ positionType: 1,
1801
+ position: [
1802
+ createValue(),
1803
+ createValue(),
1804
+ createValue(),
1805
+ createValue(),
1806
+ createValue(),
1807
+ createValue()
1808
+ ],
1809
+ flexDirection: 2,
1810
+ flexWrap: 0,
1811
+ flexGrow: 0,
1812
+ flexShrink: 0,
1813
+ flexBasis: createValue(0, 3),
1814
+ alignItems: 4,
1815
+ alignSelf: 0,
1816
+ alignContent: 1,
1817
+ justifyContent: 0,
1818
+ width: createValue(0, 3),
1819
+ height: createValue(0, 3),
1820
+ minWidth: createValue(),
1821
+ minHeight: createValue(),
1822
+ maxWidth: createValue(),
1823
+ maxHeight: createValue(),
1824
+ aspectRatio: NaN,
1825
+ margin: [
1826
+ createValue(),
1827
+ createValue(),
1828
+ createValue(),
1829
+ createValue(),
1830
+ createValue(),
1831
+ createValue()
1832
+ ],
1833
+ padding: [
1834
+ createValue(),
1835
+ createValue(),
1836
+ createValue(),
1837
+ createValue(),
1838
+ createValue(),
1839
+ createValue()
1840
+ ],
1841
+ border: [
1842
+ 0,
1843
+ 0,
1844
+ 0,
1845
+ 0,
1846
+ NaN,
1847
+ NaN
1848
+ ],
1849
+ gap: [0, 0],
1850
+ overflow: 0
1851
+ };
1852
+ }
1853
+ //#endregion
1854
+ //#region ../../flexily/src/node-zero.ts
1855
+ /**
1856
+ * Flexily Node
1857
+ *
1858
+ * Yoga-compatible Node class for flexbox layout.
1859
+ */
1860
+ /**
1861
+ * A layout node in the flexbox tree.
1862
+ */
1863
+ var Node = class Node {
1864
+ _parent = null;
1865
+ _children = [];
1866
+ _style = createDefaultStyle();
1867
+ _measureFunc = null;
1868
+ _baselineFunc = null;
1869
+ _m0;
1870
+ _m1;
1871
+ _m2;
1872
+ _m3;
1873
+ _lc0;
1874
+ _lc1;
1875
+ _measureResult = {
1876
+ width: 0,
1877
+ height: 0
1878
+ };
1879
+ _layoutResult = {
1880
+ width: 0,
1881
+ height: 0
1882
+ };
1883
+ static measureCalls = 0;
1884
+ static measureCacheHits = 0;
1885
+ /**
1886
+ * Reset measure statistics (call before calculateLayout).
1887
+ */
1888
+ static resetMeasureStats() {
1889
+ Node.measureCalls = 0;
1890
+ Node.measureCacheHits = 0;
1891
+ }
1892
+ _layout = {
1893
+ left: 0,
1894
+ top: 0,
1895
+ width: 0,
1896
+ height: 0
1897
+ };
1898
+ _flex = {
1899
+ mainSize: 0,
1900
+ baseSize: 0,
1901
+ mainMargin: 0,
1902
+ flexGrow: 0,
1903
+ flexShrink: 0,
1904
+ minMain: 0,
1905
+ maxMain: Infinity,
1906
+ mainStartMarginAuto: false,
1907
+ mainEndMarginAuto: false,
1908
+ mainStartMarginValue: 0,
1909
+ mainEndMarginValue: 0,
1910
+ marginL: 0,
1911
+ marginT: 0,
1912
+ marginR: 0,
1913
+ marginB: 0,
1914
+ frozen: false,
1915
+ lineIndex: 0,
1916
+ relativeIndex: -1,
1917
+ baseline: 0,
1918
+ lastAvailW: NaN,
1919
+ lastAvailH: NaN,
1920
+ lastOffsetX: NaN,
1921
+ lastOffsetY: NaN,
1922
+ lastAbsX: NaN,
1923
+ lastAbsY: NaN,
1924
+ layoutValid: false,
1925
+ lastDir: 0
1926
+ };
1927
+ _isDirty = true;
1928
+ _hasNewLayout = false;
1929
+ _lastCalcW = NaN;
1930
+ _lastCalcH = NaN;
1931
+ _lastCalcDir = 0;
1932
+ /**
1933
+ * Create a new layout node.
1934
+ *
1935
+ * @returns A new Node instance
1936
+ * @example
1937
+ * ```typescript
1938
+ * const root = Node.create();
1939
+ * root.setWidth(100);
1940
+ * root.setHeight(200);
1941
+ * ```
1942
+ */
1943
+ static create() {
1944
+ return new Node();
1945
+ }
1946
+ /**
1947
+ * Get the number of child nodes.
1948
+ *
1949
+ * @returns The number of children
1950
+ */
1951
+ getChildCount() {
1952
+ return this._children.length;
1953
+ }
1954
+ /**
1955
+ * Get a child node by index.
1956
+ *
1957
+ * @param index - Zero-based child index
1958
+ * @returns The child node at the given index, or undefined if index is out of bounds
1959
+ */
1960
+ getChild(index) {
1961
+ return this._children[index];
1962
+ }
1963
+ /**
1964
+ * Get the parent node.
1965
+ *
1966
+ * @returns The parent node, or null if this is a root node
1967
+ */
1968
+ getParent() {
1969
+ return this._parent;
1970
+ }
1971
+ /**
1972
+ * Insert a child node at the specified index.
1973
+ * If the child already has a parent, it will be removed from that parent first.
1974
+ * Marks the node as dirty to trigger layout recalculation.
1975
+ *
1976
+ * @param child - The child node to insert
1977
+ * @param index - The index at which to insert the child
1978
+ * @example
1979
+ * ```typescript
1980
+ * const parent = Node.create();
1981
+ * const child1 = Node.create();
1982
+ * const child2 = Node.create();
1983
+ * parent.insertChild(child1, 0);
1984
+ * parent.insertChild(child2, 1);
1985
+ * ```
1986
+ */
1987
+ insertChild(child, index) {
1988
+ if (child === this) throw new Error("Cannot insert a node as a child of itself");
1989
+ let ancestor = this._parent;
1990
+ while (ancestor !== null) {
1991
+ if (ancestor === child) throw new Error("Cannot insert an ancestor as a child (would create a cycle)");
1992
+ ancestor = ancestor._parent;
1993
+ }
1994
+ if (child._parent !== null) child._parent.removeChild(child);
1995
+ child._parent = this;
1996
+ const clampedIndex = Math.max(0, Math.min(index, this._children.length));
1997
+ this._children.splice(clampedIndex, 0, child);
1998
+ for (let i = clampedIndex + 1; i < this._children.length; i++) this._children[i]._flex.layoutValid = false;
1999
+ this.markDirty();
2000
+ }
2001
+ /**
2002
+ * Remove a child node from this node.
2003
+ * The child's parent reference will be cleared.
2004
+ * Marks the node as dirty to trigger layout recalculation.
2005
+ * Invalidates layout validity of remaining siblings whose positions may change.
2006
+ *
2007
+ * @param child - The child node to remove
2008
+ */
2009
+ removeChild(child) {
2010
+ const index = this._children.indexOf(child);
2011
+ if (index !== -1) {
2012
+ this._children.splice(index, 1);
2013
+ child._parent = null;
2014
+ for (let i = index; i < this._children.length; i++) this._children[i]._flex.layoutValid = false;
2015
+ this.markDirty();
2016
+ }
2017
+ }
2018
+ /**
2019
+ * Free this node and clean up all references.
2020
+ * Removes the node from its parent, clears all children, and removes the measure function.
2021
+ * This does not recursively free child nodes.
2022
+ */
2023
+ free() {
2024
+ if (this._parent !== null) this._parent.removeChild(this);
2025
+ for (const child of this._children) child._parent = null;
2026
+ this._children = [];
2027
+ this._measureFunc = null;
2028
+ this._baselineFunc = null;
2029
+ }
2030
+ /**
2031
+ * Free this node and all descendants recursively.
2032
+ * Each node is detached from its parent and cleaned up.
2033
+ * Uses iterative traversal to avoid stack overflow on deep trees.
2034
+ */
2035
+ freeRecursive() {
2036
+ const nodes = [];
2037
+ traversalStack.length = 0;
2038
+ traversalStack.push(this);
2039
+ while (traversalStack.length > 0) {
2040
+ const current = traversalStack.pop();
2041
+ nodes.push(current);
2042
+ for (const child of current._children) traversalStack.push(child);
2043
+ }
2044
+ for (let i = nodes.length - 1; i >= 0; i--) nodes[i].free();
2045
+ }
2046
+ /**
2047
+ * Dispose the node (calls free)
2048
+ */
2049
+ [Symbol.dispose]() {
2050
+ this.free();
2051
+ }
2052
+ /**
2053
+ * Set a measure function for intrinsic sizing.
2054
+ * The measure function is called during layout to determine the node's natural size.
2055
+ * Typically used for text nodes or other content that has an intrinsic size.
2056
+ * Marks the node as dirty to trigger layout recalculation.
2057
+ *
2058
+ * @param measureFunc - Function that returns width and height given available space and constraints
2059
+ * @example
2060
+ * ```typescript
2061
+ * const textNode = Node.create();
2062
+ * textNode.setMeasureFunc((width, widthMode, height, heightMode) => {
2063
+ * // Measure text and return dimensions
2064
+ * return { width: 50, height: 20 };
2065
+ * });
2066
+ * ```
2067
+ */
2068
+ setMeasureFunc(measureFunc) {
2069
+ this._measureFunc = measureFunc;
2070
+ this.markDirty();
2071
+ }
2072
+ /**
2073
+ * Remove the measure function from this node.
2074
+ * Marks the node as dirty to trigger layout recalculation.
2075
+ */
2076
+ unsetMeasureFunc() {
2077
+ this._measureFunc = null;
2078
+ this.markDirty();
2079
+ }
2080
+ /**
2081
+ * Check if this node has a measure function.
2082
+ *
2083
+ * @returns True if a measure function is set
2084
+ */
2085
+ hasMeasureFunc() {
2086
+ return this._measureFunc !== null;
2087
+ }
2088
+ /**
2089
+ * Set a baseline function to determine where this node's text baseline is.
2090
+ * Used for ALIGN_BASELINE to align text across siblings with different heights.
2091
+ *
2092
+ * @param baselineFunc - Function that returns baseline offset from top given width and height
2093
+ * @example
2094
+ * ```typescript
2095
+ * textNode.setBaselineFunc((width, height) => {
2096
+ * // For a text node, baseline might be at 80% of height
2097
+ * return height * 0.8;
2098
+ * });
2099
+ * ```
2100
+ */
2101
+ setBaselineFunc(baselineFunc) {
2102
+ this._baselineFunc = baselineFunc;
2103
+ this.markDirty();
2104
+ }
2105
+ /**
2106
+ * Remove the baseline function from this node.
2107
+ * Marks the node as dirty to trigger layout recalculation.
2108
+ */
2109
+ unsetBaselineFunc() {
2110
+ this._baselineFunc = null;
2111
+ this.markDirty();
2112
+ }
2113
+ /**
2114
+ * Check if this node has a baseline function.
2115
+ *
2116
+ * @returns True if a baseline function is set
2117
+ */
2118
+ hasBaselineFunc() {
2119
+ return this._baselineFunc !== null;
2120
+ }
2121
+ /**
2122
+ * Call the measure function with caching.
2123
+ * Uses a 4-entry numeric cache for fast lookup without allocations.
2124
+ * Cache is cleared when markDirty() is called.
2125
+ *
2126
+ * @returns Measured dimensions or null if no measure function
2127
+ */
2128
+ cachedMeasure(w, wm, h, hm) {
2129
+ if (!this._measureFunc) return null;
2130
+ Node.measureCalls++;
2131
+ const m0 = this._m0;
2132
+ if (m0 && m0.w === w && m0.wm === wm && m0.h === h && m0.hm === hm) {
2133
+ Node.measureCacheHits++;
2134
+ this._measureResult.width = m0.rw;
2135
+ this._measureResult.height = m0.rh;
2136
+ getTrace()?.measureCacheHit(0, w, h, m0.rw, m0.rh);
2137
+ return this._measureResult;
2138
+ }
2139
+ const m1 = this._m1;
2140
+ if (m1 && m1.w === w && m1.wm === wm && m1.h === h && m1.hm === hm) {
2141
+ Node.measureCacheHits++;
2142
+ this._measureResult.width = m1.rw;
2143
+ this._measureResult.height = m1.rh;
2144
+ getTrace()?.measureCacheHit(0, w, h, m1.rw, m1.rh);
2145
+ return this._measureResult;
2146
+ }
2147
+ const m2 = this._m2;
2148
+ if (m2 && m2.w === w && m2.wm === wm && m2.h === h && m2.hm === hm) {
2149
+ Node.measureCacheHits++;
2150
+ this._measureResult.width = m2.rw;
2151
+ this._measureResult.height = m2.rh;
2152
+ getTrace()?.measureCacheHit(0, w, h, m2.rw, m2.rh);
2153
+ return this._measureResult;
2154
+ }
2155
+ const m3 = this._m3;
2156
+ if (m3 && m3.w === w && m3.wm === wm && m3.h === h && m3.hm === hm) {
2157
+ Node.measureCacheHits++;
2158
+ this._measureResult.width = m3.rw;
2159
+ this._measureResult.height = m3.rh;
2160
+ getTrace()?.measureCacheHit(0, w, h, m3.rw, m3.rh);
2161
+ return this._measureResult;
2162
+ }
2163
+ getTrace()?.measureCacheMiss(0, w, h);
2164
+ const result = this._measureFunc(w, wm, h, hm);
2165
+ if (this._m2) {
2166
+ if (!this._m3) this._m3 = {
2167
+ w: 0,
2168
+ wm: 0,
2169
+ h: 0,
2170
+ hm: 0,
2171
+ rw: 0,
2172
+ rh: 0
2173
+ };
2174
+ this._m3.w = this._m2.w;
2175
+ this._m3.wm = this._m2.wm;
2176
+ this._m3.h = this._m2.h;
2177
+ this._m3.hm = this._m2.hm;
2178
+ this._m3.rw = this._m2.rw;
2179
+ this._m3.rh = this._m2.rh;
2180
+ }
2181
+ if (this._m1) {
2182
+ if (!this._m2) this._m2 = {
2183
+ w: 0,
2184
+ wm: 0,
2185
+ h: 0,
2186
+ hm: 0,
2187
+ rw: 0,
2188
+ rh: 0
2189
+ };
2190
+ this._m2.w = this._m1.w;
2191
+ this._m2.wm = this._m1.wm;
2192
+ this._m2.h = this._m1.h;
2193
+ this._m2.hm = this._m1.hm;
2194
+ this._m2.rw = this._m1.rw;
2195
+ this._m2.rh = this._m1.rh;
2196
+ }
2197
+ if (this._m0) {
2198
+ if (!this._m1) this._m1 = {
2199
+ w: 0,
2200
+ wm: 0,
2201
+ h: 0,
2202
+ hm: 0,
2203
+ rw: 0,
2204
+ rh: 0
2205
+ };
2206
+ this._m1.w = this._m0.w;
2207
+ this._m1.wm = this._m0.wm;
2208
+ this._m1.h = this._m0.h;
2209
+ this._m1.hm = this._m0.hm;
2210
+ this._m1.rw = this._m0.rw;
2211
+ this._m1.rh = this._m0.rh;
2212
+ }
2213
+ if (!this._m0) this._m0 = {
2214
+ w: 0,
2215
+ wm: 0,
2216
+ h: 0,
2217
+ hm: 0,
2218
+ rw: 0,
2219
+ rh: 0
2220
+ };
2221
+ this._m0.w = w;
2222
+ this._m0.wm = wm;
2223
+ this._m0.h = h;
2224
+ this._m0.hm = hm;
2225
+ this._m0.rw = result.width;
2226
+ this._m0.rh = result.height;
2227
+ this._measureResult.width = result.width;
2228
+ this._measureResult.height = result.height;
2229
+ return this._measureResult;
2230
+ }
2231
+ /**
2232
+ * Check layout cache for a previously computed size with same available dimensions.
2233
+ * Returns cached (width, height) or null if not found.
2234
+ *
2235
+ * NaN dimensions are handled specially via Object.is (NaN === NaN is false, but Object.is(NaN, NaN) is true).
2236
+ */
2237
+ getCachedLayout(availW, availH) {
2238
+ if (this._isDirty) return null;
2239
+ const lc0 = this._lc0;
2240
+ if (lc0 && Object.is(lc0.availW, availW) && Object.is(lc0.availH, availH)) {
2241
+ this._layoutResult.width = lc0.computedW;
2242
+ this._layoutResult.height = lc0.computedH;
2243
+ return this._layoutResult;
2244
+ }
2245
+ const lc1 = this._lc1;
2246
+ if (lc1 && Object.is(lc1.availW, availW) && Object.is(lc1.availH, availH)) {
2247
+ this._layoutResult.width = lc1.computedW;
2248
+ this._layoutResult.height = lc1.computedH;
2249
+ return this._layoutResult;
2250
+ }
2251
+ return null;
2252
+ }
2253
+ /**
2254
+ * Cache a computed layout result for the given available dimensions.
2255
+ * Zero-allocation: lazily allocates cache entries once, then reuses.
2256
+ */
2257
+ setCachedLayout(availW, availH, computedW, computedH) {
2258
+ if (this._lc0) {
2259
+ if (!this._lc1) this._lc1 = {
2260
+ availW: NaN,
2261
+ availH: NaN,
2262
+ computedW: 0,
2263
+ computedH: 0
2264
+ };
2265
+ this._lc1.availW = this._lc0.availW;
2266
+ this._lc1.availH = this._lc0.availH;
2267
+ this._lc1.computedW = this._lc0.computedW;
2268
+ this._lc1.computedH = this._lc0.computedH;
2269
+ }
2270
+ if (!this._lc0) this._lc0 = {
2271
+ availW: 0,
2272
+ availH: 0,
2273
+ computedW: 0,
2274
+ computedH: 0
2275
+ };
2276
+ this._lc0.availW = availW;
2277
+ this._lc0.availH = availH;
2278
+ this._lc0.computedW = computedW;
2279
+ this._lc0.computedH = computedH;
2280
+ }
2281
+ /**
2282
+ * Clear layout cache for this node and all descendants.
2283
+ * Called at the start of each calculateLayout pass.
2284
+ * Zero-allocation: invalidates entries (availW = NaN) rather than deallocating.
2285
+ * Uses iterative traversal to avoid stack overflow on deep trees.
2286
+ */
2287
+ resetLayoutCache() {
2288
+ traversalStack.length = 0;
2289
+ traversalStack.push(this);
2290
+ while (traversalStack.length > 0) {
2291
+ const node = traversalStack.pop();
2292
+ if (node._lc0) node._lc0.availW = -1;
2293
+ if (node._lc1) node._lc1.availW = -1;
2294
+ for (const child of node._children) traversalStack.push(child);
2295
+ }
2296
+ }
2297
+ /**
2298
+ * Check if this node needs layout recalculation.
2299
+ *
2300
+ * @returns True if the node is dirty and needs layout
2301
+ */
2302
+ isDirty() {
2303
+ return this._isDirty;
2304
+ }
2305
+ /**
2306
+ * Mark this node and all ancestors as dirty.
2307
+ * A dirty node needs layout recalculation.
2308
+ * This is automatically called by all style setters and tree operations.
2309
+ * Uses iterative approach to avoid stack overflow on deep trees.
2310
+ */
2311
+ markDirty() {
2312
+ let current = this;
2313
+ while (current !== null) {
2314
+ current._m0 = current._m1 = current._m2 = current._m3 = void 0;
2315
+ current._lc0 = current._lc1 = void 0;
2316
+ if (current._isDirty) break;
2317
+ current._isDirty = true;
2318
+ current._flex.layoutValid = false;
2319
+ current = current._parent;
2320
+ }
2321
+ }
2322
+ /**
2323
+ * Check if this node has new layout results since the last check.
2324
+ *
2325
+ * @returns True if layout was recalculated since the last call to markLayoutSeen
2326
+ */
2327
+ hasNewLayout() {
2328
+ return this._hasNewLayout;
2329
+ }
2330
+ /**
2331
+ * Mark that the current layout has been seen/processed.
2332
+ * Clears the hasNewLayout flag.
2333
+ */
2334
+ markLayoutSeen() {
2335
+ this._hasNewLayout = false;
2336
+ }
2337
+ /**
2338
+ * Calculate layout for this node and all descendants.
2339
+ * This runs the flexbox layout algorithm to compute positions and sizes.
2340
+ * Only recalculates if the node is marked as dirty.
2341
+ *
2342
+ * @param width - Available width for layout
2343
+ * @param height - Available height for layout
2344
+ * @param _direction - Text direction (LTR or RTL), defaults to LTR
2345
+ * @example
2346
+ * ```typescript
2347
+ * const root = Node.create();
2348
+ * root.setFlexDirection(FLEX_DIRECTION_ROW);
2349
+ * root.setWidth(100);
2350
+ * root.setHeight(50);
2351
+ *
2352
+ * const child = Node.create();
2353
+ * child.setFlexGrow(1);
2354
+ * root.insertChild(child, 0);
2355
+ *
2356
+ * root.calculateLayout(100, 50, DIRECTION_LTR);
2357
+ *
2358
+ * // Now you can read computed layout
2359
+ * console.log(child.getComputedWidth());
2360
+ * ```
2361
+ */
2362
+ calculateLayout(width, height, direction = 1) {
2363
+ const availableWidth = width ?? NaN;
2364
+ const availableHeight = height ?? NaN;
2365
+ if (!this._isDirty && Object.is(this._lastCalcW, availableWidth) && Object.is(this._lastCalcH, availableHeight) && this._lastCalcDir === direction) {
2366
+ log.debug?.("layout skip (not dirty, constraints unchanged)");
2367
+ return;
2368
+ }
2369
+ this._lastCalcW = availableWidth;
2370
+ this._lastCalcH = availableHeight;
2371
+ this._lastCalcDir = direction;
2372
+ const start = log.debug ? Date.now() : 0;
2373
+ const nodeCount = log.debug ? countNodes(this) : 0;
2374
+ Node.resetMeasureStats();
2375
+ computeLayout(this, availableWidth, availableHeight, direction);
2376
+ this._isDirty = false;
2377
+ this._hasNewLayout = true;
2378
+ markSubtreeLayoutSeen(this);
2379
+ log.debug?.("layout: %dx%d, %d nodes in %dms (measure: calls=%d hits=%d)", width, height, nodeCount, Date.now() - start, Node.measureCalls, Node.measureCacheHits);
2380
+ }
2381
+ /**
2382
+ * Get the computed left position after layout.
2383
+ *
2384
+ * @returns The left position in points
2385
+ */
2386
+ getComputedLeft() {
2387
+ return this._layout.left;
2388
+ }
2389
+ /**
2390
+ * Get the computed top position after layout.
2391
+ *
2392
+ * @returns The top position in points
2393
+ */
2394
+ getComputedTop() {
2395
+ return this._layout.top;
2396
+ }
2397
+ /**
2398
+ * Get the computed width after layout.
2399
+ *
2400
+ * @returns The width in points
2401
+ */
2402
+ getComputedWidth() {
2403
+ return this._layout.width;
2404
+ }
2405
+ /**
2406
+ * Get the computed height after layout.
2407
+ *
2408
+ * @returns The height in points
2409
+ */
2410
+ getComputedHeight() {
2411
+ return this._layout.height;
2412
+ }
2413
+ /**
2414
+ * Get the computed right edge position after layout (left + width).
2415
+ *
2416
+ * @returns The right edge position in points
2417
+ */
2418
+ getComputedRight() {
2419
+ return this._layout.left + this._layout.width;
2420
+ }
2421
+ /**
2422
+ * Get the computed bottom edge position after layout (top + height).
2423
+ *
2424
+ * @returns The bottom edge position in points
2425
+ */
2426
+ getComputedBottom() {
2427
+ return this._layout.top + this._layout.height;
2428
+ }
2429
+ /**
2430
+ * Get the computed padding for a specific edge after layout.
2431
+ * Returns the resolved padding value (percentage and logical edges resolved).
2432
+ *
2433
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
2434
+ * @returns Padding value in points
2435
+ */
2436
+ getComputedPadding(edge) {
2437
+ return getEdgeValue(this._style.padding, edge).value;
2438
+ }
2439
+ /**
2440
+ * Get the computed margin for a specific edge after layout.
2441
+ * Returns the resolved margin value (percentage and logical edges resolved).
2442
+ *
2443
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
2444
+ * @returns Margin value in points
2445
+ */
2446
+ getComputedMargin(edge) {
2447
+ return getEdgeValue(this._style.margin, edge).value;
2448
+ }
2449
+ /**
2450
+ * Get the computed border width for a specific edge after layout.
2451
+ *
2452
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
2453
+ * @returns Border width in points
2454
+ */
2455
+ getComputedBorder(edge) {
2456
+ return getEdgeBorderValue(this._style.border, edge);
2457
+ }
2458
+ get children() {
2459
+ return this._children;
2460
+ }
2461
+ get style() {
2462
+ return this._style;
2463
+ }
2464
+ get layout() {
2465
+ return this._layout;
2466
+ }
2467
+ get measureFunc() {
2468
+ return this._measureFunc;
2469
+ }
2470
+ get baselineFunc() {
2471
+ return this._baselineFunc;
2472
+ }
2473
+ get flex() {
2474
+ return this._flex;
2475
+ }
2476
+ /**
2477
+ * Set the width to a fixed value in points.
2478
+ *
2479
+ * @param value - Width in points
2480
+ */
2481
+ setWidth(value) {
2482
+ if (Number.isNaN(value)) this._style.width = {
2483
+ value: 0,
2484
+ unit: 3
2485
+ };
2486
+ else this._style.width = {
2487
+ value,
2488
+ unit: 1
2489
+ };
2490
+ this.markDirty();
2491
+ }
2492
+ /**
2493
+ * Set the width as a percentage of the parent's width.
2494
+ *
2495
+ * @param value - Width as a percentage (0-100)
2496
+ */
2497
+ setWidthPercent(value) {
2498
+ this._style.width = {
2499
+ value,
2500
+ unit: 2
2501
+ };
2502
+ this.markDirty();
2503
+ }
2504
+ /**
2505
+ * Set the width to auto (determined by layout algorithm).
2506
+ */
2507
+ setWidthAuto() {
2508
+ this._style.width = {
2509
+ value: 0,
2510
+ unit: 3
2511
+ };
2512
+ this.markDirty();
2513
+ }
2514
+ /**
2515
+ * Set the height to a fixed value in points.
2516
+ *
2517
+ * @param value - Height in points
2518
+ */
2519
+ setHeight(value) {
2520
+ if (Number.isNaN(value)) this._style.height = {
2521
+ value: 0,
2522
+ unit: 3
2523
+ };
2524
+ else this._style.height = {
2525
+ value,
2526
+ unit: 1
2527
+ };
2528
+ this.markDirty();
2529
+ }
2530
+ /**
2531
+ * Set the height as a percentage of the parent's height.
2532
+ *
2533
+ * @param value - Height as a percentage (0-100)
2534
+ */
2535
+ setHeightPercent(value) {
2536
+ this._style.height = {
2537
+ value,
2538
+ unit: 2
2539
+ };
2540
+ this.markDirty();
2541
+ }
2542
+ /**
2543
+ * Set the height to auto (determined by layout algorithm).
2544
+ */
2545
+ setHeightAuto() {
2546
+ this._style.height = {
2547
+ value: 0,
2548
+ unit: 3
2549
+ };
2550
+ this.markDirty();
2551
+ }
2552
+ /**
2553
+ * Set the minimum width in points.
2554
+ *
2555
+ * @param value - Minimum width in points
2556
+ */
2557
+ setMinWidth(value) {
2558
+ this._style.minWidth = {
2559
+ value,
2560
+ unit: 1
2561
+ };
2562
+ this.markDirty();
2563
+ }
2564
+ /**
2565
+ * Set the minimum width as a percentage of the parent's width.
2566
+ *
2567
+ * @param value - Minimum width as a percentage (0-100)
2568
+ */
2569
+ setMinWidthPercent(value) {
2570
+ this._style.minWidth = {
2571
+ value,
2572
+ unit: 2
2573
+ };
2574
+ this.markDirty();
2575
+ }
2576
+ /**
2577
+ * Set the minimum height in points.
2578
+ *
2579
+ * @param value - Minimum height in points
2580
+ */
2581
+ setMinHeight(value) {
2582
+ this._style.minHeight = {
2583
+ value,
2584
+ unit: 1
2585
+ };
2586
+ this.markDirty();
2587
+ }
2588
+ /**
2589
+ * Set the minimum height as a percentage of the parent's height.
2590
+ *
2591
+ * @param value - Minimum height as a percentage (0-100)
2592
+ */
2593
+ setMinHeightPercent(value) {
2594
+ this._style.minHeight = {
2595
+ value,
2596
+ unit: 2
2597
+ };
2598
+ this.markDirty();
2599
+ }
2600
+ /**
2601
+ * Set the maximum width in points.
2602
+ *
2603
+ * @param value - Maximum width in points
2604
+ */
2605
+ setMaxWidth(value) {
2606
+ this._style.maxWidth = {
2607
+ value,
2608
+ unit: 1
2609
+ };
2610
+ this.markDirty();
2611
+ }
2612
+ /**
2613
+ * Set the maximum width as a percentage of the parent's width.
2614
+ *
2615
+ * @param value - Maximum width as a percentage (0-100)
2616
+ */
2617
+ setMaxWidthPercent(value) {
2618
+ this._style.maxWidth = {
2619
+ value,
2620
+ unit: 2
2621
+ };
2622
+ this.markDirty();
2623
+ }
2624
+ /**
2625
+ * Set the maximum height in points.
2626
+ *
2627
+ * @param value - Maximum height in points
2628
+ */
2629
+ setMaxHeight(value) {
2630
+ this._style.maxHeight = {
2631
+ value,
2632
+ unit: 1
2633
+ };
2634
+ this.markDirty();
2635
+ }
2636
+ /**
2637
+ * Set the maximum height as a percentage of the parent's height.
2638
+ *
2639
+ * @param value - Maximum height as a percentage (0-100)
2640
+ */
2641
+ setMaxHeightPercent(value) {
2642
+ this._style.maxHeight = {
2643
+ value,
2644
+ unit: 2
2645
+ };
2646
+ this.markDirty();
2647
+ }
2648
+ /**
2649
+ * Set the aspect ratio of the node.
2650
+ * When set, the node's width/height relationship is constrained.
2651
+ * If width is defined, height = width / aspectRatio.
2652
+ * If height is defined, width = height * aspectRatio.
2653
+ *
2654
+ * @param value - Aspect ratio (width/height). Use NaN to unset.
2655
+ */
2656
+ setAspectRatio(value) {
2657
+ this._style.aspectRatio = value;
2658
+ this.markDirty();
2659
+ }
2660
+ /**
2661
+ * Set the flex grow factor.
2662
+ * Determines how much the node will grow relative to siblings when there is extra space.
2663
+ *
2664
+ * @param value - Flex grow factor (typically 0 or 1+)
2665
+ * @example
2666
+ * ```typescript
2667
+ * const child = Node.create();
2668
+ * child.setFlexGrow(1); // Will grow to fill available space
2669
+ * ```
2670
+ */
2671
+ setFlexGrow(value) {
2672
+ this._style.flexGrow = value;
2673
+ this.markDirty();
2674
+ }
2675
+ /**
2676
+ * Set the flex shrink factor.
2677
+ * Determines how much the node will shrink relative to siblings when there is insufficient space.
2678
+ *
2679
+ * @param value - Flex shrink factor (default is 1)
2680
+ */
2681
+ setFlexShrink(value) {
2682
+ this._style.flexShrink = value;
2683
+ this.markDirty();
2684
+ }
2685
+ /**
2686
+ * Set the flex basis to a fixed value in points.
2687
+ * The initial size of the node before flex grow/shrink is applied.
2688
+ *
2689
+ * @param value - Flex basis in points
2690
+ */
2691
+ setFlexBasis(value) {
2692
+ this._style.flexBasis = {
2693
+ value,
2694
+ unit: 1
2695
+ };
2696
+ this.markDirty();
2697
+ }
2698
+ /**
2699
+ * Set the flex basis as a percentage of the parent's size.
2700
+ *
2701
+ * @param value - Flex basis as a percentage (0-100)
2702
+ */
2703
+ setFlexBasisPercent(value) {
2704
+ this._style.flexBasis = {
2705
+ value,
2706
+ unit: 2
2707
+ };
2708
+ this.markDirty();
2709
+ }
2710
+ /**
2711
+ * Set the flex basis to auto (based on the node's width/height).
2712
+ */
2713
+ setFlexBasisAuto() {
2714
+ this._style.flexBasis = {
2715
+ value: 0,
2716
+ unit: 3
2717
+ };
2718
+ this.markDirty();
2719
+ }
2720
+ /**
2721
+ * Set the flex direction (main axis direction).
2722
+ *
2723
+ * @param direction - FLEX_DIRECTION_ROW, FLEX_DIRECTION_COLUMN, FLEX_DIRECTION_ROW_REVERSE, or FLEX_DIRECTION_COLUMN_REVERSE
2724
+ * @example
2725
+ * ```typescript
2726
+ * const container = Node.create();
2727
+ * container.setFlexDirection(FLEX_DIRECTION_ROW); // Lay out children horizontally
2728
+ * ```
2729
+ */
2730
+ setFlexDirection(direction) {
2731
+ this._style.flexDirection = direction;
2732
+ this.markDirty();
2733
+ }
2734
+ /**
2735
+ * Set the flex wrap behavior.
2736
+ *
2737
+ * @param wrap - WRAP_NO_WRAP, WRAP_WRAP, or WRAP_WRAP_REVERSE
2738
+ */
2739
+ setFlexWrap(wrap) {
2740
+ this._style.flexWrap = wrap;
2741
+ this.markDirty();
2742
+ }
2743
+ /**
2744
+ * Set how children are aligned along the cross axis.
2745
+ *
2746
+ * @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
2747
+ * @example
2748
+ * ```typescript
2749
+ * const container = Node.create();
2750
+ * container.setFlexDirection(FLEX_DIRECTION_ROW);
2751
+ * container.setAlignItems(ALIGN_CENTER); // Center children vertically
2752
+ * ```
2753
+ */
2754
+ setAlignItems(align) {
2755
+ this._style.alignItems = align;
2756
+ this.markDirty();
2757
+ }
2758
+ /**
2759
+ * Set how this node is aligned along the parent's cross axis.
2760
+ * Overrides the parent's alignItems for this specific child.
2761
+ *
2762
+ * @param align - ALIGN_AUTO, ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
2763
+ */
2764
+ setAlignSelf(align) {
2765
+ this._style.alignSelf = align;
2766
+ this.markDirty();
2767
+ }
2768
+ /**
2769
+ * Set how lines are aligned in a multi-line flex container.
2770
+ * Only affects containers with wrap enabled and multiple lines.
2771
+ *
2772
+ * @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, ALIGN_SPACE_BETWEEN, or ALIGN_SPACE_AROUND
2773
+ */
2774
+ setAlignContent(align) {
2775
+ this._style.alignContent = align;
2776
+ this.markDirty();
2777
+ }
2778
+ /**
2779
+ * Set how children are distributed along the main axis.
2780
+ *
2781
+ * @param justify - JUSTIFY_FLEX_START, JUSTIFY_CENTER, JUSTIFY_FLEX_END, JUSTIFY_SPACE_BETWEEN, JUSTIFY_SPACE_AROUND, or JUSTIFY_SPACE_EVENLY
2782
+ * @example
2783
+ * ```typescript
2784
+ * const container = Node.create();
2785
+ * container.setJustifyContent(JUSTIFY_SPACE_BETWEEN); // Space children evenly with edges at start/end
2786
+ * ```
2787
+ */
2788
+ setJustifyContent(justify) {
2789
+ this._style.justifyContent = justify;
2790
+ this.markDirty();
2791
+ }
2792
+ /**
2793
+ * Set padding for one or more edges.
2794
+ *
2795
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2796
+ * @param value - Padding in points
2797
+ * @example
2798
+ * ```typescript
2799
+ * node.setPadding(EDGE_ALL, 10); // Set 10pt padding on all edges
2800
+ * node.setPadding(EDGE_HORIZONTAL, 5); // Set 5pt padding on left and right
2801
+ * ```
2802
+ */
2803
+ setPadding(edge, value) {
2804
+ setEdgeValue(this._style.padding, edge, value, 1);
2805
+ this.markDirty();
2806
+ }
2807
+ /**
2808
+ * Set padding as a percentage of the parent's width.
2809
+ * Per CSS spec, percentage padding always resolves against the containing block's width.
2810
+ *
2811
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2812
+ * @param value - Padding as a percentage (0-100)
2813
+ */
2814
+ setPaddingPercent(edge, value) {
2815
+ setEdgeValue(this._style.padding, edge, value, 2);
2816
+ this.markDirty();
2817
+ }
2818
+ /**
2819
+ * Set margin for one or more edges.
2820
+ *
2821
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2822
+ * @param value - Margin in points
2823
+ * @example
2824
+ * ```typescript
2825
+ * node.setMargin(EDGE_ALL, 5); // Set 5pt margin on all edges
2826
+ * node.setMargin(EDGE_TOP, 10); // Set 10pt margin on top only
2827
+ * ```
2828
+ */
2829
+ setMargin(edge, value) {
2830
+ setEdgeValue(this._style.margin, edge, value, 1);
2831
+ this.markDirty();
2832
+ }
2833
+ /**
2834
+ * Set margin as a percentage of the parent's size.
2835
+ *
2836
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2837
+ * @param value - Margin as a percentage (0-100)
2838
+ */
2839
+ setMarginPercent(edge, value) {
2840
+ setEdgeValue(this._style.margin, edge, value, 2);
2841
+ this.markDirty();
2842
+ }
2843
+ /**
2844
+ * Set margin to auto (for centering items with margin: auto).
2845
+ *
2846
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2847
+ */
2848
+ setMarginAuto(edge) {
2849
+ setEdgeValue(this._style.margin, edge, 0, 3);
2850
+ this.markDirty();
2851
+ }
2852
+ /**
2853
+ * Set border width for one or more edges.
2854
+ *
2855
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2856
+ * @param value - Border width in points
2857
+ */
2858
+ setBorder(edge, value) {
2859
+ setEdgeBorder(this._style.border, edge, value);
2860
+ this.markDirty();
2861
+ }
2862
+ /**
2863
+ * Set gap between flex items.
2864
+ *
2865
+ * @param gutter - GUTTER_COLUMN (horizontal gap), GUTTER_ROW (vertical gap), or GUTTER_ALL (both)
2866
+ * @param value - Gap size in points
2867
+ * @example
2868
+ * ```typescript
2869
+ * container.setGap(GUTTER_ALL, 8); // Set 8pt gap between all items
2870
+ * container.setGap(GUTTER_COLUMN, 10); // Set 10pt horizontal gap only
2871
+ * ```
2872
+ */
2873
+ setGap(gutter, value) {
2874
+ if (gutter === 0) this._style.gap[0] = value;
2875
+ else if (gutter === 1) this._style.gap[1] = value;
2876
+ else if (gutter === 2) {
2877
+ this._style.gap[0] = value;
2878
+ this._style.gap[1] = value;
2879
+ }
2880
+ this.markDirty();
2881
+ }
2882
+ /**
2883
+ * Set the position type.
2884
+ *
2885
+ * @param positionType - POSITION_TYPE_STATIC, POSITION_TYPE_RELATIVE, or POSITION_TYPE_ABSOLUTE
2886
+ * @example
2887
+ * ```typescript
2888
+ * node.setPositionType(POSITION_TYPE_ABSOLUTE);
2889
+ * node.setPosition(EDGE_LEFT, 10);
2890
+ * node.setPosition(EDGE_TOP, 20);
2891
+ * ```
2892
+ */
2893
+ setPositionType(positionType) {
2894
+ this._style.positionType = positionType;
2895
+ this.markDirty();
2896
+ }
2897
+ /**
2898
+ * Set position offset for one or more edges.
2899
+ * Only applies when position type is ABSOLUTE or RELATIVE.
2900
+ *
2901
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2902
+ * @param value - Position offset in points
2903
+ */
2904
+ setPosition(edge, value) {
2905
+ if (Number.isNaN(value)) setEdgeValue(this._style.position, edge, 0, 0);
2906
+ else setEdgeValue(this._style.position, edge, value, 1);
2907
+ this.markDirty();
2908
+ }
2909
+ /**
2910
+ * Set position offset as a percentage.
2911
+ *
2912
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
2913
+ * @param value - Position offset as a percentage of parent's corresponding dimension
2914
+ */
2915
+ setPositionPercent(edge, value) {
2916
+ setEdgeValue(this._style.position, edge, value, 2);
2917
+ this.markDirty();
2918
+ }
2919
+ /**
2920
+ * Set the display type.
2921
+ *
2922
+ * @param display - DISPLAY_FLEX or DISPLAY_NONE
2923
+ */
2924
+ setDisplay(display) {
2925
+ this._style.display = display;
2926
+ this.markDirty();
2927
+ }
2928
+ /**
2929
+ * Set the overflow behavior.
2930
+ *
2931
+ * @param overflow - OVERFLOW_VISIBLE, OVERFLOW_HIDDEN, or OVERFLOW_SCROLL
2932
+ */
2933
+ setOverflow(overflow) {
2934
+ this._style.overflow = overflow;
2935
+ this.markDirty();
2936
+ }
2937
+ /**
2938
+ * Get the width style value.
2939
+ *
2940
+ * @returns Width value with unit (points, percent, or auto)
2941
+ */
2942
+ getWidth() {
2943
+ return this._style.width;
2944
+ }
2945
+ /**
2946
+ * Get the height style value.
2947
+ *
2948
+ * @returns Height value with unit (points, percent, or auto)
2949
+ */
2950
+ getHeight() {
2951
+ return this._style.height;
2952
+ }
2953
+ /**
2954
+ * Get the minimum width style value.
2955
+ *
2956
+ * @returns Minimum width value with unit
2957
+ */
2958
+ getMinWidth() {
2959
+ return this._style.minWidth;
2960
+ }
2961
+ /**
2962
+ * Get the minimum height style value.
2963
+ *
2964
+ * @returns Minimum height value with unit
2965
+ */
2966
+ getMinHeight() {
2967
+ return this._style.minHeight;
2968
+ }
2969
+ /**
2970
+ * Get the maximum width style value.
2971
+ *
2972
+ * @returns Maximum width value with unit
2973
+ */
2974
+ getMaxWidth() {
2975
+ return this._style.maxWidth;
2976
+ }
2977
+ /**
2978
+ * Get the maximum height style value.
2979
+ *
2980
+ * @returns Maximum height value with unit
2981
+ */
2982
+ getMaxHeight() {
2983
+ return this._style.maxHeight;
2984
+ }
2985
+ /**
2986
+ * Get the aspect ratio.
2987
+ *
2988
+ * @returns Aspect ratio value (NaN if not set)
2989
+ */
2990
+ getAspectRatio() {
2991
+ return this._style.aspectRatio;
2992
+ }
2993
+ /**
2994
+ * Get the flex grow factor.
2995
+ *
2996
+ * @returns Flex grow value
2997
+ */
2998
+ getFlexGrow() {
2999
+ return this._style.flexGrow;
3000
+ }
3001
+ /**
3002
+ * Get the flex shrink factor.
3003
+ *
3004
+ * @returns Flex shrink value
3005
+ */
3006
+ getFlexShrink() {
3007
+ return this._style.flexShrink;
3008
+ }
3009
+ /**
3010
+ * Get the flex basis style value.
3011
+ *
3012
+ * @returns Flex basis value with unit
3013
+ */
3014
+ getFlexBasis() {
3015
+ return this._style.flexBasis;
3016
+ }
3017
+ /**
3018
+ * Get the flex direction.
3019
+ *
3020
+ * @returns Flex direction constant
3021
+ */
3022
+ getFlexDirection() {
3023
+ return this._style.flexDirection;
3024
+ }
3025
+ /**
3026
+ * Get the flex wrap setting.
3027
+ *
3028
+ * @returns Flex wrap constant
3029
+ */
3030
+ getFlexWrap() {
3031
+ return this._style.flexWrap;
3032
+ }
3033
+ /**
3034
+ * Get the align items setting.
3035
+ *
3036
+ * @returns Align items constant
3037
+ */
3038
+ getAlignItems() {
3039
+ return this._style.alignItems;
3040
+ }
3041
+ /**
3042
+ * Get the align self setting.
3043
+ *
3044
+ * @returns Align self constant
3045
+ */
3046
+ getAlignSelf() {
3047
+ return this._style.alignSelf;
3048
+ }
3049
+ /**
3050
+ * Get the align content setting.
3051
+ *
3052
+ * @returns Align content constant
3053
+ */
3054
+ getAlignContent() {
3055
+ return this._style.alignContent;
3056
+ }
3057
+ /**
3058
+ * Get the justify content setting.
3059
+ *
3060
+ * @returns Justify content constant
3061
+ */
3062
+ getJustifyContent() {
3063
+ return this._style.justifyContent;
3064
+ }
3065
+ /**
3066
+ * Get the padding for a specific edge.
3067
+ *
3068
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
3069
+ * @returns Padding value with unit
3070
+ */
3071
+ getPadding(edge) {
3072
+ return getEdgeValue(this._style.padding, edge);
3073
+ }
3074
+ /**
3075
+ * Get the margin for a specific edge.
3076
+ *
3077
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
3078
+ * @returns Margin value with unit
3079
+ */
3080
+ getMargin(edge) {
3081
+ return getEdgeValue(this._style.margin, edge);
3082
+ }
3083
+ /**
3084
+ * Get the border width for a specific edge.
3085
+ *
3086
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
3087
+ * @returns Border width in points
3088
+ */
3089
+ getBorder(edge) {
3090
+ return getEdgeBorderValue(this._style.border, edge);
3091
+ }
3092
+ /**
3093
+ * Get the position offset for a specific edge.
3094
+ *
3095
+ * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
3096
+ * @returns Position value with unit
3097
+ */
3098
+ getPosition(edge) {
3099
+ return getEdgeValue(this._style.position, edge);
3100
+ }
3101
+ /**
3102
+ * Get the position type.
3103
+ *
3104
+ * @returns Position type constant
3105
+ */
3106
+ getPositionType() {
3107
+ return this._style.positionType;
3108
+ }
3109
+ /**
3110
+ * Get the display type.
3111
+ *
3112
+ * @returns Display constant
3113
+ */
3114
+ getDisplay() {
3115
+ return this._style.display;
3116
+ }
3117
+ /**
3118
+ * Get the overflow setting.
3119
+ *
3120
+ * @returns Overflow constant
3121
+ */
3122
+ getOverflow() {
3123
+ return this._style.overflow;
3124
+ }
3125
+ /**
3126
+ * Get the gap for column or row.
3127
+ *
3128
+ * @param gutter - GUTTER_COLUMN or GUTTER_ROW
3129
+ * @returns Gap size in points
3130
+ */
3131
+ getGap(gutter) {
3132
+ if (gutter === 0) return this._style.gap[0];
3133
+ else if (gutter === 1) return this._style.gap[1];
3134
+ return this._style.gap[0];
3135
+ }
3136
+ };
3137
+ new Intl.Segmenter(void 0, { granularity: "grapheme" });
3138
+ new Intl.Segmenter(void 0, { granularity: "grapheme" });
3139
+ //#endregion
3140
+ //#region ../packages/ag-term/src/adapters/flexily-zero-adapter.ts
3141
+ /**
3142
+ * Flexily Layout Engine Adapter
3143
+ *
3144
+ * Wraps Flexily to implement the LayoutEngine interface.
3145
+ * Uses the default zero-allocation algorithm from flexily.
3146
+ */
3147
+ /**
3148
+ * Wraps a Flexily zero-alloc node to implement LayoutNode interface.
3149
+ * Since Flexily already has a Yoga-compatible API, this is mostly delegation.
3150
+ */
3151
+ var FlexilyZeroNodeAdapter = class {
3152
+ node;
3153
+ constructor(node) {
3154
+ this.node = node;
3155
+ }
3156
+ /** Get the underlying Flexily node (for tree operations) */
3157
+ getFlexilyNode() {
3158
+ return this.node;
3159
+ }
3160
+ insertChild(child, index) {
3161
+ const flexilyChild = child.getFlexilyNode();
3162
+ this.node.insertChild(flexilyChild, index);
3163
+ }
3164
+ removeChild(child) {
3165
+ const flexilyChild = child.getFlexilyNode();
3166
+ this.node.removeChild(flexilyChild);
3167
+ }
3168
+ free() {
3169
+ this.node.free();
3170
+ }
3171
+ setMeasureFunc(measureFunc) {
3172
+ this.node.setMeasureFunc((width, widthMode, height, heightMode) => {
3173
+ return measureFunc(width, this.measureModeToString(widthMode), height, this.measureModeToString(heightMode));
3174
+ });
3175
+ }
3176
+ markDirty() {
3177
+ this.node.markDirty();
3178
+ }
3179
+ measureModeToString(mode) {
3180
+ if (mode === 1) return "exactly";
3181
+ if (mode === 2) return "at-most";
3182
+ return "undefined";
3183
+ }
3184
+ setWidth(value) {
3185
+ this.node.setWidth(value);
3186
+ }
3187
+ setWidthPercent(value) {
3188
+ this.node.setWidthPercent(value);
3189
+ }
3190
+ setWidthAuto() {
3191
+ this.node.setWidthAuto();
3192
+ }
3193
+ setHeight(value) {
3194
+ this.node.setHeight(value);
3195
+ }
3196
+ setHeightPercent(value) {
3197
+ this.node.setHeightPercent(value);
3198
+ }
3199
+ setHeightAuto() {
3200
+ this.node.setHeightAuto();
3201
+ }
3202
+ setMinWidth(value) {
3203
+ this.node.setMinWidth(value);
3204
+ }
3205
+ setMinWidthPercent(value) {
3206
+ this.node.setMinWidthPercent(value);
3207
+ }
3208
+ setMinHeight(value) {
3209
+ this.node.setMinHeight(value);
3210
+ }
3211
+ setMinHeightPercent(value) {
3212
+ this.node.setMinHeightPercent(value);
3213
+ }
3214
+ setMaxWidth(value) {
3215
+ this.node.setMaxWidth(value);
3216
+ }
3217
+ setMaxWidthPercent(value) {
3218
+ this.node.setMaxWidthPercent(value);
3219
+ }
3220
+ setMaxHeight(value) {
3221
+ this.node.setMaxHeight(value);
3222
+ }
3223
+ setMaxHeightPercent(value) {
3224
+ this.node.setMaxHeightPercent(value);
3225
+ }
3226
+ setFlexGrow(value) {
3227
+ this.node.setFlexGrow(value);
3228
+ }
3229
+ setFlexShrink(value) {
3230
+ this.node.setFlexShrink(value);
3231
+ }
3232
+ setFlexBasis(value) {
3233
+ this.node.setFlexBasis(value);
3234
+ }
3235
+ setFlexBasisPercent(value) {
3236
+ this.node.setFlexBasisPercent(value);
3237
+ }
3238
+ setFlexBasisAuto() {
3239
+ this.node.setFlexBasisAuto();
3240
+ }
3241
+ setFlexDirection(direction) {
3242
+ this.node.setFlexDirection(direction);
3243
+ }
3244
+ setFlexWrap(wrap) {
3245
+ this.node.setFlexWrap(wrap);
3246
+ }
3247
+ setAlignItems(align) {
3248
+ this.node.setAlignItems(align);
3249
+ }
3250
+ setAlignSelf(align) {
3251
+ this.node.setAlignSelf(align);
3252
+ }
3253
+ setAlignContent(align) {
3254
+ this.node.setAlignContent(align);
3255
+ }
3256
+ setJustifyContent(justify) {
3257
+ this.node.setJustifyContent(justify);
3258
+ }
3259
+ setPadding(edge, value) {
3260
+ this.node.setPadding(edge, value);
3261
+ }
3262
+ setMargin(edge, value) {
3263
+ this.node.setMargin(edge, value);
3264
+ }
3265
+ setBorder(edge, value) {
3266
+ this.node.setBorder(edge, value);
3267
+ }
3268
+ setGap(gutter, value) {
3269
+ this.node.setGap(gutter, value);
3270
+ }
3271
+ setDisplay(display) {
3272
+ this.node.setDisplay(display);
3273
+ }
3274
+ setPositionType(positionType) {
3275
+ this.node.setPositionType(positionType);
3276
+ }
3277
+ setPosition(edge, value) {
3278
+ this.node.setPosition(edge, value);
3279
+ }
3280
+ setPositionPercent(edge, value) {
3281
+ this.node.setPositionPercent(edge, value);
3282
+ }
3283
+ setOverflow(overflow) {
3284
+ this.node.setOverflow(overflow);
3285
+ }
3286
+ setAspectRatio(value) {
3287
+ this.node.setAspectRatio(value);
3288
+ }
3289
+ calculateLayout(width, height, direction) {
3290
+ this.node.calculateLayout(width, height, direction ?? 1);
3291
+ }
3292
+ getComputedLeft() {
3293
+ return this.node.getComputedLeft();
3294
+ }
3295
+ getComputedTop() {
3296
+ return this.node.getComputedTop();
3297
+ }
3298
+ getComputedWidth() {
3299
+ return this.node.getComputedWidth();
3300
+ }
3301
+ getComputedHeight() {
3302
+ return this.node.getComputedHeight();
3303
+ }
3304
+ };
3305
+ /**
3306
+ * Layout engine implementation using Flexily zero-allocation variant.
3307
+ * Optimized for high-frequency layout with reduced GC pressure.
3308
+ */
3309
+ var FlexilyZeroLayoutEngine = class {
3310
+ _constants = {
3311
+ FLEX_DIRECTION_COLUMN: 0,
3312
+ FLEX_DIRECTION_COLUMN_REVERSE: 1,
3313
+ FLEX_DIRECTION_ROW: 2,
3314
+ FLEX_DIRECTION_ROW_REVERSE: 3,
3315
+ WRAP_NO_WRAP: 0,
3316
+ WRAP_WRAP: 1,
3317
+ WRAP_WRAP_REVERSE: 2,
3318
+ ALIGN_AUTO: 0,
3319
+ ALIGN_FLEX_START: 1,
3320
+ ALIGN_CENTER: 2,
3321
+ ALIGN_FLEX_END: 3,
3322
+ ALIGN_STRETCH: 4,
3323
+ ALIGN_BASELINE: 5,
3324
+ ALIGN_SPACE_BETWEEN: 6,
3325
+ ALIGN_SPACE_AROUND: 7,
3326
+ ALIGN_SPACE_EVENLY: 8,
3327
+ JUSTIFY_FLEX_START: 0,
3328
+ JUSTIFY_CENTER: 1,
3329
+ JUSTIFY_FLEX_END: 2,
3330
+ JUSTIFY_SPACE_BETWEEN: 3,
3331
+ JUSTIFY_SPACE_AROUND: 4,
3332
+ JUSTIFY_SPACE_EVENLY: 5,
3333
+ EDGE_LEFT: 0,
3334
+ EDGE_TOP: 1,
3335
+ EDGE_RIGHT: 2,
3336
+ EDGE_BOTTOM: 3,
3337
+ EDGE_HORIZONTAL: 6,
3338
+ EDGE_VERTICAL: 7,
3339
+ EDGE_ALL: 8,
3340
+ GUTTER_COLUMN: 0,
3341
+ GUTTER_ROW: 1,
3342
+ GUTTER_ALL: 2,
3343
+ DISPLAY_FLEX: 0,
3344
+ DISPLAY_NONE: 1,
3345
+ POSITION_TYPE_STATIC: 0,
3346
+ POSITION_TYPE_RELATIVE: 1,
3347
+ POSITION_TYPE_ABSOLUTE: 2,
3348
+ OVERFLOW_VISIBLE: 0,
3349
+ OVERFLOW_HIDDEN: 1,
3350
+ OVERFLOW_SCROLL: 2,
3351
+ DIRECTION_LTR: 1,
3352
+ MEASURE_MODE_UNDEFINED: 0,
3353
+ MEASURE_MODE_EXACTLY: 1,
3354
+ MEASURE_MODE_AT_MOST: 2
3355
+ };
3356
+ createNode() {
3357
+ return new FlexilyZeroNodeAdapter(Node.create());
3358
+ }
3359
+ get constants() {
3360
+ return this._constants;
3361
+ }
3362
+ get name() {
3363
+ return "flexily-zero";
3364
+ }
3365
+ };
3366
+ /**
3367
+ * Create a Flexily zero-allocation layout engine.
3368
+ * Unlike Yoga, Flexily doesn't require async initialization.
3369
+ */
3370
+ function createFlexilyZeroEngine() {
3371
+ return new FlexilyZeroLayoutEngine();
3372
+ }
3373
+ //#endregion
3374
+ export { createFlexilyZeroEngine };