flexily 0.3.0 → 0.3.1

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 (73) hide show
  1. package/README.md +2 -0
  2. package/package.json +16 -24
  3. package/src/classic/layout.ts +2 -2
  4. package/src/layout-helpers.ts +2 -2
  5. package/dist/classic/layout.d.ts +0 -57
  6. package/dist/classic/layout.d.ts.map +0 -1
  7. package/dist/classic/layout.js +0 -1567
  8. package/dist/classic/layout.js.map +0 -1
  9. package/dist/classic/node.d.ts +0 -648
  10. package/dist/classic/node.d.ts.map +0 -1
  11. package/dist/classic/node.js +0 -1002
  12. package/dist/classic/node.js.map +0 -1
  13. package/dist/constants.d.ts +0 -59
  14. package/dist/constants.d.ts.map +0 -1
  15. package/dist/constants.js +0 -71
  16. package/dist/constants.js.map +0 -1
  17. package/dist/index-classic.d.ts +0 -30
  18. package/dist/index-classic.d.ts.map +0 -1
  19. package/dist/index-classic.js +0 -57
  20. package/dist/index-classic.js.map +0 -1
  21. package/dist/index.d.ts +0 -30
  22. package/dist/index.d.ts.map +0 -1
  23. package/dist/index.js +0 -57
  24. package/dist/index.js.map +0 -1
  25. package/dist/layout-flex-lines.d.ts +0 -77
  26. package/dist/layout-flex-lines.d.ts.map +0 -1
  27. package/dist/layout-flex-lines.js +0 -317
  28. package/dist/layout-flex-lines.js.map +0 -1
  29. package/dist/layout-helpers.d.ts +0 -45
  30. package/dist/layout-helpers.d.ts.map +0 -1
  31. package/dist/layout-helpers.js +0 -103
  32. package/dist/layout-helpers.js.map +0 -1
  33. package/dist/layout-measure.d.ts +0 -25
  34. package/dist/layout-measure.d.ts.map +0 -1
  35. package/dist/layout-measure.js +0 -231
  36. package/dist/layout-measure.js.map +0 -1
  37. package/dist/layout-stats.d.ts +0 -19
  38. package/dist/layout-stats.d.ts.map +0 -1
  39. package/dist/layout-stats.js +0 -37
  40. package/dist/layout-stats.js.map +0 -1
  41. package/dist/layout-traversal.d.ts +0 -28
  42. package/dist/layout-traversal.d.ts.map +0 -1
  43. package/dist/layout-traversal.js +0 -65
  44. package/dist/layout-traversal.js.map +0 -1
  45. package/dist/layout-zero.d.ts +0 -26
  46. package/dist/layout-zero.d.ts.map +0 -1
  47. package/dist/layout-zero.js +0 -1757
  48. package/dist/layout-zero.js.map +0 -1
  49. package/dist/logger.d.ts +0 -14
  50. package/dist/logger.d.ts.map +0 -1
  51. package/dist/logger.js +0 -61
  52. package/dist/logger.js.map +0 -1
  53. package/dist/node-zero.d.ts +0 -702
  54. package/dist/node-zero.d.ts.map +0 -1
  55. package/dist/node-zero.js +0 -1268
  56. package/dist/node-zero.js.map +0 -1
  57. package/dist/testing.d.ts +0 -69
  58. package/dist/testing.d.ts.map +0 -1
  59. package/dist/testing.js +0 -179
  60. package/dist/testing.js.map +0 -1
  61. package/dist/trace.d.ts +0 -74
  62. package/dist/trace.d.ts.map +0 -1
  63. package/dist/trace.js +0 -191
  64. package/dist/trace.js.map +0 -1
  65. package/dist/types.d.ts +0 -170
  66. package/dist/types.d.ts.map +0 -1
  67. package/dist/types.js +0 -43
  68. package/dist/types.js.map +0 -1
  69. package/dist/utils.d.ts +0 -49
  70. package/dist/utils.d.ts.map +0 -1
  71. package/dist/utils.js +0 -222
  72. package/dist/utils.js.map +0 -1
  73. package/src/beorn-logger.d.ts +0 -10
