@slotted/styles 0.1.0-beta.6 → 0.1.0-beta.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slotted/styles",
3
- "version": "0.1.0-beta.6",
3
+ "version": "0.1.0-beta.8",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -82,6 +82,16 @@
82
82
  /** The box a row's mark occupies: a control's own size, so the two agree. */
83
83
  --_row-mark: var(--slotted-app-shell-row-mark-size, var(--slotted-control-height-md, 34px));
84
84
  --_row-gap: var(--slotted-control-gap-md, 8px);
85
+ /**
86
+ * How far a focus ring drawn outside a control reaches past its box: the
87
+ * ring's width and its offset, 4px with the default theme. The three parts
88
+ * of the navigation column pad their inline sides by it, because the body
89
+ * scrolls and clips at its padding box, and a full-width control's ring
90
+ * stood outside that box on both sides.
91
+ */
92
+ --_row-ring-inset: calc(
93
+ var(--slotted-focus-ring-width, 2px) + var(--slotted-focus-ring-offset, 2px)
94
+ );
85
95
 
86
96
  /**
87
97
  * A row's type. A list of destinations is text and not a control, so it
@@ -495,7 +505,19 @@
495
505
  gap: var(--_row-gap);
496
506
  min-block-size: var(--_rail-size);
497
507
  min-inline-size: 0;
508
+ /**
509
+ * The gutter the body reserves, reserved here too. `scrollbar-gutter`
510
+ * applies to a scroll container only, and `hidden` is the overflow that
511
+ * makes one without a bar of its own: with classic scrollbars the body's
512
+ * content box ended one bar width (10px in Chrome) before the head's and
513
+ * the foot's. Nothing is clipped that was drawn before: the ring inset
514
+ * keeps a control's focus ring inside the padding box. The bar's width is
515
+ * the body's, or the gutter is the platform's full bar (15px in Chrome).
516
+ */
517
+ overflow: hidden;
498
518
  padding-block: var(--_row-inset);
519
+ scrollbar-gutter: stable;
520
+ scrollbar-width: thin;
499
521
  }
500
522
  /**
501
523
  * The inset is the rows', not the region's: on the parts, a seam drawn by
@@ -505,7 +527,13 @@
505
527
  [data-ui='app-shell']
506
528
  > [data-part='nav']
507
529
  > :is([data-part='nav-header'], [data-part='nav-body'], [data-part='nav-footer']) {
508
- padding-inline: var(--_nav-inset);
530
+ /**
531
+ * Published where it pads, beside the row geometry the root publishes:
532
+ * `side-navigation` reads it to keep its rows' box on the edge it had,
533
+ * and a row it reaches outside these parts reads nothing.
534
+ */
535
+ --slotted-app-shell-row-ring-inset: var(--_row-ring-inset);
536
+ padding-inline: calc(var(--_nav-inset) + var(--_row-ring-inset));
509
537
  }
510
538
  /**
511
539
  * The body scrolls the way `scroll-area` scrolls, and for the reasons written
@@ -1221,6 +1249,19 @@
1221
1249
  border-start-end-radius: 0;
1222
1250
  margin-inline-end: 0;
1223
1251
  }
1252
+
1253
+ /**
1254
+ * The seam re-read in each region's scope. `--_seam` declared on the root
1255
+ * holds the root's `--slotted-app-shell-border-color`, so the property written
1256
+ * on a region recoloured nothing. Declared again on every region, the chain
1257
+ * resolves where the region stands: a colour written there recolours the
1258
+ * seams the region and its parts draw, and `transparent` removes them. The
1259
+ * tone rules below state the same two declarations at a higher specificity.
1260
+ */
1261
+ [data-ui='app-shell'] > [data-part] {
1262
+ --_rule: var(--slotted-app-shell-border-color, var(--slotted-border-subtle, ButtonBorder));
1263
+ --_seam: var(--_rule-width) solid var(--_rule);
1264
+ }
1224
1265
  /* ── Separation by tone ──────────────────────────────────────────────── */
1225
1266
 
1226
1267
  /**
@@ -1238,7 +1279,8 @@
1238
1279
  * where it is declared, and a region carrying a scheme of its own must mix
1239
1280
  * its own ink.
1240
1281
  */
