@ng-native/fabric 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/fabric.d.ts CHANGED
@@ -16,5 +16,5 @@ import { type FabricUIManager } from './engine.ts';
16
16
  * Exported because the facade test iterates it: there was a second copy of this list in that file,
17
17
  * which is how the two managed to be wrong in the same way at the same time.
18
18
  */
19
- export declare const FABRIC_METHODS: readonly ["createNode", "cloneNodeWithNewChildren", "cloneNodeWithNewProps", "cloneNodeWithNewChildrenAndProps", "appendChild", "configureNextLayoutAnimation", "createChildSet", "appendChildToSet", "completeRoot", "registerEventHandler", "setIsJSResponder", "dispatchCommand", "measureInWindow"];
19
+ export declare const FABRIC_METHODS: readonly ["createNode", "cloneNodeWithNewChildren", "cloneNodeWithNewProps", "cloneNodeWithNewChildrenAndProps", "appendChild", "configureNextLayoutAnimation", "createChildSet", "appendChildToSet", "completeRoot", "registerEventHandler", "setIsJSResponder", "dispatchCommand", "measureInWindow", "getBoundingClientRect"];
20
20
  export declare function getFabricUIManager(): FabricUIManager;
package/dist/fabric.js CHANGED
@@ -30,6 +30,7 @@ export const FABRIC_METHODS = [
30
30
  'setIsJSResponder',
31
31
  'dispatchCommand',
32
32
  'measureInWindow',
33
+ 'getBoundingClientRect',
33
34
  ];
