@apliteni/apliteni-ui 0.88.0 → 0.90.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.
Files changed (2) hide show
  1. package/package.json +2 -1
  2. package/src/styles/nav.css +58 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.88.0",
3
+ "version": "0.90.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
@@ -57,6 +57,7 @@
57
57
  "build": "npm run build --workspace react",
58
58
  "prepare": "npm run build",
59
59
  "test": "for d in src stories site scripts; do [ -d \"$d\" ] || { echo \"npm test: no such directory: $d\" >&2; exit 1; }; done; node --test --test-reporter=spec --test-reporter-destination=stdout --test-reporter=./scripts/slow-tests.mjs --test-reporter-destination=stdout 'src/**/*.test.js' 'stories/**/*.test.js' 'site/**/*.test.js' 'scripts/**/*.test.js'",
60
+ "check:words": "node scripts/word-budget.mjs",
60
61
  "tokens:sync": "node scripts/sync-brand-tokens.mjs",
61
62
  "tokens:check": "node scripts/sync-brand-tokens.mjs --check",
62
63
  "tokens:drift": "node scripts/brand-drift.mjs"
@@ -12,11 +12,11 @@
12
12
  /* The rail's two widths, and the one place they are written. --ui-nav-col is the
13
13
  open column. --ui-nav-strip is twice a row's own glyph centre — the row's
14
14
  padding plus half a glyph — so a strip that wide has the glyph standing in the
15
- middle of it, exactly where it stood in the open rail. That is what lets the
16
- fold animate: the column keeps --ui-nav-col and is clipped to the strip, so
17
- the width travels and nothing inside it is laid out again. layout.css adds the
18
- shell rail's own inset to both. stories/apps/shell-states.test.js derives the
19
- strip from the resolved cascade and refuses a number that has drifted from it.
15
+ middle of it, exactly where it stood in the open rail. The fold travels that
16
+ width on the rail and on the boxes inside it, so a folded rail is only as wide
17
+ as it draws and has nothing to clip. layout.css adds the shell rail's own
18
+ inset to both. stories/apps/shell-states.test.js derives the strip from the
19
+ resolved cascade and refuses a number that has drifted from it.
20
20
  Declared for the shell as well as the nav, because the shell's rail is this
21
21
  nav with an inset around it, and two copies of 41 is the drift itself. */
22
22
  .ui-nav--side,
@@ -31,14 +31,20 @@
31
31
  been a second scroll box cutting the rows off at the rail's height. */
32
32
  transition: width var(--dur-med) var(--ease);
33
33
  }
34
- /* Every block keeps the open column while the nav clips to the strip. Without
35
- this each one stretches to whatever the nav is wide and every row inside it is
36
- laid out again on each frame of the fold. */
37
- .ui-nav--side > * { width: var(--ui-nav-col); flex: none; }
34
+ /* A block takes a width of its own rather than the rail's travelling one, and travels
35
+ it on the RAIL's clock. Declared here, not beside the fold, so the way OUT carries it:
36
+ a block with no clock snapped open while the rail was still a strip wide. */
37
+ .ui-nav--side > * {
38
+ width: var(--ui-nav-col); flex: none;
39
+ transition: width var(--dur-med) var(--ease);
40
+ }
38
41
  .ui-nav__section + .ui-nav__section { margin-top: 14px; }
39
42
  .ui-nav__list { display: flex; flex-direction: column; gap: 2px; }