1241
- [data-ui='app-shell'][data-separation='tone'] {
1282
+ [data-ui='app-shell'][data-separation='tone'],
1283
+ [data-ui='app-shell'][data-separation='tone'] > [data-part] {
1242
1284
  --_seam: none;
1243
1285
  --_seam-width: 0px;
1244
1286
  }
@@ -1365,7 +1407,7 @@
1365
1407
  [data-ui='app-shell']
1366
1408
  > [data-part='nav']:has(> [data-part='nav-rail'])
1367
1409
  > :is([data-part='nav-header'], [data-part='nav-body'], [data-part='nav-footer']) {
1368
- padding-inline-start: var(--_row-inset);
1410
+ padding-inline-start: calc(var(--_row-inset) + var(--_row-ring-inset));
1369
1411
  transition: visibility var(--_duration) step-start;
1370
1412
  }
1371
1413
  [data-ui='app-shell'][data-nav-mode='inline'][data-open]
@@ -1400,7 +1442,8 @@
1400
1442
  * a forced-colours rule of its own for.
1401
1443
  */
1402
1444
  @media (forced-colors: active) {
1403
- [data-ui='app-shell'][data-separation='tone'] {
1445
+ [data-ui='app-shell'][data-separation='tone'],
1446
+ [data-ui='app-shell'][data-separation='tone'] > [data-part] {
1404
1447
  --_seam: var(--_rule-width) solid CanvasText;
1405
1448
  --_seam-width: var(--_rule-width);
1406
1449
  }
@@ -1501,8 +1544,12 @@
1501
1544
  * mode at any width. The container query further down is the fallback for
1502
1545
  * the frame before the binding has measured, and nothing else.
1503
1546
  */
1547
+ /* The rail holds the parts' ring inset on each side as well, so a control
1548
+ at the mark's size keeps its focus ring inside the body beside the gutter. */
1504
1549
  [data-ui='app-shell'][data-nav-mode='inline'] > [data-part='nav'] {
1505
- inline-size: calc(var(--_rail-size) + 2 * var(--_nav-inset) + var(--_nav-edges));
1550
+ inline-size: calc(
1551
+ var(--_rail-size) + 2 * (var(--_nav-inset) + var(--_row-ring-inset)) + var(--_nav-edges)
1552
+ );
1506
1553
  }
1507
1554
  [data-ui='app-shell'][data-nav-mode='inline'][data-open] > [data-part='nav'] {
1508
1555
  inline-size: var(--_nav-size);
@@ -1779,7 +1826,9 @@
1779
1826
  */
1780
1827
  @container slotted-app-shell (inline-size >= 600px) {
1781
1828
  [data-ui='app-shell']:not([data-nav-mode]) > [data-part='nav'] {
1782
- inline-size: calc(var(--_rail-size) + 2 * var(--_nav-inset) + var(--_nav-edges));
1829
+ inline-size: calc(
1830
+ var(--_rail-size) + 2 * (var(--_nav-inset) + var(--_row-ring-inset)) + var(--_nav-edges)
1831
+ );
1783
1832
  }
1784
1833
  [data-ui='app-shell']:not([data-nav-mode])[data-open] > [data-part='nav'] {
1785
1834
  inline-size: var(--_nav-size);
@@ -625,14 +625,29 @@
625
625
  position: relative;
626
626
  }
627
627
 
628
- [data-ui='button'] [data-part='start'] > *:not([data-part='indicator']),
629
- [data-ui='button'] [data-part='end'] > *:not([data-part='indicator']),
628
+ [data-ui='button'] [data-part='start'] > *:not([data-part='indicator'], [data-ui='kbd']),
629
+ [data-ui='button'] [data-part='end'] > *:not([data-part='indicator'], [data-ui='kbd']),
630
630
  [data-ui='button'] [data-part='icon'] > *:not([data-part='indicator']) {
631
631
  block-size: 100%;
632
632
  display: block;
633
633
  inline-size: 100%;
634
634
  }
635
635
 
636
+ /**
637
+ * A key in a slot is sized by its own family. The slot above is a glyph's
638
+ * box: it stated `display: block` on the key, which put the legend on a line
639
+ * box's baseline instead of the key's centre, sixteen pixels square, and the
640
+ * icon's font size, which `size="inherit"` read as the text's. Measured, a
641
+ * `Kbd` legend stood 1.5px above the label's centre and a `Shortcut` 1.5px
642
+ * below it. Here the slot takes the key's measure and the label's type, and
643
+ * the flex container centres the key on the label.
644
+ */
645
+ [data-ui='button'] :is([data-part='start'], [data-part='end']):has(> [data-ui='kbd']) {
646
+ block-size: auto;
647
+ font-size: inherit;
648
+ inline-size: auto;
649
+ }
650
+
636
651
  /**
637
652
  * The label carries a wrapping line height of its own: the control's line
638
653
  * height is 1, which centres a single line inside the box and crushes the
@@ -932,6 +932,8 @@
932
932
  block-size: 100%;
933
933
  border-radius: 0;
934
934
  border: 0;
935
+ box-sizing: border-box;
936
+ padding-block-end: var(--slotted-keyboard-inset, 0px);
935
937
  }
936
938
  }
937
939
 
@@ -961,6 +963,16 @@
961
963
  * layer, which on a phone is a stray line under the browser chrome.
962
964
  */
963
965
  border: 0;
966
+ /**
967
+ * The virtual keyboard. `observeKeyboardInset` in `@slotted/core/measure`
968
+ * measures what the keyboard covers, the binding writes it on the open
969
+ * layer, and the panel's rows end above the keys: a full-screen panel is
970
+ * the layout viewport's height, and the keyboard shrinks only the visual
971
+ * one. Nought under `interactive-widget=resizes-content`, whose layout
972
+ * already shrank.
973
+ */
974
+ box-sizing: border-box;
975
+ padding-block-end: var(--slotted-keyboard-inset, 0px);
964
976
  }
965
977
 
966
978
  /* ── Forced colours ───────────────────────────────────────────────────── */
package/src/kbd/kbd.css CHANGED
@@ -237,6 +237,10 @@
237
237
  align-items: center;
238
238
  direction: ltr;
239
239
  display: inline-flex;
240
+ /* The root is a `kbd`: without these it keeps the user agent's monospace
241
+ face and its line box, which a key in the combination does not share. */
242
+ font-family: var(--slotted-kbd-font-family, var(--slotted-control-font-family, sans-serif));
243
+ line-height: 1;
240
244
  /**
241
245
  * A shortcut wider than its column wraps between caps and never inside
242
246
  * one. The row gets taller; no instruction gets shorter.
package/src/menu/menu.css CHANGED
@@ -290,6 +290,28 @@
290
290
  visibility: hidden;
291
291
  }
292
292
 
293
+ /**
294
+ * The surface as wide as its trigger: an account switcher at the foot of a
295
+ * sidebar, opened from a row the column's full width. The content takes the
296
+ * anchor's width as its size and its floor, as `popover`'s `width="anchor"`
297
+ * does, and the room the positioner reports caps both. The layer drops the
298
+ * family's floor and cap, which would hold it narrower or wider than the
299
+ * row. Opened above or below, the layer has no inline padding, so the
300
+ * content and the trigger share both edges.
301
+ */
302
+ [data-ui='menu'][data-width='anchor'] {
303
+ max-inline-size: var(--slotted-positioner-available-width, 100vw);
304
+ min-inline-size: 0;
305
+ }
306
+ [data-ui='menu'][data-width='anchor'] > [data-part='content'] {
307
+ inline-size: var(--slotted-positioner-anchor-width, auto);
308
+ max-inline-size: var(--slotted-positioner-available-width, 100vw);
309
+ min-inline-size: min(
310
+ var(--slotted-positioner-anchor-width, 0px),
311
+ var(--slotted-positioner-available-width, 100vw)
312
+ );
313
+ }
314
+
293
315
  [data-ui='menu'][data-size='sm'] {
294
316
  --_item-padding: var(--slotted-control-padding-inline-sm, 0.625rem);
295
317
  --_item-height: var(--slotted-control-height-sm, 30px);
@@ -48,6 +48,13 @@
48
48
  * there is to give.
49
49
  */
50
50
  --_standoff: min(var(--slotted-space-2, 0.25rem), var(--_inset));
51
+ /**
52
+ * The inline padding `app-shell`'s navigation parts add for an outward
53
+ * focus ring, read so a row's box keeps the edge it had there: the row
54
+ * reaches back into that padding, and its own ring is drawn inside. Nought
55
+ * outside those parts.
56
+ */
57
+ --_ring-inset: var(--slotted-app-shell-row-ring-inset, 0px);
51
58
  --_gap: var(--slotted-app-shell-row-gap, var(--slotted-control-gap-md, 8px));
52
59
  --_font-size: var(--slotted-app-shell-row-font-size, var(--slotted-font-size-sm, 0.8125rem));
53
60
  --_line-height: var(--slotted-app-shell-row-line-height, var(--slotted-line-height-sm, 1.45));
@@ -354,11 +361,11 @@
354
361
  grid-template-columns: auto minmax(0, 1fr) auto auto;
355
362
  grid-template-rows: auto auto;
356
363
  margin-block: 0;
357
- margin-inline: var(--_standoff);
364
+ margin-inline: calc(var(--_standoff) - var(--_ring-inset));
358
365
  min-block-size: var(--_row-height);
359
366
  min-inline-size: 0;
360
367
  padding-block: 0;
361
- padding-inline: calc(var(--_inset) - var(--_standoff));
368
+ padding-inline: calc(var(--_inset) - var(--_standoff) + var(--_ring-inset));
362
369
  position: relative;
363
370
  text-align: start;
364
371
  text-decoration: none;
@@ -5,6 +5,7 @@
5
5
  "--slotted-app-shell-row-inset",
6
6
  "--slotted-app-shell-row-line-height",
7
7
  "--slotted-app-shell-row-mark",
8
+ "--slotted-app-shell-row-ring-inset",
8
9
  "--slotted-border-subtle",
9
10
  "--slotted-border-width-thin",
10
11
  "--slotted-control-font-family",
package/src/tabs/tabs.css CHANGED
@@ -469,7 +469,11 @@
469
469
  * end padding, so the end inset is nought there. Below the width of a short
470
470
  * label it keeps a minimum length, centred on the content. It stands
471
471
  * `--slotted-tabs-marker-offset` above the list's edge, over the track, and the axes are physical in this one rule
472
- * because the measurement is: the translate is from the list's left edge.
472
+ * because the measurement is: the position is from the list's left edge.
473
+ * Position and length are both layout properties, so one thread advances
474
+ * both edges in the same frame: a composited `translate` beside a
475
+ * main-thread `inline-size` drifted apart while the panel rendered, and the
476
+ * bar grew and shrank on its way between tabs of unequal widths.
473
477
  */
474
478
  [data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'] {
475
479
  --_start-inset: var(--_marker-inset);
@@ -483,13 +487,11 @@
483
487
  border-radius: var(--_marker-radius);
484
488
  inline-size: var(--_length);
485
489
  inset-block-end: calc(var(--_marker-lift, 0px) + var(--_marker-offset));
486
- left: 0;
490
+ left: calc(
491
+ var(--_indicator-start, 0px) + var(--_left-inset) + (var(--_span) - var(--_length)) / 2
492
+ );
487
493
  pointer-events: none;
488
494
  position: absolute;
489
- translate: calc(
490
- var(--_indicator-start, 0px) + var(--_left-inset) + (var(--_span) - var(--_length)) / 2
491
- )
492
- 0;
493
495
  }
494
496
 
495
497
  [data-ui='tabs']:dir(rtl) > :where([data-part='list']) > [data-part='marker'] {
@@ -520,7 +522,8 @@
520
522
  --_marker-easing: var(--slotted-tabs-marker-easing, cubic-bezier(0.4, 0, 0.2, 1));
521
523
 
522
524
  transition:
523
- translate var(--slotted-duration-medium) var(--_marker-easing),
525
+ left var(--slotted-duration-medium) var(--_marker-easing),
526
+ top var(--slotted-duration-medium) var(--_marker-easing),
524
527
  inline-size var(--slotted-duration-medium) var(--_marker-easing),
525
528
  block-size var(--slotted-duration-medium) var(--_marker-easing);
526
529
  }
@@ -590,10 +593,11 @@
590
593
  > [data-part='marker'] {
591
594
  block-size: var(--_length);
592
595
  inline-size: var(--_marker-size);
593
- inset-block: 0 auto;
596
+ inset-block: calc(
597
+ var(--_indicator-start, 0px) + var(--_start-inset) + (var(--_span) - var(--_length)) / 2
598
+ )
599
+ auto;
594
600
  inset-inline: auto calc(var(--_marker-lift, 0px) + var(--_marker-offset));
595
- translate: 0
596
- calc(var(--_indicator-start, 0px) + var(--_start-inset) + (var(--_span) - var(--_length)) / 2);
597
601
  }
598
602
 
599
603
  [data-ui='tabs'][data-orientation='vertical']