@alchemy.run/sigil 0.0.0-alpha.1 → 0.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +299 -299
  2. package/dist/ansi.d.ts +223 -0
  3. package/dist/ansi.js +2 -0
  4. package/dist/{devtools-QpCMm9JH.mjs → devtools-BhYGjb7h.js} +1 -1
  5. package/dist/index-DDVME65c.d.ts +919 -0
  6. package/dist/index.d.ts +1657 -0
  7. package/dist/index.js +4643 -0
  8. package/dist/sgr-CMfEpjSk.d.ts +91 -0
  9. package/dist/truncate-CBiyyZzw.js +2156 -0
  10. package/dist/yoga-5jKhYCJC.js +3465 -0
  11. package/dist/yoga.d.ts +2 -0
  12. package/dist/yoga.js +2 -0
  13. package/package.json +37 -17
  14. package/src/ansi/chalk.ts +179 -0
  15. package/src/ansi/cursor.ts +48 -0
  16. package/src/ansi/east-asian-width.ts +215 -0
  17. package/src/ansi/escapes.ts +128 -0
  18. package/src/ansi/index.ts +27 -0
  19. package/src/ansi/sgr.ts +237 -0
  20. package/src/ansi/slice.ts +43 -0
  21. package/src/ansi/string-width.ts +236 -0
  22. package/src/ansi/strip.ts +33 -0
  23. package/src/ansi/supports-color.ts +213 -0
  24. package/src/ansi/tokenize.ts +453 -0
  25. package/src/ansi/truncate.ts +194 -0
  26. package/src/ansi/widest-line.ts +12 -0
  27. package/src/ansi/wrap.ts +766 -0
  28. package/src/ansi-tokenizer.ts +510 -0
  29. package/src/auto-bind.ts +41 -0
  30. package/src/boxes.ts +100 -0
  31. package/src/code-excerpt.ts +39 -0
  32. package/src/colorize.ts +60 -0
  33. package/src/components/AccessibilityContext.ts +5 -0
  34. package/src/components/AnimationContext.ts +24 -0
  35. package/src/components/App.tsx +781 -0
  36. package/src/components/AppContext.ts +111 -0
  37. package/src/components/BackgroundContext.ts +8 -0
  38. package/src/components/Box.tsx +116 -0
  39. package/src/components/CursorContext.ts +19 -0
  40. package/src/components/ErrorBoundary.tsx +38 -0
  41. package/src/components/ErrorOverview.tsx +133 -0
  42. package/src/components/FocusContext.ts +30 -0
  43. package/src/components/Newline.tsx +15 -0
  44. package/src/components/Spacer.tsx +10 -0
  45. package/src/components/Static.tsx +59 -0
  46. package/src/components/StderrContext.ts +26 -0
  47. package/src/components/StdinContext.ts +49 -0
  48. package/src/components/StdoutContext.ts +28 -0
  49. package/src/components/Text.tsx +144 -0
  50. package/src/components/Transform.tsx +37 -0
  51. package/src/cursor-position.ts +103 -0
  52. package/src/devtools-window-polyfill.ts +73 -0
  53. package/src/devtools.ts +43 -0
  54. package/src/dom.ts +292 -0
  55. package/src/get-max-width.ts +11 -0
  56. package/src/global.d.ts +36 -0
  57. package/src/hooks/use-animation.ts +142 -0
  58. package/src/hooks/use-app.ts +8 -0
  59. package/src/hooks/use-box-metrics.ts +134 -0
  60. package/src/hooks/use-cursor.ts +33 -0
  61. package/src/hooks/use-focus-manager.ts +62 -0
  62. package/src/hooks/use-focus.ts +83 -0
  63. package/src/hooks/use-input.ts +267 -0
  64. package/src/hooks/use-is-screen-reader-enabled.ts +12 -0
  65. package/src/hooks/use-paste.ts +78 -0
  66. package/src/hooks/use-stderr.ts +8 -0
  67. package/src/hooks/use-stdin.ts +10 -0
  68. package/src/hooks/use-stdout.ts +8 -0
  69. package/src/hooks/use-window-size.ts +41 -0
  70. package/src/indent-string.ts +16 -0
  71. package/src/index.ts +44 -0
  72. package/src/ink.tsx +1506 -0
  73. package/src/input-parser.ts +283 -0
  74. package/src/instances.ts +9 -0
  75. package/src/is-in-ci.ts +7 -0
  76. package/src/kitty-keyboard.ts +57 -0
  77. package/src/log-update.ts +370 -0
  78. package/src/measure-element.ts +62 -0
  79. package/src/measure-text.ts +31 -0
  80. package/src/output.ts +308 -0
  81. package/src/parse-keypress.ts +516 -0
  82. package/src/parse-stack-line.ts +139 -0
  83. package/src/patch-console.ts +62 -0
  84. package/src/quick-lru.ts +85 -0
  85. package/src/reconciler.ts +451 -0
  86. package/src/render-background.ts +38 -0
  87. package/src/render-border.ts +134 -0
  88. package/src/render-node-to-output.ts +191 -0
  89. package/src/render-to-string.ts +131 -0
  90. package/src/render.ts +276 -0
  91. package/src/renderer.ts +73 -0
  92. package/src/sanitize-ansi.ts +33 -0
  93. package/src/signal-exit.ts +107 -0
  94. package/src/squash-text-nodes.ts +40 -0
  95. package/src/stream.ts +30 -0
  96. package/src/styles.ts +748 -0
  97. package/src/terminal-size.ts +57 -0
  98. package/src/throttle.ts +73 -0
  99. package/src/types.ts +15 -0
  100. package/src/utils.ts +40 -0
  101. package/src/wrap-text.ts +50 -0
  102. package/src/write-synchronized.ts +9 -0
  103. package/src/yoga/config.ts +57 -0
  104. package/src/yoga/core/absoluteLayout.ts +626 -0
  105. package/src/yoga/core/baseline.ts +66 -0
  106. package/src/yoga/core/cache.ts +136 -0
  107. package/src/yoga/core/calculateLayout.ts +2920 -0
  108. package/src/yoga/core/config.ts +104 -0
  109. package/src/yoga/core/flexLine.ts +177 -0
  110. package/src/yoga/core/helpers.ts +293 -0
  111. package/src/yoga/core/layoutResults.ts +167 -0
  112. package/src/yoga/core/node.ts +611 -0
  113. package/src/yoga/core/numeric.ts +44 -0
  114. package/src/yoga/core/pixelGrid.ts +151 -0
  115. package/src/yoga/core/style.ts +887 -0
  116. package/src/yoga/core/types.ts +224 -0
  117. package/src/yoga/generated/YGEnums.ts +263 -0
  118. package/src/yoga/index.ts +19 -0
  119. package/src/yoga/node.ts +1140 -0
  120. package/dist/index.d.mts +0 -2379
  121. package/dist/index.mjs +0 -10072
