@pilates/core 1.0.0-rc.1 → 1.0.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.
@@ -20,6 +20,44 @@ export function roundLayout(root) {
20
20
  collectAbsolutes(root, 0, 0, absolutes);
21
21
  applyRounding(root, absolutes, 0, 0);
22
22
  }
23
+ /**
24
+ * Round the layout of a subtree that sits at a known absolute position.
25
+ *
26
+ * Used by the Phase 3 relayout-boundary path: when a boundary node is
27
+ * re-laid out under a cache-hit root, its children's positions are in
28
+ * floating-point space. We round them in isolation using the boundary
29
+ * node's already-rounded absolute position as the origin.
30
+ *
31
+ * The boundary node's own `width`/`height` are explicit integers (that is
32
+ * the boundary invariant) and its `left`/`top` were restored from the
33
+ * parent's rounded cache, so they are already integers. We therefore do
34
+ * NOT re-round the boundary node itself — only its children. The parent
35
+ * absolute corner is `(parentAbsX + node.left, parentAbsY + node.top)`.
36
+ *
37
+ * @internal
38
+ */
39
+ export function roundLayoutSubtree(node, parentAbsX, parentAbsY) {
40
+ // Use the pre-rounding float left/top (node._floatLeft/Top) rather than the
41
+ // rounded integer _layout.left/top. The boundary node's _layout.left/top were
42
+ // restored from the parent's rounded cache (integers), but the true float
43
+ // position is stored in _floatLeft/Top (also restored from cache). Using the
44
+ // float position ensures that absolute coordinates of the boundary's children
45
+ // are computed in the same floating-point space as the full-tree roundLayout pass.
46
+ const nodeAbsX = parentAbsX + node._floatLeft;
47
+ const nodeAbsY = parentAbsY + node._floatTop;
48
+ const absolutes = new Map();
49
+ // Collect children relative to the node's absolute corner.
50
+ for (let i = 0; i < node.getChildCount(); i++) {
51
+ collectAbsolutes(node.getChild(i), nodeAbsX, nodeAbsY, absolutes);
52
+ }
53
+ // Round children (their positions are relative to `node`, so
54
+ // parentRoundedX/Y for each child is node's absolute corner rounded).
55
+ const roundedNodeX = Math.round(nodeAbsX);
56
+ const roundedNodeY = Math.round(nodeAbsY);
57
+ for (let i = 0; i < node.getChildCount(); i++) {
58
+ applyRounding(node.getChild(i), absolutes, roundedNodeX, roundedNodeY);
59
+ }
60
+ }
23
61
  function collectAbsolutes(node, parentX, parentY, out) {
24
62
  const x = parentX + node.layout.left;
25
63
  const y = parentY + node.layout.top;
@@ -34,10 +72,10 @@ function applyRounding(node, abs, parentRoundedX, parentRoundedY) {
34
72
  const roundedY = Math.round(my.y);
35
73
  const roundedR = Math.round(my.x + my.w);
36
74
  const roundedB = Math.round(my.y + my.h);
37
- node.layout.left = roundedX - parentRoundedX;
38
- node.layout.top = roundedY - parentRoundedY;
39
- node.layout.width = Math.max(0, roundedR - roundedX);
40
- node.layout.height = Math.max(0, roundedB - roundedY);
75
+ node._layout.left = roundedX - parentRoundedX;
76
+ node._layout.top = roundedY - parentRoundedY;
77
+ node._layout.width = Math.max(0, roundedR - roundedX);
78
+ node._layout.height = Math.max(0, roundedB - roundedY);
41
79
  for (let i = 0; i < node.getChildCount(); i++) {
42
80
  applyRounding(node.getChild(i), abs, roundedX, roundedY);
43
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"round.js","sourceRoot":"","sources":["../../src/algorithm/round.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC7C,gBAAgB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IACxC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,gBAAgB,CACvB,IAAU,EACV,OAAe,EACf,OAAe,EACf,GAAyB;IAEzB,MAAM,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IACrC,MAAM,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;IACpC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CACpB,IAAU,EACV,GAAyB,EACzB,cAAsB,EACtB,cAAsB;IAEtB,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAEzC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,QAAQ,GAAG,cAAc,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,QAAQ,GAAG,cAAc,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAEtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"round.js","sourceRoot":"","sources":["../../src/algorithm/round.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export declare const VERSION = "1.0.0-rc.1";
2
2
  export { Node } from './node.js';
3
3
  export { Edge } from './edge.js';
4
- export type { Align, Display, FlexDirection, FlexWrap, Justify, Length, PositionType, Style, } from './style.js';
4
+ export type { Align, Display, FlexDirection, FlexWrap, Justify, Length, Overflow, PositionType, Style, } from './style.js';
5
5
  export { MeasureMode } from './measure-func.js';
6
6
  export type { MeasureFunc, MeasureSize } from './measure-func.js';
7
7
  export type { ComputedLayout } from './layout.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,eAAe,CAAC;AAGpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EACV,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,OAAO,EACP,MAAM,EACN,YAAY,EACZ,KAAK,GACN,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGlE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,eAAe,CAAC;AAGpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EACV,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,OAAO,EACP,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,KAAK,GACN,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGlE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,YAAY,CAAC;AAEpC,OAAO;AACP,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,eAAe;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,yEAAyE;AACzE,uDAAuD;AACvD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,YAAY,CAAC;AAEpC,OAAO;AACP,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,eAAe;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAajC,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,yEAAyE;AACzE,uDAAuD;AACvD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,oBAAoB,CAAC"}
package/dist/layout.d.ts CHANGED
@@ -10,6 +10,14 @@ export interface ComputedLayout {
10
10
  top: number;
11
11
  width: number;
12
12
  height: number;
13
+ /**
14
+ * Natural content width. For nodes with `overflow !== 'visible'`, this
15
+ * is the bounding box of children unbounded by the parent's content
16
+ * width. For non-overflow nodes, equals the node's own `width`.
17
+ */
18
+ scrollWidth: number;
19
+ /** See {@link scrollWidth}. */
20
+ scrollHeight: number;
13
21
  }
14
22
  export declare function defaultLayout(): ComputedLayout;
15
23
  //# sourceMappingURL=layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAE9C"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAE9C"}
package/dist/layout.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export function defaultLayout() {
2
- return { left: 0, top: 0, width: 0, height: 0 };
2
+ return { left: 0, top: 0, width: 0, height: 0, scrollWidth: 0, scrollHeight: 0 };
3
3
  }
4
4
  //# sourceMappingURL=layout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAsBA,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;AACnF,CAAC"}
package/dist/node.d.ts CHANGED
@@ -15,19 +15,109 @@
15
15
  * - `measure` — optional measure function for leaf intrinsic sizing.
16
16
  * - `dirty` — set on style/tree mutation; consumed by the algorithm.
17
17
  */
18
+ import { type LayoutCache, MeasureCache } from './algorithm/cache.js';
18
19
  import { Edge } from './edge.js';
19
20
  import { type ComputedLayout } from './layout.js';
20
21
  import type { MeasureFunc } from './measure-func.js';
21
- import { type Align, type Display, type FlexDirection, type FlexWrap, type Justify, type Length, type PositionType, type Style } from './style.js';
22
+ import { type Align, type Display, type FlexDirection, type FlexWrap, type Justify, type Length, type Overflow, type PositionType, type Style } from './style.js';
22
23
  export declare class Node {
23
- /** Public-but-internal: read by the layout algorithm and by `getComputedLayout`. */
24
- readonly style: Style;
25
- readonly layout: ComputedLayout;
24
+ /**
25
+ * Backing storage for `style`. Mutated by this class's setters and read
26
+ * by the algorithm via the public `style` getter. The leading `_` and
27
+ * `@internal` mark this as algorithm-only — consumers must use the
28
+ * `setX()` methods.
29
+ *
30
+ * @internal
31
+ */
32
+ readonly _style: Style;
33
+ /**
34
+ * Backing storage for `layout`. Written by the algorithm in this package
35
+ * (see `algorithm/`); read externally via the public `layout` getter or
36
+ * the safer `getComputedLayout()` snapshot.
37
+ *
38
+ * @internal
39
+ */
40
+ readonly _layout: ComputedLayout;
41
+ /**
42
+ * Horizontal scroll offset. Mutable; defaults to 0. Read by the renderer
43
+ * when painting children of an `overflow !== 'visible'` node — children's
44
+ * paint origin is translated by `(-scrollLeft, -scrollTop)`. NOT clamped
45
+ * by this class — bounds clamping is the consumer's job (`<ScrollView>`
46
+ * clamps before writing). Direct mutation does not mark the node dirty
47
+ * because scroll offset is a paint-time concern, not layout.
48
+ */
49
+ scrollLeft: number;
50
+ /** See {@link scrollLeft}. */
51
+ scrollTop: number;
52
+ /** Read-only view of `_layout.scrollWidth`. See {@link scrollLeft}. */
53
+ get scrollWidth(): number;
54
+ /** Read-only view of `_layout.scrollHeight`. */
55
+ get scrollHeight(): number;
56
+ /**
57
+ * Read-only view of this node's style. Mutating the returned object is
58
+ * blocked at the type level — call `setX()` methods to change style so
59
+ * `markDirty()` runs.
60
+ */
61
+ get style(): Readonly<Style>;
62
+ /**
63
+ * Read-only view of this node's most recently computed layout. Use
64
+ * `getComputedLayout()` for a stable copy if you need to retain it past
65
+ * the next `calculateLayout()` call.
66
+ */
67
+ get layout(): Readonly<ComputedLayout>;
26
68
  private readonly _children;
27
69
  private _parent;
28
70
  private _measure;
29
71
  /** True if style or tree has changed since the last `calculateLayout()`. */
30
72
  private _dirty;
73
+ /**
74
+ * True if any descendant has been marked dirty (even if dirty propagation
75
+ * was stopped by a relayout boundary before reaching this node). Used by
76
+ * the root cache-hit path to skip `layoutChildren` for subtrees that have
77
+ * no mutations at all — not just subtrees where this node itself is clean.
78
+ *
79
+ * Invariant: `_dirty` implies `_hasDirtyDescendant` on the parent (if any).
80
+ * Cleared by `clearDirty()` after each `calculateLayout()`.
81
+ */
82
+ _hasDirtyDescendant: boolean;
83
+ /**
84
+ * Lazy-allocated measure-func result cache. Created the first time
85
+ * `setMeasureFunc()` installs a measurer. Cleared by `markDirty()`
86
+ * (which fires on every style/tree mutation) and by re-installing
87
+ * the measure function. Read by `callMeasureFunc()` in
88
+ * `algorithm/main-axis.ts`.
89
+ *
90
+ * @internal
91
+ */
92
+ _measureCache?: MeasureCache;
93
+ /**
94
+ * Lazy-allocated layout-cache. Created the first time `layoutChildren`
95
+ * (or `calculateLayout` at the root) stores a result. Cleared by
96
+ * `markDirty()`. Read by `layoutChildren` and the root
97
+ * `calculateLayout` path in `algorithm/`.
98
+ *
99
+ * @internal
100
+ */
101
+ _layoutCache?: LayoutCache;
102
+ /**
103
+ * Pre-rounding (float) left/top position of this node within its parent,
104
+ * as computed by the flex algorithm BEFORE `roundLayout` converts positions
105
+ * to integers.
106
+ *
107
+ * Written by the position-write helpers in `algorithm/main-axis.ts` at the
108
+ * same time as `_layout.left/top`. After `roundLayout` runs, `_layout.left/top`
109
+ * become integers but `_floatLeft/Top` retain the float values. These are
110
+ * captured by `snapshotForCache` and restored by `restoreFromCache` so that
111
+ * `roundLayoutSubtree` can compute the correct absolute float coordinate for
112
+ * a re-laid-out boundary node's children.
113
+ *
114
+ * Initialized to 0 (same as `_layout.left/top`).
115
+ *
116
+ * @internal
117
+ */
118
+ _floatLeft: number;
119
+ /** See {@link _floatLeft}. @internal */
120
+ _floatTop: number;
31
121
  /** Construct via `Node.create()` to mirror Yoga's factory style. */
32
122
  static create(): Node;
33
123
  insertChild(child: Node, index: number): void;
@@ -42,7 +132,16 @@ export declare class Node {
42
132
  getMeasureFunc(): MeasureFunc | null;
43
133
  setFlexDirection(value: FlexDirection): void;
44
134
  setFlexWrap(value: FlexWrap): void;
45
- /** CSS `flex` shorthand: grow=value, shrink=1, basis=0 (when value > 0). */
135
+ /**
136
+ * CSS `flex` shorthand: grow=value, shrink=1, basis=0 (when value > 0).
137
+ *
138
+ * Note that the implied `shrink: 1` follows CSS, not Yoga: Yoga's
139
+ * default `flexShrink` is 0, and `setFlex(N)` in Yoga also leaves
140
+ * shrink at 0. Pilates intentionally tracks CSS here so consumers
141
+ * who think in CSS terms get the result they expect; consumers
142
+ * porting from Ink (which wraps Yoga) should call `setFlexShrink(0)`
143
+ * after `setFlex` if they need the Yoga behaviour.
144
+ */
46
145
  setFlex(value: number): void;
47
146
  setFlexGrow(value: number): void;
48
147
  setFlexShrink(value: number): void;
@@ -55,6 +154,11 @@ export declare class Node {
55
154
  setMaxWidth(value: number | undefined): void;
56
155
  /** Pass `undefined` to remove an upper bound. */
57
156
  setMaxHeight(value: number | undefined): void;
157
+ /**
158
+ * Pass `undefined` to clear the constraint. Must be a positive finite
159
+ * number when set. See `style.ts` for the full derivation rules.
160
+ */
161
+ setAspectRatio(value: number | undefined): void;
58
162
  setPadding(edge: Edge, value: number): void;
59
163
  setMargin(edge: Edge, value: number): void;
60
164
  setGap(axis: 'row' | 'column', value: number): void;
@@ -66,6 +170,9 @@ export declare class Node {
66
170
  /** Pass `undefined` to leave that edge unconstrained. */
67
171
  setPosition(edge: Edge, value: number | undefined): void;
68
172
  setDisplay(value: Display): void;
173
+ setOverflow(overflow: Overflow): void;
174
+ setOverflowX(overflow: Overflow): void;
175
+ setOverflowY(overflow: Overflow): void;
69
176
  /**
70
177
  * Compute layout for this node and its descendants.
71
178
  *
@@ -84,13 +191,79 @@ export declare class Node {
84
191
  * Before `calculateLayout()` has run, all values are 0.
85
192
  */
86
193
  getComputedLayout(): ComputedLayout;
194
+ /**
195
+ * A node is a relayout boundary iff its layout size is fully
196
+ * independent of both parent flex distribution and descendant changes:
197
+ *
198
+ * 1. `width` AND `height` are explicit numbers (not `'auto'`) — pins
199
+ * the node's own preferred size on both axes.
200
+ * 2. `flexGrow <= 0` — the node won't be grown by parent free space.
201
+ * 3. `flexShrink <= 0` — the node won't be shrunk by parent overflow.
202
+ *
203
+ * The early spec draft argued (1) alone was sufficient ("flex grow/shrink
204
+ * adjust size based on parent state, not descendant state"). The fuzzer
205
+ * disproved this: with `flexGrow > 0`, the parent's flex distribution
206
+ * gives the boundary a post-grow width different from style.width. After
207
+ * a descendant mutation dirties the boundary but not its ancestors, the
208
+ * cached parent layout reuses the post-grow width, but the cold
209
+ * recompute may produce a different post-grow width if any sibling
210
+ * changed (or even due to micro-rounding interactions). The fuzzer
211
+ * surfaced this with a `setFlexGrow(1)` boundary producing
212
+ * `cached=17 vs cold=16` width drift.
213
+ *
214
+ * Conditions (2) + (3) ensure the boundary's actual size equals its
215
+ * style values exactly, so the cached parent layout stays valid no
216
+ * matter what siblings do.
217
+ *
218
+ * Boundaries stop the upward dirty propagation in `markDirtyFromChild()`
219
+ * so descendant mutations don't invalidate ancestor layout caches.
220
+ *
221
+ * See `docs/superpowers/specs/2026-05-09-relayout-boundaries-design.md`
222
+ * for the full rationale and edge-case analysis.
223
+ */
224
+ private isLayoutBoundary;
87
225
  /**
88
226
  * Walk up the tree marking every ancestor dirty too. The algorithm uses
89
227
  * this hint to short-circuit work in subtrees that did not change.
90
228
  */
91
229
  markDirty(): void;
230
+ /**
231
+ * Called when a child (or descendant via recursion) is mutated. Marks
232
+ * this node dirty and propagates upward — but stops here if this node
233
+ * is a relayout boundary. The boundary semantics apply only when the
234
+ * mutation originates in a descendant, not when this node's own setters
235
+ * call `markDirty()` directly.
236
+ *
237
+ * See `isLayoutBoundary()` for the boundary definition and rationale.
238
+ */
239
+ private markDirtyFromChild;
240
+ /**
241
+ * Propagate the "has a dirty descendant somewhere below" signal upward
242
+ * without marking ancestors `_dirty`. Called when a relayout boundary
243
+ * stops the dirty propagation but still needs to let the root know that
244
+ * some subtree needs attention. Stops if the parent is already dirty
245
+ * (in which case the root will recompute everything anyway) or already
246
+ * has a dirty descendant flag set.
247
+ */
248
+ private markHasDirtyDescendant;
249
+ /**
250
+ * Set dirty + clear caches + propagate up unconditionally, bypassing
251
+ * the layout-boundary short-circuit in `markDirty()`. Used only by
252
+ * `markDirtyDeep` in `algorithm/cache.ts` for differential-mode and
253
+ * fuzzer validation that need to force the full tree onto the cold
254
+ * path regardless of boundary semantics.
255
+ *
256
+ * @internal
257
+ */
258
+ _forceDirty(): void;
92
259
  isDirty(): boolean;
93
- /** Internal: called by the algorithm once layout is fresh. */
260
+ /**
261
+ * Called by the algorithm once layout is fresh. Not part of the public
262
+ * API — consumers should treat layout cleanliness as derived state and
263
+ * never reach in to clear the flag themselves.
264
+ *
265
+ * @internal
266
+ */
94
267
  clearDirty(): void;
95
268
  }
96
269
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}