@apliteni/apliteni-ui 0.76.0 → 0.77.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.
@@ -56,13 +56,13 @@
56
56
 
57
57
  <!-- rule: disabled-legibility -->
58
58
 
59
- **Rule:** Give a disabled control its own ink and surface pair, and take the accent off it.
59
+ **Rule:** Give a disabled control its own ink, surface and edge, and take the accent off it.
60
60
 
61
61
  **Do:** Unavailable reads as unavailable with the pointer nowhere near it.
62
62
 
63
63
  **Don't:** Unavailable keeps the live paint, so only the cursor reports the state.
64
64
 
65
- **Except:** A disabled label must stay legible, so the pair changes rather than fades. Only the label-free switch track may fade.
65
+ **Except:** A disabled label must stay legible, so the pair changes rather than fades. Only the label-free switch track may fade, and a control that draws no box when it is on — a ghost button — draws none when it is off, so its ink carries the state alone. Where the browser fades a control for you, as Chromium does a disabled select, reset that fade: it takes the edge and the words down together, and the words are what a reader still has to read.
66
66
 
67
67
  ## Touch field text
68
68
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  **Don't:** Give the input a separate muted outline while the button uses `--ring`.
14
14
 
15
- **Except:** Text-entry controls may match `:focus-visible` on mouse focus. Surface backgrounds set the gap colour and recompose `--ring`; adjust width and colour at the root.
15
+ **Except:** A scroll region inside a surface takes `--ring-scroll`: the same 1px gap and 2px band, drawn inward, without the halo. `--ring` is drawn for a 32px control, where the halo is a glint; around a 400px region it spreads 14px past the band and lights the surface instead of the box that scrolls. A box that is itself the outermost surface — a panel, a card — keeps `--ring`. Text-entry controls may match `:focus-visible` on mouse focus. Surface backgrounds set the gap colour and recompose `--ring`; adjust width and colour at the root.
16
16
 
17
17
  ## Busy controls
18
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.76.0",
3
+ "version": "0.77.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
@@ -216,6 +216,10 @@
216
216
  min-height: 0;
217
217
  overflow: auto;
218
218
  }
219
+ .rx-modal__body:focus-visible {
220
+ outline: var(--ring-scroll);
221
+ outline-offset: var(--ring-scroll-offset);
222
+ }
219
223
  .rx-modal__body > * {
220
224
  flex-shrink: 0;
221
225
  }
@@ -22,6 +22,12 @@
22
22
  the rounded corners / clipping its last column. Clipping to the card's
23
23
  border-box also keeps zebra stripes from escaping the radius. */
24
24
  .ui-card:has(> .ui-table) { overflow-x: auto; }
25
+ /* Which makes the card a keyboard stop whenever no cell holds a control, so it
26
+ answered with the native outline. It is a scroll region, so it takes --ring-scroll:
27
+ the band drawn inward, inside the card's 24px padding and clear of the table.
28
+ --elev-rest is left alone: the band is an outline, not a layer of the shadow list.
29
+ why: docs/specification.md#the-focus-ring */
30
+ .ui-card:has(> .ui-table):focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
25
31
 
26
32
  /* Vertical stacks space cards with the container's gap — see .ui-card-stack.
27
33
  (No `.ui-card + .ui-card` margin: it leaks into grid/flex rows and misaligns.) */
@@ -143,6 +143,14 @@
143
143
  overflow-y: auto;
144
144
  padding: var(--space-2);
145
145
  }
146
+ /* Rows are `role="option" tabindex="-1"`, so the LIST takes the keyboard stop. The
147
+ wired palette's Tab trap holds one item and never hands it over; the markup the
148
+ kit publishes as a string, rendered open without the wiring, has no trap and did
149
+ arrive at the native outline. The band is drawn INWARD, on the list: the panel clips
150
+ with `overflow: hidden`, so an outset one is cut off, and the panel is not the box
151
+ that scrolls. The list's own 8px of padding is where it lands.
152
+ why: docs/specification.md#the-focus-ring */
153
+ .ui-cmdk__list:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
146
154
  .ui-cmdk__group + .ui-cmdk__group { margin-top: var(--space-2); }
147
155
 