@@ -0,0 +1,626 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Derived from Yoga. See THIRD_PARTY_NOTICES.md.
3
+
4
+ // Port of yoga/algorithm/AbsoluteLayout.cpp. Grid-specific branches are kept
5
+ // where they read from style, but Display.Grid is not otherwise supported.
6
+
7
+ import {
8
+ Align,
9
+ Dimension,
10
+ Direction,
11
+ Display,
12
+ Errata,
13
+ FlexDirection,
14
+ Justify,
15
+ PositionType,
16
+ Wrap,
17
+ } from "../generated/YGEnums.ts";
18
+ import {
19
+ type LayoutData,
20
+ LayoutPassReason,
21
+ calculateLayoutInternal,
22
+ cleanupContentsNodesRecursively,
23
+ } from "./calculateLayout.ts";
24
+ import {
25
+ PhysicalEdge,
26
+ SizingMode,
27
+ boundAxis,
28
+ dimension,
29
+ flexEndEdge,
30
+ flexStartEdge,
31
+ getPositionOfOppositeEdge,
32
+ inlineStartEdge,
33
+ isRow,
34
+ needsTrailingPosition,
35
+ resolveChildAlignment,
36
+ resolveChildJustification,
37
+ resolveCrossDirection,
38
+ resolveDirection,
39
+ setChildTrailingPosition,
40
+ } from "./helpers.ts";
41
+ import type { Node } from "./node.ts";
42
+ import { isDefined, isUndefined } from "./numeric.ts";
43
+
44
+ function setFlexStartLayoutPosition(
45
+ parent: Node,
46
+ child: Node,
47
+ direction: Direction,
48
+ axis: FlexDirection,
49
+ containingBlockWidth: number,
50
+ ): void {
51
+ let position =
52
+ child.style.computeFlexStartMargin(axis, direction, containingBlockWidth) +
53
+ parent.layout.border(flexStartEdge(axis));
54
+
55
+ // https://www.w3.org/TR/css-grid-1/#abspos
56
+ // absolute positioned grid items are positioned relative to the padding edge
57
+ // of the grid container
58
+ if (
59
+ !child.hasErrata(Errata.AbsolutePositionWithoutInsetsExcludesPadding) &&
60
+ parent.style.display() !== Display.Grid
61
+ ) {
62
+ position += parent.layout.padding(flexStartEdge(axis));
63
+ }
64
+
65
+ child.setLayoutPosition(position, flexStartEdge(axis));
66
+ }
67
+
68
+ function setFlexEndLayoutPosition(
69
+ parent: Node,
70
+ child: Node,
71
+ direction: Direction,
72
+ axis: FlexDirection,
73
+ containingBlockWidth: number,
74
+ ): void {
75
+ let flexEndPosition =
76
+ parent.layout.border(flexEndEdge(axis)) +
77
+ child.style.computeFlexEndMargin(axis, direction, containingBlockWidth);
78
+
79
+ // https://www.w3.org/TR/css-grid-1/#abspos
80
+ // absolute positioned grid items are positioned relative to the padding edge
81
+ // of the grid container
82
+ if (
83
+ !child.hasErrata(Errata.AbsolutePositionWithoutInsetsExcludesPadding) &&
84
+ parent.style.display() !== Display.Grid
85
+ ) {
86
+ flexEndPosition += parent.layout.padding(flexEndEdge(axis));
87
+ }
88
+
89
+ child.setLayoutPosition(
90
+ getPositionOfOppositeEdge(flexEndPosition, axis, parent, child),
91
+ flexStartEdge(axis),
92
+ );
93
+ }
94
+
95
+ function setCenterLayoutPosition(
96
+ parent: Node,
97
+ child: Node,
98
+ direction: Direction,
99
+ axis: FlexDirection,
100
+ containingBlockWidth: number,
101
+ ): void {
102
+ let parentContentBoxSize =
103
+ parent.layout.measuredDimension(dimension(axis)) -
104
+ parent.layout.border(flexStartEdge(axis)) -
105
+ parent.layout.border(flexEndEdge(axis));
106
+
107
+ // https://www.w3.org/TR/css-grid-1/#abspos
108
+ // absolute positioned grid items are positioned relative to the padding edge
109
+ // of the grid container
110
+ if (
111
+ !child.hasErrata(Errata.AbsolutePositionWithoutInsetsExcludesPadding) &&
112
+ parent.style.display() !== Display.Grid
113
+ ) {
114
+ parentContentBoxSize -= parent.layout.padding(flexStartEdge(axis));
115
+ parentContentBoxSize -= parent.layout.padding(flexEndEdge(axis));
116
+ }
117
+
118
+ const childOuterSize =
119
+ child.layout.measuredDimension(dimension(axis)) +
120
+ child.style.computeMarginForAxis(axis, containingBlockWidth);
121
+
122
+ let position =
123
+ (parentContentBoxSize - childOuterSize) / 2.0 +
124
+ parent.layout.border(flexStartEdge(axis)) +
125
+ child.style.computeFlexStartMargin(axis, direction, containingBlockWidth);
126
+
127
+ // https://www.w3.org/TR/css-grid-1/#abspos
128
+ // absolute positioned grid items are positioned relative to the padding edge
129
+ // of the grid container
130
+ if (
131
+ !child.hasErrata(Errata.AbsolutePositionWithoutInsetsExcludesPadding) &&
132
+ parent.style.display() !== Display.Grid
133
+ ) {
134
+ position += parent.layout.padding(flexStartEdge(axis));
135
+ }
136
+
137
+ child.setLayoutPosition(position, flexStartEdge(axis));
138
+ }
139
+
140
+ function justifyAbsoluteChild(
141
+ parent: Node,
142
+ child: Node,
143
+ direction: Direction,
144
+ mainAxis: FlexDirection,
145
+ containingBlockWidth: number,
146
+ ): void {
147
+ const justify =
148
+ parent.style.display() === Display.Grid
149
+ ? resolveChildJustification(parent, child)
150
+ : parent.style.justifyContent();
151
+ switch (justify) {
152
+ case Justify.Start:
153
+ case Justify.Auto:
154
+ case Justify.Stretch:
155
+ case Justify.FlexStart:
156
+ case Justify.SpaceBetween:
157
+ setFlexStartLayoutPosition(parent, child, direction, mainAxis, containingBlockWidth);
158
+ break;
159
+ case Justify.End:
160
+ case Justify.FlexEnd:
161
+ setFlexEndLayoutPosition(parent, child, direction, mainAxis, containingBlockWidth);
162
+ break;
163
+ case Justify.Center:
164
+ case Justify.SpaceAround:
165
+ case Justify.SpaceEvenly:
166
+ setCenterLayoutPosition(parent, child, direction, mainAxis, containingBlockWidth);
167
+ break;
168
+ }
169
+ }
170
+
171
+ function alignAbsoluteChild(
172
+ parent: Node,
173
+ child: Node,
174
+ direction: Direction,
175
+ crossAxis: FlexDirection,
176
+ containingBlockWidth: number,
177
+ ): void {
178
+ let itemAlign = resolveChildAlignment(parent, child);
179
+ const parentWrap = parent.style.flexWrap();
180
+ if (parentWrap === Wrap.WrapReverse) {
181
+ if (itemAlign === Align.FlexEnd) {
182
+ itemAlign = Align.FlexStart;
183
+ } else if (itemAlign !== Align.Center) {
184
+ itemAlign = Align.FlexEnd;
185
+ }
186
+ }
187
+
188
+ switch (itemAlign) {
189
+ case Align.Start:
190
+ case Align.Auto:
191
+ case Align.FlexStart:
192
+ case Align.Baseline:
193
+ case Align.SpaceAround:
194
+ case Align.SpaceBetween:
195
+ case Align.Stretch:
196
+ case Align.SpaceEvenly:
197
+ setFlexStartLayoutPosition(parent, child, direction, crossAxis, containingBlockWidth);
198
+ break;
199
+ case Align.End:
200
+ case Align.FlexEnd:
201
+ setFlexEndLayoutPosition(parent, child, direction, crossAxis, containingBlockWidth);
202
+ break;
203
+ case Align.Center:
204
+ setCenterLayoutPosition(parent, child, direction, crossAxis, containingBlockWidth);
205
+ break;
206
+ }
207
+ }
208
+
209
+ /*
210
+ * Absolutely positioned nodes do not participate in flex layout and thus their
211
+ * positions can be determined independently from the rest of their siblings.
212
+ * For each axis there are essentially two cases:
213
+ *
214
+ * 1) The node has insets defined. In this case we can just use these to
215
+ * determine the position of the node.
216
+ * 2) The node does not have insets defined. In this case we look at the style
217
+ * of the parent to position the node. Things like justify content and
218
+ * align content will move absolute children around. If none of these
219
+ * special properties are defined, the child is positioned at the start
220
+ * (defined by flex direction) of the leading flex line.
221
+ *
222
+ * This function does that positioning for the given axis. The spec has more
223
+ * information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items
224
+ */
225
+ function positionAbsoluteChild(
226
+ containingNode: Node,
227
+ parent: Node,
228
+ child: Node,
229
+ direction: Direction,
230
+ axis: FlexDirection,
231
+ isMainAxis: boolean,
232
+ containingBlockWidth: number,
233
+ containingBlockHeight: number,
234
+ ): void {
235
+ const isAxisRow = isRow(axis);
236
+ const containingBlockSize = isAxisRow ? containingBlockWidth : containingBlockHeight;
237
+
238
+ // The inline-start position takes priority over the end position in the case
239
+ // that they are both set and the node has a fixed width. Thus we only have 2
240
+ // cases here: if inline-start is defined and if inline-end is defined.
241
+ //
242
+ // Despite checking inline-start to honor prioritization of insets, we write
243
+ // to the flex-start edge because this algorithm works by positioning on the
244
+ // flex-start edge and then filling in the flex-end direction at the end if
245
+ // necessary.
246
+ if (
247
+ child.style.isInlineStartPositionDefined(axis, direction) &&
248
+ !child.style.isInlineStartPositionAuto(axis, direction)
249
+ ) {
250
+ const positionRelativeToInlineStart =
251
+ child.style.computeInlineStartPosition(axis, direction, containingBlockSize) +
252
+ containingNode.style.computeInlineStartBorder(axis, direction) +
253
+ child.style.computeInlineStartMargin(axis, direction, containingBlockSize);
254
+ const positionRelativeToFlexStart =
255
+ inlineStartEdge(axis, direction) !== flexStartEdge(axis)
256
+ ? getPositionOfOppositeEdge(positionRelativeToInlineStart, axis, containingNode, child)
257
+ : positionRelativeToInlineStart;
258
+
259
+ child.setLayoutPosition(positionRelativeToFlexStart, flexStartEdge(axis));
260
+ } else if (
261
+ child.style.isInlineEndPositionDefined(axis, direction) &&
262
+ !child.style.isInlineEndPositionAuto(axis, direction)
263
+ ) {
264
+ const positionRelativeToInlineStart =
265
+ containingNode.layout.measuredDimension(dimension(axis)) -
266
+ child.layout.measuredDimension(dimension(axis)) -
267
+ containingNode.style.computeInlineEndBorder(axis, direction) -
268
+ child.style.computeInlineEndMargin(axis, direction, containingBlockSize) -
269
+ child.style.computeInlineEndPosition(axis, direction, containingBlockSize);
270
+ const positionRelativeToFlexStart =
271
+ inlineStartEdge(axis, direction) !== flexStartEdge(axis)
272
+ ? getPositionOfOppositeEdge(positionRelativeToInlineStart, axis, containingNode, child)
273
+ : positionRelativeToInlineStart;
274
+
275
+ child.setLayoutPosition(positionRelativeToFlexStart, flexStartEdge(axis));
276
+ } else if (isMainAxis) {
277
+ justifyAbsoluteChild(parent, child, direction, axis, containingBlockWidth);
278
+ } else {
279
+ alignAbsoluteChild(parent, child, direction, axis, containingBlockWidth);
280
+ }
281
+ }
282
+
283
+ export function layoutAbsoluteChild(
284
+ containingNode: Node,
285
+ node: Node,
286
+ child: Node,
287
+ containingBlockWidth: number,
288
+ containingBlockHeight: number,
289
+ widthMode: SizingMode,
290
+ direction: Direction,
291
+ layoutMarkerData: LayoutData,
292
+ depth: number,
293
+ generationCount: number,
294
+ ): void {
295
+ // For grid containers, use inline (Row) and block (Column) axes for
296
+ // positioning, since grid alignment properties (justify-self, align-self)
297
+ // operate on inline/block axes, not main/cross axes based on flex-direction.
298
+ const mainAxis =
299
+ node.style.display() === Display.Grid
300
+ ? resolveDirection(FlexDirection.Row, direction)
301
+ : resolveDirection(node.style.flexDirection(), direction);
302
+ const crossAxis =
303
+ node.style.display() === Display.Grid
304
+ ? FlexDirection.Column
305
+ : resolveCrossDirection(mainAxis, direction);
306
+ const isMainAxisRow = isRow(mainAxis);
307
+
308
+ let childWidth = NaN;
309
+ let childHeight = NaN;
310
+ let childWidthSizingMode: SizingMode = SizingMode.MaxContent;
311
+ let childHeightSizingMode: SizingMode = SizingMode.MaxContent;
312
+
313
+ const marginRow = child.style.computeMarginForAxis(FlexDirection.Row, containingBlockWidth);
314
+ const marginColumn = child.style.computeMarginForAxis(FlexDirection.Column, containingBlockWidth);
315
+
316
+ if (child.hasDefiniteLength(Dimension.Width, containingBlockWidth)) {
317
+ childWidth =
318
+ child.getResolvedDimension(
319
+ direction,
320
+ Dimension.Width,
321
+ containingBlockWidth,
322
+ containingBlockWidth,
323
+ ) + marginRow;
324
+ } else {
325
+ // If the child doesn't have a specified width, compute the width based on
326
+ // the left/right offsets if they're defined.
327
+ if (
328
+ child.style.isFlexStartPositionDefined(FlexDirection.Row, direction) &&
329
+ child.style.isFlexEndPositionDefined(FlexDirection.Row, direction) &&
330
+ !child.style.isFlexStartPositionAuto(FlexDirection.Row, direction) &&
331
+ !child.style.isFlexEndPositionAuto(FlexDirection.Row, direction)
332
+ ) {
333
+ childWidth =
334
+ containingNode.layout.measuredDimension(Dimension.Width) -
335
+ (containingNode.style.computeFlexStartBorder(FlexDirection.Row, direction) +
336
+ containingNode.style.computeFlexEndBorder(FlexDirection.Row, direction)) -
337
+ (child.style.computeFlexStartPosition(FlexDirection.Row, direction, containingBlockWidth) +
338
+ child.style.computeFlexEndPosition(FlexDirection.Row, direction, containingBlockWidth));
339
+ childWidth = boundAxis(
340
+ child,
341
+ FlexDirection.Row,
342
+ direction,
343
+ childWidth,
344
+ containingBlockWidth,
345
+ containingBlockWidth,
346
+ );
347
+ }
348
+ }
349
+
350
+ if (child.hasDefiniteLength(Dimension.Height, containingBlockHeight)) {
351
+ childHeight =
352
+ child.getResolvedDimension(
353
+ direction,
354
+ Dimension.Height,
355
+ containingBlockHeight,
356
+ containingBlockWidth,
357
+ ) + marginColumn;
358
+ } else {
359
+ // If the child doesn't have a specified height, compute the height based
360
+ // on the top/bottom offsets if they're defined.
361
+ if (
362
+ child.style.isFlexStartPositionDefined(FlexDirection.Column, direction) &&
363
+ child.style.isFlexEndPositionDefined(FlexDirection.Column, direction) &&
364
+ !child.style.isFlexStartPositionAuto(FlexDirection.Column, direction) &&
365
+ !child.style.isFlexEndPositionAuto(FlexDirection.Column, direction)
366
+ ) {
367
+ childHeight =
368
+ containingNode.layout.measuredDimension(Dimension.Height) -
369
+ (containingNode.style.computeFlexStartBorder(FlexDirection.Column, direction) +
370
+ containingNode.style.computeFlexEndBorder(FlexDirection.Column, direction)) -
371
+ (child.style.computeFlexStartPosition(
372
+ FlexDirection.Column,
373
+ direction,
374
+ containingBlockHeight,
375
+ ) +
376
+ child.style.computeFlexEndPosition(
377
+ FlexDirection.Column,
378
+ direction,
379
+ containingBlockHeight,
380
+ ));
381
+ childHeight = boundAxis(
382
+ child,
383
+ FlexDirection.Column,
384
+ direction,
385
+ childHeight,
386
+ containingBlockHeight,
387
+ containingBlockWidth,
388
+ );
389
+ }
390
+ }
391
+
392
+ // Exactly one dimension needs to be defined for us to be able to do aspect
393
+ // ratio calculation. One dimension being the anchor and the other being
394
+ // flexible.
395
+ const childStyle = child.style;
396
+ if (isUndefined(childWidth) !== isUndefined(childHeight)) {
397
+ if (isDefined(childStyle.aspectRatio())) {
398
+ if (isUndefined(childWidth)) {
399
+ childWidth = marginRow + (childHeight - marginColumn) * childStyle.aspectRatio();
400
+ } else if (isUndefined(childHeight)) {
401
+ childHeight = marginColumn + (childWidth - marginRow) / childStyle.aspectRatio();
402
+ }
403
+ }
404
+ }
405
+
406
+ // If we're still missing one or the other dimension, measure the content.
407
+ if (isUndefined(childWidth) || isUndefined(childHeight)) {
408
+ childWidthSizingMode = isUndefined(childWidth) ? SizingMode.MaxContent : SizingMode.StretchFit;
409
+ childHeightSizingMode = isUndefined(childHeight)
410
+ ? SizingMode.MaxContent
411
+ : SizingMode.StretchFit;
412
+
413
+ // If the size of the owner is defined then try to constrain the absolute
414
+ // child to that size as well. This allows text within the absolute child
415
+ // to wrap to the size of its owner. This is the same behavior as many
416
+ // browsers implement.
417
+ if (
418
+ !isMainAxisRow &&
419
+ isUndefined(childWidth) &&
420
+ widthMode !== SizingMode.MaxContent &&
421
+ isDefined(containingBlockWidth) &&
422
+ containingBlockWidth > 0
423
+ ) {
424
+ childWidth = containingBlockWidth;
425
+ childWidthSizingMode = SizingMode.FitContent;
426
+ }
427
+
428
+ calculateLayoutInternal(
429
+ child,
430
+ childWidth,
431
+ childHeight,
432
+ direction,
433
+ childWidthSizingMode,
434
+ childHeightSizingMode,
435
+ containingBlockWidth,
436
+ containingBlockHeight,
437
+ false,
438
+ LayoutPassReason.AbsMeasureChild,
439
+ layoutMarkerData,
440
+ depth,
441
+ generationCount,
442
+ );
443
+ childWidth =
444
+ child.layout.measuredDimension(Dimension.Width) +
445
+ child.style.computeMarginForAxis(FlexDirection.Row, containingBlockWidth);
446
+ childHeight =
447
+ child.layout.measuredDimension(Dimension.Height) +
448
+ child.style.computeMarginForAxis(FlexDirection.Column, containingBlockWidth);
449
+ }
450
+
451
+ calculateLayoutInternal(
452
+ child,
453
+ childWidth,
454
+ childHeight,
455
+ direction,
456
+ SizingMode.StretchFit,
457
+ SizingMode.StretchFit,
458
+ containingBlockWidth,
459
+ containingBlockHeight,
460
+ true,
461
+ LayoutPassReason.AbsLayout,
462
+ layoutMarkerData,
463
+ depth,
464
+ generationCount,
465
+ );
466
+
467
+ positionAbsoluteChild(
468
+ containingNode,
469
+ node,
470
+ child,
471
+ direction,
472
+ mainAxis,
473
+ true /*isMainAxis*/,
474
+ containingBlockWidth,
475
+ containingBlockHeight,
476
+ );
477
+ positionAbsoluteChild(
478
+ containingNode,
479
+ node,
480
+ child,
481
+ direction,
482
+ crossAxis,
483
+ false /*isMainAxis*/,
484
+ containingBlockWidth,
485
+ containingBlockHeight,
486
+ );
487
+ }
488
+
489
+ export function layoutAbsoluteDescendants(
490
+ containingNode: Node,
491
+ currentNode: Node,
492
+ widthSizingMode: SizingMode,
493
+ currentNodeDirection: Direction,
494
+ layoutMarkerData: LayoutData,
495
+ currentDepth: number,
496
+ generationCount: number,
497
+ currentNodeLeftOffsetFromContainingBlock: number,
498
+ currentNodeTopOffsetFromContainingBlock: number,
499
+ containingNodeAvailableInnerWidth: number,
500
+ containingNodeAvailableInnerHeight: number,
501
+ ): boolean {
502
+ let hasNewLayout = false;
503
+ for (const child of currentNode.getLayoutChildren()) {
504
+ if (child.style.display() === Display.None) {
505
+ continue;
506
+ } else if (child.style.positionType() === PositionType.Absolute) {
507
+ const absoluteErrata = currentNode.hasErrata(Errata.AbsolutePercentAgainstInnerSize);
508
+ const containingBlockWidth = absoluteErrata
509
+ ? containingNodeAvailableInnerWidth
510
+ : containingNode.layout.measuredDimension(Dimension.Width) -
511
+ containingNode.style.computeBorderForAxis(FlexDirection.Row);
512
+ const containingBlockHeight = absoluteErrata
513
+ ? containingNodeAvailableInnerHeight
514
+ : containingNode.layout.measuredDimension(Dimension.Height) -
515
+ containingNode.style.computeBorderForAxis(FlexDirection.Column);
516
+
517
+ layoutAbsoluteChild(
518
+ containingNode,
519
+ currentNode,
520
+ child,
521
+ containingBlockWidth,
522
+ containingBlockHeight,
523
+ widthSizingMode,
524
+ currentNodeDirection,
525
+ layoutMarkerData,
526
+ currentDepth,
527
+ generationCount,
528
+ );
529
+
530
+ hasNewLayout = hasNewLayout || child.hasNewLayout_;
531
+
532
+ /*
533
+ * At this point the child has its position set but only on its the
534
+ * parent's flexStart edge. Additionally, this position should be
535
+ * interpreted relative to the containing block of the child if it had
536
+ * insets defined. So we need to adjust the position by subtracting the
537
+ * the parents offset from the containing block. However, getting that
538
+ * offset is complicated since the two nodes can have different main/cross
539
+ * axes.
540
+ */
541
+ const parentMainAxis = resolveDirection(
542
+ currentNode.style.flexDirection(),
543
+ currentNodeDirection,
544
+ );
545
+ const parentCrossAxis = resolveCrossDirection(parentMainAxis, currentNodeDirection);
546
+
547
+ if (needsTrailingPosition(parentMainAxis)) {
548
+ const mainInsetsDefined = isRow(parentMainAxis)
549
+ ? child.style.horizontalInsetsDefined()
550
+ : child.style.verticalInsetsDefined();
551
+ setChildTrailingPosition(
552
+ mainInsetsDefined ? containingNode : currentNode,
553
+ child,
554
+ parentMainAxis,
555
+ );
556
+ }
557
+ if (needsTrailingPosition(parentCrossAxis)) {
558
+ const crossInsetsDefined = isRow(parentCrossAxis)
559
+ ? child.style.horizontalInsetsDefined()
560
+ : child.style.verticalInsetsDefined();
561
+ setChildTrailingPosition(
562
+ crossInsetsDefined ? containingNode : currentNode,
563
+ child,
564
+ parentCrossAxis,
565
+ );
566
+ }
567
+
568
+ /*
569
+ * At this point we know the left and top physical edges of the child are
570
+ * set with positions that are relative to the containing block if insets
571
+ * are defined
572
+ */
573
+ const childLeftPosition = child.layout.position(PhysicalEdge.Left);
574
+ const childTopPosition = child.layout.position(PhysicalEdge.Top);
575
+
576
+ const childLeftOffsetFromParent = child.style.horizontalInsetsDefined()
577
+ ? childLeftPosition - currentNodeLeftOffsetFromContainingBlock
578
+ : childLeftPosition;
579
+ const childTopOffsetFromParent = child.style.verticalInsetsDefined()
580
+ ? childTopPosition - currentNodeTopOffsetFromContainingBlock
581
+ : childTopPosition;
582
+
583
+ child.setLayoutPosition(childLeftOffsetFromParent, PhysicalEdge.Left);
584
+ child.setLayoutPosition(childTopOffsetFromParent, PhysicalEdge.Top);
585
+ } else if (
586
+ child.style.positionType() === PositionType.Static &&
587
+ !child.alwaysFormsContainingBlock
588
+ ) {
589
+ // We may write new layout results for absolute descendants of "child"
590
+ // which are positioned relative to the current containing block instead
591
+ // of their parent. "child" may not be dirty, or have new constraints, so
592
+ // absolute positioning may be the first time during this layout pass
593
+ // that we need to mutate these descendents. Make sure the path of nodes
594
+ // to them is mutable before positioning.
595
+ child.cloneChildrenIfNeeded();
596
+ const childDirection = child.resolveDirection(currentNodeDirection);
597
+ // By now all descendants of the containing block that are not absolute
598
+ // will have their positions set for left and top.
599
+ const childLeftOffsetFromContainingBlock =
600
+ currentNodeLeftOffsetFromContainingBlock + child.layout.position(PhysicalEdge.Left);
601
+ const childTopOffsetFromContainingBlock =
602
+ currentNodeTopOffsetFromContainingBlock + child.layout.position(PhysicalEdge.Top);
603
+
604
+ hasNewLayout =
605
+ layoutAbsoluteDescendants(
606
+ containingNode,
607
+ child,
608
+ widthSizingMode,
609
+ childDirection,
610
+ layoutMarkerData,
611
+ currentDepth + 1,
612
+ generationCount,
613
+ childLeftOffsetFromContainingBlock,
614
+ childTopOffsetFromContainingBlock,
615
+ containingNodeAvailableInnerWidth,
616
+ containingNodeAvailableInnerHeight,
617
+ ) || hasNewLayout;
618
+
619
+ cleanupContentsNodesRecursively(child, /* didPerformLayout */ hasNewLayout);
620
+ if (hasNewLayout) {
621
+ child.hasNewLayout_ = hasNewLayout;
622
+ }
623
+ }
624
+ }
625
+ return hasNewLayout;
626
+ }
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Derived from Yoga. See THIRD_PARTY_NOTICES.md.
3
+
4
+ // Port of yoga/algorithm/Baseline.cpp.
5
+
6
+ import { Align, Dimension, PositionType } from "../generated/YGEnums.ts";
7
+ import { PhysicalEdge, isColumn, resolveChildAlignment } from "./helpers.ts";
8
+ import type { Node } from "./node.ts";
9
+
10
+ export function calculateBaseline(node: Node): number {
11
+ if (node.hasBaselineFunc()) {
12
+ const baseline = node.baseline(
13
+ node.layout.measuredDimension(Dimension.Width),
14
+ node.layout.measuredDimension(Dimension.Height),
15
+ );
16
+
17
+ if (Number.isNaN(baseline)) {
18
+ throw new Error("Expect custom baseline function to not return NaN");
19
+ }
20
+ return baseline;
21
+ }
22
+
23
+ let baselineChild: Node | null = null;
24
+ for (const child of node.getLayoutChildren()) {
25
+ if (child.lineIndex > 0) {
26
+ break;
27
+ }
28
+ if (child.style.positionType() === PositionType.Absolute) {
29
+ continue;
30
+ }
31
+ if (resolveChildAlignment(node, child) === Align.Baseline || child.isReferenceBaseline_) {
32
+ baselineChild = child;
33
+ break;
34
+ }
35
+
36
+ if (baselineChild === null) {
37
+ baselineChild = child;
38
+ }
39
+ }
40
+
41
+ if (baselineChild === null) {
42
+ return node.layout.measuredDimension(Dimension.Height);
43
+ }
44
+
45
+ const baseline = calculateBaseline(baselineChild);
46
+ return baseline + baselineChild.layout.position(PhysicalEdge.Top);
47
+ }
48
+
49
+ export function isBaselineLayout(node: Node): boolean {
50
+ if (isColumn(node.style.flexDirection())) {
51
+ return false;
52
+ }
53
+ if (node.style.alignItems() === Align.Baseline) {
54
+ return true;
55
+ }
56
+ for (const child of node.getLayoutChildren()) {
57
+ if (
58
+ child.style.positionType() !== PositionType.Absolute &&
59
+ child.style.alignSelf() === Align.Baseline
60
+ ) {
61
+ return true;
62
+ }
63
+ }
64
+
65
+ return false;
66
+ }