40
43
  .ui-nav__cap {
41
44
  /* rank: label */
45
+ /* Words, never a control, at BOTH widths — as __label, __badge and __caret below.
46
+ why: docs/specification.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
47
+ pointer-events: none;
42
48
  font-size: var(--text-sm);
43
49
  font-weight: var(--weight-medium);
44
50
  color: var(--text);
@@ -101,6 +107,7 @@
101
107
  .ui-nav__item.is-current .ui-nav__ic svg { opacity: 1; stroke: currentColor; } /* motion: still — the glyph brightens with its row, whose own highlight already transitions */
102
108
  .ui-nav__label {
103
109
  flex: 1 1 auto; min-width: 0;
110
+ pointer-events: none; /* words, not a control — see .ui-nav__cap */
104
111
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
105
112
  /* The words go before the closing edge reaches them, which is most of why the
106
113
  fold is worth animating — a label cut through by that edge reads as the rail
@@ -129,6 +136,7 @@
129
136
  /* Per-item badge / counter */
130
137
  .ui-nav__badge {
131
138
  flex: none;
139
+ pointer-events: none; /* a count, not a control — see .ui-nav__cap */
132
140
  min-width: 20px;
133
141
  height: 19px;
134
142
  padding: 0 6px;
@@ -163,6 +171,7 @@
163
171
  .ui-nav__group { display: flex; flex-direction: column; }
164
172
  .ui-nav__caret {
165
173
  flex: none;
174
+ pointer-events: none; /* a mark on the toggle, not a control — see .ui-nav__cap */
166
175
  width: 7px; height: 7px;
167
176
  border-right: 1.6px solid var(--muted);
168
177
  border-bottom: 1.6px solid var(--muted);
@@ -223,53 +232,52 @@
223
232
  border-inline-start-width var(--dur-med) var(--ease);
224
233
  }
225
234
 
226
- /* Collapsed (icon-only) rail — the same fold the shell's rail makes, drawn once
227
- rather than pressed: the column keeps its width and the nav clips to the
228
- strip, so no row is laid out again and no glyph moves. A group's children stay
229
- rows here, because wireNav() toggles the list's `hidden` attribute and nothing
230
- else, so folding .ui-nav__sub away left the toggle announcing a list it could
231
- not open. What goes is the indent and the words, and sidebarNav({ collapsed })
232
- hands each row its name as a `title` so a pointer can still read it. The
233
- shell's rail draws a chip of its own instead, on keyboard focus as well — see
234
- layout.css. */
235
- .ui-nav--side.is-collapsed {
236
- width: var(--ui-nav-strip);
237
- /* clip, not hidden: a standalone rail has nothing around it to clip for it,
238
- and `hidden` would make this a scroll box in both axes and cut the rows off
239
- at whatever height it was given. `clip` across leaves `visible` down alone,
240
- which is the one pair that does. */
241
- overflow-x: clip;
242
- overflow-y: visible;
235
+ /* Collapsed (icon-only) rail — the same fold the shell's rail makes. A group's
236
+ children stay rows here, because wireNav() toggles the list's `hidden` attribute
237
+ and nothing else, so folding .ui-nav__sub away left the toggle announcing a list it
238
+ could not open. What goes is the indent and the words, and sidebarNav({ collapsed })
239
+ hands each row its name as a `title` so a pointer can still read it. The shell's
240
+ rail draws a chip of its own instead, on keyboard focus as well — see layout.css. */
241
+ .ui-nav--side.is-collapsed { width: var(--ui-nav-strip); }
242
+ /* Every box in the rail closes with it, whether it paints or not. A block that keeps
243
+ the open column paints nothing and still takes the pointer off 175px of the page
244
+ beside a positioned rail (#588); clipping it instead cut the rows' ring (#575).
245
+ why: docs/specification.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
246
+ .ui-nav--side.is-collapsed > * { width: var(--ui-nav-strip); }
247
+ .ui-nav--side.is-collapsed .ui-nav__item { width: var(--ui-nav-strip); }
248
+ /* The heading is the one box that keeps the open column: its line breaks are the rail's
249
+ height. Inert at both widths, so the column draws and takes nothing; the 175px it adds
250
+ to a page's scrollable width is the one thing this rail does not promise. */
251
+ .ui-nav--side.is-collapsed .ui-nav__cap { width: var(--ui-nav-col); }
252
+ /* The row takes the rail's clock too, so its box IS the rail's box in every frame and
253
+ not only at either end. Waiting out the words on a --dur-fast delay left the open
254
+ column's hit area inside a half-shut rail. (Restates the base it replaces.) */
255
+ .ui-nav--side.is-collapsed .ui-nav__item {
256
+ transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
257
+ width var(--dur-med) var(--ease);
243
258
  }
259
+ /* What that delay was protecting, kept without it: the words hold their own width
260
+ instead of being squeezed out by the closing row. They overflow it and cost nothing —
261
+ inert at either width, and painting nothing at opacity 0. */
262
+ .ui-nav--side.is-collapsed .ui-nav__label { min-width: max-content; }
244
263
  .ui-nav--side.is-collapsed .ui-nav__cap,
245
264
  .ui-nav--side.is-collapsed .ui-nav__label,
246
265
  .ui-nav--side.is-collapsed .ui-nav__badge,
247
- .ui-nav--side.is-collapsed .ui-nav__caret { opacity: 0; pointer-events: none; }
266
+ .ui-nav--side.is-collapsed .ui-nav__caret { opacity: 0; }
248
267
  .ui-nav--side.is-collapsed .ui-nav__sub {
249
268
  margin-inline-start: 0; padding-inline-start: 0; border-inline-start-width: 0;
250
269
  }
251
270
  .ui-nav--side.is-collapsed .ui-nav__item:not(:has(.ui-nav__ic))::after { opacity: 0.62; }
252
271
 
253
- /* The current row on a folded rail: ONE plate on the glyph column, and nothing
254
- else. The open rail's marker is a 3px bar standing in the row's own left
255
- padding; on the strip that padding is the rail's edge, so the bar reads as a
256
- tick on the rail rather than a mark on a row — and a nested row puts it
257
- --space-3 further out again, outside the rail altogether. The hairline cannot
258
- close either: a row keeps the open column and the rail clips it, so its right
259
- edge is drawn off the strip.
260
-
261
- The plate is the strip. --ui-nav-strip is twice a row's own glyph centre, so a
262
- box that wide standing at the row's edge is centred on the glyph, and the mark
263
- lands where the reader is already looking. --surface-3 is the kit's quiet
264
- non-text fill — a step off the rail in both themes, carrying a glyph and never
265
- a word. The references mark current the same way and with no hue at all:
266
- Cloudflare's docs rail paints a flat plate, and lessly-ui's rail is "a plate and
267
- the weight step, no hue". Here the glyph's own step from 0.66 to full ink is the
268
- second half of that pair. See #429.
269
-
270
- `isolation` is what puts the plate behind the glyph: a positioned ::before paints
271
- over its row's content, and a negative z-index with no stacking context of its
272
- own would drop it behind the rail instead. */
272
+ /* The current row on a folded rail: one plate on the glyph column, and nothing else.
273
+ The open rail's 3px marker would stand in the rail's edge at this width, and a
274
+ nested row would put it outside the rail; the hairline would be the same mark said
275
+ twice. The plate is the strip, so it is centred on the glyph, and --surface-3 is the
276
+ kit's quiet non-text fill — a step off the rail in both themes. The glyph's own step
277
+ from 0.66 to full ink is the second half of that pair. `isolation` is what puts the
278
+ plate behind the glyph: a positioned ::before paints over its row's content, and a
279
+ negative z-index with no stacking context of its own would drop it behind the rail.
280
+ why: #429 */
273
281
  .ui-nav--side.is-collapsed .ui-nav__item.is-active { isolation: isolate; background: none; }
274
282
  /* At rest only — box-shadow carries the hairline AND the focus ring (WCAG 2.4.7). */
275
283
  .ui-nav--side.is-collapsed .ui-nav__item.is-active:not(:focus-visible) { box-shadow: none; }
@@ -281,10 +289,9 @@
281
289
  background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
282
290
  z-index: -1;
283
291
  }
284
- /* Hover's hairline is an outline on a row that keeps the open column, so on the
285
- strip it too is drawn with no right edge. A folded rail answers a pointer with
286
- the row's own ink and the name beside it, which is the whole readout at this
287
- width. At rest only, so the focus ring is left standing. */
292
+ /* A folded rail answers a pointer with the row's own ink and the name beside it,
293
+ which is the whole readout at this width — the hover wash stands, the edge
294
+ around it does not. At rest only, so the focus ring is left standing. */
288
295
  .ui-nav--side.is-collapsed .ui-nav__item:hover:not(:focus-visible) { outline: none; }
289
296
 
290
297
  /* -- Horizontal tabs ----------------------------------------------------- */