148
156
  /* Sentence case at 13px medium — the kit's label role, not a heading and not a
@@ -99,16 +99,27 @@
99
99
  color: var(--strong);
100
100
  }
101
101
  .ui-confirm__body {
102
- margin: 0;
103
102
  flex: 1 1 auto;
104
103
  min-height: 0;
105
104
  overflow-y: auto;
105
+ /* The padding is the ring's clearance from the glyphs, as on .ui-table-scroll; the
106
+ negative margin spends it out of the panel's --space-5, not out of the text
107
+ column the three slots share. #531 */
108
+ margin: 0 calc(-1 * var(--space-1));
109
+ padding: var(--space-1);
106
110
  font-family: var(--font-sans);
107
111
  font-size: var(--text-sm);
108
112
  font-weight: var(--weight-normal);
109
113
  line-height: 1.55;
110
114
  color: var(--text);
111
115
  }
116
+ /* A consequence long enough to scroll is a keyboard stop, and answered with the
117
+ native outline. The wired dialog's trap wraps between the two answers, which both
118
+ follow it; the markup the kit publishes as a string, rendered open without the
119
+ wiring, has no trap and makes it the first stop. The band is drawn INWARD, inside
120
+ the --space-1 above, which is what keeps it off the glyphs.
121
+ why: docs/specification.md#the-focus-ring */
122
+ .ui-confirm__body:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
112
123
  .ui-confirm__acts {
113
124
  display: flex;
114
125
  flex: none;
@@ -180,6 +180,12 @@
180
180
  font-size: var(--text-sm);
181
181
  line-height: 1.55;
182
182
  }
183
+ /* A body of prose scrolls, so the browser makes it a keyboard stop and it answered
184
+ with the native outline. The band is drawn INWARD, inside the 20px padding: the body
185
+ is flush with a panel that is itself flush with a screen edge, so an outset ring — on
186
+ either box — is painted off-screen. Measured at 390, where an outset one left no
187
+ indicator at all. why: docs/specification.md#the-focus-ring */
188
+ .ui-drawer__body:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
183
189
 
184
190
  .ui-drawer__footer {
185
191
  display: flex;
@@ -284,6 +284,12 @@
284
284
  .ui-dropdown__search-input:focus-visible { outline: 2px solid transparent; border-color: var(--accent); box-shadow: var(--ring); }
285
285
 
286
286
  .ui-dropdown__list { max-height: 300px; overflow-y: auto; }
287
+ /* Rows are `role="option" tabindex="-1"`, so the LIST takes the keyboard stop and
288
+ answered with the native outline. The band is drawn INWARD, on the list: an outset
289
+ one 6px inside a --radius-lg corner leaves the panel, and the panel is not the box
290
+ that scrolls. It lands in the rows' own 9px of padding, never on a label.
291
+ why: docs/specification.md#the-focus-ring */
292
+ .ui-dropdown__list:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
287
293
  /* A row is `display: flex`, which outranks the UA's [hidden], so a row the
288
294
  query hides is put away here. */
289
295
  .ui-dropdown__list [hidden] { display: none; } /* motion: still — a row the query no longer matches is gone on the next keystroke */
@@ -55,6 +55,9 @@
55
55
  UA's grey-out, so a disabled one had looked exactly like a live one.
56
56
  `background-color`, not `background` — the shorthand also resets the three
57
57
  longhands the chevron is drawn with (#511). Held by stories/select-chevron.test.js.
58
+ `opacity` is the other half of that grey-out, and no colour here outranks it, so
59
+ the fade is reset below — it took the edge and the words down together. #564,
60
+ argued at docs/specification.md#colour-and-contrast.
58
61
  why: docs/specification.md#icons-and-glyphs */
59
62
  .ui-input:disabled,
60
63
  .ui-select:disabled,
@@ -62,6 +65,7 @@
62
65
  background-color: var(--disabled-surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
63
66
  border-color: var(--disabled-border);
64
67
  /* muted-ink: state — unavailable control */ color: var(--disabled-ink);
68
+ opacity: 1; /* fade-reset: the UA's select:disabled grey-out. #564 */
65
69
  cursor: not-allowed;
66
70
  }
67
71
 
@@ -188,7 +188,13 @@
188
188
  .ui-table--compact th:last-child,
189
189
  .ui-table--compact td:last-child { padding-right: var(--space-3); }
190
190
  .ui-table-scroll { overflow: auto; max-height: var(--ui-table-height, 70vh); padding: 0 var(--space-1); }
191
- .ui-table-scroll:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); }
191
+ /* The kit's first ringed scroller, and a scroll region inside a card like the rest, so
192
+ it draws the band inward too rather than spending a halo across the card around it.
193
+ It had no room of its own to draw in — the padding above is horizontal — which is the
194
+ second reason the band is an outline: it is painted over the rows, in the cell padding
195
+ of the first and last, rather than under them. #531
196
+ why: docs/specification.md#the-focus-ring */
197
+ .ui-table-scroll:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
192
198
  .ui-table--sticky { border-collapse: separate; border-spacing: 0; }