package/dist/node-zero.js DELETED
@@ -1,1268 +0,0 @@
1
- /**
2
- * Flexily Node
3
- *
4
- * Yoga-compatible Node class for flexbox layout.
5
- */
6
- import * as C from "./constants.js";
7
- import { computeLayout, countNodes, markSubtreeLayoutSeen } from "./layout-zero.js";
8
- import { createDefaultStyle, } from "./types.js";
9
- import { setEdgeValue, setEdgeBorder, getEdgeValue, getEdgeBorderValue, traversalStack } from "./utils.js";
10
- import { log } from "./logger.js";
11
- /**
12
- * A layout node in the flexbox tree.
13
- */
14
- export class Node {
15
- // Tree structure
16
- _parent = null;
17
- _children = [];
18
- // Style
19
- _style = createDefaultStyle();
20
- // Measure function for intrinsic sizing
21
- _measureFunc = null;
22
- // Baseline function for baseline alignment
23
- _baselineFunc = null;
24
- // Measure cache - 4-entry numeric cache (faster than Map<string,...>)
25
- // Each entry stores: w, wm, h, hm, rw, rh
26
- // Cleared when markDirty() is called since content may have changed
27
- _m0;
28
- _m1;
29
- _m2;
30
- _m3;
31
- // Layout cache - 2-entry cache for sizing pass (availW, availH -> computedW, computedH)
32
- // Cleared at start of each calculateLayout pass via resetLayoutCache()
33
- // This avoids redundant recursive layout calls during intrinsic sizing
34
- _lc0;
35
- _lc1;
36
- // Stable result objects for zero-allocation cache returns
37
- // These are mutated in place instead of creating new objects on each cache hit
38
- _measureResult = {
39
- width: 0,
40
- height: 0,
41
- };
42
- _layoutResult = {
43
- width: 0,
44
- height: 0,
45
- };
46
- // Static counters for cache statistics (reset per layout pass)
47
- static measureCalls = 0;
48
- static measureCacheHits = 0;
49
- /**
50
- * Reset measure statistics (call before calculateLayout).
51
- */
52
- static resetMeasureStats() {
53
- Node.measureCalls = 0;
54
- Node.measureCacheHits = 0;
55
- }
56
- // Computed layout
57
- _layout = { left: 0, top: 0, width: 0, height: 0 };
58
- // Per-node flex calculation state (reused across layout passes to avoid allocation)
59
- _flex = {
60
- mainSize: 0,
61
- baseSize: 0,
62
- mainMargin: 0,
63
- flexGrow: 0,
64
- flexShrink: 0,
65
- minMain: 0,
66
- maxMain: Infinity,
67
- mainStartMarginAuto: false,
68
- mainEndMarginAuto: false,
69
- mainStartMarginValue: 0,
70
- mainEndMarginValue: 0,
71
- marginL: 0,
72
- marginT: 0,
73
- marginR: 0,
74
- marginB: 0,
75
- frozen: false,
76
- lineIndex: 0,
77
- relativeIndex: -1,
78
- baseline: 0,
79
- // Constraint fingerprinting
80
- lastAvailW: NaN,
81
- lastAvailH: NaN,
82
- lastOffsetX: NaN,
83
- lastOffsetY: NaN,
84
- layoutValid: false,
85
- lastDir: 0,
86
- };
87
- // Dirty flags
88
- _isDirty = true;
89
- _hasNewLayout = false;
90
- // Last calculateLayout() inputs (for constraint-aware skip)
91
- _lastCalcW = NaN;
92
- _lastCalcH = NaN;
93
- _lastCalcDir = 0;
94
- // ============================================================================
95
- // Static Factory
96
- // ============================================================================
97
- /**
98
- * Create a new layout node.
99
- *
100
- * @returns A new Node instance
101
- * @example
102
- * ```typescript
103
- * const root = Node.create();
104
- * root.setWidth(100);
105
- * root.setHeight(200);
106
- * ```
107
- */
108
- static create() {
109
- return new Node();
110
- }
111
- // ============================================================================
112
- // Tree Operations
113
- // ============================================================================
114
- /**
115
- * Get the number of child nodes.
116
- *
117
- * @returns The number of children
118
- */
119
- getChildCount() {
120
- return this._children.length;
121
- }
122
- /**
123
- * Get a child node by index.
124
- *
125
- * @param index - Zero-based child index
126
- * @returns The child node at the given index, or undefined if index is out of bounds
127
- */
128
- getChild(index) {
129
- return this._children[index];
130
- }
131
- /**
132
- * Get the parent node.
133
- *
134
- * @returns The parent node, or null if this is a root node
135
- */
136
- getParent() {
137
- return this._parent;
138
- }
139
- /**
140
- * Insert a child node at the specified index.
141
- * If the child already has a parent, it will be removed from that parent first.
142
- * Marks the node as dirty to trigger layout recalculation.
143
- *
144
- * @param child - The child node to insert
145
- * @param index - The index at which to insert the child
146
- * @example
147
- * ```typescript
148
- * const parent = Node.create();
149
- * const child1 = Node.create();
150
- * const child2 = Node.create();
151
- * parent.insertChild(child1, 0);
152
- * parent.insertChild(child2, 1);
153
- * ```
154
- */
155
- insertChild(child, index) {
156
- if (child._parent !== null) {
157
- child._parent.removeChild(child);
158
- }
159
- child._parent = this;
160
- // Clamp index to valid range to ensure deterministic behavior
161
- const clampedIndex = Math.max(0, Math.min(index, this._children.length));
162
- this._children.splice(clampedIndex, 0, child);
163
- // Invalidate layoutValid for siblings after the insertion point
164
- // Their positions may change due to the insertion
165
- for (let i = clampedIndex + 1; i < this._children.length; i++) {
166
- this._children[i]._flex.layoutValid = false;
167
- }
168
- this.markDirty();
169
- }
170
- /**
171
- * Remove a child node from this node.
172
- * The child's parent reference will be cleared.
173
- * Marks the node as dirty to trigger layout recalculation.
174
- * Invalidates layout validity of remaining siblings whose positions may change.
175
- *
176
- * @param child - The child node to remove
177
- */
178
- removeChild(child) {
179
- const index = this._children.indexOf(child);
180
- if (index !== -1) {
181
- this._children.splice(index, 1);
182
- child._parent = null;
183
- // Invalidate layoutValid for remaining siblings after the removal point
184
- // Their positions may change due to the removal
185
- for (let i = index; i < this._children.length; i++) {
186
- this._children[i]._flex.layoutValid = false;
187
- }
188
- this.markDirty();
189
- }
190
- }
191
- /**
192
- * Free this node and clean up all references.
193
- * Removes the node from its parent, clears all children, and removes the measure function.
194
- * This does not recursively free child nodes.
195
- */
196
- free() {
197
- // Remove from parent
198
- if (this._parent !== null) {
199
- this._parent.removeChild(this);
200
- }
201
- // Clear children
202
- for (const child of this._children) {
203
- child._parent = null;
204
- }
205
- this._children = [];
206
- this._measureFunc = null;
207
- this._baselineFunc = null;
208
- }
209
- /**
210
- * Dispose the node (calls free)
211
- */
212
- [Symbol.dispose]() {
213
- this.free();
214
- }
215
- // ============================================================================
216
- // Measure Function
217
- // ============================================================================
218
- /**
219
- * Set a measure function for intrinsic sizing.
220
- * The measure function is called during layout to determine the node's natural size.
221
- * Typically used for text nodes or other content that has an intrinsic size.
222
- * Marks the node as dirty to trigger layout recalculation.
223
- *
224
- * @param measureFunc - Function that returns width and height given available space and constraints
225
- * @example
226
- * ```typescript
227
- * const textNode = Node.create();
228
- * textNode.setMeasureFunc((width, widthMode, height, heightMode) => {
229
- * // Measure text and return dimensions
230
- * return { width: 50, height: 20 };
231
- * });
232
- * ```
233
- */
234
- setMeasureFunc(measureFunc) {
235
- this._measureFunc = measureFunc;
236
- this.markDirty();
237
- }
238
- /**
239
- * Remove the measure function from this node.
240
- * Marks the node as dirty to trigger layout recalculation.
241
- */
242
- unsetMeasureFunc() {
243
- this._measureFunc = null;
244
- this.markDirty();
245
- }
246
- /**
247
- * Check if this node has a measure function.
248
- *
249
- * @returns True if a measure function is set
250
- */
251
- hasMeasureFunc() {
252
- return this._measureFunc !== null;
253
- }
254
- // ============================================================================
255
- // Baseline Function
256
- // ============================================================================
257
- /**
258
- * Set a baseline function to determine where this node's text baseline is.
259
- * Used for ALIGN_BASELINE to align text across siblings with different heights.
260
- *
261
- * @param baselineFunc - Function that returns baseline offset from top given width and height
262
- * @example
263
- * ```typescript
264
- * textNode.setBaselineFunc((width, height) => {
265
- * // For a text node, baseline might be at 80% of height
266
- * return height * 0.8;
267
- * });
268
- * ```
269
- */
270
- setBaselineFunc(baselineFunc) {
271
- this._baselineFunc = baselineFunc;
272
- this.markDirty();
273
- }
274
- /**
275
- * Remove the baseline function from this node.
276
- * Marks the node as dirty to trigger layout recalculation.
277
- */
278
- unsetBaselineFunc() {
279
- this._baselineFunc = null;
280
- this.markDirty();
281
- }
282
- /**
283
- * Check if this node has a baseline function.
284
- *
285
- * @returns True if a baseline function is set
286
- */
287
- hasBaselineFunc() {
288
- return this._baselineFunc !== null;
289
- }
290
- /**
291
- * Call the measure function with caching.
292
- * Uses a 4-entry numeric cache for fast lookup without allocations.
293
- * Cache is cleared when markDirty() is called.
294
- *
295
- * @returns Measured dimensions or null if no measure function
296
- */
297
- cachedMeasure(w, wm, h, hm) {
298
- if (!this._measureFunc)
299
- return null;
300
- Node.measureCalls++;
301
- // Check 4-entry cache (most recent first)
302
- // Returns stable _measureResult object to avoid allocation on cache hit
303
- const m0 = this._m0;
304
- if (m0 && m0.w === w && m0.wm === wm && m0.h === h && m0.hm === hm) {
305
- Node.measureCacheHits++;
306
- this._measureResult.width = m0.rw;
307
- this._measureResult.height = m0.rh;
308
- return this._measureResult;
309
- }
310
- const m1 = this._m1;
311
- if (m1 && m1.w === w && m1.wm === wm && m1.h === h && m1.hm === hm) {
312
- Node.measureCacheHits++;
313
- this._measureResult.width = m1.rw;
314
- this._measureResult.height = m1.rh;
315
- return this._measureResult;
316
- }
317
- const m2 = this._m2;
318
- if (m2 && m2.w === w && m2.wm === wm && m2.h === h && m2.hm === hm) {
319
- Node.measureCacheHits++;
320
- this._measureResult.width = m2.rw;
321
- this._measureResult.height = m2.rh;
322
- return this._measureResult;
323
- }
324
- const m3 = this._m3;
325
- if (m3 && m3.w === w && m3.wm === wm && m3.h === h && m3.hm === hm) {
326
- Node.measureCacheHits++;
327
- this._measureResult.width = m3.rw;
328
- this._measureResult.height = m3.rh;
329
- return this._measureResult;
330
- }
331
- // Call actual measure function
332
- const result = this._measureFunc(w, wm, h, hm);
333
- // Zero-allocation: rotate entries by copying values, lazily allocate on first use
334
- // Rotate: m3 <- m2 <- m1 <- m0 <- new values
335
- if (this._m2) {
336
- if (!this._m3)
337
- this._m3 = { w: 0, wm: 0, h: 0, hm: 0, rw: 0, rh: 0 };
338
- this._m3.w = this._m2.w;
339
- this._m3.wm = this._m2.wm;
340
- this._m3.h = this._m2.h;
341
- this._m3.hm = this._m2.hm;
342
- this._m3.rw = this._m2.rw;
343
- this._m3.rh = this._m2.rh;
344
- }
345
- if (this._m1) {
346
- if (!this._m2)
347
- this._m2 = { w: 0, wm: 0, h: 0, hm: 0, rw: 0, rh: 0 };
348
- this._m2.w = this._m1.w;
349
- this._m2.wm = this._m1.wm;
350
- this._m2.h = this._m1.h;
351
- this._m2.hm = this._m1.hm;
352
- this._m2.rw = this._m1.rw;
353
- this._m2.rh = this._m1.rh;
354
- }
355
- if (this._m0) {
356
- if (!this._m1)
357
- this._m1 = { w: 0, wm: 0, h: 0, hm: 0, rw: 0, rh: 0 };
358
- this._m1.w = this._m0.w;
359
- this._m1.wm = this._m0.wm;
360
- this._m1.h = this._m0.h;
361
- this._m1.hm = this._m0.hm;
362
- this._m1.rw = this._m0.rw;
363
- this._m1.rh = this._m0.rh;
364
- }
365
- if (!this._m0)
366
- this._m0 = { w: 0, wm: 0, h: 0, hm: 0, rw: 0, rh: 0 };
367
- this._m0.w = w;
368
- this._m0.wm = wm;
369
- this._m0.h = h;
370
- this._m0.hm = hm;
371
- this._m0.rw = result.width;
372
- this._m0.rh = result.height;
373
- // Return stable result object (same as cache hits)
374
- this._measureResult.width = result.width;
375
- this._measureResult.height = result.height;
376
- return this._measureResult;
377
- }
378
- // ============================================================================
379
- // Layout Caching (for intrinsic sizing pass)
380
- // ============================================================================
381
- /**
382
- * Check layout cache for a previously computed size with same available dimensions.
383
- * Returns cached (width, height) or null if not found.
384
- *
385
- * NaN dimensions are handled specially via Object.is (NaN === NaN is false, but Object.is(NaN, NaN) is true).
386
- */
387
- getCachedLayout(availW, availH) {
388
- // Never return cached layout for dirty nodes - content may have changed
389
- if (this._isDirty) {
390
- return null;
391
- }
392
- // Returns stable _layoutResult object to avoid allocation on cache hit
393
- const lc0 = this._lc0;
394
- if (lc0 && Object.is(lc0.availW, availW) && Object.is(lc0.availH, availH)) {
395
- this._layoutResult.width = lc0.computedW;
396
- this._layoutResult.height = lc0.computedH;
397
- return this._layoutResult;
398
- }
399
- const lc1 = this._lc1;
400
- if (lc1 && Object.is(lc1.availW, availW) && Object.is(lc1.availH, availH)) {
401
- this._layoutResult.width = lc1.computedW;
402
- this._layoutResult.height = lc1.computedH;
403
- return this._layoutResult;
404
- }
405
- return null;
406
- }
407
- /**
408
- * Cache a computed layout result for the given available dimensions.
409
- * Zero-allocation: lazily allocates cache entries once, then reuses.
410
- */
411
- setCachedLayout(availW, availH, computedW, computedH) {
412
- // Rotate entries: copy _lc0 values to _lc1, then update _lc0
413
- if (this._lc0) {
414
- // Lazily allocate _lc1 on first rotation
415
- if (!this._lc1) {
416
- this._lc1 = { availW: NaN, availH: NaN, computedW: 0, computedH: 0 };
417
- }
418
- this._lc1.availW = this._lc0.availW;
419
- this._lc1.availH = this._lc0.availH;
420
- this._lc1.computedW = this._lc0.computedW;
421
- this._lc1.computedH = this._lc0.computedH;
422
- }
423
- // Lazily allocate _lc0 on first use
424
- if (!this._lc0) {
425
- this._lc0 = { availW: 0, availH: 0, computedW: 0, computedH: 0 };
426
- }
427
- this._lc0.availW = availW;
428
- this._lc0.availH = availH;
429
- this._lc0.computedW = computedW;
430
- this._lc0.computedH = computedH;
431
- }
432
- /**
433
- * Clear layout cache for this node and all descendants.
434
- * Called at the start of each calculateLayout pass.
435
- * Zero-allocation: invalidates entries (availW = NaN) rather than deallocating.
436
- * Uses iterative traversal to avoid stack overflow on deep trees.
437
- */
438
- resetLayoutCache() {
439
- traversalStack.length = 0;
440
- traversalStack.push(this);
441
- while (traversalStack.length > 0) {
442
- const node = traversalStack.pop();
443
- // Invalidate using -1 sentinel (not NaN — NaN is a legitimate "unconstrained" query
444
- // value and Object.is(NaN, NaN) === true would cause false cache hits)
445
- if (node._lc0)
446
- node._lc0.availW = -1;
447
- if (node._lc1)
448
- node._lc1.availW = -1;
449
- for (const child of node._children) {
450
- traversalStack.push(child);
451
- }
452
- }
453
- }
454
- // ============================================================================
455
- // Dirty Tracking
456
- // ============================================================================
457
- /**
458
- * Check if this node needs layout recalculation.
459
- *
460
- * @returns True if the node is dirty and needs layout
461
- */
462
- isDirty() {
463
- return this._isDirty;
464
- }
465
- /**
466
- * Mark this node and all ancestors as dirty.
467
- * A dirty node needs layout recalculation.
468
- * This is automatically called by all style setters and tree operations.
469
- * Uses iterative approach to avoid stack overflow on deep trees.
470
- */
471
- markDirty() {
472
- let current = this;
473
- while (current !== null) {
474
- // Always clear caches - even if already dirty, a child's content change
475
- // may invalidate cached layout results that used the old child size
476
- current._m0 = current._m1 = current._m2 = current._m3 = undefined;
477
- current._lc0 = current._lc1 = undefined;
478
- // Skip setting dirty flag if already dirty (but still cleared caches above)
479
- if (current._isDirty)
480
- break;
481
- current._isDirty = true;
482
- // Invalidate layout fingerprint
483
- current._flex.layoutValid = false;
484
- current = current._parent;
485
- }
486
- }
487
- /**
488
- * Check if this node has new layout results since the last check.
489
- *
490
- * @returns True if layout was recalculated since the last call to markLayoutSeen
491
- */
492
- hasNewLayout() {
493
- return this._hasNewLayout;
494
- }
495
- /**
496
- * Mark that the current layout has been seen/processed.
497
- * Clears the hasNewLayout flag.
498
- */
499
- markLayoutSeen() {
500
- this._hasNewLayout = false;
501
- }
502
- // ============================================================================
503
- // Layout Calculation
504
- // ============================================================================
505
- /**
506
- * Calculate layout for this node and all descendants.
507
- * This runs the flexbox layout algorithm to compute positions and sizes.
508
- * Only recalculates if the node is marked as dirty.
509
- *
510
- * @param width - Available width for layout
511
- * @param height - Available height for layout
512
- * @param _direction - Text direction (LTR or RTL), defaults to LTR
513
- * @example
514
- * ```typescript
515
- * const root = Node.create();
516
- * root.setFlexDirection(FLEX_DIRECTION_ROW);
517
- * root.setWidth(100);
518
- * root.setHeight(50);
519
- *
520
- * const child = Node.create();
521
- * child.setFlexGrow(1);
522
- * root.insertChild(child, 0);
523
- *
524
- * root.calculateLayout(100, 50, DIRECTION_LTR);
525
- *
526
- * // Now you can read computed layout
527
- * console.log(child.getComputedWidth());
528
- * ```
529
- */
530
- calculateLayout(width, height, direction = C.DIRECTION_LTR) {
531
- // Treat undefined as unconstrained (NaN signals content-based sizing)
532
- const availableWidth = width ?? NaN;
533
- const availableHeight = height ?? NaN;
534
- // Skip if not dirty AND constraints unchanged (use Object.is for NaN equality)
535
- if (!this._isDirty &&
536
- Object.is(this._lastCalcW, availableWidth) &&
537
- Object.is(this._lastCalcH, availableHeight) &&
538
- this._lastCalcDir === direction) {
539
- log.debug?.("layout skip (not dirty, constraints unchanged)");
540
- return;
541
- }
542
- // Track constraints for future skip check
543
- this._lastCalcW = availableWidth;
544
- this._lastCalcH = availableHeight;
545
- this._lastCalcDir = direction;
546
- const start = Date.now();
547
- const nodeCount = countNodes(this);
548
- // Reset measure statistics for this layout pass
549
- Node.resetMeasureStats();
550
- // Run the layout algorithm
551
- computeLayout(this, availableWidth, availableHeight, direction);
552
- // Mark layout computed
553
- this._isDirty = false;
554
- this._hasNewLayout = true;
555
- markSubtreeLayoutSeen(this);
556
- log.debug?.("layout: %dx%d, %d nodes in %dms (measure: calls=%d hits=%d)", width, height, nodeCount, Date.now() - start, Node.measureCalls, Node.measureCacheHits);
557
- }
558
- // ============================================================================
559
- // Layout Results
560
- // ============================================================================
561
- /**
562
- * Get the computed left position after layout.
563
- *
564
- * @returns The left position in points
565
- */
566
- getComputedLeft() {
567
- return this._layout.left;
568
- }
569
- /**
570
- * Get the computed top position after layout.
571
- *
572
- * @returns The top position in points
573
- */
574
- getComputedTop() {
575
- return this._layout.top;
576
- }
577
- /**
578
- * Get the computed width after layout.
579
- *
580
- * @returns The width in points
581
- */
582
- getComputedWidth() {
583
- return this._layout.width;
584
- }
585
- /**
586
- * Get the computed height after layout.
587
- *
588
- * @returns The height in points
589
- */
590
- getComputedHeight() {
591
- return this._layout.height;
592
- }
593
- // ============================================================================
594
- // Internal Accessors (for layout algorithm)
595
- // ============================================================================
596
- get children() {
597
- return this._children;
598
- }
599
- get style() {
600
- return this._style;
601
- }
602
- get layout() {
603
- return this._layout;
604
- }
605
- get measureFunc() {
606
- return this._measureFunc;
607
- }
608
- get baselineFunc() {
609
- return this._baselineFunc;
610
- }
611
- get flex() {
612
- return this._flex;
613
- }
614
- // ============================================================================
615
- // Width Setters
616
- // ============================================================================
617
- /**
618
- * Set the width to a fixed value in points.
619
- *
620
- * @param value - Width in points
621
- */
622
- setWidth(value) {
623
- // NaN means "auto" in Yoga API
624
- if (Number.isNaN(value)) {
625
- this._style.width = { value: 0, unit: C.UNIT_AUTO };
626
- }
627
- else {
628
- this._style.width = { value, unit: C.UNIT_POINT };
629
- }
630
- this.markDirty();
631
- }
632
- /**
633
- * Set the width as a percentage of the parent's width.
634
- *
635
- * @param value - Width as a percentage (0-100)
636
- */
637
- setWidthPercent(value) {
638
- this._style.width = { value, unit: C.UNIT_PERCENT };
639
- this.markDirty();
640
- }
641
- /**
642
- * Set the width to auto (determined by layout algorithm).
643
- */
644
- setWidthAuto() {
645
- this._style.width = { value: 0, unit: C.UNIT_AUTO };
646
- this.markDirty();
647
- }
648
- // ============================================================================
649
- // Height Setters
650
- // ============================================================================
651
- /**
652
- * Set the height to a fixed value in points.
653
- *
654
- * @param value - Height in points
655
- */
656
- setHeight(value) {
657
- // NaN means "auto" in Yoga API
658
- if (Number.isNaN(value)) {
659
- this._style.height = { value: 0, unit: C.UNIT_AUTO };
660
- }
661
- else {
662
- this._style.height = { value, unit: C.UNIT_POINT };
663
- }
664
- this.markDirty();
665
- }
666
- /**
667
- * Set the height as a percentage of the parent's height.
668
- *
669
- * @param value - Height as a percentage (0-100)
670
- */
671
- setHeightPercent(value) {
672
- this._style.height = { value, unit: C.UNIT_PERCENT };
673
- this.markDirty();
674
- }
675
- /**
676
- * Set the height to auto (determined by layout algorithm).
677
- */
678
- setHeightAuto() {
679
- this._style.height = { value: 0, unit: C.UNIT_AUTO };
680
- this.markDirty();
681
- }
682
- // ============================================================================
683
- // Min/Max Size Setters
684
- // ============================================================================
685
- /**
686
- * Set the minimum width in points.
687
- *
688
- * @param value - Minimum width in points
689
- */
690
- setMinWidth(value) {
691
- this._style.minWidth = { value, unit: C.UNIT_POINT };
692
- this.markDirty();
693
- }
694
- /**
695
- * Set the minimum width as a percentage of the parent's width.
696
- *
697
- * @param value - Minimum width as a percentage (0-100)
698
- */
699
- setMinWidthPercent(value) {
700
- this._style.minWidth = { value, unit: C.UNIT_PERCENT };
701
- this.markDirty();
702
- }
703
- /**
704
- * Set the minimum height in points.
705
- *
706
- * @param value - Minimum height in points
707
- */
708
- setMinHeight(value) {
709
- this._style.minHeight = { value, unit: C.UNIT_POINT };
710
- this.markDirty();
711
- }
712
- /**
713
- * Set the minimum height as a percentage of the parent's height.
714
- *
715
- * @param value - Minimum height as a percentage (0-100)
716
- */
717
- setMinHeightPercent(value) {
718
- this._style.minHeight = { value, unit: C.UNIT_PERCENT };
719
- this.markDirty();
720
- }
721
- /**
722
- * Set the maximum width in points.
723
- *
724
- * @param value - Maximum width in points
725
- */
726
- setMaxWidth(value) {
727
- this._style.maxWidth = { value, unit: C.UNIT_POINT };
728
- this.markDirty();
729
- }
730
- /**
731
- * Set the maximum width as a percentage of the parent's width.
732
- *
733
- * @param value - Maximum width as a percentage (0-100)
734
- */
735
- setMaxWidthPercent(value) {
736
- this._style.maxWidth = { value, unit: C.UNIT_PERCENT };
737
- this.markDirty();
738
- }
739
- /**
740
- * Set the maximum height in points.
741
- *
742
- * @param value - Maximum height in points
743
- */
744
- setMaxHeight(value) {
745
- this._style.maxHeight = { value, unit: C.UNIT_POINT };
746
- this.markDirty();
747
- }
748
- /**
749
- * Set the maximum height as a percentage of the parent's height.
750
- *
751
- * @param value - Maximum height as a percentage (0-100)
752
- */
753
- setMaxHeightPercent(value) {
754
- this._style.maxHeight = { value, unit: C.UNIT_PERCENT };
755
- this.markDirty();
756
- }
757
- /**
758
- * Set the aspect ratio of the node.
759
- * When set, the node's width/height relationship is constrained.
760
- * If width is defined, height = width / aspectRatio.
761
- * If height is defined, width = height * aspectRatio.
762
- *
763
- * @param value - Aspect ratio (width/height). Use NaN to unset.
764
- */
765
- setAspectRatio(value) {
766
- this._style.aspectRatio = value;
767
- this.markDirty();
768
- }
769
- // ============================================================================
770
- // Flex Setters
771
- // ============================================================================
772
- /**
773
- * Set the flex grow factor.
774
- * Determines how much the node will grow relative to siblings when there is extra space.
775
- *
776
- * @param value - Flex grow factor (typically 0 or 1+)
777
- * @example
778
- * ```typescript
779
- * const child = Node.create();
780
- * child.setFlexGrow(1); // Will grow to fill available space
781
- * ```
782
- */
783
- setFlexGrow(value) {
784
- this._style.flexGrow = value;
785
- this.markDirty();
786
- }
787
- /**
788
- * Set the flex shrink factor.
789
- * Determines how much the node will shrink relative to siblings when there is insufficient space.
790
- *
791
- * @param value - Flex shrink factor (default is 1)
792
- */
793
- setFlexShrink(value) {
794
- this._style.flexShrink = value;
795
- this.markDirty();
796
- }
797
- /**
798
- * Set the flex basis to a fixed value in points.
799
- * The initial size of the node before flex grow/shrink is applied.
800
- *
801
- * @param value - Flex basis in points
802
- */
803
- setFlexBasis(value) {
804
- this._style.flexBasis = { value, unit: C.UNIT_POINT };
805
- this.markDirty();
806
- }
807
- /**
808
- * Set the flex basis as a percentage of the parent's size.
809
- *
810
- * @param value - Flex basis as a percentage (0-100)
811
- */
812
- setFlexBasisPercent(value) {
813
- this._style.flexBasis = { value, unit: C.UNIT_PERCENT };
814
- this.markDirty();
815
- }
816
- /**
817
- * Set the flex basis to auto (based on the node's width/height).
818
- */
819
- setFlexBasisAuto() {
820
- this._style.flexBasis = { value: 0, unit: C.UNIT_AUTO };
821
- this.markDirty();
822
- }
823
- /**
824
- * Set the flex direction (main axis direction).
825
- *
826
- * @param direction - FLEX_DIRECTION_ROW, FLEX_DIRECTION_COLUMN, FLEX_DIRECTION_ROW_REVERSE, or FLEX_DIRECTION_COLUMN_REVERSE
827
- * @example
828
- * ```typescript
829
- * const container = Node.create();
830
- * container.setFlexDirection(FLEX_DIRECTION_ROW); // Lay out children horizontally
831
- * ```
832
- */
833
- setFlexDirection(direction) {
834
- this._style.flexDirection = direction;
835
- this.markDirty();
836
- }
837
- /**
838
- * Set the flex wrap behavior.
839
- *
840
- * @param wrap - WRAP_NO_WRAP, WRAP_WRAP, or WRAP_WRAP_REVERSE
841
- */
842
- setFlexWrap(wrap) {
843
- this._style.flexWrap = wrap;
844
- this.markDirty();
845
- }
846
- // ============================================================================
847
- // Alignment Setters
848
- // ============================================================================
849
- /**
850
- * Set how children are aligned along the cross axis.
851
- *
852
- * @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
853
- * @example
854
- * ```typescript
855
- * const container = Node.create();
856
- * container.setFlexDirection(FLEX_DIRECTION_ROW);
857
- * container.setAlignItems(ALIGN_CENTER); // Center children vertically
858
- * ```
859
- */
860
- setAlignItems(align) {
861
- this._style.alignItems = align;
862
- this.markDirty();
863
- }
864
- /**
865
- * Set how this node is aligned along the parent's cross axis.
866
- * Overrides the parent's alignItems for this specific child.
867
- *
868
- * @param align - ALIGN_AUTO, ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
869
- */
870
- setAlignSelf(align) {
871
- this._style.alignSelf = align;
872
- this.markDirty();
873
- }
874
- /**
875
- * Set how lines are aligned in a multi-line flex container.
876
- * Only affects containers with wrap enabled and multiple lines.
877
- *
878
- * @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, ALIGN_SPACE_BETWEEN, or ALIGN_SPACE_AROUND
879
- */
880
- setAlignContent(align) {
881
- this._style.alignContent = align;
882
- this.markDirty();
883
- }
884
- /**
885
- * Set how children are distributed along the main axis.
886
- *
887
- * @param justify - JUSTIFY_FLEX_START, JUSTIFY_CENTER, JUSTIFY_FLEX_END, JUSTIFY_SPACE_BETWEEN, JUSTIFY_SPACE_AROUND, or JUSTIFY_SPACE_EVENLY
888
- * @example
889
- * ```typescript
890
- * const container = Node.create();
891
- * container.setJustifyContent(JUSTIFY_SPACE_BETWEEN); // Space children evenly with edges at start/end
892
- * ```
893
- */
894
- setJustifyContent(justify) {
895
- this._style.justifyContent = justify;
896
- this.markDirty();
897
- }
898
- // ============================================================================
899
- // Spacing Setters
900
- // ============================================================================
901
- /**
902
- * Set padding for one or more edges.
903
- *
904
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
905
- * @param value - Padding in points
906
- * @example
907
- * ```typescript
908
- * node.setPadding(EDGE_ALL, 10); // Set 10pt padding on all edges
909
- * node.setPadding(EDGE_HORIZONTAL, 5); // Set 5pt padding on left and right
910
- * ```
911
- */
912
- setPadding(edge, value) {
913
- setEdgeValue(this._style.padding, edge, value, C.UNIT_POINT);
914
- this.markDirty();
915
- }
916
- /**
917
- * Set padding as a percentage of the parent's width.
918
- * Per CSS spec, percentage padding always resolves against the containing block's width.
919
- *
920
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
921
- * @param value - Padding as a percentage (0-100)
922
- */
923
- setPaddingPercent(edge, value) {
924
- setEdgeValue(this._style.padding, edge, value, C.UNIT_PERCENT);
925
- this.markDirty();
926
- }
927
- /**
928
- * Set margin for one or more edges.
929
- *
930
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
931
- * @param value - Margin in points
932
- * @example
933
- * ```typescript
934
- * node.setMargin(EDGE_ALL, 5); // Set 5pt margin on all edges
935
- * node.setMargin(EDGE_TOP, 10); // Set 10pt margin on top only
936
- * ```
937
- */
938
- setMargin(edge, value) {
939
- setEdgeValue(this._style.margin, edge, value, C.UNIT_POINT);
940
- this.markDirty();
941
- }
942
- /**
943
- * Set margin as a percentage of the parent's size.
944
- *
945
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
946
- * @param value - Margin as a percentage (0-100)
947
- */
948
- setMarginPercent(edge, value) {
949
- setEdgeValue(this._style.margin, edge, value, C.UNIT_PERCENT);
950
- this.markDirty();
951
- }
952
- /**
953
- * Set margin to auto (for centering items with margin: auto).
954
- *
955
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
956
- */
957
- setMarginAuto(edge) {
958
- setEdgeValue(this._style.margin, edge, 0, C.UNIT_AUTO);
959
- this.markDirty();
960
- }
961
- /**
962
- * Set border width for one or more edges.
963
- *
964
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
965
- * @param value - Border width in points
966
- */
967
- setBorder(edge, value) {
968
- setEdgeBorder(this._style.border, edge, value);
969
- this.markDirty();
970
- }
971
- /**
972
- * Set gap between flex items.
973
- *
974
- * @param gutter - GUTTER_COLUMN (horizontal gap), GUTTER_ROW (vertical gap), or GUTTER_ALL (both)
975
- * @param value - Gap size in points
976
- * @example
977
- * ```typescript
978
- * container.setGap(GUTTER_ALL, 8); // Set 8pt gap between all items
979
- * container.setGap(GUTTER_COLUMN, 10); // Set 10pt horizontal gap only
980
- * ```
981
- */
982
- setGap(gutter, value) {
983
- if (gutter === C.GUTTER_COLUMN) {
984
- this._style.gap[0] = value;
985
- }
986
- else if (gutter === C.GUTTER_ROW) {
987
- this._style.gap[1] = value;
988
- }
989
- else if (gutter === C.GUTTER_ALL) {
990
- this._style.gap[0] = value;
991
- this._style.gap[1] = value;
992
- }
993
- this.markDirty();
994
- }
995
- // ============================================================================
996
- // Position Setters
997
- // ============================================================================
998
- /**
999
- * Set the position type.
1000
- *
1001
- * @param positionType - POSITION_TYPE_STATIC, POSITION_TYPE_RELATIVE, or POSITION_TYPE_ABSOLUTE
1002
- * @example
1003
- * ```typescript
1004
- * node.setPositionType(POSITION_TYPE_ABSOLUTE);
1005
- * node.setPosition(EDGE_LEFT, 10);
1006
- * node.setPosition(EDGE_TOP, 20);
1007
- * ```
1008
- */
1009
- setPositionType(positionType) {
1010
- this._style.positionType = positionType;
1011
- this.markDirty();
1012
- }
1013
- /**
1014
- * Set position offset for one or more edges.
1015
- * Only applies when position type is ABSOLUTE or RELATIVE.
1016
- *
1017
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
1018
- * @param value - Position offset in points
1019
- */
1020
- setPosition(edge, value) {
1021
- // NaN means "auto" (unset) in Yoga API
1022
- if (Number.isNaN(value)) {
1023
- setEdgeValue(this._style.position, edge, 0, C.UNIT_UNDEFINED);
1024
- }
1025
- else {
1026
- setEdgeValue(this._style.position, edge, value, C.UNIT_POINT);
1027
- }
1028
- this.markDirty();
1029
- }
1030
- /**
1031
- * Set position offset as a percentage.
1032
- *
1033
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
1034
- * @param value - Position offset as a percentage of parent's corresponding dimension
1035
- */
1036
- setPositionPercent(edge, value) {
1037
- setEdgeValue(this._style.position, edge, value, C.UNIT_PERCENT);
1038
- this.markDirty();
1039
- }
1040
- // ============================================================================
1041
- // Other Setters
1042
- // ============================================================================
1043
- /**
1044
- * Set the display type.
1045
- *
1046
- * @param display - DISPLAY_FLEX or DISPLAY_NONE
1047
- */
1048
- setDisplay(display) {
1049
- this._style.display = display;
1050
- this.markDirty();
1051
- }
1052
- /**
1053
- * Set the overflow behavior.
1054
- *
1055
- * @param overflow - OVERFLOW_VISIBLE, OVERFLOW_HIDDEN, or OVERFLOW_SCROLL
1056
- */
1057
- setOverflow(overflow) {
1058
- this._style.overflow = overflow;
1059
- this.markDirty();
1060
- }
1061
- // ============================================================================
1062
- // Style Getters
1063
- // ============================================================================
1064
- /**
1065
- * Get the width style value.
1066
- *
1067
- * @returns Width value with unit (points, percent, or auto)
1068
- */
1069
- getWidth() {
1070
- return this._style.width;
1071
- }
1072
- /**
1073
- * Get the height style value.
1074
- *
1075
- * @returns Height value with unit (points, percent, or auto)
1076
- */
1077
- getHeight() {
1078
- return this._style.height;
1079
- }
1080
- /**
1081
- * Get the minimum width style value.
1082
- *
1083
- * @returns Minimum width value with unit
1084
- */
1085
- getMinWidth() {
1086
- return this._style.minWidth;
1087
- }
1088
- /**
1089
- * Get the minimum height style value.
1090
- *
1091
- * @returns Minimum height value with unit
1092
- */
1093
- getMinHeight() {
1094
- return this._style.minHeight;
1095
- }
1096
- /**
1097
- * Get the maximum width style value.
1098
- *
1099
- * @returns Maximum width value with unit
1100
- */
1101
- getMaxWidth() {
1102
- return this._style.maxWidth;
1103
- }
1104
- /**
1105
- * Get the maximum height style value.
1106
- *
1107
- * @returns Maximum height value with unit
1108
- */
1109
- getMaxHeight() {
1110
- return this._style.maxHeight;
1111
- }
1112
- /**
1113
- * Get the aspect ratio.
1114
- *
1115
- * @returns Aspect ratio value (NaN if not set)
1116
- */
1117
- getAspectRatio() {
1118
- return this._style.aspectRatio;
1119
- }
1120
- /**
1121
- * Get the flex grow factor.
1122
- *
1123
- * @returns Flex grow value
1124
- */
1125
- getFlexGrow() {
1126
- return this._style.flexGrow;
1127
- }
1128
- /**
1129
- * Get the flex shrink factor.
1130
- *
1131
- * @returns Flex shrink value
1132
- */
1133
- getFlexShrink() {
1134
- return this._style.flexShrink;
1135
- }
1136
- /**
1137
- * Get the flex basis style value.
1138
- *
1139
- * @returns Flex basis value with unit
1140
- */
1141
- getFlexBasis() {
1142
- return this._style.flexBasis;
1143
- }
1144
- /**
1145
- * Get the flex direction.
1146
- *
1147
- * @returns Flex direction constant
1148
- */
1149
- getFlexDirection() {
1150
- return this._style.flexDirection;
1151
- }
1152
- /**
1153
- * Get the flex wrap setting.
1154
- *
1155
- * @returns Flex wrap constant
1156
- */
1157
- getFlexWrap() {
1158
- return this._style.flexWrap;
1159
- }
1160
- /**
1161
- * Get the align items setting.
1162
- *
1163
- * @returns Align items constant
1164
- */
1165
- getAlignItems() {
1166
- return this._style.alignItems;
1167
- }
1168
- /**
1169
- * Get the align self setting.
1170
- *
1171
- * @returns Align self constant
1172
- */
1173
- getAlignSelf() {
1174
- return this._style.alignSelf;
1175
- }
1176
- /**
1177
- * Get the align content setting.
1178
- *
1179
- * @returns Align content constant
1180
- */
1181
- getAlignContent() {
1182
- return this._style.alignContent;
1183
- }
1184
- /**
1185
- * Get the justify content setting.
1186
- *
1187
- * @returns Justify content constant
1188
- */
1189
- getJustifyContent() {
1190
- return this._style.justifyContent;
1191
- }
1192
- /**
1193
- * Get the padding for a specific edge.
1194
- *
1195
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
1196
- * @returns Padding value with unit
1197
- */
1198
- getPadding(edge) {
1199
- return getEdgeValue(this._style.padding, edge);
1200
- }
1201
- /**
1202
- * Get the margin for a specific edge.
1203
- *
1204
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
1205
- * @returns Margin value with unit
1206
- */
1207
- getMargin(edge) {
1208
- return getEdgeValue(this._style.margin, edge);
1209
- }
1210
- /**
1211
- * Get the border width for a specific edge.
1212
- *
1213
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
1214
- * @returns Border width in points
1215
- */
1216
- getBorder(edge) {
1217
- return getEdgeBorderValue(this._style.border, edge);
1218
- }
1219
- /**
1220
- * Get the position offset for a specific edge.
1221
- *
1222
- * @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
1223
- * @returns Position value with unit
1224
- */
1225
- getPosition(edge) {
1226
- return getEdgeValue(this._style.position, edge);
1227
- }
1228
- /**
1229
- * Get the position type.
1230
- *
1231
- * @returns Position type constant
1232
- */
1233
- getPositionType() {
1234
- return this._style.positionType;
1235
- }
1236
- /**
1237
- * Get the display type.
1238
- *
1239
- * @returns Display constant
1240
- */
1241
- getDisplay() {
1242
- return this._style.display;
1243
- }
1244
- /**
1245
- * Get the overflow setting.
1246
- *
1247
- * @returns Overflow constant
1248
- */
1249
- getOverflow() {
1250
- return this._style.overflow;
1251
- }
1252
- /**
1253
- * Get the gap for column or row.
1254
- *
1255
- * @param gutter - GUTTER_COLUMN or GUTTER_ROW
1256
- * @returns Gap size in points
1257
- */
1258
- getGap(gutter) {
1259
- if (gutter === C.GUTTER_COLUMN) {
1260
- return this._style.gap[0];
1261
- }
1262
- else if (gutter === C.GUTTER_ROW) {
1263
- return this._style.gap[1];
1264
- }
1265
- return this._style.gap[0]; // Default to column gap
1266
- }
1267
- }
1268
- //# sourceMappingURL=node-zero.js.map