flexily 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-CBBoxR_p.mjs +26 -0
- package/dist/constants-BNURa6H7.mjs +65 -0
- package/dist/constants-BNURa6H7.mjs.map +1 -0
- package/dist/constants-D7ythAJC.d.mts +64 -0
- package/dist/constants-D7ythAJC.d.mts.map +1 -0
- package/{src/classic/node.ts → dist/index-classic.d.mts} +118 -619
- package/dist/index-classic.d.mts.map +1 -0
- package/dist/index-classic.mjs +1909 -0
- package/dist/index-classic.mjs.map +1 -0
- package/dist/index.d.mts +195 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3279 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node-zero-75maLs2s.d.mts +762 -0
- package/dist/node-zero-75maLs2s.d.mts.map +1 -0
- package/dist/src-BWyhokNZ.mjs +692 -0
- package/dist/src-BWyhokNZ.mjs.map +1 -0
- package/dist/src-DdSLylRA.mjs +816 -0
- package/dist/src-DdSLylRA.mjs.map +1 -0
- package/dist/testing.d.mts +55 -0
- package/dist/testing.d.mts.map +1 -0
- package/dist/testing.mjs +154 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types--IozHd4V.mjs +283 -0
- package/dist/types--IozHd4V.mjs.map +1 -0
- package/dist/types-DG1H4DVR.d.mts +157 -0
- package/dist/types-DG1H4DVR.d.mts.map +1 -0
- package/package.json +33 -24
- package/src/CLAUDE.md +0 -527
- package/src/classic/layout.ts +0 -1843
- package/src/constants.ts +0 -82
- package/src/create-flexily.ts +0 -153
- package/src/index-classic.ts +0 -110
- package/src/index.ts +0 -133
- package/src/layout-flex-lines.ts +0 -413
- package/src/layout-helpers.ts +0 -160
- package/src/layout-measure.ts +0 -259
- package/src/layout-stats.ts +0 -41
- package/src/layout-traversal.ts +0 -70
- package/src/layout-zero.ts +0 -2219
- package/src/logger.ts +0 -68
- package/src/monospace-measurer.ts +0 -68
- package/src/node-zero.ts +0 -1508
- package/src/pretext-measurer.ts +0 -86
- package/src/test-measurer.ts +0 -219
- package/src/testing.ts +0 -215
- package/src/text-layout.ts +0 -75
- package/src/trace.ts +0 -252
- package/src/types.ts +0 -236
- package/src/utils.ts +0 -243
|
@@ -0,0 +1,1909 @@
|
|
|
1
|
+
import { $ as WRAP_WRAP, A as GUTTER_ROW, B as OVERFLOW_HIDDEN, C as EDGE_VERTICAL, D as FLEX_DIRECTION_ROW_REVERSE, E as FLEX_DIRECTION_ROW, F as JUSTIFY_SPACE_BETWEEN, G as POSITION_TYPE_STATIC, H as OVERFLOW_VISIBLE, I as JUSTIFY_SPACE_EVENLY, J as UNIT_PERCENT, K as UNIT_AUTO, L as MEASURE_MODE_AT_MOST, M as JUSTIFY_FLEX_END, N as JUSTIFY_FLEX_START, O as GUTTER_ALL, P as JUSTIFY_SPACE_AROUND, Q as WRAP_NO_WRAP, R as MEASURE_MODE_EXACTLY, S as EDGE_TOP, T as FLEX_DIRECTION_COLUMN_REVERSE, U as POSITION_TYPE_ABSOLUTE, V as OVERFLOW_SCROLL, W as POSITION_TYPE_RELATIVE, Y as UNIT_POINT, Z as UNIT_UNDEFINED, _ as EDGE_END, a as ALIGN_FLEX_START, b as EDGE_RIGHT, c as ALIGN_SPACE_EVENLY, d as DIRECTION_LTR, et as WRAP_WRAP_REVERSE, f as DIRECTION_RTL, g as EDGE_BOTTOM, h as EDGE_ALL, i as ALIGN_FLEX_END, j as JUSTIFY_CENTER, k as GUTTER_COLUMN, l as ALIGN_STRETCH, m as DISPLAY_NONE, n as ALIGN_BASELINE, o as ALIGN_SPACE_AROUND, p as DISPLAY_FLEX, r as ALIGN_CENTER, s as ALIGN_SPACE_BETWEEN, t as ALIGN_AUTO, u as DIRECTION_INHERIT, v as EDGE_HORIZONTAL, w as FLEX_DIRECTION_COLUMN, x as EDGE_START, y as EDGE_LEFT, z as MEASURE_MODE_UNDEFINED } from "./constants-BNURa6H7.mjs";
|
|
2
|
+
import { a as getEdgeBorderValue, c as setEdgeBorder, i as applyMinMax, l as setEdgeValue, n as createValue, o as getEdgeValue, r as log, s as resolveValue, t as createDefaultStyle } from "./types--IozHd4V.mjs";
|
|
3
|
+
//#region src/classic/layout.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flexily Layout Algorithm
|
|
6
|
+
*
|
|
7
|
+
* Core flexbox layout computation extracted from node.ts.
|
|
8
|
+
* Based on Planning-nl/flexbox.js reference implementation.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Check if flex direction is row-oriented (horizontal main axis).
|
|
12
|
+
*/
|
|
13
|
+
function isRowDirection(flexDirection) {
|
|
14
|
+
return flexDirection === 2 || flexDirection === 3;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if flex direction is reversed.
|
|
18
|
+
*/
|
|
19
|
+
function isReverseDirection(flexDirection) {
|
|
20
|
+
return flexDirection === 3 || flexDirection === 1;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the logical edge value (START/END) for a given physical index.
|
|
24
|
+
* Returns undefined if no logical value applies to this physical edge.
|
|
25
|
+
*
|
|
26
|
+
* The mapping depends on flex direction and text direction:
|
|
27
|
+
* - Row LTR: START→left, END→right (swapped if reverse)
|
|
28
|
+
* - Row RTL: START→right, END→left (swapped if reverse)
|
|
29
|
+
* - Column: START→top, END→bottom (swapped if reverse)
|
|
30
|
+
*/
|
|
31
|
+
function getLogicalEdgeValue(arr, physicalIndex, _flexDirection, direction = 1) {
|
|
32
|
+
const isRTL = direction === 2;
|
|
33
|
+
if (physicalIndex === 0) return isRTL ? arr[5] : arr[4];
|
|
34
|
+
else if (physicalIndex === 2) return isRTL ? arr[4] : arr[5];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolve logical (START/END) margins/padding to physical values.
|
|
38
|
+
* EDGE_START/EDGE_END always resolve along the inline (horizontal) axis:
|
|
39
|
+
* - LTR: START→left, END→right
|
|
40
|
+
* - RTL: START→right, END→left
|
|
41
|
+
*
|
|
42
|
+
* Physical edges (LEFT/RIGHT/TOP/BOTTOM) are used directly.
|
|
43
|
+
* When both physical and logical are set, logical takes precedence.
|
|
44
|
+
*/
|
|
45
|
+
function resolveEdgeValue(arr, physicalIndex, flexDirection, availableSize, direction = 1) {
|
|
46
|
+
const logicalValue = getLogicalEdgeValue(arr, physicalIndex, flexDirection, direction);
|
|
47
|
+
if (logicalValue && logicalValue.unit !== 0) return resolveValue(logicalValue, availableSize);
|
|
48
|
+
return resolveValue(arr[physicalIndex], availableSize);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if a logical edge margin is set to auto.
|
|
52
|
+
*/
|
|
53
|
+
function isEdgeAuto(arr, physicalIndex, flexDirection, direction = 1) {
|
|
54
|
+
const logicalValue = getLogicalEdgeValue(arr, physicalIndex, flexDirection, direction);
|
|
55
|
+
if (logicalValue && logicalValue.unit !== 0) return logicalValue.unit === 3;
|
|
56
|
+
return arr[physicalIndex].unit === 3;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve logical (START/END) border widths to physical values.
|
|
60
|
+
* Border values are plain numbers (always points), so resolution is simpler
|
|
61
|
+
* than for margin/padding. Uses NaN as the "not set" sentinel for logical slots.
|
|
62
|
+
* When both physical and logical are set, logical takes precedence.
|
|
63
|
+
*/
|
|
64
|
+
function resolveEdgeBorderValue(arr, physicalIndex, _flexDirection, direction = 1) {
|
|
65
|
+
const isRTL = direction === 2;
|
|
66
|
+
let logicalSlot;
|
|
67
|
+
if (physicalIndex === 0) logicalSlot = isRTL ? 5 : 4;
|
|
68
|
+
else if (physicalIndex === 2) logicalSlot = isRTL ? 4 : 5;
|
|
69
|
+
if (logicalSlot !== void 0 && !Number.isNaN(arr[logicalSlot])) return arr[logicalSlot];
|
|
70
|
+
return arr[physicalIndex];
|
|
71
|
+
}
|
|
72
|
+
function markSubtreeLayoutSeen(node) {
|
|
73
|
+
for (const child of node.children) {
|
|
74
|
+
child["_hasNewLayout"] = true;
|
|
75
|
+
markSubtreeLayoutSeen(child);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function countNodes(node) {
|
|
79
|
+
let count = 1;
|
|
80
|
+
for (const child of node.children) count += countNodes(child);
|
|
81
|
+
return count;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Epsilon value for floating point comparisons in flex distribution.
|
|
85
|
+
* Used to determine when remaining space is negligible and iteration should stop.
|
|
86
|
+
*/
|
|
87
|
+
const EPSILON_FLOAT = .001;
|
|
88
|
+
/**
|
|
89
|
+
* Break children into flex lines based on available main-axis space.
|
|
90
|
+
*
|
|
91
|
+
* @param children - All children to potentially wrap
|
|
92
|
+
* @param mainAxisSize - Available main-axis space (NaN for unconstrained)
|
|
93
|
+
* @param mainGap - Gap between items on main axis
|
|
94
|
+
* @param wrap - Wrap mode (WRAP_NO_WRAP, WRAP_WRAP, WRAP_WRAP_REVERSE)
|
|
95
|
+
* @returns Array of flex lines
|
|
96
|
+
*/
|
|
97
|
+
function breakIntoLines(children, mainAxisSize, mainGap, wrap) {
|
|
98
|
+
if (wrap === 0 || Number.isNaN(mainAxisSize) || children.length === 0) return [{
|
|
99
|
+
children,
|
|
100
|
+
crossSize: 0,
|
|
101
|
+
crossStart: 0
|
|
102
|
+
}];
|
|
103
|
+
const lines = [];
|
|
104
|
+
let currentLine = [];
|
|
105
|
+
let lineMainSize = 0;
|
|
106
|
+
for (const child of children) {
|
|
107
|
+
const childMainSize = Math.max(child.minMain, Math.min(child.maxMain, child.baseSize)) + child.mainMargin;
|
|
108
|
+
const gapIfNotFirst = currentLine.length > 0 ? mainGap : 0;
|
|
109
|
+
if (currentLine.length > 0 && lineMainSize + gapIfNotFirst + childMainSize > mainAxisSize) {
|
|
110
|
+
lines.push({
|
|
111
|
+
children: currentLine,
|
|
112
|
+
crossSize: 0,
|
|
113
|
+
crossStart: 0
|
|
114
|
+
});
|
|
115
|
+
currentLine = [child];
|
|
116
|
+
lineMainSize = childMainSize;
|
|
117
|
+
} else {
|
|
118
|
+
currentLine.push(child);
|
|
119
|
+
lineMainSize += gapIfNotFirst + childMainSize;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (currentLine.length > 0) lines.push({
|
|
123
|
+
children: currentLine,
|
|
124
|
+
crossSize: 0,
|
|
125
|
+
crossStart: 0
|
|
126
|
+
});
|
|
127
|
+
if (wrap === 2) lines.reverse();
|
|
128
|
+
return lines;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Distribute free space among flex children using grow or shrink factors.
|
|
132
|
+
* Handles both positive (grow) and negative (shrink) free space.
|
|
133
|
+
*
|
|
134
|
+
* For shrinking, per CSS Flexbox spec, the shrink factor is weighted by the item's
|
|
135
|
+
* base size: scaledShrinkFactor = flexShrink * baseSize
|
|
136
|
+
*
|
|
137
|
+
* @param children - Array of child layout info to distribute space among
|
|
138
|
+
* @param freeSpace - Amount of space to distribute (positive for grow, negative for shrink)
|
|
139
|
+
*/
|
|
140
|
+
function distributeFlexSpace(children, initialFreeSpace) {
|
|
141
|
+
const isGrowing = initialFreeSpace > 0;
|
|
142
|
+
if (initialFreeSpace === 0) return;
|
|
143
|
+
if (children.length === 1) {
|
|
144
|
+
const child = children[0];
|
|
145
|
+
if (isGrowing ? child.flexGrow > 0 : child.flexShrink > 0) {
|
|
146
|
+
const target = child.baseSize + initialFreeSpace;
|
|
147
|
+
child.mainSize = Math.max(child.minMain, Math.min(child.maxMain, target));
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
let totalBase = 0;
|
|
152
|
+
for (const childLayout of children) totalBase += childLayout.baseSize;
|
|
153
|
+
const containerInner = initialFreeSpace + totalBase;
|
|
154
|
+
for (const childLayout of children) childLayout.frozen = false;
|
|
155
|
+
let freeSpace = initialFreeSpace;
|
|
156
|
+
let iterations = 0;
|
|
157
|
+
const maxIterations = children.length + 1;
|
|
158
|
+
while (iterations++ < maxIterations) {
|
|
159
|
+
let totalFlex = 0;
|
|
160
|
+
for (const childLayout of children) {
|
|
161
|
+
if (childLayout.frozen) continue;
|
|
162
|
+
if (isGrowing) totalFlex += childLayout.flexGrow;
|
|
163
|
+
else totalFlex += childLayout.flexShrink * childLayout.baseSize;
|
|
164
|
+
}
|
|
165
|
+
if (totalFlex === 0) break;
|
|
166
|
+
let effectiveFreeSpace = freeSpace;
|
|
167
|
+
if (isGrowing && totalFlex < 1) effectiveFreeSpace = freeSpace * totalFlex;
|
|
168
|
+
let totalViolation = 0;
|
|
169
|
+
for (const childLayout of children) {
|
|
170
|
+
if (childLayout.frozen) continue;
|
|
171
|
+
const flexFactor = isGrowing ? childLayout.flexGrow : childLayout.flexShrink * childLayout.baseSize;
|
|
172
|
+
const ratio = totalFlex > 0 ? flexFactor / totalFlex : 0;
|
|
173
|
+
const target = childLayout.baseSize + effectiveFreeSpace * ratio;
|
|
174
|
+
const clamped = Math.max(childLayout.minMain, Math.min(childLayout.maxMain, target));
|
|
175
|
+
const violation = clamped - target;
|
|
176
|
+
totalViolation += violation;
|
|
177
|
+
childLayout.mainSize = clamped;
|
|
178
|
+
}
|
|
179
|
+
let anyFrozen = false;
|
|
180
|
+
if (Math.abs(totalViolation) < EPSILON_FLOAT) {
|
|
181
|
+
for (const childLayout of children) childLayout.frozen = true;
|
|
182
|
+
break;
|
|
183
|
+
} else if (totalViolation > 0) for (const childLayout of children) {
|
|
184
|
+
if (childLayout.frozen) continue;
|
|
185
|
+
const target = childLayout.baseSize + (isGrowing ? childLayout.flexGrow : childLayout.flexShrink * childLayout.baseSize) / totalFlex * effectiveFreeSpace;
|
|
186
|
+
if (childLayout.mainSize > target + EPSILON_FLOAT) {
|
|
187
|
+
childLayout.frozen = true;
|
|
188
|
+
anyFrozen = true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else for (const childLayout of children) {
|
|
192
|
+
if (childLayout.frozen) continue;
|
|
193
|
+
const flexFactor = isGrowing ? childLayout.flexGrow : childLayout.flexShrink * childLayout.baseSize;
|
|
194
|
+
const target = childLayout.baseSize + flexFactor / totalFlex * effectiveFreeSpace;
|
|
195
|
+
if (childLayout.mainSize < target - EPSILON_FLOAT) {
|
|
196
|
+
childLayout.frozen = true;
|
|
197
|
+
anyFrozen = true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!anyFrozen) break;
|
|
201
|
+
let frozenSpace = 0;
|
|
202
|
+
let unfrozenBase = 0;
|
|
203
|
+
for (const childLayout of children) if (childLayout.frozen) frozenSpace += childLayout.mainSize;
|
|
204
|
+
else unfrozenBase += childLayout.baseSize;
|
|
205
|
+
freeSpace = containerInner - frozenSpace - unfrozenBase;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Compute layout for a node tree.
|
|
210
|
+
*
|
|
211
|
+
* @param root - Root node of the tree
|
|
212
|
+
* @param availableWidth - Available width for layout
|
|
213
|
+
* @param availableHeight - Available height for layout
|
|
214
|
+
* @param direction - Text direction (LTR or RTL), affects horizontal edge resolution
|
|
215
|
+
*/
|
|
216
|
+
function computeLayout(root, availableWidth, availableHeight, direction = 1) {
|
|
217
|
+
layoutNode(root, availableWidth, availableHeight, 0, 0, 0, 0, direction);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Layout a node and its children.
|
|
221
|
+
*
|
|
222
|
+
* @param absX - Absolute X position from document root (for Yoga-compatible edge rounding)
|
|
223
|
+
* @param absY - Absolute Y position from document root (for Yoga-compatible edge rounding)
|
|
224
|
+
* @param direction - Text direction (LTR or RTL), affects horizontal edge resolution
|
|
225
|
+
*/
|
|
226
|
+
function layoutNode(node, availableWidth, availableHeight, offsetX, offsetY, absX, absY, direction = 1) {
|
|
227
|
+
log.debug?.("layoutNode called: availW=%d, availH=%d, offsetX=%d, offsetY=%d, absX=%d, absY=%d, children=%d", availableWidth, availableHeight, offsetX, offsetY, absX, absY, node.children.length);
|
|
228
|
+
const style = node.style;
|
|
229
|
+
const layout = node.layout;
|
|
230
|
+
if (style.display === 1) {
|
|
231
|
+
layout.left = 0;
|
|
232
|
+
layout.top = 0;
|
|
233
|
+
layout.width = 0;
|
|
234
|
+
layout.height = 0;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const marginLeft = resolveEdgeValue(style.margin, 0, style.flexDirection, availableWidth, direction);
|
|
238
|
+
const marginTop = resolveEdgeValue(style.margin, 1, style.flexDirection, availableWidth, direction);
|
|
239
|
+
const marginRight = resolveEdgeValue(style.margin, 2, style.flexDirection, availableWidth, direction);
|
|
240
|
+
const marginBottom = resolveEdgeValue(style.margin, 3, style.flexDirection, availableWidth, direction);
|
|
241
|
+
const paddingLeft = resolveEdgeValue(style.padding, 0, style.flexDirection, availableWidth, direction);
|
|
242
|
+
const paddingTop = resolveEdgeValue(style.padding, 1, style.flexDirection, availableWidth, direction);
|
|
243
|
+
const paddingRight = resolveEdgeValue(style.padding, 2, style.flexDirection, availableWidth, direction);
|
|
244
|
+
const paddingBottom = resolveEdgeValue(style.padding, 3, style.flexDirection, availableWidth, direction);
|
|
245
|
+
const borderLeft = resolveEdgeBorderValue(style.border, 0, style.flexDirection, direction);
|
|
246
|
+
const borderTop = resolveEdgeBorderValue(style.border, 1, style.flexDirection, direction);
|
|
247
|
+
const borderRight = resolveEdgeBorderValue(style.border, 2, style.flexDirection, direction);
|
|
248
|
+
const borderBottom = resolveEdgeBorderValue(style.border, 3, style.flexDirection, direction);
|
|
249
|
+
let nodeWidth;
|
|
250
|
+
if (style.width.unit === 1) nodeWidth = style.width.value;
|
|
251
|
+
else if (style.width.unit === 2) nodeWidth = resolveValue(style.width, availableWidth);
|
|
252
|
+
else if (Number.isNaN(availableWidth)) nodeWidth = NaN;
|
|
253
|
+
else nodeWidth = availableWidth - marginLeft - marginRight;
|
|
254
|
+
nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
|
|
255
|
+
let nodeHeight;
|
|
256
|
+
if (style.height.unit === 1) nodeHeight = style.height.value;
|
|
257
|
+
else if (style.height.unit === 2) nodeHeight = resolveValue(style.height, availableHeight);
|
|
258
|
+
else if (Number.isNaN(availableHeight)) nodeHeight = NaN;
|
|
259
|
+
else nodeHeight = availableHeight - marginTop - marginBottom;
|
|
260
|
+
const aspectRatio = style.aspectRatio;
|
|
261
|
+
if (!Number.isNaN(aspectRatio) && aspectRatio > 0) {
|
|
262
|
+
const widthIsAuto = Number.isNaN(nodeWidth) || style.width.unit === 3;
|
|
263
|
+
const heightIsAuto = Number.isNaN(nodeHeight) || style.height.unit === 3;
|
|
264
|
+
if (widthIsAuto && !heightIsAuto && !Number.isNaN(nodeHeight)) nodeWidth = nodeHeight * aspectRatio;
|
|
265
|
+
else if (heightIsAuto && !widthIsAuto && !Number.isNaN(nodeWidth)) nodeHeight = nodeWidth / aspectRatio;
|
|
266
|
+
}
|
|
267
|
+
nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
|
|
268
|
+
const innerLeft = borderLeft + paddingLeft;
|
|
269
|
+
const innerTop = borderTop + paddingTop;
|
|
270
|
+
const innerRight = borderRight + paddingRight;
|
|
271
|
+
const innerBottom = borderBottom + paddingBottom;
|
|
272
|
+
const minInnerWidth = innerLeft + innerRight;
|
|
273
|
+
const minInnerHeight = innerTop + innerBottom;
|
|
274
|
+
if (!Number.isNaN(nodeWidth) && nodeWidth < minInnerWidth) nodeWidth = minInnerWidth;
|
|
275
|
+
if (!Number.isNaN(nodeHeight) && nodeHeight < minInnerHeight) nodeHeight = minInnerHeight;
|
|
276
|
+
const contentWidth = Number.isNaN(nodeWidth) ? NaN : Math.max(0, nodeWidth - innerLeft - innerRight);
|
|
277
|
+
const contentHeight = Number.isNaN(nodeHeight) ? NaN : Math.max(0, nodeHeight - innerTop - innerBottom);
|
|
278
|
+
let parentPosOffsetX = 0;
|
|
279
|
+
let parentPosOffsetY = 0;
|
|
280
|
+
if (style.positionType === 1) {
|
|
281
|
+
const leftPos = style.position[0];
|
|
282
|
+
const topPos = style.position[1];
|
|
283
|
+
const rightPos = style.position[2];
|
|
284
|
+
const bottomPos = style.position[3];
|
|
285
|
+
if (leftPos.unit !== 0) parentPosOffsetX = resolveValue(leftPos, availableWidth);
|
|
286
|
+
else if (rightPos.unit !== 0) parentPosOffsetX = -resolveValue(rightPos, availableWidth);
|
|
287
|
+
if (topPos.unit !== 0) parentPosOffsetY = resolveValue(topPos, availableHeight);
|
|
288
|
+
else if (bottomPos.unit !== 0) parentPosOffsetY = -resolveValue(bottomPos, availableHeight);
|
|
289
|
+
}
|
|
290
|
+
if (node.hasMeasureFunc() && node.children.length === 0) {
|
|
291
|
+
const measureFunc = node.measureFunc;
|
|
292
|
+
const widthIsAuto = style.width.unit === 3 || style.width.unit === 0 || Number.isNaN(nodeWidth);
|
|
293
|
+
const heightIsAuto = style.height.unit === 3 || style.height.unit === 0 || Number.isNaN(nodeHeight);
|
|
294
|
+
const widthMode = widthIsAuto ? 2 : 1;
|
|
295
|
+
const heightMode = heightIsAuto ? 0 : 1;
|
|
296
|
+
const measured = measureFunc(Number.isNaN(contentWidth) ? Infinity : contentWidth, widthMode, Number.isNaN(contentHeight) ? Infinity : contentHeight, heightMode);
|
|
297
|
+
if (widthIsAuto) nodeWidth = measured.width + innerLeft + innerRight;
|
|
298
|
+
if (heightIsAuto) nodeHeight = measured.height + innerTop + innerBottom;
|
|
299
|
+
layout.width = Math.round(nodeWidth);
|
|
300
|
+
layout.height = Math.round(nodeHeight);
|
|
301
|
+
layout.left = Math.round(offsetX + marginLeft);
|
|
302
|
+
layout.top = Math.round(offsetY + marginTop);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (node.children.length === 0) {
|
|
306
|
+
if (Number.isNaN(nodeWidth)) nodeWidth = innerLeft + innerRight;
|
|
307
|
+
if (Number.isNaN(nodeHeight)) nodeHeight = innerTop + innerBottom;
|
|
308
|
+
layout.width = Math.round(nodeWidth);
|
|
309
|
+
layout.height = Math.round(nodeHeight);
|
|
310
|
+
layout.left = Math.round(offsetX + marginLeft);
|
|
311
|
+
layout.top = Math.round(offsetY + marginTop);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const relativeChildren = node.children.filter((c) => c.style.positionType !== 2 && c.style.display !== 1);
|
|
315
|
+
const absoluteChildren = node.children.filter((c) => c.style.positionType === 2 && c.style.display !== 1);
|
|
316
|
+
log.debug?.("layoutNode: node.children=%d, relativeChildren=%d, absolute=%d", node.children.length, relativeChildren.length, absoluteChildren.length);
|
|
317
|
+
if (relativeChildren.length > 0) {
|
|
318
|
+
const isRow = isRowDirection(style.flexDirection);
|
|
319
|
+
const isReverse = isReverseDirection(style.flexDirection);
|
|
320
|
+
const mainAxisSize = isRow ? contentWidth : contentHeight;
|
|
321
|
+
const crossAxisSize = isRow ? contentHeight : contentWidth;
|
|
322
|
+
const mainGap = isRow ? style.gap[0] : style.gap[1];
|
|
323
|
+
const children = [];
|
|
324
|
+
let totalBaseMain = 0;
|
|
325
|
+
for (const child of relativeChildren) {
|
|
326
|
+
const childStyle = child.style;
|
|
327
|
+
const mainStartIndex = isRow ? isReverse ? 2 : 0 : isReverse ? 3 : 1;
|
|
328
|
+
const mainEndIndex = isRow ? isReverse ? 0 : 2 : isReverse ? 1 : 3;
|
|
329
|
+
const mainStartMarginAuto = isEdgeAuto(childStyle.margin, mainStartIndex, style.flexDirection);
|
|
330
|
+
const mainEndMarginAuto = isEdgeAuto(childStyle.margin, mainEndIndex, style.flexDirection);
|
|
331
|
+
const parentWidth = isRow ? mainAxisSize : crossAxisSize;
|
|
332
|
+
const mainStartMarginValue = mainStartMarginAuto ? 0 : resolveEdgeValue(childStyle.margin, mainStartIndex, style.flexDirection, parentWidth, direction);
|
|
333
|
+
const mainEndMarginValue = mainEndMarginAuto ? 0 : resolveEdgeValue(childStyle.margin, mainEndIndex, style.flexDirection, parentWidth, direction);
|
|
334
|
+
const mainMargin = mainStartMarginValue + mainEndMarginValue;
|
|
335
|
+
let baseSize = 0;
|
|
336
|
+
if (childStyle.flexBasis.unit === 1) baseSize = childStyle.flexBasis.value;
|
|
337
|
+
else if (childStyle.flexBasis.unit === 2) baseSize = mainAxisSize * (childStyle.flexBasis.value / 100);
|
|
338
|
+
else {
|
|
339
|
+
const sizeVal = isRow ? childStyle.width : childStyle.height;
|
|
340
|
+
if (sizeVal.unit === 1) baseSize = sizeVal.value;
|
|
341
|
+
else if (sizeVal.unit === 2) baseSize = mainAxisSize * (sizeVal.value / 100);
|
|
342
|
+
else if (child.hasMeasureFunc() && childStyle.flexGrow === 0) {
|
|
343
|
+
const availCross = crossAxisSize - (isRow ? resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction));
|
|
344
|
+
const measured = child.measureFunc(mainAxisSize, 2, availCross, 0);
|
|
345
|
+
baseSize = isRow ? measured.width : measured.height;
|
|
346
|
+
} else if (child.children.length > 0) {
|
|
347
|
+
layoutNode(child, isRow ? NaN : crossAxisSize, isRow ? crossAxisSize : NaN, 0, 0, 0, 0, direction);
|
|
348
|
+
baseSize = isRow ? child.layout.width : child.layout.height;
|
|
349
|
+
} else {
|
|
350
|
+
const parentWidth = isRow ? mainAxisSize : crossAxisSize;
|
|
351
|
+
baseSize = (isRow ? resolveEdgeValue(childStyle.padding, 0, childStyle.flexDirection, parentWidth, direction) + resolveEdgeValue(childStyle.padding, 2, childStyle.flexDirection, parentWidth, direction) : resolveEdgeValue(childStyle.padding, 1, childStyle.flexDirection, parentWidth, direction) + resolveEdgeValue(childStyle.padding, 3, childStyle.flexDirection, parentWidth, direction)) + (isRow ? resolveEdgeBorderValue(childStyle.border, 0, childStyle.flexDirection, direction) + resolveEdgeBorderValue(childStyle.border, 2, childStyle.flexDirection, direction) : resolveEdgeBorderValue(childStyle.border, 1, childStyle.flexDirection, direction) + resolveEdgeBorderValue(childStyle.border, 3, childStyle.flexDirection, direction));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const minVal = isRow ? childStyle.minWidth : childStyle.minHeight;
|
|
355
|
+
const maxVal = isRow ? childStyle.maxWidth : childStyle.maxHeight;
|
|
356
|
+
const minMain = minVal.unit !== 0 ? resolveValue(minVal, mainAxisSize) : 0;
|
|
357
|
+
const maxMain = maxVal.unit !== 0 ? resolveValue(maxVal, mainAxisSize) : Infinity;
|
|
358
|
+
children.push({
|
|
359
|
+
node: child,
|
|
360
|
+
mainSize: baseSize,
|
|
361
|
+
baseSize,
|
|
362
|
+
mainMargin,
|
|
363
|
+
flexGrow: childStyle.flexGrow,
|
|
364
|
+
flexShrink: childStyle.flexShrink,
|
|
365
|
+
minMain,
|
|
366
|
+
maxMain,
|
|
367
|
+
mainStartMarginAuto,
|
|
368
|
+
mainEndMarginAuto,
|
|
369
|
+
mainStartMarginValue,
|
|
370
|
+
mainEndMarginValue,
|
|
371
|
+
frozen: false
|
|
372
|
+
});
|
|
373
|
+
totalBaseMain += baseSize + mainMargin;
|
|
374
|
+
}
|
|
375
|
+
const lines = breakIntoLines(children, mainAxisSize, mainGap, style.flexWrap);
|
|
376
|
+
const crossGap = isRow ? style.gap[1] : style.gap[0];
|
|
377
|
+
for (const line of lines) {
|
|
378
|
+
const lineChildren = line.children;
|
|
379
|
+
if (lineChildren.length === 0) continue;
|
|
380
|
+
const lineTotalBaseMain = lineChildren.reduce((sum, c) => sum + c.baseSize + c.mainMargin, 0);
|
|
381
|
+
const lineTotalGaps = lineChildren.length > 1 ? mainGap * (lineChildren.length - 1) : 0;
|
|
382
|
+
let effectiveMainSize = mainAxisSize;
|
|
383
|
+
if (Number.isNaN(mainAxisSize)) {
|
|
384
|
+
const maxMainVal = isRow ? style.maxWidth : style.maxHeight;
|
|
385
|
+
if (maxMainVal.unit !== 0) {
|
|
386
|
+
const maxMain = resolveValue(maxMainVal, isRow ? availableWidth : availableHeight);
|
|
387
|
+
if (!Number.isNaN(maxMain) && lineTotalBaseMain + lineTotalGaps > maxMain) effectiveMainSize = maxMain - (isRow ? innerLeft + innerRight : innerTop + innerBottom);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (!Number.isNaN(effectiveMainSize)) distributeFlexSpace(lineChildren, effectiveMainSize - lineTotalBaseMain - lineTotalGaps);
|
|
391
|
+
for (const childLayout of lineChildren) childLayout.mainSize = Math.max(childLayout.minMain, Math.min(childLayout.maxMain, childLayout.mainSize));
|
|
392
|
+
}
|
|
393
|
+
const totalGaps = children.length > 1 ? mainGap * (children.length - 1) : 0;
|
|
394
|
+
const usedMain = children.reduce((sum, c) => sum + c.mainSize + c.mainMargin, 0) + totalGaps;
|
|
395
|
+
const remainingSpace = Number.isNaN(mainAxisSize) ? 0 : mainAxisSize - usedMain;
|
|
396
|
+
const totalAutoMargins = children.reduce((sum, c) => sum + (c.mainStartMarginAuto ? 1 : 0) + (c.mainEndMarginAuto ? 1 : 0), 0);
|
|
397
|
+
let hasAutoMargins = totalAutoMargins > 0;
|
|
398
|
+
if (hasAutoMargins) {
|
|
399
|
+
const autoMarginValue = remainingSpace / totalAutoMargins;
|
|
400
|
+
for (const childLayout of children) {
|
|
401
|
+
if (childLayout.mainStartMarginAuto) childLayout.mainStartMarginValue = autoMarginValue;
|
|
402
|
+
if (childLayout.mainEndMarginAuto) childLayout.mainEndMarginValue = autoMarginValue;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
let startOffset = 0;
|
|
406
|
+
let itemSpacing = mainGap;
|
|
407
|
+
if (!hasAutoMargins) switch (style.justifyContent) {
|
|
408
|
+
case 2:
|
|
409
|
+
startOffset = remainingSpace;
|
|
410
|
+
break;
|
|
411
|
+
case 1:
|
|
412
|
+
startOffset = remainingSpace / 2;
|
|
413
|
+
break;
|
|
414
|
+
case 3:
|
|
415
|
+
if (children.length > 1 && remainingSpace > 0) itemSpacing = mainGap + remainingSpace / (children.length - 1);
|
|
416
|
+
break;
|
|
417
|
+
case 4:
|
|
418
|
+
if (children.length > 0) {
|
|
419
|
+
const extraSpace = remainingSpace / children.length;
|
|
420
|
+
startOffset = extraSpace / 2;
|
|
421
|
+
itemSpacing = mainGap + extraSpace;
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
case 5:
|
|
425
|
+
if (children.length > 0) {
|
|
426
|
+
const extraSpace = remainingSpace / (children.length + 1);
|
|
427
|
+
startOffset = extraSpace;
|
|
428
|
+
itemSpacing = mainGap + extraSpace;
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
let maxBaseline = 0;
|
|
433
|
+
const childBaselines = [];
|
|
434
|
+
if ((style.alignItems === 5 || relativeChildren.some((c) => c.style.alignSelf === 5)) && isRow) for (let i = 0; i < children.length; i++) {
|
|
435
|
+
const childLayout = children[i];
|
|
436
|
+
const child = childLayout.node;
|
|
437
|
+
const childStyle = child.style;
|
|
438
|
+
const topMargin = resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction);
|
|
439
|
+
let childWidth;
|
|
440
|
+
let childHeight;
|
|
441
|
+
const widthDim = childStyle.width;
|
|
442
|
+
const heightDim = childStyle.height;
|
|
443
|
+
if (widthDim.unit === 1) childWidth = widthDim.value;
|
|
444
|
+
else if (widthDim.unit === 2 && !Number.isNaN(mainAxisSize)) childWidth = mainAxisSize * (widthDim.value / 100);
|
|
445
|
+
else childWidth = childLayout.mainSize;
|
|
446
|
+
if (heightDim.unit === 1) childHeight = heightDim.value;
|
|
447
|
+
else if (heightDim.unit === 2 && !Number.isNaN(crossAxisSize)) childHeight = crossAxisSize * (heightDim.value / 100);
|
|
448
|
+
else {
|
|
449
|
+
layoutNode(child, childLayout.mainSize, NaN, 0, 0, 0, 0, direction);
|
|
450
|
+
childWidth = child.layout.width;
|
|
451
|
+
childHeight = child.layout.height;
|
|
452
|
+
}
|
|
453
|
+
let baseline;
|
|
454
|
+
if (child.baselineFunc !== null) baseline = topMargin + child.baselineFunc(childWidth, childHeight);
|
|
455
|
+
else baseline = topMargin + childHeight;
|
|
456
|
+
childBaselines.push(baseline);
|
|
457
|
+
maxBaseline = Math.max(maxBaseline, baseline);
|
|
458
|
+
}
|
|
459
|
+
const childLineIndex = /* @__PURE__ */ new Map();
|
|
460
|
+
const lineCrossOffsets = [];
|
|
461
|
+
let cumulativeCrossOffset = 0;
|
|
462
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
463
|
+
const line = lines[lineIdx];
|
|
464
|
+
lineCrossOffsets.push(cumulativeCrossOffset);
|
|
465
|
+
let maxLineCross = 0;
|
|
466
|
+
for (const childLayout of line.children) {
|
|
467
|
+
childLineIndex.set(childLayout, lineIdx);
|
|
468
|
+
const childStyle = childLayout.node.style;
|
|
469
|
+
const crossDim = isRow ? childStyle.height : childStyle.width;
|
|
470
|
+
const crossMarginStart = isRow ? resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction);
|
|
471
|
+
const crossMarginEnd = isRow ? resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction);
|
|
472
|
+
let childCross = 0;
|
|
473
|
+
if (crossDim.unit === 1) childCross = crossDim.value;
|
|
474
|
+
else if (crossDim.unit === 2 && !Number.isNaN(crossAxisSize)) childCross = crossAxisSize * (crossDim.value / 100);
|
|
475
|
+
else if (childLayout.node.children.length > 0) childCross = isRow ? childLayout.node.layout.height : childLayout.node.layout.width;
|
|
476
|
+
else childCross = 0;
|
|
477
|
+
maxLineCross = Math.max(maxLineCross, childCross + crossMarginStart + crossMarginEnd);
|
|
478
|
+
}
|
|
479
|
+
line.crossSize = maxLineCross > 0 ? maxLineCross : crossAxisSize / lines.length;
|
|
480
|
+
cumulativeCrossOffset += line.crossSize + crossGap;
|
|
481
|
+
}
|
|
482
|
+
const isWrapReverse = style.flexWrap === 2;
|
|
483
|
+
const numLines = lines.length;
|
|
484
|
+
if (!Number.isNaN(crossAxisSize) && numLines > 0) {
|
|
485
|
+
const freeSpace = crossAxisSize - (cumulativeCrossOffset - crossGap);
|
|
486
|
+
const alignContent = style.alignContent;
|
|
487
|
+
if (freeSpace > 0 || alignContent === 4) switch (alignContent) {
|
|
488
|
+
case 3:
|
|
489
|
+
for (let i = 0; i < numLines; i++) lineCrossOffsets[i] += freeSpace;
|
|
490
|
+
break;
|
|
491
|
+
case 2:
|
|
492
|
+
const centerOffset = freeSpace / 2;
|
|
493
|
+
for (let i = 0; i < numLines; i++) lineCrossOffsets[i] += centerOffset;
|
|
494
|
+
break;
|
|
495
|
+
case 6:
|
|
496
|
+
if (numLines > 1) {
|
|
497
|
+
const gap = freeSpace / (numLines - 1);
|
|
498
|
+
for (let i = 1; i < numLines; i++) lineCrossOffsets[i] += gap * i;
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
case 7:
|
|
502
|
+
const halfGap = freeSpace / (numLines * 2);
|
|
503
|
+
for (let i = 0; i < numLines; i++) lineCrossOffsets[i] += halfGap + halfGap * 2 * i;
|
|
504
|
+
break;
|
|
505
|
+
case 8:
|
|
506
|
+
if (numLines > 0) {
|
|
507
|
+
const spaceEvenlyGap = freeSpace / (numLines + 1);
|
|
508
|
+
for (let i = 0; i < numLines; i++) lineCrossOffsets[i] += spaceEvenlyGap * (i + 1);
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
case 4:
|
|
512
|
+
if (freeSpace > 0 && numLines > 0) {
|
|
513
|
+
const extraPerLine = freeSpace / numLines;
|
|
514
|
+
for (let i = 0; i < numLines; i++) {
|
|
515
|
+
lines[i].crossSize += extraPerLine;
|
|
516
|
+
if (i > 0) lineCrossOffsets[i] = lineCrossOffsets[i - 1] + lines[i - 1].crossSize + crossGap;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
if (isWrapReverse) {
|
|
522
|
+
let totalLineCrossSize = 0;
|
|
523
|
+
for (let i = 0; i < numLines; i++) totalLineCrossSize += lines[i].crossSize;
|
|
524
|
+
totalLineCrossSize += crossGap * (numLines - 1);
|
|
525
|
+
const crossStartOffset = crossAxisSize - totalLineCrossSize;
|
|
526
|
+
for (let i = 0; i < numLines; i++) lineCrossOffsets[i] += crossStartOffset;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const effectiveReverse = isRow ? direction === 2 !== isReverse : isReverse;
|
|
530
|
+
let mainPos = effectiveReverse ? mainAxisSize - startOffset : startOffset;
|
|
531
|
+
let currentLineIdx = -1;
|
|
532
|
+
log.debug?.("positioning children: isRow=%s, startOffset=%d, relativeChildren=%d, isReverse=%s, lines=%d", isRow, startOffset, relativeChildren.length, isReverse, lines.length);
|
|
533
|
+
for (let i = 0; i < children.length; i++) {
|
|
534
|
+
const childLayout = children[i];
|
|
535
|
+
const child = childLayout.node;
|
|
536
|
+
const childStyle = child.style;
|
|
537
|
+
const childLineIdx = childLineIndex.get(childLayout) ?? 0;
|
|
538
|
+
if (childLineIdx !== currentLineIdx) {
|
|
539
|
+
currentLineIdx = childLineIdx;
|
|
540
|
+
mainPos = effectiveReverse ? mainAxisSize - startOffset : startOffset;
|
|
541
|
+
}
|
|
542
|
+
const lineCrossOffset = lineCrossOffsets[childLineIdx] ?? 0;
|
|
543
|
+
let childMarginLeft;
|
|
544
|
+
let childMarginTop;
|
|
545
|
+
let childMarginRight;
|
|
546
|
+
let childMarginBottom;
|
|
547
|
+
if (isRow) {
|
|
548
|
+
childMarginLeft = childLayout.mainStartMarginAuto && !isReverse ? childLayout.mainStartMarginValue : childLayout.mainEndMarginAuto && isReverse ? childLayout.mainEndMarginValue : resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction);
|
|
549
|
+
childMarginRight = childLayout.mainEndMarginAuto && !isReverse ? childLayout.mainEndMarginValue : childLayout.mainStartMarginAuto && isReverse ? childLayout.mainStartMarginValue : resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction);
|
|
550
|
+
childMarginTop = resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction);
|
|
551
|
+
childMarginBottom = resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction);
|
|
552
|
+
} else {
|
|
553
|
+
childMarginTop = childLayout.mainStartMarginAuto && !isReverse ? childLayout.mainStartMarginValue : childLayout.mainEndMarginAuto && isReverse ? childLayout.mainEndMarginValue : resolveEdgeValue(childStyle.margin, 1, style.flexDirection, contentWidth, direction);
|
|
554
|
+
childMarginBottom = childLayout.mainEndMarginAuto && !isReverse ? childLayout.mainEndMarginValue : childLayout.mainStartMarginAuto && isReverse ? childLayout.mainStartMarginValue : resolveEdgeValue(childStyle.margin, 3, style.flexDirection, contentWidth, direction);
|
|
555
|
+
childMarginLeft = resolveEdgeValue(childStyle.margin, 0, style.flexDirection, contentWidth, direction);
|
|
556
|
+
childMarginRight = resolveEdgeValue(childStyle.margin, 2, style.flexDirection, contentWidth, direction);
|
|
557
|
+
}
|
|
558
|
+
const childMainSize = childLayout.mainSize;
|
|
559
|
+
let alignment = style.alignItems;
|
|
560
|
+
if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
|
|
561
|
+
let childCrossSize;
|
|
562
|
+
const crossDim = isRow ? childStyle.height : childStyle.width;
|
|
563
|
+
const crossMargin = isRow ? childMarginTop + childMarginBottom : childMarginLeft + childMarginRight;
|
|
564
|
+
const parentCrossDim = isRow ? style.height : style.width;
|
|
565
|
+
const parentHasDefiniteCross = parentCrossDim.unit === 1 || parentCrossDim.unit === 2 || !Number.isNaN(crossAxisSize);
|
|
566
|
+
if (crossDim.unit === 1) childCrossSize = crossDim.value;
|
|
567
|
+
else if (crossDim.unit === 2) childCrossSize = resolveValue(crossDim, crossAxisSize);
|
|
568
|
+
else if (parentHasDefiniteCross && alignment === 4) childCrossSize = crossAxisSize - crossMargin;
|
|
569
|
+
else childCrossSize = NaN;
|
|
570
|
+
const crossMinVal = isRow ? childStyle.minHeight : childStyle.minWidth;
|
|
571
|
+
const crossMaxVal = isRow ? childStyle.maxHeight : childStyle.maxWidth;
|
|
572
|
+
const crossMin = crossMinVal.unit !== 0 ? resolveValue(crossMinVal, crossAxisSize) : 0;
|
|
573
|
+
const crossMax = crossMaxVal.unit !== 0 ? resolveValue(crossMaxVal, crossAxisSize) : Infinity;
|
|
574
|
+
if (Number.isNaN(childCrossSize)) {
|
|
575
|
+
if (crossMin > 0) childCrossSize = crossMin;
|
|
576
|
+
} else childCrossSize = Math.max(crossMin, Math.min(crossMax, childCrossSize));
|
|
577
|
+
const mainDim = isRow ? childStyle.width : childStyle.height;
|
|
578
|
+
const mainIsAuto = mainDim.unit === 3 || mainDim.unit === 0;
|
|
579
|
+
const hasFlexGrow = childLayout.flexGrow > 0;
|
|
580
|
+
const parentMainDim = isRow ? style.width : style.height;
|
|
581
|
+
parentMainDim.unit === 1 || parentMainDim.unit;
|
|
582
|
+
let effectiveMainSize;
|
|
583
|
+
if (hasFlexGrow) effectiveMainSize = childMainSize;
|
|
584
|
+
else if (mainIsAuto) effectiveMainSize = childMainSize;
|
|
585
|
+
else effectiveMainSize = childMainSize;
|
|
586
|
+
let childWidth = isRow ? effectiveMainSize : childCrossSize;
|
|
587
|
+
let childHeight = isRow ? childCrossSize : effectiveMainSize;
|
|
588
|
+
if (child.hasMeasureFunc() && child.children.length === 0 && !hasFlexGrow) {
|
|
589
|
+
const widthAuto = childStyle.width.unit === 3 || childStyle.width.unit === 0;
|
|
590
|
+
const heightAuto = childStyle.height.unit === 3 || childStyle.height.unit === 0;
|
|
591
|
+
if (widthAuto || heightAuto) {
|
|
592
|
+
const widthMode = widthAuto ? 2 : 1;
|
|
593
|
+
const heightMode = heightAuto ? 0 : 1;
|
|
594
|
+
const rawAvailW = widthAuto ? isRow ? mainAxisSize - mainPos : crossAxisSize - crossMargin : childStyle.width.value;
|
|
595
|
+
const rawAvailH = heightAuto ? isRow ? crossAxisSize - crossMargin : mainAxisSize - mainPos : childStyle.height.value;
|
|
596
|
+
const availW = Number.isNaN(rawAvailW) ? Infinity : rawAvailW;
|
|
597
|
+
const availH = Number.isNaN(rawAvailH) ? Infinity : rawAvailH;
|
|
598
|
+
const measured = child.measureFunc(availW, widthMode, availH, heightMode);
|
|
599
|
+
if (widthAuto) childWidth = measured.width;
|
|
600
|
+
if (heightAuto) childHeight = measured.height;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
let childX;
|
|
604
|
+
let childY;
|
|
605
|
+
if (effectiveReverse) if (isRow) {
|
|
606
|
+
childX = mainPos - childMainSize - childMarginRight;
|
|
607
|
+
childY = lineCrossOffset + childMarginTop;
|
|
608
|
+
} else {
|
|
609
|
+
childX = lineCrossOffset + childMarginLeft;
|
|
610
|
+
childY = mainPos - childMainSize - childMarginTop;
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
childX = isRow ? mainPos + childMarginLeft : lineCrossOffset + childMarginLeft;
|
|
614
|
+
childY = isRow ? lineCrossOffset + childMarginTop : mainPos + childMarginTop;
|
|
615
|
+
}
|
|
616
|
+
const fractionalLeft = innerLeft + childX;
|
|
617
|
+
const fractionalTop = innerTop + childY;
|
|
618
|
+
let posOffsetX = 0;
|
|
619
|
+
let posOffsetY = 0;
|
|
620
|
+
if (childStyle.positionType === 1) {
|
|
621
|
+
const relLeftPos = childStyle.position[0];
|
|
622
|
+
const relTopPos = childStyle.position[1];
|
|
623
|
+
const relRightPos = childStyle.position[2];
|
|
624
|
+
const relBottomPos = childStyle.position[3];
|
|
625
|
+
if (relLeftPos.unit !== 0) posOffsetX = resolveValue(relLeftPos, contentWidth);
|
|
626
|
+
else if (relRightPos.unit !== 0) posOffsetX = -resolveValue(relRightPos, contentWidth);
|
|
627
|
+
if (relTopPos.unit !== 0) posOffsetY = resolveValue(relTopPos, contentHeight);
|
|
628
|
+
else if (relBottomPos.unit !== 0) posOffsetY = -resolveValue(relBottomPos, contentHeight);
|
|
629
|
+
}
|
|
630
|
+
const absChildLeft = absX + marginLeft + parentPosOffsetX + fractionalLeft + posOffsetX;
|
|
631
|
+
const absChildTop = absY + marginTop + parentPosOffsetY + fractionalTop + posOffsetY;
|
|
632
|
+
let roundedAbsMainStart;
|
|
633
|
+
let roundedAbsMainEnd;
|
|
634
|
+
let edgeBasedMainSize;
|
|
635
|
+
const useEdgeBasedRounding = childMainSize > 0;
|
|
636
|
+
const childPaddingL = resolveEdgeValue(childStyle.padding, 0, childStyle.flexDirection, contentWidth, direction);
|
|
637
|
+
const childPaddingT = resolveEdgeValue(childStyle.padding, 1, childStyle.flexDirection, contentWidth, direction);
|
|
638
|
+
const childPaddingR = resolveEdgeValue(childStyle.padding, 2, childStyle.flexDirection, contentWidth, direction);
|
|
639
|
+
const childPaddingB = resolveEdgeValue(childStyle.padding, 3, childStyle.flexDirection, contentWidth, direction);
|
|
640
|
+
const childBorderL = resolveEdgeBorderValue(childStyle.border, 0, childStyle.flexDirection, direction);
|
|
641
|
+
const childBorderT = resolveEdgeBorderValue(childStyle.border, 1, childStyle.flexDirection, direction);
|
|
642
|
+
const childBorderR = resolveEdgeBorderValue(childStyle.border, 2, childStyle.flexDirection, direction);
|
|
643
|
+
const childBorderB = resolveEdgeBorderValue(childStyle.border, 3, childStyle.flexDirection, direction);
|
|
644
|
+
const childMinW = childPaddingL + childPaddingR + childBorderL + childBorderR;
|
|
645
|
+
const childMinH = childPaddingT + childPaddingB + childBorderT + childBorderB;
|
|
646
|
+
const childMinMain = isRow ? childMinW : childMinH;
|
|
647
|
+
const constrainedMainSize = Math.max(childMainSize, childMinMain);
|
|
648
|
+
if (useEdgeBasedRounding) if (isRow) {
|
|
649
|
+
roundedAbsMainStart = Math.round(absChildLeft);
|
|
650
|
+
roundedAbsMainEnd = Math.round(absChildLeft + constrainedMainSize);
|
|
651
|
+
edgeBasedMainSize = roundedAbsMainEnd - roundedAbsMainStart;
|
|
652
|
+
} else {
|
|
653
|
+
roundedAbsMainStart = Math.round(absChildTop);
|
|
654
|
+
roundedAbsMainEnd = Math.round(absChildTop + constrainedMainSize);
|
|
655
|
+
edgeBasedMainSize = roundedAbsMainEnd - roundedAbsMainStart;
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
roundedAbsMainStart = isRow ? Math.round(absChildLeft) : Math.round(absChildTop);
|
|
659
|
+
edgeBasedMainSize = childMinMain;
|
|
660
|
+
}
|
|
661
|
+
const childLeft = Math.round(fractionalLeft + posOffsetX);
|
|
662
|
+
const childTop = Math.round(fractionalTop + posOffsetY);
|
|
663
|
+
const crossDimForLayoutCall = isRow ? childStyle.height : childStyle.width;
|
|
664
|
+
const crossIsAutoForLayoutCall = crossDimForLayoutCall.unit === 3 || crossDimForLayoutCall.unit === 0;
|
|
665
|
+
const mainIsPercent = (isRow ? childStyle.width : childStyle.height).unit === 2;
|
|
666
|
+
const crossIsPercent = crossDimForLayoutCall.unit === 2;
|
|
667
|
+
let passWidthToChild;
|
|
668
|
+
if (isRow && mainIsAuto && !hasFlexGrow) passWidthToChild = NaN;
|
|
669
|
+
else if (!isRow && crossIsAutoForLayoutCall && !parentHasDefiniteCross) passWidthToChild = NaN;
|
|
670
|
+
else if (isRow && mainIsPercent) passWidthToChild = contentWidth;
|
|
671
|
+
else if (!isRow && crossIsPercent) passWidthToChild = contentWidth;
|
|
672
|
+
else passWidthToChild = childWidth;
|
|
673
|
+
let passHeightToChild;
|
|
674
|
+
if (!isRow && mainIsAuto && !hasFlexGrow) passHeightToChild = NaN;
|
|
675
|
+
else if (isRow && crossIsAutoForLayoutCall && !parentHasDefiniteCross) passHeightToChild = NaN;
|
|
676
|
+
else if (!isRow && mainIsPercent) passHeightToChild = contentHeight;
|
|
677
|
+
else if (isRow && crossIsPercent) passHeightToChild = contentHeight;
|
|
678
|
+
else passHeightToChild = childHeight;
|
|
679
|
+
const childAbsX = absChildLeft - childMarginLeft;
|
|
680
|
+
const childAbsY = absChildTop - childMarginTop;
|
|
681
|
+
layoutNode(child, passWidthToChild, passHeightToChild, childLeft, childTop, childAbsX, childAbsY, direction);
|
|
682
|
+
if (childWidth < childMinW) childWidth = childMinW;
|
|
683
|
+
if (childHeight < childMinH) childHeight = childMinH;
|
|
684
|
+
const hasMeasure = child.hasMeasureFunc() && child.children.length === 0;
|
|
685
|
+
if (!mainIsAuto || hasFlexGrow || hasMeasure || !Number.isNaN(effectiveMainSize)) if (isRow) child.layout.width = edgeBasedMainSize;
|
|
686
|
+
else child.layout.height = edgeBasedMainSize;
|
|
687
|
+
const crossDimForCheck = isRow ? childStyle.height : childStyle.width;
|
|
688
|
+
const crossIsAuto = crossDimForCheck.unit === 3 || crossDimForCheck.unit === 0;
|
|
689
|
+
const parentCrossIsAuto = !parentHasDefiniteCross;
|
|
690
|
+
const hasCrossMinMax = crossMinVal.unit !== 0 || crossMaxVal.unit !== 0;
|
|
691
|
+
if (!crossIsAuto || !parentCrossIsAuto && alignment === 4 || hasCrossMinMax && !Number.isNaN(childCrossSize)) if (isRow) child.layout.height = Math.round(childHeight);
|
|
692
|
+
else child.layout.width = Math.round(childWidth);
|
|
693
|
+
child.layout.left = childLeft;
|
|
694
|
+
child.layout.top = childTop;
|
|
695
|
+
childWidth = child.layout.width;
|
|
696
|
+
childHeight = child.layout.height;
|
|
697
|
+
const finalCrossSize = isRow ? child.layout.height : child.layout.width;
|
|
698
|
+
let crossOffset = 0;
|
|
699
|
+
const crossStartMargin = isRow ? childStyle.margin[1] : childStyle.margin[0];
|
|
700
|
+
const crossEndMargin = isRow ? childStyle.margin[3] : childStyle.margin[2];
|
|
701
|
+
const hasAutoStartMargin = crossStartMargin.unit === 3;
|
|
702
|
+
const hasAutoEndMargin = crossEndMargin.unit === 3;
|
|
703
|
+
const availableCrossSpace = crossAxisSize - finalCrossSize - crossMargin;
|
|
704
|
+
if (hasAutoStartMargin && hasAutoEndMargin) crossOffset = availableCrossSpace / 2;
|
|
705
|
+
else if (hasAutoStartMargin) crossOffset = availableCrossSpace;
|
|
706
|
+
else if (hasAutoEndMargin) crossOffset = 0;
|
|
707
|
+
else switch (alignment) {
|
|
708
|
+
case 3:
|
|
709
|
+
crossOffset = availableCrossSpace;
|
|
710
|
+
break;
|
|
711
|
+
case 2:
|
|
712
|
+
crossOffset = availableCrossSpace / 2;
|
|
713
|
+
break;
|
|
714
|
+
case 5:
|
|
715
|
+
if (isRow && childBaselines.length > 0) crossOffset = maxBaseline - childBaselines[i];
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
if (crossOffset !== 0) if (isRow) child.layout.top += Math.round(crossOffset);
|
|
719
|
+
else child.layout.left += Math.round(crossOffset);
|
|
720
|
+
const fractionalMainSize = constrainedMainSize;
|
|
721
|
+
const totalMainMargin = childLayout.mainStartMarginValue + childLayout.mainEndMarginValue;
|
|
722
|
+
log.debug?.(" child %d: mainPos=%d → top=%d (fractionalMainSize=%d, totalMainMargin=%d)", i, mainPos, child.layout.top, fractionalMainSize, totalMainMargin);
|
|
723
|
+
if (effectiveReverse) {
|
|
724
|
+
mainPos -= fractionalMainSize + totalMainMargin;
|
|
725
|
+
if (i < children.length - 1) mainPos -= itemSpacing;
|
|
726
|
+
} else {
|
|
727
|
+
mainPos += fractionalMainSize + totalMainMargin;
|
|
728
|
+
if (i < children.length - 1) mainPos += itemSpacing;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
let actualUsedMain = 0;
|
|
732
|
+
for (const childLayout of children) {
|
|
733
|
+
const childMainSize = isRow ? childLayout.node.layout.width : childLayout.node.layout.height;
|
|
734
|
+
const totalMainMargin = childLayout.mainStartMarginValue + childLayout.mainEndMarginValue;
|
|
735
|
+
actualUsedMain += childMainSize + totalMainMargin;
|
|
736
|
+
}
|
|
737
|
+
actualUsedMain += totalGaps;
|
|
738
|
+
if (isRow && style.width.unit !== 1 && style.width.unit !== 2) nodeWidth = actualUsedMain + innerLeft + innerRight;
|
|
739
|
+
if (!isRow && style.height.unit !== 1 && style.height.unit !== 2) nodeHeight = actualUsedMain + innerTop + innerBottom;
|
|
740
|
+
let maxCrossSize = 0;
|
|
741
|
+
for (const childLayout of children) {
|
|
742
|
+
const childCross = isRow ? childLayout.node.layout.height : childLayout.node.layout.width;
|
|
743
|
+
const childMargin = isRow ? resolveEdgeValue(childLayout.node.style.margin, 1, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childLayout.node.style.margin, 3, style.flexDirection, contentWidth, direction) : resolveEdgeValue(childLayout.node.style.margin, 0, style.flexDirection, contentWidth, direction) + resolveEdgeValue(childLayout.node.style.margin, 2, style.flexDirection, contentWidth, direction);
|
|
744
|
+
maxCrossSize = Math.max(maxCrossSize, childCross + childMargin);
|
|
745
|
+
}
|
|
746
|
+
if (isRow && style.height.unit !== 1 && style.height.unit !== 2 && Number.isNaN(availableHeight)) nodeHeight = maxCrossSize + innerTop + innerBottom;
|
|
747
|
+
if (!isRow && style.width.unit !== 1 && style.width.unit !== 2 && Number.isNaN(availableWidth)) nodeWidth = maxCrossSize + innerLeft + innerRight;
|
|
748
|
+
}
|
|
749
|
+
nodeWidth = applyMinMax(nodeWidth, style.minWidth, style.maxWidth, availableWidth);
|
|
750
|
+
nodeHeight = applyMinMax(nodeHeight, style.minHeight, style.maxHeight, availableHeight);
|
|
751
|
+
if (!Number.isNaN(nodeWidth) && nodeWidth < minInnerWidth) nodeWidth = minInnerWidth;
|
|
752
|
+
if (!Number.isNaN(nodeHeight) && nodeHeight < minInnerHeight) nodeHeight = minInnerHeight;
|
|
753
|
+
const absNodeLeft = absX + marginLeft + parentPosOffsetX;
|
|
754
|
+
const absNodeTop = absY + marginTop + parentPosOffsetY;
|
|
755
|
+
const absNodeRight = absNodeLeft + nodeWidth;
|
|
756
|
+
const absNodeBottom = absNodeTop + nodeHeight;
|
|
757
|
+
const roundedAbsLeft = Math.round(absNodeLeft);
|
|
758
|
+
const roundedAbsTop = Math.round(absNodeTop);
|
|
759
|
+
const roundedAbsRight = Math.round(absNodeRight);
|
|
760
|
+
const roundedAbsBottom = Math.round(absNodeBottom);
|
|
761
|
+
layout.width = roundedAbsRight - roundedAbsLeft;
|
|
762
|
+
layout.height = roundedAbsBottom - roundedAbsTop;
|
|
763
|
+
const roundedAbsParentLeft = Math.round(absX);
|
|
764
|
+
const roundedAbsParentTop = Math.round(absY);
|
|
765
|
+
layout.left = roundedAbsLeft - roundedAbsParentLeft;
|
|
766
|
+
layout.top = roundedAbsTop - roundedAbsParentTop;
|
|
767
|
+
const absInnerLeft = borderLeft;
|
|
768
|
+
const absInnerTop = borderTop;
|
|
769
|
+
const absInnerRight = borderRight;
|
|
770
|
+
const absInnerBottom = borderBottom;
|
|
771
|
+
const absPaddingBoxW = nodeWidth - absInnerLeft - absInnerRight;
|
|
772
|
+
const absPaddingBoxH = nodeHeight - absInnerTop - absInnerBottom;
|
|
773
|
+
const absContentBoxW = absPaddingBoxW - paddingLeft - paddingRight;
|
|
774
|
+
const absContentBoxH = absPaddingBoxH - paddingTop - paddingBottom;
|
|
775
|
+
const isRow = isRowDirection(style.flexDirection);
|
|
776
|
+
for (const child of absoluteChildren) {
|
|
777
|
+
const childStyle = child.style;
|
|
778
|
+
const childMarginLeft = resolveEdgeValue(childStyle.margin, 0, style.flexDirection, nodeWidth, direction);
|
|
779
|
+
const childMarginTop = resolveEdgeValue(childStyle.margin, 1, style.flexDirection, nodeWidth, direction);
|
|
780
|
+
const childMarginRight = resolveEdgeValue(childStyle.margin, 2, style.flexDirection, nodeWidth, direction);
|
|
781
|
+
const childMarginBottom = resolveEdgeValue(childStyle.margin, 3, style.flexDirection, nodeWidth, direction);
|
|
782
|
+
const leftPos = childStyle.position[0];
|
|
783
|
+
const topPos = childStyle.position[1];
|
|
784
|
+
const rightPos = childStyle.position[2];
|
|
785
|
+
const bottomPos = childStyle.position[3];
|
|
786
|
+
const hasLeft = leftPos.unit !== 0;
|
|
787
|
+
const hasRight = rightPos.unit !== 0;
|
|
788
|
+
const hasTop = topPos.unit !== 0;
|
|
789
|
+
const hasBottom = bottomPos.unit !== 0;
|
|
790
|
+
const leftOffset = resolveValue(leftPos, absContentBoxW);
|
|
791
|
+
const topOffset = resolveValue(topPos, absContentBoxH);
|
|
792
|
+
const rightOffset = resolveValue(rightPos, absContentBoxW);
|
|
793
|
+
const bottomOffset = resolveValue(bottomPos, absContentBoxH);
|
|
794
|
+
const contentW = absPaddingBoxW;
|
|
795
|
+
const contentH = absPaddingBoxH;
|
|
796
|
+
let childAvailWidth;
|
|
797
|
+
const widthIsAuto = childStyle.width.unit === 3 || childStyle.width.unit === 0;
|
|
798
|
+
const widthIsPercent = childStyle.width.unit === 2;
|
|
799
|
+
if (widthIsAuto && hasLeft && hasRight) childAvailWidth = contentW - leftOffset - rightOffset - childMarginLeft - childMarginRight;
|
|
800
|
+
else if (widthIsAuto) childAvailWidth = NaN;
|
|
801
|
+
else if (widthIsPercent) childAvailWidth = absContentBoxW;
|
|
802
|
+
else childAvailWidth = contentW;
|
|
803
|
+
let childAvailHeight;
|
|
804
|
+
const heightIsAuto = childStyle.height.unit === 3 || childStyle.height.unit === 0;
|
|
805
|
+
const heightIsPercent = childStyle.height.unit === 2;
|
|
806
|
+
if (heightIsAuto && hasTop && hasBottom) childAvailHeight = contentH - topOffset - bottomOffset - childMarginTop - childMarginBottom;
|
|
807
|
+
else if (heightIsAuto) childAvailHeight = NaN;
|
|
808
|
+
else if (heightIsPercent) childAvailHeight = absContentBoxH;
|
|
809
|
+
else childAvailHeight = contentH;
|
|
810
|
+
let childX = childMarginLeft + leftOffset;
|
|
811
|
+
let childY = childMarginTop + topOffset;
|
|
812
|
+
const childAbsX = absX + marginLeft + absInnerLeft + leftOffset;
|
|
813
|
+
const childAbsY = absY + marginTop + absInnerTop + topOffset;
|
|
814
|
+
const clampIfNumber = (v) => Number.isNaN(v) ? NaN : Math.max(0, v);
|
|
815
|
+
layoutNode(child, clampIfNumber(childAvailWidth), clampIfNumber(childAvailHeight), layout.left + absInnerLeft + childX, layout.top + absInnerTop + childY, childAbsX, childAbsY, direction);
|
|
816
|
+
const childWidth = child.layout.width;
|
|
817
|
+
const childHeight = child.layout.height;
|
|
818
|
+
if (!hasLeft && !hasRight) if (isRow) {
|
|
819
|
+
const freeSpaceX = contentW - childWidth - childMarginLeft - childMarginRight;
|
|
820
|
+
switch (style.justifyContent) {
|
|
821
|
+
case 1:
|
|
822
|
+
childX = childMarginLeft + freeSpaceX / 2;
|
|
823
|
+
break;
|
|
824
|
+
case 2:
|
|
825
|
+
childX = childMarginLeft + freeSpaceX;
|
|
826
|
+
break;
|
|
827
|
+
default:
|
|
828
|
+
childX = childMarginLeft;
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
} else {
|
|
832
|
+
let alignment = style.alignItems;
|
|
833
|
+
if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
|
|
834
|
+
const freeSpaceX = contentW - childWidth - childMarginLeft - childMarginRight;
|
|
835
|
+
switch (alignment) {
|
|
836
|
+
case 2:
|
|
837
|
+
childX = childMarginLeft + freeSpaceX / 2;
|
|
838
|
+
break;
|
|
839
|
+
case 3:
|
|
840
|
+
childX = childMarginLeft + freeSpaceX;
|
|
841
|
+
break;
|
|
842
|
+
case 4: break;
|
|
843
|
+
default:
|
|
844
|
+
childX = childMarginLeft;
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
else if (!hasLeft && hasRight) childX = contentW - rightOffset - childMarginRight - childWidth;
|
|
849
|
+
else if (hasLeft && hasRight && widthIsAuto) child.layout.width = Math.round(childAvailWidth);
|
|
850
|
+
if (!hasTop && !hasBottom) if (isRow) {
|
|
851
|
+
let alignment = style.alignItems;
|
|
852
|
+
if (childStyle.alignSelf !== 0) alignment = childStyle.alignSelf;
|
|
853
|
+
const freeSpaceY = contentH - childHeight - childMarginTop - childMarginBottom;
|
|
854
|
+
switch (alignment) {
|
|
855
|
+
case 2:
|
|
856
|
+
childY = childMarginTop + freeSpaceY / 2;
|
|
857
|
+
break;
|
|
858
|
+
case 3:
|
|
859
|
+
childY = childMarginTop + freeSpaceY;
|
|
860
|
+
break;
|
|
861
|
+
case 4: break;
|
|
862
|
+
default:
|
|
863
|
+
childY = childMarginTop;
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
866
|
+
} else {
|
|
867
|
+
const freeSpaceY = contentH - childHeight - childMarginTop - childMarginBottom;
|
|
868
|
+
switch (style.justifyContent) {
|
|
869
|
+
case 1:
|
|
870
|
+
childY = childMarginTop + freeSpaceY / 2;
|
|
871
|
+
break;
|
|
872
|
+
case 2:
|
|
873
|
+
childY = childMarginTop + freeSpaceY;
|
|
874
|
+
break;
|
|
875
|
+
default:
|
|
876
|
+
childY = childMarginTop;
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
else if (!hasTop && hasBottom) childY = contentH - bottomOffset - childMarginBottom - childHeight;
|
|
881
|
+
else if (hasTop && hasBottom && heightIsAuto) child.layout.height = Math.round(childAvailHeight);
|
|
882
|
+
child.layout.left = Math.round(absInnerLeft + childX);
|
|
883
|
+
child.layout.top = Math.round(absInnerTop + childY);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
let layoutNodeCalls = 0;
|
|
887
|
+
let layoutSizingCalls = 0;
|
|
888
|
+
let layoutPositioningCalls = 0;
|
|
889
|
+
let layoutCacheHits = 0;
|
|
890
|
+
function resetLayoutStats() {
|
|
891
|
+
layoutNodeCalls = 0;
|
|
892
|
+
layoutSizingCalls = 0;
|
|
893
|
+
layoutPositioningCalls = 0;
|
|
894
|
+
layoutCacheHits = 0;
|
|
895
|
+
}
|
|
896
|
+
//#endregion
|
|
897
|
+
//#region src/classic/node.ts
|
|
898
|
+
/**
|
|
899
|
+
* Flexily Node
|
|
900
|
+
*
|
|
901
|
+
* Yoga-compatible Node class for flexbox layout.
|
|
902
|
+
*/
|
|
903
|
+
/**
|
|
904
|
+
* A layout node in the flexbox tree.
|
|
905
|
+
*/
|
|
906
|
+
var Node = class Node {
|
|
907
|
+
_parent = null;
|
|
908
|
+
_children = [];
|
|
909
|
+
_style = createDefaultStyle();
|
|
910
|
+
_measureFunc = null;
|
|
911
|
+
_baselineFunc = null;
|
|
912
|
+
_layout = {
|
|
913
|
+
left: 0,
|
|
914
|
+
top: 0,
|
|
915
|
+
width: 0,
|
|
916
|
+
height: 0
|
|
917
|
+
};
|
|
918
|
+
_isDirty = true;
|
|
919
|
+
_hasNewLayout = false;
|
|
920
|
+
/**
|
|
921
|
+
* Create a new layout node.
|
|
922
|
+
*
|
|
923
|
+
* @returns A new Node instance
|
|
924
|
+
* @example
|
|
925
|
+
* ```typescript
|
|
926
|
+
* const root = Node.create();
|
|
927
|
+
* root.setWidth(100);
|
|
928
|
+
* root.setHeight(200);
|
|
929
|
+
* ```
|
|
930
|
+
*/
|
|
931
|
+
static create() {
|
|
932
|
+
return new Node();
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Get the number of child nodes.
|
|
936
|
+
*
|
|
937
|
+
* @returns The number of children
|
|
938
|
+
*/
|
|
939
|
+
getChildCount() {
|
|
940
|
+
return this._children.length;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Get a child node by index.
|
|
944
|
+
*
|
|
945
|
+
* @param index - Zero-based child index
|
|
946
|
+
* @returns The child node at the given index, or undefined if index is out of bounds
|
|
947
|
+
*/
|
|
948
|
+
getChild(index) {
|
|
949
|
+
return this._children[index];
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Get the parent node.
|
|
953
|
+
*
|
|
954
|
+
* @returns The parent node, or null if this is a root node
|
|
955
|
+
*/
|
|
956
|
+
getParent() {
|
|
957
|
+
return this._parent;
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Insert a child node at the specified index.
|
|
961
|
+
* If the child already has a parent, it will be removed from that parent first.
|
|
962
|
+
* Marks the node as dirty to trigger layout recalculation.
|
|
963
|
+
*
|
|
964
|
+
* @param child - The child node to insert
|
|
965
|
+
* @param index - The index at which to insert the child
|
|
966
|
+
* @example
|
|
967
|
+
* ```typescript
|
|
968
|
+
* const parent = Node.create();
|
|
969
|
+
* const child1 = Node.create();
|
|
970
|
+
* const child2 = Node.create();
|
|
971
|
+
* parent.insertChild(child1, 0);
|
|
972
|
+
* parent.insertChild(child2, 1);
|
|
973
|
+
* ```
|
|
974
|
+
*/
|
|
975
|
+
insertChild(child, index) {
|
|
976
|
+
if (child === this) throw new Error("Cannot insert a node as a child of itself");
|
|
977
|
+
let ancestor = this._parent;
|
|
978
|
+
while (ancestor !== null) {
|
|
979
|
+
if (ancestor === child) throw new Error("Cannot insert an ancestor as a child (would create a cycle)");
|
|
980
|
+
ancestor = ancestor._parent;
|
|
981
|
+
}
|
|
982
|
+
if (child._parent !== null) child._parent.removeChild(child);
|
|
983
|
+
child._parent = this;
|
|
984
|
+
this._children.splice(index, 0, child);
|
|
985
|
+
this.markDirty();
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Remove a child node from this node.
|
|
989
|
+
* The child's parent reference will be cleared.
|
|
990
|
+
* Marks the node as dirty to trigger layout recalculation.
|
|
991
|
+
*
|
|
992
|
+
* @param child - The child node to remove
|
|
993
|
+
*/
|
|
994
|
+
removeChild(child) {
|
|
995
|
+
const index = this._children.indexOf(child);
|
|
996
|
+
if (index !== -1) {
|
|
997
|
+
this._children.splice(index, 1);
|
|
998
|
+
child._parent = null;
|
|
999
|
+
this.markDirty();
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Free this node and clean up all references.
|
|
1004
|
+
* Removes the node from its parent, clears all children, and removes the measure function.
|
|
1005
|
+
* This does not recursively free child nodes.
|
|
1006
|
+
*/
|
|
1007
|
+
free() {
|
|
1008
|
+
if (this._parent !== null) this._parent.removeChild(this);
|
|
1009
|
+
for (const child of this._children) child._parent = null;
|
|
1010
|
+
this._children = [];
|
|
1011
|
+
this._measureFunc = null;
|
|
1012
|
+
this._baselineFunc = null;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Free this node and all descendants recursively.
|
|
1016
|
+
* Each node is detached from its parent and cleaned up.
|
|
1017
|
+
*/
|
|
1018
|
+
freeRecursive() {
|
|
1019
|
+
const children = [...this._children];
|
|
1020
|
+
for (const child of children) child.freeRecursive();
|
|
1021
|
+
this.free();
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Dispose the node (calls free)
|
|
1025
|
+
*/
|
|
1026
|
+
[Symbol.dispose]() {
|
|
1027
|
+
this.free();
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Set a measure function for intrinsic sizing.
|
|
1031
|
+
* The measure function is called during layout to determine the node's natural size.
|
|
1032
|
+
* Typically used for text nodes or other content that has an intrinsic size.
|
|
1033
|
+
* Marks the node as dirty to trigger layout recalculation.
|
|
1034
|
+
*
|
|
1035
|
+
* @param measureFunc - Function that returns width and height given available space and constraints
|
|
1036
|
+
* @example
|
|
1037
|
+
* ```typescript
|
|
1038
|
+
* const textNode = Node.create();
|
|
1039
|
+
* textNode.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
1040
|
+
* // Measure text and return dimensions
|
|
1041
|
+
* return { width: 50, height: 20 };
|
|
1042
|
+
* });
|
|
1043
|
+
* ```
|
|
1044
|
+
*/
|
|
1045
|
+
setMeasureFunc(measureFunc) {
|
|
1046
|
+
this._measureFunc = measureFunc;
|
|
1047
|
+
this.markDirty();
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Remove the measure function from this node.
|
|
1051
|
+
* Marks the node as dirty to trigger layout recalculation.
|
|
1052
|
+
*/
|
|
1053
|
+
unsetMeasureFunc() {
|
|
1054
|
+
this._measureFunc = null;
|
|
1055
|
+
this.markDirty();
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Check if this node has a measure function.
|
|
1059
|
+
*
|
|
1060
|
+
* @returns True if a measure function is set
|
|
1061
|
+
*/
|
|
1062
|
+
hasMeasureFunc() {
|
|
1063
|
+
return this._measureFunc !== null;
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Set a baseline function to determine where this node's text baseline is.
|
|
1067
|
+
* Used for ALIGN_BASELINE to align text across siblings with different heights.
|
|
1068
|
+
*
|
|
1069
|
+
* @param baselineFunc - Function that returns baseline offset from top given width and height
|
|
1070
|
+
* @example
|
|
1071
|
+
* ```typescript
|
|
1072
|
+
* textNode.setBaselineFunc((width, height) => {
|
|
1073
|
+
* // For a text node, baseline might be at 80% of height
|
|
1074
|
+
* return height * 0.8;
|
|
1075
|
+
* });
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
setBaselineFunc(baselineFunc) {
|
|
1079
|
+
this._baselineFunc = baselineFunc;
|
|
1080
|
+
this.markDirty();
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Remove the baseline function from this node.
|
|
1084
|
+
* Marks the node as dirty to trigger layout recalculation.
|
|
1085
|
+
*/
|
|
1086
|
+
unsetBaselineFunc() {
|
|
1087
|
+
this._baselineFunc = null;
|
|
1088
|
+
this.markDirty();
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Check if this node has a baseline function.
|
|
1092
|
+
*
|
|
1093
|
+
* @returns True if a baseline function is set
|
|
1094
|
+
*/
|
|
1095
|
+
hasBaselineFunc() {
|
|
1096
|
+
return this._baselineFunc !== null;
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Check if this node needs layout recalculation.
|
|
1100
|
+
*
|
|
1101
|
+
* @returns True if the node is dirty and needs layout
|
|
1102
|
+
*/
|
|
1103
|
+
isDirty() {
|
|
1104
|
+
return this._isDirty;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Mark this node and all ancestors as dirty.
|
|
1108
|
+
* A dirty node needs layout recalculation.
|
|
1109
|
+
* This is automatically called by all style setters and tree operations.
|
|
1110
|
+
*/
|
|
1111
|
+
markDirty() {
|
|
1112
|
+
this._isDirty = true;
|
|
1113
|
+
if (this._parent !== null) this._parent.markDirty();
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Check if this node has new layout results since the last check.
|
|
1117
|
+
*
|
|
1118
|
+
* @returns True if layout was recalculated since the last call to markLayoutSeen
|
|
1119
|
+
*/
|
|
1120
|
+
hasNewLayout() {
|
|
1121
|
+
return this._hasNewLayout;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Mark that the current layout has been seen/processed.
|
|
1125
|
+
* Clears the hasNewLayout flag.
|
|
1126
|
+
*/
|
|
1127
|
+
markLayoutSeen() {
|
|
1128
|
+
this._hasNewLayout = false;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Calculate layout for this node and all descendants.
|
|
1132
|
+
* This runs the flexbox layout algorithm to compute positions and sizes.
|
|
1133
|
+
* Only recalculates if the node is marked as dirty.
|
|
1134
|
+
*
|
|
1135
|
+
* @param width - Available width for layout
|
|
1136
|
+
* @param height - Available height for layout
|
|
1137
|
+
* @param _direction - Text direction (LTR or RTL), defaults to LTR
|
|
1138
|
+
* @example
|
|
1139
|
+
* ```typescript
|
|
1140
|
+
* const root = Node.create();
|
|
1141
|
+
* root.setFlexDirection(FLEX_DIRECTION_ROW);
|
|
1142
|
+
* root.setWidth(100);
|
|
1143
|
+
* root.setHeight(50);
|
|
1144
|
+
*
|
|
1145
|
+
* const child = Node.create();
|
|
1146
|
+
* child.setFlexGrow(1);
|
|
1147
|
+
* root.insertChild(child, 0);
|
|
1148
|
+
*
|
|
1149
|
+
* root.calculateLayout(100, 50, DIRECTION_LTR);
|
|
1150
|
+
*
|
|
1151
|
+
* // Now you can read computed layout
|
|
1152
|
+
* console.log(child.getComputedWidth());
|
|
1153
|
+
* ```
|
|
1154
|
+
*/
|
|
1155
|
+
calculateLayout(width, height, _direction = 1) {
|
|
1156
|
+
if (!this._isDirty) {
|
|
1157
|
+
log.debug?.("layout skip (not dirty)");
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const start = Date.now();
|
|
1161
|
+
const nodeCount = countNodes(this);
|
|
1162
|
+
computeLayout(this, width ?? NaN, height ?? NaN, _direction);
|
|
1163
|
+
this._isDirty = false;
|
|
1164
|
+
this._hasNewLayout = true;
|
|
1165
|
+
markSubtreeLayoutSeen(this);
|
|
1166
|
+
log.debug?.("layout: %dx%d, %d nodes in %dms", width, height, nodeCount, Date.now() - start);
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Get the computed left position after layout.
|
|
1170
|
+
*
|
|
1171
|
+
* @returns The left position in points
|
|
1172
|
+
*/
|
|
1173
|
+
getComputedLeft() {
|
|
1174
|
+
return this._layout.left;
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Get the computed top position after layout.
|
|
1178
|
+
*
|
|
1179
|
+
* @returns The top position in points
|
|
1180
|
+
*/
|
|
1181
|
+
getComputedTop() {
|
|
1182
|
+
return this._layout.top;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Get the computed width after layout.
|
|
1186
|
+
*
|
|
1187
|
+
* @returns The width in points
|
|
1188
|
+
*/
|
|
1189
|
+
getComputedWidth() {
|
|
1190
|
+
return this._layout.width;
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Get the computed height after layout.
|
|
1194
|
+
*
|
|
1195
|
+
* @returns The height in points
|
|
1196
|
+
*/
|
|
1197
|
+
getComputedHeight() {
|
|
1198
|
+
return this._layout.height;
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Get the computed right edge position after layout (left + width).
|
|
1202
|
+
*/
|
|
1203
|
+
getComputedRight() {
|
|
1204
|
+
return this._layout.left + this._layout.width;
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Get the computed bottom edge position after layout (top + height).
|
|
1208
|
+
*/
|
|
1209
|
+
getComputedBottom() {
|
|
1210
|
+
return this._layout.top + this._layout.height;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Get the computed padding for a specific edge after layout.
|
|
1214
|
+
*/
|
|
1215
|
+
getComputedPadding(edge) {
|
|
1216
|
+
return getEdgeValue(this._style.padding, edge).value;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Get the computed margin for a specific edge after layout.
|
|
1220
|
+
*/
|
|
1221
|
+
getComputedMargin(edge) {
|
|
1222
|
+
return getEdgeValue(this._style.margin, edge).value;
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Get the computed border width for a specific edge after layout.
|
|
1226
|
+
*/
|
|
1227
|
+
getComputedBorder(edge) {
|
|
1228
|
+
return getEdgeBorderValue(this._style.border, edge);
|
|
1229
|
+
}
|
|
1230
|
+
get children() {
|
|
1231
|
+
return this._children;
|
|
1232
|
+
}
|
|
1233
|
+
get style() {
|
|
1234
|
+
return this._style;
|
|
1235
|
+
}
|
|
1236
|
+
get layout() {
|
|
1237
|
+
return this._layout;
|
|
1238
|
+
}
|
|
1239
|
+
get measureFunc() {
|
|
1240
|
+
return this._measureFunc;
|
|
1241
|
+
}
|
|
1242
|
+
get baselineFunc() {
|
|
1243
|
+
return this._baselineFunc;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Set the width to a fixed value in points.
|
|
1247
|
+
*
|
|
1248
|
+
* @param value - Width in points
|
|
1249
|
+
*/
|
|
1250
|
+
setWidth(value) {
|
|
1251
|
+
if (Number.isNaN(value)) this._style.width = {
|
|
1252
|
+
value: 0,
|
|
1253
|
+
unit: 3
|
|
1254
|
+
};
|
|
1255
|
+
else this._style.width = {
|
|
1256
|
+
value,
|
|
1257
|
+
unit: 1
|
|
1258
|
+
};
|
|
1259
|
+
this.markDirty();
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Set the width as a percentage of the parent's width.
|
|
1263
|
+
*
|
|
1264
|
+
* @param value - Width as a percentage (0-100)
|
|
1265
|
+
*/
|
|
1266
|
+
setWidthPercent(value) {
|
|
1267
|
+
this._style.width = {
|
|
1268
|
+
value,
|
|
1269
|
+
unit: 2
|
|
1270
|
+
};
|
|
1271
|
+
this.markDirty();
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Set the width to auto (determined by layout algorithm).
|
|
1275
|
+
*/
|
|
1276
|
+
setWidthAuto() {
|
|
1277
|
+
this._style.width = {
|
|
1278
|
+
value: 0,
|
|
1279
|
+
unit: 3
|
|
1280
|
+
};
|
|
1281
|
+
this.markDirty();
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Set the height to a fixed value in points.
|
|
1285
|
+
*
|
|
1286
|
+
* @param value - Height in points
|
|
1287
|
+
*/
|
|
1288
|
+
setHeight(value) {
|
|
1289
|
+
if (Number.isNaN(value)) this._style.height = {
|
|
1290
|
+
value: 0,
|
|
1291
|
+
unit: 3
|
|
1292
|
+
};
|
|
1293
|
+
else this._style.height = {
|
|
1294
|
+
value,
|
|
1295
|
+
unit: 1
|
|
1296
|
+
};
|
|
1297
|
+
this.markDirty();
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Set the height as a percentage of the parent's height.
|
|
1301
|
+
*
|
|
1302
|
+
* @param value - Height as a percentage (0-100)
|
|
1303
|
+
*/
|
|
1304
|
+
setHeightPercent(value) {
|
|
1305
|
+
this._style.height = {
|
|
1306
|
+
value,
|
|
1307
|
+
unit: 2
|
|
1308
|
+
};
|
|
1309
|
+
this.markDirty();
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Set the height to auto (determined by layout algorithm).
|
|
1313
|
+
*/
|
|
1314
|
+
setHeightAuto() {
|
|
1315
|
+
this._style.height = {
|
|
1316
|
+
value: 0,
|
|
1317
|
+
unit: 3
|
|
1318
|
+
};
|
|
1319
|
+
this.markDirty();
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Set the minimum width in points.
|
|
1323
|
+
*
|
|
1324
|
+
* @param value - Minimum width in points
|
|
1325
|
+
*/
|
|
1326
|
+
setMinWidth(value) {
|
|
1327
|
+
this._style.minWidth = {
|
|
1328
|
+
value,
|
|
1329
|
+
unit: 1
|
|
1330
|
+
};
|
|
1331
|
+
this.markDirty();
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Set the minimum width as a percentage of the parent's width.
|
|
1335
|
+
*
|
|
1336
|
+
* @param value - Minimum width as a percentage (0-100)
|
|
1337
|
+
*/
|
|
1338
|
+
setMinWidthPercent(value) {
|
|
1339
|
+
this._style.minWidth = {
|
|
1340
|
+
value,
|
|
1341
|
+
unit: 2
|
|
1342
|
+
};
|
|
1343
|
+
this.markDirty();
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Set the minimum height in points.
|
|
1347
|
+
*
|
|
1348
|
+
* @param value - Minimum height in points
|
|
1349
|
+
*/
|
|
1350
|
+
setMinHeight(value) {
|
|
1351
|
+
this._style.minHeight = {
|
|
1352
|
+
value,
|
|
1353
|
+
unit: 1
|
|
1354
|
+
};
|
|
1355
|
+
this.markDirty();
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Set the minimum height as a percentage of the parent's height.
|
|
1359
|
+
*
|
|
1360
|
+
* @param value - Minimum height as a percentage (0-100)
|
|
1361
|
+
*/
|
|
1362
|
+
setMinHeightPercent(value) {
|
|
1363
|
+
this._style.minHeight = {
|
|
1364
|
+
value,
|
|
1365
|
+
unit: 2
|
|
1366
|
+
};
|
|
1367
|
+
this.markDirty();
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Set the maximum width in points.
|
|
1371
|
+
*
|
|
1372
|
+
* @param value - Maximum width in points
|
|
1373
|
+
*/
|
|
1374
|
+
setMaxWidth(value) {
|
|
1375
|
+
this._style.maxWidth = {
|
|
1376
|
+
value,
|
|
1377
|
+
unit: 1
|
|
1378
|
+
};
|
|
1379
|
+
this.markDirty();
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Set the maximum width as a percentage of the parent's width.
|
|
1383
|
+
*
|
|
1384
|
+
* @param value - Maximum width as a percentage (0-100)
|
|
1385
|
+
*/
|
|
1386
|
+
setMaxWidthPercent(value) {
|
|
1387
|
+
this._style.maxWidth = {
|
|
1388
|
+
value,
|
|
1389
|
+
unit: 2
|
|
1390
|
+
};
|
|
1391
|
+
this.markDirty();
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Set the maximum height in points.
|
|
1395
|
+
*
|
|
1396
|
+
* @param value - Maximum height in points
|
|
1397
|
+
*/
|
|
1398
|
+
setMaxHeight(value) {
|
|
1399
|
+
this._style.maxHeight = {
|
|
1400
|
+
value,
|
|
1401
|
+
unit: 1
|
|
1402
|
+
};
|
|
1403
|
+
this.markDirty();
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Set the maximum height as a percentage of the parent's height.
|
|
1407
|
+
*
|
|
1408
|
+
* @param value - Maximum height as a percentage (0-100)
|
|
1409
|
+
*/
|
|
1410
|
+
setMaxHeightPercent(value) {
|
|
1411
|
+
this._style.maxHeight = {
|
|
1412
|
+
value,
|
|
1413
|
+
unit: 2
|
|
1414
|
+
};
|
|
1415
|
+
this.markDirty();
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Set the aspect ratio of the node.
|
|
1419
|
+
* When set, the node's width/height relationship is constrained.
|
|
1420
|
+
* If width is defined, height = width / aspectRatio.
|
|
1421
|
+
* If height is defined, width = height * aspectRatio.
|
|
1422
|
+
*
|
|
1423
|
+
* @param value - Aspect ratio (width/height). Use NaN to unset.
|
|
1424
|
+
*/
|
|
1425
|
+
setAspectRatio(value) {
|
|
1426
|
+
this._style.aspectRatio = value;
|
|
1427
|
+
this.markDirty();
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Set the flex grow factor.
|
|
1431
|
+
* Determines how much the node will grow relative to siblings when there is extra space.
|
|
1432
|
+
*
|
|
1433
|
+
* @param value - Flex grow factor (typically 0 or 1+)
|
|
1434
|
+
* @example
|
|
1435
|
+
* ```typescript
|
|
1436
|
+
* const child = Node.create();
|
|
1437
|
+
* child.setFlexGrow(1); // Will grow to fill available space
|
|
1438
|
+
* ```
|
|
1439
|
+
*/
|
|
1440
|
+
setFlexGrow(value) {
|
|
1441
|
+
this._style.flexGrow = value;
|
|
1442
|
+
this.markDirty();
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* Set the flex shrink factor.
|
|
1446
|
+
* Determines how much the node will shrink relative to siblings when there is insufficient space.
|
|
1447
|
+
*
|
|
1448
|
+
* @param value - Flex shrink factor (default is 1)
|
|
1449
|
+
*/
|
|
1450
|
+
setFlexShrink(value) {
|
|
1451
|
+
this._style.flexShrink = value;
|
|
1452
|
+
this.markDirty();
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Set the flex basis to a fixed value in points.
|
|
1456
|
+
* The initial size of the node before flex grow/shrink is applied.
|
|
1457
|
+
*
|
|
1458
|
+
* @param value - Flex basis in points
|
|
1459
|
+
*/
|
|
1460
|
+
setFlexBasis(value) {
|
|
1461
|
+
this._style.flexBasis = {
|
|
1462
|
+
value,
|
|
1463
|
+
unit: 1
|
|
1464
|
+
};
|
|
1465
|
+
this.markDirty();
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Set the flex basis as a percentage of the parent's size.
|
|
1469
|
+
*
|
|
1470
|
+
* @param value - Flex basis as a percentage (0-100)
|
|
1471
|
+
*/
|
|
1472
|
+
setFlexBasisPercent(value) {
|
|
1473
|
+
this._style.flexBasis = {
|
|
1474
|
+
value,
|
|
1475
|
+
unit: 2
|
|
1476
|
+
};
|
|
1477
|
+
this.markDirty();
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Set the flex basis to auto (based on the node's width/height).
|
|
1481
|
+
*/
|
|
1482
|
+
setFlexBasisAuto() {
|
|
1483
|
+
this._style.flexBasis = {
|
|
1484
|
+
value: 0,
|
|
1485
|
+
unit: 3
|
|
1486
|
+
};
|
|
1487
|
+
this.markDirty();
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Set the flex direction (main axis direction).
|
|
1491
|
+
*
|
|
1492
|
+
* @param direction - FLEX_DIRECTION_ROW, FLEX_DIRECTION_COLUMN, FLEX_DIRECTION_ROW_REVERSE, or FLEX_DIRECTION_COLUMN_REVERSE
|
|
1493
|
+
* @example
|
|
1494
|
+
* ```typescript
|
|
1495
|
+
* const container = Node.create();
|
|
1496
|
+
* container.setFlexDirection(FLEX_DIRECTION_ROW); // Lay out children horizontally
|
|
1497
|
+
* ```
|
|
1498
|
+
*/
|
|
1499
|
+
setFlexDirection(direction) {
|
|
1500
|
+
this._style.flexDirection = direction;
|
|
1501
|
+
this.markDirty();
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Set the flex wrap behavior.
|
|
1505
|
+
*
|
|
1506
|
+
* @param wrap - WRAP_NO_WRAP, WRAP_WRAP, or WRAP_WRAP_REVERSE
|
|
1507
|
+
*/
|
|
1508
|
+
setFlexWrap(wrap) {
|
|
1509
|
+
this._style.flexWrap = wrap;
|
|
1510
|
+
this.markDirty();
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Set how children are aligned along the cross axis.
|
|
1514
|
+
*
|
|
1515
|
+
* @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
|
|
1516
|
+
* @example
|
|
1517
|
+
* ```typescript
|
|
1518
|
+
* const container = Node.create();
|
|
1519
|
+
* container.setFlexDirection(FLEX_DIRECTION_ROW);
|
|
1520
|
+
* container.setAlignItems(ALIGN_CENTER); // Center children vertically
|
|
1521
|
+
* ```
|
|
1522
|
+
*/
|
|
1523
|
+
setAlignItems(align) {
|
|
1524
|
+
this._style.alignItems = align;
|
|
1525
|
+
this.markDirty();
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Set how this node is aligned along the parent's cross axis.
|
|
1529
|
+
* Overrides the parent's alignItems for this specific child.
|
|
1530
|
+
*
|
|
1531
|
+
* @param align - ALIGN_AUTO, ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, or ALIGN_BASELINE
|
|
1532
|
+
*/
|
|
1533
|
+
setAlignSelf(align) {
|
|
1534
|
+
this._style.alignSelf = align;
|
|
1535
|
+
this.markDirty();
|
|
1536
|
+
}
|
|
1537
|
+
/**
|
|
1538
|
+
* Set how lines are aligned in a multi-line flex container.
|
|
1539
|
+
* Only affects containers with wrap enabled and multiple lines.
|
|
1540
|
+
*
|
|
1541
|
+
* @param align - ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH, ALIGN_SPACE_BETWEEN, or ALIGN_SPACE_AROUND
|
|
1542
|
+
*/
|
|
1543
|
+
setAlignContent(align) {
|
|
1544
|
+
this._style.alignContent = align;
|
|
1545
|
+
this.markDirty();
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Set how children are distributed along the main axis.
|
|
1549
|
+
*
|
|
1550
|
+
* @param justify - JUSTIFY_FLEX_START, JUSTIFY_CENTER, JUSTIFY_FLEX_END, JUSTIFY_SPACE_BETWEEN, JUSTIFY_SPACE_AROUND, or JUSTIFY_SPACE_EVENLY
|
|
1551
|
+
* @example
|
|
1552
|
+
* ```typescript
|
|
1553
|
+
* const container = Node.create();
|
|
1554
|
+
* container.setJustifyContent(JUSTIFY_SPACE_BETWEEN); // Space children evenly with edges at start/end
|
|
1555
|
+
* ```
|
|
1556
|
+
*/
|
|
1557
|
+
setJustifyContent(justify) {
|
|
1558
|
+
this._style.justifyContent = justify;
|
|
1559
|
+
this.markDirty();
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Set padding for one or more edges.
|
|
1563
|
+
*
|
|
1564
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1565
|
+
* @param value - Padding in points
|
|
1566
|
+
* @example
|
|
1567
|
+
* ```typescript
|
|
1568
|
+
* node.setPadding(EDGE_ALL, 10); // Set 10pt padding on all edges
|
|
1569
|
+
* node.setPadding(EDGE_HORIZONTAL, 5); // Set 5pt padding on left and right
|
|
1570
|
+
* ```
|
|
1571
|
+
*/
|
|
1572
|
+
setPadding(edge, value) {
|
|
1573
|
+
setEdgeValue(this._style.padding, edge, value, 1);
|
|
1574
|
+
this.markDirty();
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Set padding as a percentage of the parent's width.
|
|
1578
|
+
* Per CSS spec, percentage padding always resolves against the containing block's width.
|
|
1579
|
+
*
|
|
1580
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1581
|
+
* @param value - Padding as a percentage (0-100)
|
|
1582
|
+
*/
|
|
1583
|
+
setPaddingPercent(edge, value) {
|
|
1584
|
+
setEdgeValue(this._style.padding, edge, value, 2);
|
|
1585
|
+
this.markDirty();
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Set margin for one or more edges.
|
|
1589
|
+
*
|
|
1590
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1591
|
+
* @param value - Margin in points
|
|
1592
|
+
* @example
|
|
1593
|
+
* ```typescript
|
|
1594
|
+
* node.setMargin(EDGE_ALL, 5); // Set 5pt margin on all edges
|
|
1595
|
+
* node.setMargin(EDGE_TOP, 10); // Set 10pt margin on top only
|
|
1596
|
+
* ```
|
|
1597
|
+
*/
|
|
1598
|
+
setMargin(edge, value) {
|
|
1599
|
+
setEdgeValue(this._style.margin, edge, value, 1);
|
|
1600
|
+
this.markDirty();
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Set margin as a percentage of the parent's size.
|
|
1604
|
+
*
|
|
1605
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1606
|
+
* @param value - Margin as a percentage (0-100)
|
|
1607
|
+
*/
|
|
1608
|
+
setMarginPercent(edge, value) {
|
|
1609
|
+
setEdgeValue(this._style.margin, edge, value, 2);
|
|
1610
|
+
this.markDirty();
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Set margin to auto (for centering items with margin: auto).
|
|
1614
|
+
*
|
|
1615
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1616
|
+
*/
|
|
1617
|
+
setMarginAuto(edge) {
|
|
1618
|
+
setEdgeValue(this._style.margin, edge, 0, 3);
|
|
1619
|
+
this.markDirty();
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Set border width for one or more edges.
|
|
1623
|
+
*
|
|
1624
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1625
|
+
* @param value - Border width in points
|
|
1626
|
+
*/
|
|
1627
|
+
setBorder(edge, value) {
|
|
1628
|
+
setEdgeBorder(this._style.border, edge, value);
|
|
1629
|
+
this.markDirty();
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Set gap between flex items.
|
|
1633
|
+
*
|
|
1634
|
+
* @param gutter - GUTTER_COLUMN (horizontal gap), GUTTER_ROW (vertical gap), or GUTTER_ALL (both)
|
|
1635
|
+
* @param value - Gap size in points
|
|
1636
|
+
* @example
|
|
1637
|
+
* ```typescript
|
|
1638
|
+
* container.setGap(GUTTER_ALL, 8); // Set 8pt gap between all items
|
|
1639
|
+
* container.setGap(GUTTER_COLUMN, 10); // Set 10pt horizontal gap only
|
|
1640
|
+
* ```
|
|
1641
|
+
*/
|
|
1642
|
+
setGap(gutter, value) {
|
|
1643
|
+
if (gutter === 0) this._style.gap[0] = value;
|
|
1644
|
+
else if (gutter === 1) this._style.gap[1] = value;
|
|
1645
|
+
else if (gutter === 2) {
|
|
1646
|
+
this._style.gap[0] = value;
|
|
1647
|
+
this._style.gap[1] = value;
|
|
1648
|
+
}
|
|
1649
|
+
this.markDirty();
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Set the position type.
|
|
1653
|
+
*
|
|
1654
|
+
* @param positionType - POSITION_TYPE_STATIC, POSITION_TYPE_RELATIVE, or POSITION_TYPE_ABSOLUTE
|
|
1655
|
+
* @example
|
|
1656
|
+
* ```typescript
|
|
1657
|
+
* node.setPositionType(POSITION_TYPE_ABSOLUTE);
|
|
1658
|
+
* node.setPosition(EDGE_LEFT, 10);
|
|
1659
|
+
* node.setPosition(EDGE_TOP, 20);
|
|
1660
|
+
* ```
|
|
1661
|
+
*/
|
|
1662
|
+
setPositionType(positionType) {
|
|
1663
|
+
this._style.positionType = positionType;
|
|
1664
|
+
this.markDirty();
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Set position offset for one or more edges.
|
|
1668
|
+
* Only applies when position type is ABSOLUTE or RELATIVE.
|
|
1669
|
+
*
|
|
1670
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1671
|
+
* @param value - Position offset in points
|
|
1672
|
+
*/
|
|
1673
|
+
setPosition(edge, value) {
|
|
1674
|
+
if (Number.isNaN(value)) setEdgeValue(this._style.position, edge, 0, 0);
|
|
1675
|
+
else setEdgeValue(this._style.position, edge, value, 1);
|
|
1676
|
+
this.markDirty();
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Set position offset as a percentage.
|
|
1680
|
+
*
|
|
1681
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_HORIZONTAL, EDGE_VERTICAL, or EDGE_ALL
|
|
1682
|
+
* @param value - Position offset as a percentage of parent's corresponding dimension
|
|
1683
|
+
*/
|
|
1684
|
+
setPositionPercent(edge, value) {
|
|
1685
|
+
setEdgeValue(this._style.position, edge, value, 2);
|
|
1686
|
+
this.markDirty();
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Set the display type.
|
|
1690
|
+
*
|
|
1691
|
+
* @param display - DISPLAY_FLEX or DISPLAY_NONE
|
|
1692
|
+
*/
|
|
1693
|
+
setDisplay(display) {
|
|
1694
|
+
this._style.display = display;
|
|
1695
|
+
this.markDirty();
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Set the overflow behavior.
|
|
1699
|
+
*
|
|
1700
|
+
* @param overflow - OVERFLOW_VISIBLE, OVERFLOW_HIDDEN, or OVERFLOW_SCROLL
|
|
1701
|
+
*/
|
|
1702
|
+
setOverflow(overflow) {
|
|
1703
|
+
this._style.overflow = overflow;
|
|
1704
|
+
this.markDirty();
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Get the width style value.
|
|
1708
|
+
*
|
|
1709
|
+
* @returns Width value with unit (points, percent, or auto)
|
|
1710
|
+
*/
|
|
1711
|
+
getWidth() {
|
|
1712
|
+
return this._style.width;
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Get the height style value.
|
|
1716
|
+
*
|
|
1717
|
+
* @returns Height value with unit (points, percent, or auto)
|
|
1718
|
+
*/
|
|
1719
|
+
getHeight() {
|
|
1720
|
+
return this._style.height;
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Get the minimum width style value.
|
|
1724
|
+
*
|
|
1725
|
+
* @returns Minimum width value with unit
|
|
1726
|
+
*/
|
|
1727
|
+
getMinWidth() {
|
|
1728
|
+
return this._style.minWidth;
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Get the minimum height style value.
|
|
1732
|
+
*
|
|
1733
|
+
* @returns Minimum height value with unit
|
|
1734
|
+
*/
|
|
1735
|
+
getMinHeight() {
|
|
1736
|
+
return this._style.minHeight;
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Get the maximum width style value.
|
|
1740
|
+
*
|
|
1741
|
+
* @returns Maximum width value with unit
|
|
1742
|
+
*/
|
|
1743
|
+
getMaxWidth() {
|
|
1744
|
+
return this._style.maxWidth;
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Get the maximum height style value.
|
|
1748
|
+
*
|
|
1749
|
+
* @returns Maximum height value with unit
|
|
1750
|
+
*/
|
|
1751
|
+
getMaxHeight() {
|
|
1752
|
+
return this._style.maxHeight;
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Get the aspect ratio.
|
|
1756
|
+
*
|
|
1757
|
+
* @returns Aspect ratio value (NaN if not set)
|
|
1758
|
+
*/
|
|
1759
|
+
getAspectRatio() {
|
|
1760
|
+
return this._style.aspectRatio;
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Get the flex grow factor.
|
|
1764
|
+
*
|
|
1765
|
+
* @returns Flex grow value
|
|
1766
|
+
*/
|
|
1767
|
+
getFlexGrow() {
|
|
1768
|
+
return this._style.flexGrow;
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Get the flex shrink factor.
|
|
1772
|
+
*
|
|
1773
|
+
* @returns Flex shrink value
|
|
1774
|
+
*/
|
|
1775
|
+
getFlexShrink() {
|
|
1776
|
+
return this._style.flexShrink;
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Get the flex basis style value.
|
|
1780
|
+
*
|
|
1781
|
+
* @returns Flex basis value with unit
|
|
1782
|
+
*/
|
|
1783
|
+
getFlexBasis() {
|
|
1784
|
+
return this._style.flexBasis;
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Get the flex direction.
|
|
1788
|
+
*
|
|
1789
|
+
* @returns Flex direction constant
|
|
1790
|
+
*/
|
|
1791
|
+
getFlexDirection() {
|
|
1792
|
+
return this._style.flexDirection;
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Get the flex wrap setting.
|
|
1796
|
+
*
|
|
1797
|
+
* @returns Flex wrap constant
|
|
1798
|
+
*/
|
|
1799
|
+
getFlexWrap() {
|
|
1800
|
+
return this._style.flexWrap;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Get the align items setting.
|
|
1804
|
+
*
|
|
1805
|
+
* @returns Align items constant
|
|
1806
|
+
*/
|
|
1807
|
+
getAlignItems() {
|
|
1808
|
+
return this._style.alignItems;
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Get the align self setting.
|
|
1812
|
+
*
|
|
1813
|
+
* @returns Align self constant
|
|
1814
|
+
*/
|
|
1815
|
+
getAlignSelf() {
|
|
1816
|
+
return this._style.alignSelf;
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Get the align content setting.
|
|
1820
|
+
*
|
|
1821
|
+
* @returns Align content constant
|
|
1822
|
+
*/
|
|
1823
|
+
getAlignContent() {
|
|
1824
|
+
return this._style.alignContent;
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Get the justify content setting.
|
|
1828
|
+
*
|
|
1829
|
+
* @returns Justify content constant
|
|
1830
|
+
*/
|
|
1831
|
+
getJustifyContent() {
|
|
1832
|
+
return this._style.justifyContent;
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Get the padding for a specific edge.
|
|
1836
|
+
*
|
|
1837
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
|
|
1838
|
+
* @returns Padding value with unit
|
|
1839
|
+
*/
|
|
1840
|
+
getPadding(edge) {
|
|
1841
|
+
return getEdgeValue(this._style.padding, edge);
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Get the margin for a specific edge.
|
|
1845
|
+
*
|
|
1846
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
|
|
1847
|
+
* @returns Margin value with unit
|
|
1848
|
+
*/
|
|
1849
|
+
getMargin(edge) {
|
|
1850
|
+
return getEdgeValue(this._style.margin, edge);
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Get the border width for a specific edge.
|
|
1854
|
+
*
|
|
1855
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
|
|
1856
|
+
* @returns Border width in points
|
|
1857
|
+
*/
|
|
1858
|
+
getBorder(edge) {
|
|
1859
|
+
return getEdgeBorderValue(this._style.border, edge);
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Get the position offset for a specific edge.
|
|
1863
|
+
*
|
|
1864
|
+
* @param edge - EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, or EDGE_BOTTOM
|
|
1865
|
+
* @returns Position value with unit
|
|
1866
|
+
*/
|
|
1867
|
+
getPosition(edge) {
|
|
1868
|
+
return getEdgeValue(this._style.position, edge);
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Get the position type.
|
|
1872
|
+
*
|
|
1873
|
+
* @returns Position type constant
|
|
1874
|
+
*/
|
|
1875
|
+
getPositionType() {
|
|
1876
|
+
return this._style.positionType;
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Get the display type.
|
|
1880
|
+
*
|
|
1881
|
+
* @returns Display constant
|
|
1882
|
+
*/
|
|
1883
|
+
getDisplay() {
|
|
1884
|
+
return this._style.display;
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Get the overflow setting.
|
|
1888
|
+
*
|
|
1889
|
+
* @returns Overflow constant
|
|
1890
|
+
*/
|
|
1891
|
+
getOverflow() {
|
|
1892
|
+
return this._style.overflow;
|
|
1893
|
+
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Get the gap for column or row.
|
|
1896
|
+
*
|
|
1897
|
+
* @param gutter - GUTTER_COLUMN or GUTTER_ROW
|
|
1898
|
+
* @returns Gap size in points
|
|
1899
|
+
*/
|
|
1900
|
+
getGap(gutter) {
|
|
1901
|
+
if (gutter === 0) return this._style.gap[0];
|
|
1902
|
+
else if (gutter === 1) return this._style.gap[1];
|
|
1903
|
+
return this._style.gap[0];
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
//#endregion
|
|
1907
|
+
export { ALIGN_AUTO, ALIGN_BASELINE, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_FLEX_START, ALIGN_SPACE_AROUND, ALIGN_SPACE_BETWEEN, ALIGN_SPACE_EVENLY, ALIGN_STRETCH, DIRECTION_INHERIT, DIRECTION_LTR, DIRECTION_RTL, DISPLAY_FLEX, DISPLAY_NONE, EDGE_ALL, EDGE_BOTTOM, EDGE_END, EDGE_HORIZONTAL, EDGE_LEFT, EDGE_RIGHT, EDGE_START, EDGE_TOP, EDGE_VERTICAL, FLEX_DIRECTION_COLUMN, FLEX_DIRECTION_COLUMN_REVERSE, FLEX_DIRECTION_ROW, FLEX_DIRECTION_ROW_REVERSE, GUTTER_ALL, GUTTER_COLUMN, GUTTER_ROW, JUSTIFY_CENTER, JUSTIFY_FLEX_END, JUSTIFY_FLEX_START, JUSTIFY_SPACE_AROUND, JUSTIFY_SPACE_BETWEEN, JUSTIFY_SPACE_EVENLY, MEASURE_MODE_AT_MOST, MEASURE_MODE_EXACTLY, MEASURE_MODE_UNDEFINED, Node, OVERFLOW_HIDDEN, OVERFLOW_SCROLL, OVERFLOW_VISIBLE, POSITION_TYPE_ABSOLUTE, POSITION_TYPE_RELATIVE, POSITION_TYPE_STATIC, UNIT_AUTO, UNIT_PERCENT, UNIT_POINT, UNIT_UNDEFINED, WRAP_NO_WRAP, WRAP_WRAP, WRAP_WRAP_REVERSE, createDefaultStyle, createValue, layoutCacheHits, layoutNodeCalls, layoutPositioningCalls, layoutSizingCalls, resetLayoutStats };
|
|
1908
|
+
|
|
1909
|
+
//# sourceMappingURL=index-classic.mjs.map
|