193
199
  .ui-table--sticky thead th { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--table-bg); --ring-gap: var(--table-bg); padding-top: var(--space-2); }
194
200
  .ui-table--pinned .ui-table__identity, .ui-table--pinned .ui-table__selection { position: sticky; left: 0; z-index: var(--z-base); background: var(--table-bg); --ring-gap: var(--table-bg); border-right: 1px solid var(--border); }
@@ -194,7 +194,11 @@
194
194
  why: docs/specification.md#colour-and-contrast */
195
195
  --disabled-ink: var(--muted);
196
196
  --disabled-surface: var(--surface);
197
- --disabled-border: var(--border);
197
+ /* One rung below the hairline, so an off box is not the live box with quieter words
198
+ in it: dark answered both with --border. 1.16:1 on the card against the live
199
+ 1.27:1, and as far down as the headroom goes. #564
200
+ why: docs/specification.md#colour-and-contrast */
201
+ --disabled-border: var(--surface-3);
198
202
  /* The ink of a disabled control that paints no box of its own — a ghost button. With
199
203
  no surface beside it, it is read on whatever is behind it, so it is set to clear the
200
204
  floor on the dullest ground there is (--surface-3). #273
@@ -265,6 +269,13 @@
265
269
  --ring-gap-width: 1px;
266
270
  --ring-gap: var(--bg);
267
271
  --ring: 0 0 0 var(--ring-gap-width) var(--ring-gap), 0 0 0 calc(var(--ring-gap-width) + var(--ring-width)) var(--ring-color), 0 0 12px 2px color-mix(in srgb, var(--ring-color) 45%, transparent);
272
+ /* What a scroll region inside a surface takes: --ring's gap and band, drawn inward,
273
+ no halo. An OUTLINE, because an inset shadow is painted under the box's own
274
+ children and a table scrolled under one erases it. The gap is left unpainted, so
275
+ neither half reads --ring-gap and neither is recomposed per surface. Chosen by
276
+ Artur on #531 round r30. why: docs/specification.md#the-focus-ring */
277
+ --ring-scroll: var(--ring-width) solid var(--ring-color);
278
+ --ring-scroll-offset: calc(-1 * (var(--ring-gap-width) + var(--ring-width)));
268
279
 
269
280
  /* The ink a cast shadow is made of, and the specular white that reads as gloss on a
270
281
  raised surface. Effects mix these instead of writing rgba(). */
@@ -371,6 +382,8 @@
371
382
  /* Disabled text stays on the card surface; its ink marks the unavailable state. */
372
383
  --disabled-ink: var(--muted);
373
384
  --disabled-surface: var(--surface);
385
+ /* The hairline, where dark takes the rung under it: light's field edge is already
386
+ --border-strong, so the two states read 1.52:1 and 1.24:1. #564 */
374
387
  --disabled-border: var(--border);
375
388
  --disabled-ink-bare: #585e6c;
376
389
 
@@ -563,7 +576,9 @@
563
576
  .ui-success { --code-bg: var(--wash-code-bg); }
564
577
 
565
578
  /* A container focused itself paints outside its own surface; descendants only
566
- * inherit its inside gap again after focus moves to them. */
579
+ * inherit its inside gap again after focus moves to them. A scroll region inside one
580
+ * needs no entry here: --ring-scroll paints no gap of its own, so the 1px it leaves is
581
+ * whatever the region is already standing on. #531 */
567
582
  .ui-card:focus-visible,
568
583
  .ui-cmdk__panel:focus-visible,
569
584
  .ui-confirm__panel:focus-visible,