@react-x11/components 0.16.1 → 0.17.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.
@@ -1 +1 @@
1
- {"version":3,"file":"flex.d.ts","sourceRoot":"","sources":["../../../src/html/layout/flex.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,GAAG,EAAwB,MAAM,YAAY,CAAC;AA4BvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwBhD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,aAAa,EAClB,YAAY,EAAE,MAAM,GACnB,MAAM,CAmbR"}
1
+ {"version":3,"file":"flex.d.ts","sourceRoot":"","sources":["../../../src/html/layout/flex.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,GAAG,EAAwB,MAAM,YAAY,CAAC;AA4BvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwBhD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,aAAa,EAClB,YAAY,EAAE,MAAM,GACnB,MAAM,CA6aR"}
@@ -210,11 +210,7 @@ export function layoutFlex(box, ctx, contentWidth) {
210
210
  root.setWidth(contentWidth);
211
211
  const direction = box.style.direction === 'rtl' ? Y.DIRECTION_RTL : Y.DIRECTION_LTR;
212
212
  const row = box.style.flexDirection.startsWith('row');
213
- // Yoga aligns the lines of a box that wraps, or of a row that aligns by
214
- // baselines, in one pass of its own, which drops a margin
215
- // (`lineMarginFix`) — and not those of a column that does not wrap,
216
- // whatever it aligns by, whose margins Yoga keeps
217
- let baselines = row &&
213
+ const baselines = row &&
218
214
  (box.style.alignItems === 'baseline' ||
219
215
  items.some(({ box: child }) => child.style.alignSelf === 'baseline'));
220
216
  // An `auto` margin across a row that wraps takes the room its line has
@@ -232,35 +228,43 @@ export function layoutFlex(box, ctx, contentWidth) {
232
228
  }
233
229
  }
234
230
  else if (baselines) {
235
- // Yoga takes a row that does not wrap through that pass as well, and
236
- // sets its line there as tall as its items and not the row: an item
237
- // centred or at the end of a row of a height was centred or ended in
238
- // the items' height. It has sized that line already, as the most any
239
- // item reaches down to its bottom edge — a baseline, to Yoga — and the
240
- // largest bottom margin besides, whichever items those are: a row of
241
- // no height of its own was as tall as both. And it sets an item with
242
- // an `auto` margin by its baseline: at the top, where the margin puts
243
- // it at the bottom, and every item beside it as far down as its height
244
- // reached. That item takes no part in aligning the line by baselines
245
- // (9.4 step 8), and Yoga is told the alignment its margins come to.
246
- // With fewer than two items left that do take part, they come to their
247
- // line's start (8.3), which Yoga is told as well: then nothing in the
248
- // row is aligned by its baseline, Yoga takes no such pass, and the line
249
- // is the row. Two or more are lined up by their baselines once those
250
- // are known (`baselineLines`), and the row laid out again with none.
231
+ // Yoga takes a row aligned by baselines through that pass whether it
232
+ // wraps or not, and sets an item with an `auto` margin there by its
233
+ // baseline: at the top, where the margin puts it at the bottom, and
234
+ // every item beside it as far down as its height reached. That item
235
+ // takes no part in aligning the line by baselines (9.4 step 8), and
236
+ // Yoga is told the alignment its margins come to.
251
237
  for (const { box: child, node } of items) {
252
238
  const aligned = autoAcross(child.style, false);
253
239
  if (aligned)
254
240
  node.setAlignSelf(ALIGN[aligned]);
255
241
  }
256
- const aligned = items.filter(({ box: child }) => byBaseline(box.style, child.style));
257
- if (aligned.length < 2) {
258
- for (const { node } of aligned)
259
- node.setAlignSelf(Y.ALIGN_FLEX_START);
260
- if (box.style.alignItems === 'baseline') {
261
- root.setAlignItems(Y.ALIGN_FLEX_START);
262
- }
263
- baselines = false;
242
+ }
243
+ // Items aligned by their baselines, which Yoga cannot see, are told they
244
+ // are at their lines' starts, which is where one is that shares its line
245
+ // with no other (8.3); those that do share one are lined up by their
246
+ // baselines once those are known (`baselineLines`), and the row laid out
247
+ // again. Told an item is aligned by its baseline, Yoga sizes each line
248
+ // of the row as the most any item on it reaches down to its bottom edge
249
+ // — a baseline, to Yoga — and the largest bottom margin besides,
250
+ // whichever items those are, and stretches the items on the line to
251
+ // that: a row of no height of its own was as tall as both, and
252
+ // `align-content` had that much less room to share out. And it takes a
253
+ // row that does not wrap through its pass for lines, which sets the one
254
+ // line there as tall as its items and not the row: an item centred or at
255
+ // the end of a row of a height was centred or ended in the items'
256
+ // height. Told none is, it takes neither. A row whose lines wrap in
257
+ // reverse is left to Yoga.
258
+ const started = new Set();
259
+ if (baselines && box.style.flexWrap !== 'wrap-reverse') {
260
+ for (const { box: child, node } of items) {
261
+ if (!byBaseline(box.style, child.style))
262
+ continue;
263
+ node.setAlignSelf(Y.ALIGN_FLEX_START);
264
+ started.add(child);
265
+ }
266
+ if (box.style.alignItems === 'baseline') {
267
+ root.setAlignItems(Y.ALIGN_FLEX_START);
264
268
  }
265
269
  }
266
270
  // frozen at its least size on the one line of a box that does not
@@ -397,31 +401,23 @@ export function layoutFlex(box, ctx, contentWidth) {
397
401
  ctx.flexDepth = depth;
398
402
  }
399
403
  }
400
- // whether Yoga's last layout took its pass for lines (`placeItems`)
401
- let lined = box.style.flexWrap !== 'nowrap' || baselines;
402
- let bottom = placeItems(box, ctx, items, row, own, lined, contentWidth, undefined, crossed ? crossLines(box.style, items, contentWidth, columnGap) : undefined);
403
- // Items aligned by their baselines, which Yoga cannot see, are aligned
404
- // with their baselines known (`baselineLines`)
405
- // by the flex layout again, set at their lines' starts with the margins
406
- // that put their baselines together, which makes each line as tall as
407
- // that does
408
- const lines = baselines ? baselineLines(box.style, items) : null;
409
- const started = new Set();
404
+ // Yoga aligns the lines of a box that wraps in one pass of its own, which
405
+ // drops a margin (`lineMarginFix`), and keeps the margins of one that
406
+ // does not, which it takes through that pass only where it is told an
407
+ // item is aligned by its baseline: here, never
408
+ const lined = box.style.flexWrap !== 'nowrap';
409
+ let bottom = placeItems(box, ctx, items, row, own, lined, contentWidth, started, crossed ? crossLines(box.style, items, contentWidth, columnGap) : undefined);
410
+ // Items that share a line and are aligned by their baselines are laid
411
+ // out by the flex layout again, set at their lines' starts with the
412
+ // margins that put their baselines together (`baselineLines`), which
413
+ // makes each line as tall as that does
414
+ const lines = started.size > 1 ? baselineLines(box.style, items) : null;
410
415
  if (lines) {
411
- // every one of them, and the box's own `baseline` too, which is what
412
- // takes Yoga down that pass
413
416
  for (const line of lines) {
414
- line.forEach(({ box: child, node }, i) => {
415
- node.setAlignSelf(Y.ALIGN_FLEX_START);
417
+ line.forEach(({ node }, i) => {
416
418
  node.setMargin(Y.EDGE_TOP, line.margins[i]);
417
- started.add(child);
418
419
  });
419
420
  }
420
- if (box.style.alignItems === 'baseline') {
421
- root.setAlignItems(Y.ALIGN_FLEX_START);
422
- }
423
- // so it takes it only where the row wraps
424
- lined = box.style.flexWrap !== 'nowrap';
425
421
  ctx.flexDepth = depth + 1;
426
422
  try {
427
423
  calculate();
@@ -618,6 +614,11 @@ crossed) {
618
614
  let bottom = 0;
619
615
  // the lines of a row that wraps in reverse are turned round to run up it
620
616
  const reverse = row && box.style.flexWrap === 'wrap-reverse';
617
+ // the left edge a column's items aligned by baselines share, where it
618
+ // does not wrap (`baselineEdge`); a column that wraps is `crossed`
619
+ const edge = row || box.style.flexWrap !== 'nowrap'
620
+ ? NaN
621
+ : baselineEdge(box.style, items);
621
622
  for (const { box: child, node, laid } of items) {
622
623
  const placed = crossed?.get(child);
623
624
  const across = lined && !placed
@@ -625,7 +626,11 @@ crossed) {
625
626
  : 0;
626
627
  const itemHeight = row ? heightOf(node, laid) : laid.main;
627
628
  const left = box.contentX +
628
- (placed ? placed.x : node.getComputedLeft() + (row ? 0 : across));
629
+ (placed
630
+ ? placed.x
631
+ : !Number.isNaN(edge) && byBaseline(box.style, child.style, false)
632
+ ? edge
633
+ : node.getComputedLeft() + (row ? 0 : across));
629
634
  // which Yoga turns an item round in by the height it laid it out at, and
630
635
  // not the one it is (`unspace`)
631
636
  const top = box.contentY +
@@ -2475,15 +2480,15 @@ function contentBottom(box) {
2475
2480
  * its bottom edge, so it lined them up by their bottoms. With the items laid
2476
2481
  * out, each line's, and for each the top margin that sets it at the line's
2477
2482
  * start with its first baseline where the lowest-reaching one's is — or
2478
- * null where no line has two to align.
2483
+ * null where no line has two to align. Not for a row whose lines wrap in
2484
+ * reverse, which grow from their ends and are left to Yoga (`layoutFlex`).
2479
2485
  */
2480
2486
  function baselineLines(style, items) {
2481
- // a line that grows from its end is aligned from there, and left to Yoga
2482
- if (style.flexWrap === 'wrap-reverse')
2483
- return null;
2484
2487
  const wraps = style.flexWrap !== 'nowrap';
2485
- // along a line the items go the way the main axis does, and the next
2486
- // line starts where one does not
2488
+ // along a line the items go the way the main axis does, each margin box
2489
+ // after the last one's end, and the next line starts before it (9.3): at
2490
+ // the line's start, where an item with a margin before it was further
2491
+ // along than one alone on the line before
2487
2492
  const back = (style.flexDirection === 'row-reverse') !== (style.direction === 'rtl');
2488
2493
  const out = [];
2489
2494
  let line = [];
@@ -2504,12 +2509,18 @@ function baselineLines(style, items) {
2504
2509
  out.push(Object.assign(line, { margins }));
2505
2510
  };
2506
2511
  for (const item of items) {
2507
- const box = item.box;
2508
- if (wraps && line.length && (back ? box.x >= last : box.x <= last)) {
2512
+ const { box, node } = item;
2513
+ const left = node.getComputedLeft() - node.getComputedMargin(Y.EDGE_LEFT);
2514
+ const right = node.getComputedLeft() +
2515
+ node.getComputedWidth() +
2516
+ node.getComputedMargin(Y.EDGE_RIGHT);
2517
+ if (wraps &&
2518
+ line.length &&
2519
+ (back ? right > last + 0.01 : left < last - 0.01)) {
2509
2520
  close();
2510
2521
  line = [];
2511
2522
  }
2512
- last = box.x;
2523
+ last = back ? left : right;
2513
2524
  if (byBaseline(style, box.style))
2514
2525
  line.push(item);
2515
2526
  }
@@ -2520,11 +2531,41 @@ function baselineLines(style, items) {
2520
2531
  /** Whether an item takes part in aligning its line by baselines (CSS
2521
2532
  * Flexbox 8.3, 9.4 step 8): aligned by its baseline, with no `auto`
2522
2533
  * margin across the line, which takes it over its alignment. */
2523
- function byBaseline(container, item) {
2534
+ function byBaseline(container, item,
2535
+ /** Whether the line is a row's, across which its margins are its top
2536
+ * and bottom ones; a column's are its left and right ones. */
2537
+ row = true) {
2524
2538
  const aligned = item.alignSelf === AUTO ? container.alignItems : item.alignSelf;
2525
2539
  return (aligned === 'baseline' &&
2526
- item.marginTop !== AUTO &&
2527
- item.marginBottom !== AUTO);
2540
+ (row ? item.marginTop : item.marginLeft) !== AUTO &&
2541
+ (row ? item.marginBottom : item.marginRight) !== AUTO);
2542
+ }
2543
+ /**
2544
+ * Where the items a column that does not wrap aligns by baselines have
2545
+ * their left edges, from its content box's: NaN where it has none.
2546
+ *
2547
+ * A horizontal item has no baseline across a column, and one is made from
2548
+ * its border box — the line-under edge of the vertical writing mode it is
2549
+ * taken to have, its left, whichever way its text runs (CSS Box Alignment
2550
+ * 3, 9.1). So the items share their left edges, and are set together at
2551
+ * the line's cross start, the column's left or, where it runs right to
2552
+ * left, its right (9.3; CSS Flexbox 8.3), as Chrome sets them: as far from
2553
+ * there as the most any of them reaches past its edge on that side. Yoga
2554
+ * never aligns a column by baselines, and sets each at its line's start
2555
+ * with its margin there, so that is the furthest any of them is from the
2556
+ * start: the rightmost left edge, or from the right the leftmost.
2557
+ */
2558
+ function baselineEdge(container, items) {
2559
+ const rtl = container.direction === 'rtl';
2560
+ let edge = NaN;
2561
+ for (const { box, node } of items) {
2562
+ if (!byBaseline(container, box.style, false))
2563
+ continue;
2564
+ const left = node.getComputedLeft();
2565
+ if (!(rtl ? left >= edge : left <= edge))
2566
+ edge = left;
2567
+ }
2568
+ return edge;
2528
2569
  }
2529
2570
  /**
2530
2571
  * Whether Yoga made a line of a row that wraps the row's height, where its
@@ -2622,13 +2663,13 @@ function autoAcross(item, reverse) {
2622
2663
  }
2623
2664
  /**
2624
2665
  * How far an item is from where it belongs across its line, where Yoga
2625
- * (3.2.1) aligned the lines in the pass it takes for a box that wraps or
2626
- * aligns by baselines: it sets an item aligned to its line's start there
2627
- * as though it had no margin at that side, and one centred as though it had
2628
- * none at either — `items-start` in a wrapping row put every card's top
2629
- * margin under it. By the margin at the start of the line's cross axis, and
2630
- * by half what it exceeds the one at the end by, as Yoga holds them: for an
2631
- * item set at its line's start (`started`), its baseline's.
2666
+ * (3.2.1) aligned the lines in the pass it takes for a box that wraps: it
2667
+ * sets an item aligned to its line's start there as though it had no
2668
+ * margin at that side, and one centred as though it had none at either —
2669
+ * `items-start` in a wrapping row put every card's top margin under it. By
2670
+ * the margin at the start of the line's cross axis, and by half what it
2671
+ * exceeds the one at the end by, as Yoga holds them: for an item set at
2672
+ * its line's start (`started`), its baseline's.
2632
2673
  *
2633
2674
  * A row whose lines wrap in reverse Yoga lays out as though they wrapped
2634
2675
  * forward, and then turns each item over across the box, its margins with
@@ -2637,9 +2678,7 @@ function autoAcross(item, reverse) {
2637
2678
  * stretched, is its bottom margin down from its line's top where it is its
2638
2679
  * top one; and one centred, half the difference. A column's, whose cross
2639
2680
  * axis runs right to left, or that wraps in reverse, is left as Yoga has
2640
- * it, and so is an item an `auto` margin aligns in a row that does not
2641
- * wrap: where Yoga still takes that pass for such a row, its items are
2642
- * laid out again without it, aligned by their baselines (`layoutFlex`).
2681
+ * it, and so is an item an `auto` margin aligns across a column.
2643
2682
  */
2644
2683
  function lineMarginFix(container, item, node, row,
2645
2684
  /** Whether the flex box has a definite height. */
@@ -2656,10 +2695,7 @@ own, started = false) {
2656
2695
  if (started)
2657
2696
  align = 'flex-start';
2658
2697
  else if (lead === AUTO || trail === AUTO) {
2659
- align =
2660
- row && container.flexWrap !== 'nowrap'
2661
- ? autoAcross(style, reverse)
2662
- : null;
2698
+ align = row ? autoAcross(style, reverse) : null;
2663
2699
  }
2664
2700
  else {
2665
2701
  align = style.alignSelf === AUTO ? container.alignItems : style.alignSelf;
@@ -2985,9 +3021,10 @@ function wrapsColumn(style, width) {
2985
3021
  * item with an `auto` margin across its line takes the room the line has
2986
3022
  * past it on that side (8.1), and none where there is none; a stretched
2987
3023
  * item is as wide as its line less its margins, within its limits (9.4,
2988
- * step 11), and as tall as the column made it; and the rest are where
2989
- * `align-self` says, a baseline at the line's start, as a column has none
2990
- * across it to align by.
3024
+ * step 11), and as tall as the column made it; those aligned by baselines
3025
+ * share their left edges, set together at the line's start, where a column
3026
+ * that does not wrap sets them (`baselineEdge`); and the rest are where
3027
+ * `align-self` says.
2991
3028
  */
2992
3029
  function crossLines(style, items,
2993
3030
  /** The flex box's content width. */
@@ -3018,7 +3055,26 @@ gap) {
3018
3055
  lead.push(fromRight ? r : l);
3019
3056
  trail.push(fromRight ? l : r);
3020
3057
  });
3021
- const across = lines.map((line) => line.reduce((most, i) => Math.max(most, sizes[i] + lead[i] + trail[i]), 0));
3058
+ // A line is as wide as its widest item, margins and all, and as the
3059
+ // items it aligns by baselines come to, sharing their left edges: the
3060
+ // most any reaches from the line's start to that edge, and the most any
3061
+ // reaches past it (`baselineEdge`; 9.4 step 8). `reach` is each line's
3062
+ // first, where those items' left edges are from its start.
3063
+ const reach = [];
3064
+ const across = lines.map((line) => {
3065
+ let most = 0;
3066
+ let before = -Infinity;
3067
+ let after = -Infinity;
3068
+ for (const i of line) {
3069
+ most = Math.max(most, sizes[i] + lead[i] + trail[i]);
3070
+ if (!byBaseline(style, items[i].box.style, false))
3071
+ continue;
3072
+ before = Math.max(before, lead[i] + (fromRight ? sizes[i] : 0));
3073
+ after = Math.max(after, trail[i] + (fromRight ? 0 : sizes[i]));
3074
+ }
3075
+ reach.push(before);
3076
+ return Math.max(most, before + after);
3077
+ });
3022
3078
  const count = lines.length;
3023
3079
  let room = width - gap * (count - 1);
3024
3080
  for (const size of across)
@@ -3087,6 +3143,9 @@ gap) {
3087
3143
  itemWidth = least;
3088
3144
  itemWidth = Math.max(itemWidth, box.horizontalExtra);
3089
3145
  }
3146
+ else if (byBaseline(style, own, false)) {
3147
+ offset = reach[k] - (fromRight ? itemWidth : 0);
3148
+ }
3090
3149
  else {
3091
3150
  const align = own.alignSelf === AUTO ? style.alignItems : own.alignSelf;
3092
3151
  if (align === 'center')