34
35
  export function getFabricUIManager() {
35
36
  const raw = globalThis
@@ -1 +1 @@
1
- {"version":3,"file":"fabric.js","sourceRoot":"","sources":["../src/fabric.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY;IACZ,0BAA0B;IAC1B,uBAAuB;IACvB,kCAAkC;IAClC,aAAa;IACb,8BAA8B;IAC9B,gBAAgB;IAChB,kBAAkB;IAClB,cAAc;IACd,sBAAsB;IACtB,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;CACoC,CAAC;AAexD,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAI,UAAkE;SAC5E,qBAAqB,CAAC;IAEzB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,gFAAgF;YAC9E,sDAAsD,CACzD,CAAC;IACJ,CAAC;IAED,gGAAgG;IAChG,4FAA4F;IAC5F,MAAM,MAAM,GAAqE,EAAE,CAAC;IACpF,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,gGAAgG;IAChG,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO,MAAM,CAAC,8BAA8B,CAAC,CAAC;IACzE,OAAO,MAAoC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,UAGZ,CAAC;IACF,MAAM,IAAI,GAAG,kCAAkC,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,CAChB,CAAC;IACjE,MAAM,IAAI,GACR,cAAc,EAAE,KAAK,SAAS;QAC5B,CAAC,CAAC,iCAAiC;QACnC,CAAC,CAAC,6BAA6B,CAAC;IACpC,OAAO,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC;AACrC,CAAC","sourcesContent":["/**\n * `global.nativeFabricUIManager` is a lazy caching proxy: every property access mints a\n * fresh host function. Read each method exactly once into a plain object (this is what\n * RN's own `FabricUIManager.js` does with its CACHED_PROPERTIES list).\n */\nimport { nativePlatform, type FabricUIManager } from './engine.ts';\n\n/**\n * Every method of `FabricUIManager`, and nothing else.\n *\n * A name missing here is `undefined` on device and nowhere else, because the fake the suite runs\n * against implements the interface directly - so every test passes and every device fails. That\n * is not hypothetical: `measureInWindow` was added to the interface and to the engine and left out\n * here, and the anchored overlays it was built for could never have worked.\n *\n * `AllMethodsListed` below is what makes that impossible now rather than merely tested for.\n * Exported because the facade test iterates it: there was a second copy of this list in that file,\n * which is how the two managed to be wrong in the same way at the same time.\n */\nexport const FABRIC_METHODS = [\n 'createNode',\n 'cloneNodeWithNewChildren',\n 'cloneNodeWithNewProps',\n 'cloneNodeWithNewChildrenAndProps',\n 'appendChild',\n 'configureNextLayoutAnimation',\n 'createChildSet',\n 'appendChildToSet',\n 'completeRoot',\n 'registerEventHandler',\n 'setIsJSResponder',\n 'dispatchCommand',\n 'measureInWindow',\n] as const satisfies readonly (keyof FabricUIManager)[];\n\n/**\n * A method the interface declares and the list above forgets.\n *\n * `satisfies` already checks that every name in the list is a real method. This is the other\n * direction, which is the one that bites: it resolves to `never` when the list is complete, and to\n * the missing name when it is not - so forgetting one is a compile error naming it rather than a\n * silent no-op on every phone.\n */\ntype AssertNever<T extends never> = T;\ntype AllMethodsListed = AssertNever<\n Exclude<keyof FabricUIManager, (typeof FABRIC_METHODS)[number]>\n>;\n\nexport function getFabricUIManager(): FabricUIManager {\n const raw = (globalThis as { nativeFabricUIManager?: Record<string, unknown> })\n .nativeFabricUIManager;\n\n if (!raw) {\n throw new Error(\n 'nativeFabricUIManager is not available. The New Architecture must be enabled, ' +\n 'and mount() must run inside an AppRegistry runnable.',\n );\n }\n\n // Typed with the check above, which is `never` when the list is complete and so adds nothing; a\n // check nothing refers to is an unused local to a consumer compiling with `noUnusedLocals`.\n const facade: Record<string, unknown> & { [name in AllMethodsListed]?: never } = {};\n for (const name of FABRIC_METHODS) {\n const value = raw[name];\n if (typeof value === 'function') facade[name] = value.bind(raw);\n }\n // Asked for, a layout animation that is off moves nothing, and the views jump to where it ends.\n if (!layoutAnimationsOn()) delete facade['configureNextLayoutAnimation'];\n return facade as unknown as FabricUIManager;\n}\n\n/**\n * Whether native plays a layout animation on this platform. React Native turns them off on\n * Android unless the app turns them on, and `configureNextLayoutAnimation` is there to call either\n * way. Read from React Native's feature flags module through the two globals its own\n * `TurboModuleRegistry` reads, so nothing of React Native is imported. Taken as on where there is\n * no flag to read.\n */\nfunction layoutAnimationsOn(): boolean {\n const host = globalThis as {\n __turboModuleProxy?: (name: string) => unknown;\n nativeModuleProxy?: Record<string, unknown>;\n };\n const name = 'NativeReactNativeFeatureFlagsCxx';\n const flags = (host.__turboModuleProxy?.(name) ?? host.nativeModuleProxy?.[name]) as\n Record<string, (() => boolean) | undefined> | null | undefined;\n const flag =\n nativePlatform() === 'android'\n ? 'enableLayoutAnimationsOnAndroid'\n : 'enableLayoutAnimationsOnIOS';\n return flags?.[flag]?.() !== false;\n}\n"]}
1
+ {"version":3,"file":"fabric.js","sourceRoot":"","sources":["../src/fabric.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY;IACZ,0BAA0B;IAC1B,uBAAuB;IACvB,kCAAkC;IAClC,aAAa;IACb,8BAA8B;IAC9B,gBAAgB;IAChB,kBAAkB;IAClB,cAAc;IACd,sBAAsB;IACtB,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,uBAAuB;CAC8B,CAAC;AAexD,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAI,UAAkE;SAC5E,qBAAqB,CAAC;IAEzB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,gFAAgF;YAC9E,sDAAsD,CACzD,CAAC;IACJ,CAAC;IAED,gGAAgG;IAChG,4FAA4F;IAC5F,MAAM,MAAM,GAAqE,EAAE,CAAC;IACpF,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,gGAAgG;IAChG,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO,MAAM,CAAC,8BAA8B,CAAC,CAAC;IACzE,OAAO,MAAoC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,UAGZ,CAAC;IACF,MAAM,IAAI,GAAG,kCAAkC,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,CAChB,CAAC;IACjE,MAAM,IAAI,GACR,cAAc,EAAE,KAAK,SAAS;QAC5B,CAAC,CAAC,iCAAiC;QACnC,CAAC,CAAC,6BAA6B,CAAC;IACpC,OAAO,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC;AACrC,CAAC","sourcesContent":["/**\n * `global.nativeFabricUIManager` is a lazy caching proxy: every property access mints a\n * fresh host function. Read each method exactly once into a plain object (this is what\n * RN's own `FabricUIManager.js` does with its CACHED_PROPERTIES list).\n */\nimport { nativePlatform, type FabricUIManager } from './engine.ts';\n\n/**\n * Every method of `FabricUIManager`, and nothing else.\n *\n * A name missing here is `undefined` on device and nowhere else, because the fake the suite runs\n * against implements the interface directly - so every test passes and every device fails. That\n * is not hypothetical: `measureInWindow` was added to the interface and to the engine and left out\n * here, and the anchored overlays it was built for could never have worked.\n *\n * `AllMethodsListed` below is what makes that impossible now rather than merely tested for.\n * Exported because the facade test iterates it: there was a second copy of this list in that file,\n * which is how the two managed to be wrong in the same way at the same time.\n */\nexport const FABRIC_METHODS = [\n 'createNode',\n 'cloneNodeWithNewChildren',\n 'cloneNodeWithNewProps',\n 'cloneNodeWithNewChildrenAndProps',\n 'appendChild',\n 'configureNextLayoutAnimation',\n 'createChildSet',\n 'appendChildToSet',\n 'completeRoot',\n 'registerEventHandler',\n 'setIsJSResponder',\n 'dispatchCommand',\n 'measureInWindow',\n 'getBoundingClientRect',\n] as const satisfies readonly (keyof FabricUIManager)[];\n\n/**\n * A method the interface declares and the list above forgets.\n *\n * `satisfies` already checks that every name in the list is a real method. This is the other\n * direction, which is the one that bites: it resolves to `never` when the list is complete, and to\n * the missing name when it is not - so forgetting one is a compile error naming it rather than a\n * silent no-op on every phone.\n */\ntype AssertNever<T extends never> = T;\ntype AllMethodsListed = AssertNever<\n Exclude<keyof FabricUIManager, (typeof FABRIC_METHODS)[number]>\n>;\n\nexport function getFabricUIManager(): FabricUIManager {\n const raw = (globalThis as { nativeFabricUIManager?: Record<string, unknown> })\n .nativeFabricUIManager;\n\n if (!raw) {\n throw new Error(\n 'nativeFabricUIManager is not available. The New Architecture must be enabled, ' +\n 'and mount() must run inside an AppRegistry runnable.',\n );\n }\n\n // Typed with the check above, which is `never` when the list is complete and so adds nothing; a\n // check nothing refers to is an unused local to a consumer compiling with `noUnusedLocals`.\n const facade: Record<string, unknown> & { [name in AllMethodsListed]?: never } = {};\n for (const name of FABRIC_METHODS) {\n const value = raw[name];\n if (typeof value === 'function') facade[name] = value.bind(raw);\n }\n // Asked for, a layout animation that is off moves nothing, and the views jump to where it ends.\n if (!layoutAnimationsOn()) delete facade['configureNextLayoutAnimation'];\n return facade as unknown as FabricUIManager;\n}\n\n/**\n * Whether native plays a layout animation on this platform. React Native turns them off on\n * Android unless the app turns them on, and `configureNextLayoutAnimation` is there to call either\n * way. Read from React Native's feature flags module through the two globals its own\n * `TurboModuleRegistry` reads, so nothing of React Native is imported. Taken as on where there is\n * no flag to read.\n */\nfunction layoutAnimationsOn(): boolean {\n const host = globalThis as {\n __turboModuleProxy?: (name: string) => unknown;\n nativeModuleProxy?: Record<string, unknown>;\n };\n const name = 'NativeReactNativeFeatureFlagsCxx';\n const flags = (host.__turboModuleProxy?.(name) ?? host.nativeModuleProxy?.[name]) as\n Record<string, (() => boolean) | undefined> | null | undefined;\n const flag =\n nativePlatform() === 'android'\n ? 'enableLayoutAnimationsOnAndroid'\n : 'enableLayoutAnimationsOnIOS';\n return flags?.[flag]?.() !== false;\n}\n"]}
package/dist/flow.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Block layout, as what a flex column has to be told to lay boxes out the same way.
3
+ *
4
+ * Yoga has no block layout, and a block container's in-flow children already sit where a flex
5
+ * column puts them: one under the other, each as wide as the container. What differs is settled
6
+ * from the tree and its styles, before layout, and comes back as a plan for the container:
7
+ *
8
+ * - Adjoining vertical margins collapse (CSS 2.2, 8.3.1): between siblings, between a box and its
9
+ * first and last child, and through an empty box. Yoga adds margins, so each collapsed margin
10
+ * is given to one box and the others get none.
11
+ * - A block container holding only inline-blocks lays them out in lines: a wrapping row. Among
12
+ * blocks, each run of them is a line box of its own, one box alone included, which the engine
13
+ * commits a view for: the line is at least as tall as its strut, which a box alone has too.
14
+ *
15
+ * Only margins in points collapse. A percentage margin is of the containing block's width, which
16
+ * nothing knows before layout, so a container holding one keeps every margin as written.
17
+ *
18
+ * This reads a tree it does not own, through `FlowTree`, so the engine's nodes and a test's
19
+ * fixtures are planned by the same code.
20
+ */
21
+ /** The styles the plan is made from, as React Native names them. */
22
+ export type FlowKey = 'display' | 'position' | 'marginTop' | 'marginBottom' | 'paddingTop' | 'paddingBottom' | 'borderTopWidth' | 'borderBottomWidth' | 'height' | 'minHeight' | 'overflow' | 'aspectRatio';
23
+ export interface FlowTree<T> {
24
+ /** The boxes a node holds, in order, without any that is `display: none`. */
25
+ children(node: T): readonly T[];
26
+ /** A style of the node: a number of points, a keyword, a percentage, or nothing. */
27
+ style(node: T, key: FlowKey): unknown;
28
+ /** Whether the node holds text of its own, which keeps its edges apart. */
29
+ hasText(node: T): boolean;
30
+ /** Whether the node is a run of text, which has no style and sits in a line as a word does. */
31
+ isText?(node: T): boolean;
32
+ }
33
+ export interface FlowPlan<T> {
34
+ /** A column of blocks, or lines of inline-blocks. */
35
+ kind: 'block' | 'lines';
36
+ /** The margins each in-flow child is laid out with, or nothing where they stay as written. */
37
+ margins: Map<T, {
38
+ top: number;
39
+ bottom: number;
40
+ }> | null;
41
+ /**
42
+ * The in-flow children that sit in a line among blocks: an inline-block, inline-flex or
43
+ * inline-grid box. Each is as wide as its content, and its margins do not collapse.
44
+ */
45
+ inline: ReadonlySet<T>;
46
+ /**
47
+ * Each run of those with nothing but each other between them, by its first box, one box alone
48
+ * a run too: they share a line box, which sits under the margin the blocks before it collapse
49
+ * to.
50
+ */
51
+ lines: ReadonlyMap<T, FlowLine<T>>;
52
+ }
53
+ export interface FlowLine<T> {
54
+ boxes: readonly T[];
55
+ /** The margin over the line box. Its boxes keep their own margins inside it. */
56
+ top: number;
57
+ }
58
+ /** Whether a `display` lays its children out as blocks. */
59
+ export declare const isBlockContainer: (display: unknown) => boolean;
60
+ /**
61
+ * A box in a block's flow, as a flex column's item: its `auto` margins and its `justify-self`,
62
+ * on the props React Native is given. Yoga gives an `auto` margin the room left over, on either
63
+ * axis, which stops the box stretching.
64
+ *
65
+ * A block's `auto` margins down its height are none, and across its width they are none where
66
+ * the width is `auto` too, since the block fills its container (CSS 2.2, 10.3.3): they centre or
67
+ * push a block whose width is set, `fit-content` (`fitted`) or held under a `max-width`. A
68
+ * `justify-self` puts a block where it says, at the width of its content where it has none of
69
+ * its own, and leaves it to any `auto` margin it has. An inline-block's `auto` margins are none
70
+ * (10.3.9), and `justify-self` is nothing to it.
71
+ */
72
+ export declare function placeInFlow(props: Record<string, unknown>, inLine: boolean, fitted: boolean): void;
73
+ /**
74
+ * How a block container lays its children out, or nothing for any other box. `inBlock` is
75
+ * whether the container is itself an in-flow child of a block container, which is what lets its
76
+ * children's margins pass through its edges.
77
+ */
78
+ export declare function planFlow<T>(tree: FlowTree<T>, container: T, inBlock: boolean): FlowPlan<T> | null;
package/dist/flow.js ADDED
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Block layout, as what a flex column has to be told to lay boxes out the same way.
3
+ *
4
+ * Yoga has no block layout, and a block container's in-flow children already sit where a flex
5
+ * column puts them: one under the other, each as wide as the container. What differs is settled
6
+ * from the tree and its styles, before layout, and comes back as a plan for the container:
7
+ *
8
+ * - Adjoining vertical margins collapse (CSS 2.2, 8.3.1): between siblings, between a box and its
9
+ * first and last child, and through an empty box. Yoga adds margins, so each collapsed margin
10
+ * is given to one box and the others get none.
11
+ * - A block container holding only inline-blocks lays them out in lines: a wrapping row. Among
12
+ * blocks, each run of them is a line box of its own, one box alone included, which the engine
13
+ * commits a view for: the line is at least as tall as its strut, which a box alone has too.
14
+ *
15
+ * Only margins in points collapse. A percentage margin is of the containing block's width, which
16
+ * nothing knows before layout, so a container holding one keeps every margin as written.
17
+ *
18
+ * This reads a tree it does not own, through `FlowTree`, so the engine's nodes and a test's
19
+ * fixtures are planned by the same code.
20
+ */
21
+ const NONE = { positive: 0, negative: 0 };
22
+ const join = (a, b) => ({
23
+ positive: Math.max(a.positive, b.positive),
24
+ negative: Math.min(a.negative, b.negative),
25
+ });
26
+ const sum = (margins) => margins.positive + margins.negative;
27
+ const only = (value) => value >= 0 ? { positive: value, negative: 0 } : { positive: 0, negative: value };
28
+ const BLOCK_CONTAINERS = new Set(['block', 'flow-root', 'inline-block']);
29
+ const INLINE_LEVEL = new Set(['inline-block', 'inline-flex', 'inline-grid']);
30
+ const inlineLevel = (tree, node) => INLINE_LEVEL.has(tree.style(node, 'display'));
31
+ /** Whether a `display` lays its children out as blocks. */
32
+ export const isBlockContainer = (display) => BLOCK_CONTAINERS.has(display);
33
+ /** A margin in points: `auto` is none on this axis, and a percentage is not known yet. */
34
+ function points(value) {
35
+ if (value === undefined || value === null || value === 'auto')
36
+ return 0;
37
+ return typeof value === 'number' ? value : undefined;
38
+ }
39
+ const isZero = (value) => points(value) === 0;
40
+ function inFlow(tree, node) {
41
+ return tree.style(node, 'position') !== 'absolute';
42
+ }
43
+ function ownMargins(tree, node) {
44
+ return {
45
+ top: only(points(tree.style(node, 'marginTop')) ?? 0),
46
+ bottom: only(points(tree.style(node, 'marginBottom')) ?? 0),
47
+ through: false,
48
+ };
49
+ }
50
+ /**
51
+ * Which of a block container's edges its children's margins pass through: one with no padding
52
+ * or border, on a box that does not start a formatting context of its own.
53
+ */
54
+ function openEdges(tree, node, inBlock) {
55
+ const style = (key) => tree.style(node, key);
56
+ const open = inBlock && style('display') === 'block' && !startsContext(tree, node);
57
+ const clear = (padding, border) => isZero(style(padding)) && isZero(style(border));
58
+ const height = style('height');
59
+ return {
60
+ top: open && clear('paddingTop', 'borderTopWidth'),
61
+ bottom: open &&
62
+ (height == null || height === 'auto') &&
63
+ isZero(style('minHeight')) &&
64
+ clear('paddingBottom', 'borderBottomWidth'),
65
+ emptyHeight: isZero(height),
66
+ };
67
+ }
68
+ /** A box that clips, or keeps a proportion, lays its content out apart from what is around it. */
69
+ function startsContext(tree, node) {
70
+ return ((tree.style(node, 'overflow') ?? 'visible') !== 'visible' ||
71
+ tree.style(node, 'aspectRatio') != null);
72
+ }
73
+ /** The runs of inline-level boxes among a container's in-flow children, one box a run too. */
74
+ function runsOf(tree, flow) {
75
+ const runs = new Map();
76
+ let run = [];
77
+ for (const child of [...flow, undefined]) {
78
+ if (child !== undefined && inlineLevel(tree, child)) {
79
+ run.push(child);
80
+ continue;
81
+ }
82
+ if (run.length)
83
+ runs.set(run[0], run);
84
+ run = [];
85
+ }
86
+ return runs;
87
+ }
88
+ /** The margins between a container's in-flow children, and what is left at its edges. */
89
+ function collapseChildren(tree, flow, openTop) {
90
+ const margins = new Map();
91
+ const runs = runsOf(tree, flow);
92
+ const lines = new Map();
93
+ let atTop = openTop;
94
+ let top = NONE;
95
+ let pending = NONE;
96
+ let emitted = 0;
97
+ let last;
98
+ let lineLast = false;
99
+ for (const child of flow) {
100
+ if (inlineLevel(tree, child)) {
101
+ // The boxes after the first of a line are in it already.
102
+ if (!runs.has(child))
103
+ continue;
104
+ // A line: the margins before it end here, and its boxes keep their own inside it.
105
+ if (atTop)
106
+ top = pending;
107
+ lines.set(child, { boxes: runs.get(child), top: sum(pending) - emitted });
108
+ [atTop, pending, emitted, last, lineLast] = [false, NONE, 0, child, true];
109
+ continue;
110
+ }
111
+ lineLast = false;
112
+ const shown = analyse(tree, child, true).own;
113
+ pending = join(pending, shown.top);
114
+ margins.set(child, { top: atTop ? 0 : sum(pending) - emitted, bottom: 0 });
115
+ if (!atTop)
116
+ emitted = sum(pending);
117
+ if (shown.through) {
118
+ pending = join(pending, shown.bottom);
119
+ continue;
120
+ }
121
+ if (atTop)
122
+ top = pending;
123
+ atTop = false;
124
+ pending = shown.bottom;
125
+ emitted = 0;
126
+ last = child;
127
+ }
128
+ // A line at the end keeps its own bottom margin: nothing after it is left to add.
129
+ const edges = { atTop, top, pending, emitted, last: lineLast ? undefined : last, lineLast };
130
+ return { margins, lines, ...edges };
131
+ }
132
+ /** A block container's plan, and its own margins with its children's collapsed into them. */
133
+ function collapseBlock(tree, node, flow, inBlock) {
134
+ const own = ownMargins(tree, node);
135
+ const open = openEdges(tree, node, inBlock);
136
+ const { margins, lines, atTop, top, pending, emitted, last, lineLast } = collapseChildren(tree, flow, open.top);
137
+ own.top = join(own.top, top);
138
+ if (lineLast) {
139
+ // Nothing collapses through a line: the container's own bottom margin stands.
140
+ }
141
+ else if (atTop && (open.top || !last)) {
142
+ // Nothing in it holds its top edge away from what follows.
143
+ own.top = join(own.top, pending);
144
+ own.through = open.top && open.bottom && !tree.hasText(node) && open.emptyHeight;
145
+ }
146
+ else if (open.bottom) {
147
+ own.bottom = join(own.bottom, pending);
148
+ }
149
+ else if (last) {
150
+ // ponytail: where the last thing with a bottom edge is a line of several boxes, with an
151
+ // empty block after it, that block's margin is dropped: a line has no margin of its own to
152
+ // carry it. Give a line a bottom if a gap is seen missing under one.
153
+ const edge = margins.get(last);
154
+ if (edge)
155
+ edge.bottom = sum(pending) - emitted;
156
+ }
157
+ const inline = new Set(flow.filter((child) => inlineLevel(tree, child)));
158
+ return { own, plan: { kind: 'block', margins, inline, lines } };
159
+ }
160
+ /** What a node shows its siblings, and how it lays its own children out if it is a block. */
161
+ function analyse(tree, node, inBlock) {
162
+ if (!isBlockContainer(tree.style(node, 'display'))) {
163
+ return { own: ownMargins(tree, node), plan: null };
164
+ }
165
+ const flow = tree.children(node).filter((child) => inFlow(tree, child));
166
+ const none = new Set();
167
+ // Text beside inline-level boxes is on their line, as words are: with no block among them,
168
+ // the container is lines of both. Text alone, or among blocks, is a block of its own.
169
+ const inLine = (child) => inlineLevel(tree, child) || tree.isText?.(child) === true;
170
+ if (flow.some((child) => inlineLevel(tree, child)) && flow.every(inLine)) {
171
+ const plan = { kind: 'lines', margins: null, inline: none, lines: new Map() };
172
+ return { own: ownMargins(tree, node), plan };
173
+ }
174
+ const known = (child, key) => points(tree.style(child, key)) !== undefined;
175
+ if (!flow.every((child) => known(child, 'marginTop') && known(child, 'marginBottom'))) {
176
+ const inline = new Set(flow.filter((child) => inlineLevel(tree, child)));
177
+ // Margins stay as written, so a line box has none over it.
178
+ const lines = new Map([...runsOf(tree, flow)].map(([first, boxes]) => [first, { boxes, top: 0 }]));
179
+ return { own: ownMargins(tree, node), plan: { kind: 'block', margins: null, inline, lines } };
180
+ }
181
+ return collapseBlock(tree, node, flow, inBlock);
182
+ }
183
+ /** The margin keys across a box's width, and down its height, in any form React Native reads. */
184
+ const ACROSS = ['marginLeft', 'marginRight', 'marginStart', 'marginEnd', 'marginHorizontal'];
185
+ const DOWN = ['marginTop', 'marginBottom', 'marginVertical'];
186
+ /** Where a `justify-self` puts a block in its container, as a flex column's item is aligned. */
187
+ const JUSTIFIED = {
188
+ start: 'flex-start',
189
+ 'flex-start': 'flex-start',
190
+ 'self-start': 'flex-start',
191
+ left: 'flex-start',
192
+ center: 'center',
193
+ end: 'flex-end',
194
+ 'flex-end': 'flex-end',
195
+ 'self-end': 'flex-end',
196
+ right: 'flex-end',
197
+ };
198
+ const isSet = (value) => value != null && value !== 'auto';
199
+ const autoToZero = (props, keys) => {
200
+ for (const key of keys)
201
+ if (props[key] === 'auto')
202
+ props[key] = 0;
203
+ };
204
+ /**
205
+ * A block with no width and a `max-width`, centred or pushed by its `auto` margins: it fills its
206
+ * container up to the cap (CSS 2.2, 10.4), where Yoga keeps a box with an `auto` margin at the
207
+ * width of its content. So it is given the whole width, which the cap holds it under, and keeps
208
+ * its `auto` margins. Whether it has a cap is the answer.
209
+ *
210
+ * ponytail: the whole width is the container's, where a browser takes the block's margins of a
211
+ * length off it first, so a block in a container narrower than its cap and those margins is as
212
+ * wide as the container. Of a content box it is the width inside the padding, and that would
213
+ * overflow by the padding there, so a content box with padding or a border across it is left at
214
+ * the width of its content. Give it a width read back from layout if one is seen.
215
+ */
216
+ function fillUnderCap(props) {
217
+ if (props['maxWidth'] == null || props['maxWidth'] === 'none')
218
+ return false;
219
+ const across = [...ACROSS, 'margin'].map((key) => props[key]);
220
+ if (!across.includes('auto'))
221
+ return false;
222
+ if (props['boxSizing'] !== 'content-box' || !EDGES_ACROSS.some((key) => props[key])) {
223
+ props['width'] = '100%';
224
+ }
225
+ return true;
226
+ }
227
+ const EDGES_ACROSS = [
228
+ ...['paddingLeft', 'paddingRight', 'paddingStart', 'paddingEnd', 'paddingHorizontal'],
229
+ ...['padding', 'borderLeftWidth', 'borderRightWidth', 'borderStartWidth', 'borderEndWidth'],
230
+ 'borderWidth',
231
+ ];
232
+ /**
233
+ * A box in a block's flow, as a flex column's item: its `auto` margins and its `justify-self`,
234
+ * on the props React Native is given. Yoga gives an `auto` margin the room left over, on either
235
+ * axis, which stops the box stretching.
236
+ *
237
+ * A block's `auto` margins down its height are none, and across its width they are none where
238
+ * the width is `auto` too, since the block fills its container (CSS 2.2, 10.3.3): they centre or
239
+ * push a block whose width is set, `fit-content` (`fitted`) or held under a `max-width`. A
240
+ * `justify-self` puts a block where it says, at the width of its content where it has none of
241
+ * its own, and leaves it to any `auto` margin it has. An inline-block's `auto` margins are none
242
+ * (10.3.9), and `justify-self` is nothing to it.
243
+ */
244
+ export function placeInFlow(props, inLine, fitted) {
245
+ autoToZero(props, DOWN);
246
+ const justify = inLine
247
+ ? undefined
248
+ : JUSTIFIED[String(props['justifySelf']).replace(/^safe /, '')];
249
+ if (justify)
250
+ props['alignSelf'] = justify;
251
+ const sized = !inLine && (fitted || justify !== undefined || isSet(props['width']));
252
+ if (sized || (!inLine && fillUnderCap(props))) {
253
+ // Down its height only: one written for every side is still there across its width.
254
+ if (props['margin'] === 'auto') {
255
+ props['marginHorizontal'] ??= 'auto';
256
+ props['margin'] = 0;
257
+ }
258
+ return;
259
+ }
260
+ autoToZero(props, [...ACROSS, 'margin']);
261
+ }
262
+ /**
263
+ * How a block container lays its children out, or nothing for any other box. `inBlock` is
264
+ * whether the container is itself an in-flow child of a block container, which is what lets its
265
+ * children's margins pass through its edges.
266
+ */
267
+ export function planFlow(tree, container, inBlock) {
268
+ return analyse(tree, container, inBlock).plan;
269
+ }
270
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Block layout, as what a flex column has to be told to lay boxes out the same way.\n *\n * Yoga has no block layout, and a block container's in-flow children already sit where a flex\n * column puts them: one under the other, each as wide as the container. What differs is settled\n * from the tree and its styles, before layout, and comes back as a plan for the container:\n *\n * - Adjoining vertical margins collapse (CSS 2.2, 8.3.1): between siblings, between a box and its\n * first and last child, and through an empty box. Yoga adds margins, so each collapsed margin\n * is given to one box and the others get none.\n * - A block container holding only inline-blocks lays them out in lines: a wrapping row. Among\n * blocks, each run of them is a line box of its own, one box alone included, which the engine\n * commits a view for: the line is at least as tall as its strut, which a box alone has too.\n *\n * Only margins in points collapse. A percentage margin is of the containing block's width, which\n * nothing knows before layout, so a container holding one keeps every margin as written.\n *\n * This reads a tree it does not own, through `FlowTree`, so the engine's nodes and a test's\n * fixtures are planned by the same code.\n */\n\n/** The styles the plan is made from, as React Native names them. */\nexport type FlowKey =\n | 'display'\n | 'position'\n | 'marginTop'\n | 'marginBottom'\n | 'paddingTop'\n | 'paddingBottom'\n | 'borderTopWidth'\n | 'borderBottomWidth'\n | 'height'\n | 'minHeight'\n | 'overflow'\n | 'aspectRatio';\n\nexport interface FlowTree<T> {\n /** The boxes a node holds, in order, without any that is `display: none`. */\n children(node: T): readonly T[];\n /** A style of the node: a number of points, a keyword, a percentage, or nothing. */\n style(node: T, key: FlowKey): unknown;\n /** Whether the node holds text of its own, which keeps its edges apart. */\n hasText(node: T): boolean;\n /** Whether the node is a run of text, which has no style and sits in a line as a word does. */\n isText?(node: T): boolean;\n}\n\nexport interface FlowPlan<T> {\n /** A column of blocks, or lines of inline-blocks. */\n kind: 'block' | 'lines';\n /** The margins each in-flow child is laid out with, or nothing where they stay as written. */\n margins: Map<T, { top: number; bottom: number }> | null;\n /**\n * The in-flow children that sit in a line among blocks: an inline-block, inline-flex or\n * inline-grid box. Each is as wide as its content, and its margins do not collapse.\n */\n inline: ReadonlySet<T>;\n /**\n * Each run of those with nothing but each other between them, by its first box, one box alone\n * a run too: they share a line box, which sits under the margin the blocks before it collapse\n * to.\n */\n lines: ReadonlyMap<T, FlowLine<T>>;\n}\n\nexport interface FlowLine<T> {\n boxes: readonly T[];\n /** The margin over the line box. Its boxes keep their own margins inside it. */\n top: number;\n}\n\n/** A set of adjoining margins: the largest positive and the most negative, which add. */\ninterface Margins {\n positive: number;\n negative: number;\n}\nconst NONE: Margins = { positive: 0, negative: 0 };\nconst join = (a: Margins, b: Margins): Margins => ({\n positive: Math.max(a.positive, b.positive),\n negative: Math.min(a.negative, b.negative),\n});\nconst sum = (margins: Margins): number => margins.positive + margins.negative;\nconst only = (value: number): Margins =>\n value >= 0 ? { positive: value, negative: 0 } : { positive: 0, negative: value };\n\n/** What a box's margins come to once its children's have collapsed into them. */\ninterface Collapsed {\n top: Margins;\n bottom: Margins;\n /** An empty box: its top and bottom margins adjoin, and collapse as one. */\n through: boolean;\n}\n\nconst BLOCK_CONTAINERS = new Set(['block', 'flow-root', 'inline-block']);\nconst INLINE_LEVEL = new Set(['inline-block', 'inline-flex', 'inline-grid']);\nconst inlineLevel = <T>(tree: FlowTree<T>, node: T) =>\n INLINE_LEVEL.has(tree.style(node, 'display') as string);\n\n/** Whether a `display` lays its children out as blocks. */\nexport const isBlockContainer = (display: unknown): boolean =>\n BLOCK_CONTAINERS.has(display as string);\n\n/** A margin in points: `auto` is none on this axis, and a percentage is not known yet. */\nfunction points(value: unknown): number | undefined {\n if (value === undefined || value === null || value === 'auto') return 0;\n return typeof value === 'number' ? value : undefined;\n}\nconst isZero = (value: unknown) => points(value) === 0;\n\nfunction inFlow<T>(tree: FlowTree<T>, node: T): boolean {\n return tree.style(node, 'position') !== 'absolute';\n}\n\nfunction ownMargins<T>(tree: FlowTree<T>, node: T): Collapsed {\n return {\n top: only(points(tree.style(node, 'marginTop')) ?? 0),\n bottom: only(points(tree.style(node, 'marginBottom')) ?? 0),\n through: false,\n };\n}\n\n/**\n * Which of a block container's edges its children's margins pass through: one with no padding\n * or border, on a box that does not start a formatting context of its own.\n */\nfunction openEdges<T>(tree: FlowTree<T>, node: T, inBlock: boolean) {\n const style = (key: FlowKey) => tree.style(node, key);\n const open = inBlock && style('display') === 'block' && !startsContext(tree, node);\n const clear = (padding: FlowKey, border: FlowKey) =>\n isZero(style(padding)) && isZero(style(border));\n const height = style('height');\n return {\n top: open && clear('paddingTop', 'borderTopWidth'),\n bottom:\n open &&\n (height == null || height === 'auto') &&\n isZero(style('minHeight')) &&\n clear('paddingBottom', 'borderBottomWidth'),\n emptyHeight: isZero(height),\n };\n}\n\n/** A box that clips, or keeps a proportion, lays its content out apart from what is around it. */\nfunction startsContext<T>(tree: FlowTree<T>, node: T): boolean {\n return (\n (tree.style(node, 'overflow') ?? 'visible') !== 'visible' ||\n tree.style(node, 'aspectRatio') != null\n );\n}\n\n/** The runs of inline-level boxes among a container's in-flow children, one box a run too. */\nfunction runsOf<T>(tree: FlowTree<T>, flow: readonly T[]): Map<T, T[]> {\n const runs = new Map<T, T[]>();\n let run: T[] = [];\n for (const child of [...flow, undefined]) {\n if (child !== undefined && inlineLevel(tree, child)) {\n run.push(child);\n continue;\n }\n if (run.length) runs.set(run[0]!, run);\n run = [];\n }\n return runs;\n}\n\n/** The margins between a container's in-flow children, and what is left at its edges. */\nfunction collapseChildren<T>(tree: FlowTree<T>, flow: readonly T[], openTop: boolean) {\n const margins = new Map<T, { top: number; bottom: number }>();\n const runs = runsOf(tree, flow);\n const lines = new Map<T, FlowLine<T>>();\n let atTop = openTop;\n let top = NONE;\n let pending = NONE;\n let emitted = 0;\n let last: T | undefined;\n let lineLast = false;\n for (const child of flow) {\n if (inlineLevel(tree, child)) {\n // The boxes after the first of a line are in it already.\n if (!runs.has(child)) continue;\n // A line: the margins before it end here, and its boxes keep their own inside it.\n if (atTop) top = pending;\n lines.set(child, { boxes: runs.get(child)!, top: sum(pending) - emitted });\n [atTop, pending, emitted, last, lineLast] = [false, NONE, 0, child, true];\n continue;\n }\n lineLast = false;\n const shown = analyse(tree, child, true).own;\n pending = join(pending, shown.top);\n margins.set(child, { top: atTop ? 0 : sum(pending) - emitted, bottom: 0 });\n if (!atTop) emitted = sum(pending);\n if (shown.through) {\n pending = join(pending, shown.bottom);\n continue;\n }\n if (atTop) top = pending;\n atTop = false;\n pending = shown.bottom;\n emitted = 0;\n last = child;\n }\n // A line at the end keeps its own bottom margin: nothing after it is left to add.\n const edges = { atTop, top, pending, emitted, last: lineLast ? undefined : last, lineLast };\n return { margins, lines, ...edges };\n}\n\n/** A block container's plan, and its own margins with its children's collapsed into them. */\nfunction collapseBlock<T>(tree: FlowTree<T>, node: T, flow: readonly T[], inBlock: boolean) {\n const own = ownMargins(tree, node);\n const open = openEdges(tree, node, inBlock);\n const { margins, lines, atTop, top, pending, emitted, last, lineLast } = collapseChildren(\n tree,\n flow,\n open.top,\n );\n own.top = join(own.top, top);\n if (lineLast) {\n // Nothing collapses through a line: the container's own bottom margin stands.\n } else if (atTop && (open.top || !last)) {\n // Nothing in it holds its top edge away from what follows.\n own.top = join(own.top, pending);\n own.through = open.top && open.bottom && !tree.hasText(node) && open.emptyHeight;\n } else if (open.bottom) {\n own.bottom = join(own.bottom, pending);\n } else if (last) {\n // ponytail: where the last thing with a bottom edge is a line of several boxes, with an\n // empty block after it, that block's margin is dropped: a line has no margin of its own to\n // carry it. Give a line a bottom if a gap is seen missing under one.\n const edge = margins.get(last);\n if (edge) edge.bottom = sum(pending) - emitted;\n }\n const inline = new Set(flow.filter((child) => inlineLevel(tree, child)));\n return { own, plan: { kind: 'block', margins, inline, lines } as FlowPlan<T> };\n}\n\n/** What a node shows its siblings, and how it lays its own children out if it is a block. */\nfunction analyse<T>(\n tree: FlowTree<T>,\n node: T,\n inBlock: boolean,\n): { own: Collapsed; plan: FlowPlan<T> | null } {\n if (!isBlockContainer(tree.style(node, 'display'))) {\n return { own: ownMargins(tree, node), plan: null };\n }\n const flow = tree.children(node).filter((child) => inFlow(tree, child));\n const none: ReadonlySet<T> = new Set();\n // Text beside inline-level boxes is on their line, as words are: with no block among them,\n // the container is lines of both. Text alone, or among blocks, is a block of its own.\n const inLine = (child: T) => inlineLevel(tree, child) || tree.isText?.(child) === true;\n if (flow.some((child) => inlineLevel(tree, child)) && flow.every(inLine)) {\n const plan: FlowPlan<T> = { kind: 'lines', margins: null, inline: none, lines: new Map() };\n return { own: ownMargins(tree, node), plan };\n }\n const known = (child: T, key: FlowKey) => points(tree.style(child, key)) !== undefined;\n if (!flow.every((child) => known(child, 'marginTop') && known(child, 'marginBottom'))) {\n const inline = new Set(flow.filter((child) => inlineLevel(tree, child)));\n // Margins stay as written, so a line box has none over it.\n const lines = new Map(\n [...runsOf(tree, flow)].map(([first, boxes]) => [first, { boxes, top: 0 }]),\n );\n return { own: ownMargins(tree, node), plan: { kind: 'block', margins: null, inline, lines } };\n }\n return collapseBlock(tree, node, flow, inBlock);\n}\n\n/** The margin keys across a box's width, and down its height, in any form React Native reads. */\nconst ACROSS = ['marginLeft', 'marginRight', 'marginStart', 'marginEnd', 'marginHorizontal'];\nconst DOWN = ['marginTop', 'marginBottom', 'marginVertical'];\n\n/** Where a `justify-self` puts a block in its container, as a flex column's item is aligned. */\nconst JUSTIFIED: Readonly<Record<string, string>> = {\n start: 'flex-start',\n 'flex-start': 'flex-start',\n 'self-start': 'flex-start',\n left: 'flex-start',\n center: 'center',\n end: 'flex-end',\n 'flex-end': 'flex-end',\n 'self-end': 'flex-end',\n right: 'flex-end',\n};\n\nconst isSet = (value: unknown) => value != null && value !== 'auto';\nconst autoToZero = (props: Record<string, unknown>, keys: readonly string[]) => {\n for (const key of keys) if (props[key] === 'auto') props[key] = 0;\n};\n\n/**\n * A block with no width and a `max-width`, centred or pushed by its `auto` margins: it fills its\n * container up to the cap (CSS 2.2, 10.4), where Yoga keeps a box with an `auto` margin at the\n * width of its content. So it is given the whole width, which the cap holds it under, and keeps\n * its `auto` margins. Whether it has a cap is the answer.\n *\n * ponytail: the whole width is the container's, where a browser takes the block's margins of a\n * length off it first, so a block in a container narrower than its cap and those margins is as\n * wide as the container. Of a content box it is the width inside the padding, and that would\n * overflow by the padding there, so a content box with padding or a border across it is left at\n * the width of its content. Give it a width read back from layout if one is seen.\n */\nfunction fillUnderCap(props: Record<string, unknown>): boolean {\n if (props['maxWidth'] == null || props['maxWidth'] === 'none') return false;\n const across = [...ACROSS, 'margin'].map((key) => props[key]);\n if (!across.includes('auto')) return false;\n if (props['boxSizing'] !== 'content-box' || !EDGES_ACROSS.some((key) => props[key])) {\n props['width'] = '100%';\n }\n return true;\n}\nconst EDGES_ACROSS = [\n ...['paddingLeft', 'paddingRight', 'paddingStart', 'paddingEnd', 'paddingHorizontal'],\n ...['padding', 'borderLeftWidth', 'borderRightWidth', 'borderStartWidth', 'borderEndWidth'],\n 'borderWidth',\n];\n\n/**\n * A box in a block's flow, as a flex column's item: its `auto` margins and its `justify-self`,\n * on the props React Native is given. Yoga gives an `auto` margin the room left over, on either\n * axis, which stops the box stretching.\n *\n * A block's `auto` margins down its height are none, and across its width they are none where\n * the width is `auto` too, since the block fills its container (CSS 2.2, 10.3.3): they centre or\n * push a block whose width is set, `fit-content` (`fitted`) or held under a `max-width`. A\n * `justify-self` puts a block where it says, at the width of its content where it has none of\n * its own, and leaves it to any `auto` margin it has. An inline-block's `auto` margins are none\n * (10.3.9), and `justify-self` is nothing to it.\n */\nexport function placeInFlow(\n props: Record<string, unknown>,\n inLine: boolean,\n fitted: boolean,\n): void {\n autoToZero(props, DOWN);\n const justify = inLine\n ? undefined\n : JUSTIFIED[String(props['justifySelf']).replace(/^safe /, '')];\n if (justify) props['alignSelf'] = justify;\n const sized = !inLine && (fitted || justify !== undefined || isSet(props['width']));\n if (sized || (!inLine && fillUnderCap(props))) {\n // Down its height only: one written for every side is still there across its width.\n if (props['margin'] === 'auto') {\n props['marginHorizontal'] ??= 'auto';\n props['margin'] = 0;\n }\n return;\n }\n autoToZero(props, [...ACROSS, 'margin']);\n}\n\n/**\n * How a block container lays its children out, or nothing for any other box. `inBlock` is\n * whether the container is itself an in-flow child of a block container, which is what lets its\n * children's margins pass through its edges.\n */\nexport function planFlow<T>(tree: FlowTree<T>, container: T, inBlock: boolean): FlowPlan<T> | null {\n return analyse(tree, container, inBlock).plan;\n}\n"]}
package/dist/grid.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * CSS Grid, as a function from a container's style and its items to where each item goes.
3
+ *
4
+ * It follows CSS Grid Layout Level 1: placement (8.5), track sizing (11.3 to 11.8) and alignment
5
+ * (10). It knows nothing about Yoga or a device. Whatever lays the items out says how big each
6
+ * one's content is through `measure`, and gets back a rectangle for each against the container's
7
+ * content box.
8
+ *
9
+ * Not here: subgrid, last-baseline alignment (read as start), and right-to-left columns.
10
+ */
11
+ export type Style = Readonly<Record<string, string>>;
12
+ export interface GridItem {
13
+ /** The item's style, with every shorthand spread over its sides. */
14
+ readonly style: Style;
15
+ /**
16
+ * The item's border box with its content at its narrowest (`min`), at its widest (`max`), or
17
+ * at a given width.
18
+ */
19
+ measure(width: 'min' | 'max' | number): {
20
+ width: number;
21
+ height: number;
22
+ };
23
+ /**
24
+ * How far under the item's top edge its baseline is, at a given width: the first line of its
25
+ * text, or its bottom edge where it has none. Only how items differ is read, so it may be
26
+ * counted from anywhere. Without it an item aligned to a baseline sits at the start.
27
+ */
28
+ baseline?(width: number): number;
29
+ /**
30
+ * The item's padding and border across and down: what no size takes its border box under, and
31
+ * what a size is written without where its `box-sizing` is `content-box`.
32
+ */
33
+ readonly frame?: {
34
+ readonly width: number;
35
+ readonly height: number;
36
+ };
37
+ }
38
+ export interface Rect {
39
+ left: number;
40
+ top: number;
41
+ width: number;
42
+ height: number;
43
+ }
44
+ export interface GridLayout {
45
+ /** The content box: what was available, or what the tracks came to where nothing was. */
46
+ width: number;
47
+ height: number;
48
+ /** What the tracks and gaps come to, which is more than the box when they overflow. */
49
+ usedWidth: number;
50
+ usedHeight: number;
51
+ /** A rectangle per item, against the content box. */
52
+ items: Rect[];
53
+ /**
54
+ * The grid lines an out-of-flow child's placement names, as the edges of what it is placed
55
+ * against: each a distance from the content box's left or top edge, and nothing where the
56
+ * side is `auto`, or a line the grid has not got, which is the container's padding edge.
57
+ */
58
+ area(style: Style): Edges;
59
+ }
60
+ export interface Edges {
61
+ left?: number;
62
+ right?: number;
63
+ top?: number;
64
+ bottom?: number;
65
+ }
66
+ /**
67
+ * Lay a grid out in a content box of `width` by `height`. A side left out is as big as the tracks
68
+ * come to, and a percentage along it is of that size, resolved by a second pass.
69
+ */
70
+ export declare function layOutGrid(style: Style, items: readonly GridItem[], available?: {
71
+ width?: number;
72
+ height?: number;
73
+ }): GridLayout;