flexily 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +14 -22
- package/src/classic/layout.ts +2 -2
- package/src/layout-helpers.ts +2 -2
- package/dist/classic/layout.d.ts +0 -57
- package/dist/classic/layout.d.ts.map +0 -1
- package/dist/classic/layout.js +0 -1567
- package/dist/classic/layout.js.map +0 -1
- package/dist/classic/node.d.ts +0 -648
- package/dist/classic/node.d.ts.map +0 -1
- package/dist/classic/node.js +0 -1002
- package/dist/classic/node.js.map +0 -1
- package/dist/constants.d.ts +0 -59
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -71
- package/dist/constants.js.map +0 -1
- package/dist/index-classic.d.ts +0 -30
- package/dist/index-classic.d.ts.map +0 -1
- package/dist/index-classic.js +0 -57
- package/dist/index-classic.js.map +0 -1
- package/dist/index.d.ts +0 -30
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -57
- package/dist/index.js.map +0 -1
- package/dist/layout-flex-lines.d.ts +0 -77
- package/dist/layout-flex-lines.d.ts.map +0 -1
- package/dist/layout-flex-lines.js +0 -317
- package/dist/layout-flex-lines.js.map +0 -1
- package/dist/layout-helpers.d.ts +0 -45
- package/dist/layout-helpers.d.ts.map +0 -1
- package/dist/layout-helpers.js +0 -103
- package/dist/layout-helpers.js.map +0 -1
- package/dist/layout-measure.d.ts +0 -25
- package/dist/layout-measure.d.ts.map +0 -1
- package/dist/layout-measure.js +0 -231
- package/dist/layout-measure.js.map +0 -1
- package/dist/layout-stats.d.ts +0 -19
- package/dist/layout-stats.d.ts.map +0 -1
- package/dist/layout-stats.js +0 -37
- package/dist/layout-stats.js.map +0 -1
- package/dist/layout-traversal.d.ts +0 -28
- package/dist/layout-traversal.d.ts.map +0 -1
- package/dist/layout-traversal.js +0 -65
- package/dist/layout-traversal.js.map +0 -1
- package/dist/layout-zero.d.ts +0 -26
- package/dist/layout-zero.d.ts.map +0 -1
- package/dist/layout-zero.js +0 -1757
- package/dist/layout-zero.js.map +0 -1
- package/dist/logger.d.ts +0 -14
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -61
- package/dist/logger.js.map +0 -1
- package/dist/node-zero.d.ts +0 -702
- package/dist/node-zero.d.ts.map +0 -1
- package/dist/node-zero.js +0 -1268
- package/dist/node-zero.js.map +0 -1
- package/dist/testing.d.ts +0 -69
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -179
- package/dist/testing.js.map +0 -1
- package/dist/trace.d.ts +0 -74
- package/dist/trace.d.ts.map +0 -1
- package/dist/trace.js +0 -191
- package/dist/trace.js.map +0 -1
- package/dist/types.d.ts +0 -170
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -43
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts +0 -49
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -222
- package/dist/utils.js.map +0 -1
- 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
|