@apliteni/apliteni-ui 0.26.0 → 0.30.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 (48) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/react/README.md +111 -2
  4. package/react/dist/index.css +11 -13
  5. package/react/dist/index.d.ts +111 -4
  6. package/react/dist/index.js +811 -167
  7. package/src/components/back.js +57 -0
  8. package/src/components/command-palette.js +597 -0
  9. package/src/components/confirm.js +3 -2
  10. package/src/components/drawer.js +31 -2
  11. package/src/components/dropdown.js +192 -17
  12. package/src/components/feedback.js +2 -2
  13. package/src/components/index.js +5 -2
  14. package/src/components/loading.js +3 -2
  15. package/src/components/nav.js +15 -7
  16. package/src/components/overlay.js +67 -14
  17. package/src/components/pagination.js +344 -0
  18. package/src/components/shell.js +11 -2
  19. package/src/components/tabs.js +7 -1
  20. package/src/components/tooltip.js +237 -0
  21. package/src/components/topbar.js +9 -4
  22. package/src/index.css +4 -0
  23. package/src/index.js +4 -0
  24. package/src/inline.js +8 -0
  25. package/src/motion.js +43 -2
  26. package/src/styles/back.css +42 -0
  27. package/src/styles/badge.css +5 -7
  28. package/src/styles/base.css +8 -7
  29. package/src/styles/button.css +14 -0
  30. package/src/styles/card.css +12 -8
  31. package/src/styles/code.css +3 -4
  32. package/src/styles/command-palette.css +321 -0
  33. package/src/styles/confirm.css +11 -11
  34. package/src/styles/drawer.css +57 -15
  35. package/src/styles/dropdown.css +70 -11
  36. package/src/styles/feedback.css +2 -0
  37. package/src/styles/footer.css +3 -4
  38. package/src/styles/input.css +7 -1
  39. package/src/styles/layout.css +3 -2
  40. package/src/styles/loading.css +5 -0
  41. package/src/styles/nav.css +12 -8
  42. package/src/styles/pagination.css +124 -0
  43. package/src/styles/success.css +3 -2
  44. package/src/styles/table.css +4 -5
  45. package/src/styles/tabs.css +3 -0
  46. package/src/styles/tooltip.css +65 -0
  47. package/src/styles/topbar.css +3 -4
  48. package/src/tokens/tokens.css +14 -8
@@ -18,10 +18,9 @@
18
18
  .ui-nav__section + .ui-nav__section { margin-top: 14px; }
19
19
  .ui-nav__list { display: flex; flex-direction: column; gap: 2px; }
20
20
  .ui-nav__cap {
21
- font-size: 11px;
22
- font-weight: 600;
23
- letter-spacing: 0.16em;
24
- text-transform: uppercase;
21
+ /* rank: label */
22
+ font-size: var(--text-sm);
23
+ font-weight: var(--weight-medium);
25
24
  color: var(--muted);
26
25
  padding: 4px 12px 8px;
27
26
  }
@@ -64,7 +63,7 @@
64
63
  width: 3px; height: 17px;
65
64
  border-radius: 3px;
66
65
  background: var(--accent);
67
- transform: translateY(-50%);
66
+ transform: translateY(-50%); /* motion: still — a mark on the current row, whose own highlight already transitions; this centres it, it does not travel */
68
67
  }
69
68
  .ui-nav__item:focus-visible { outline: none; box-shadow: var(--ring); }
70
69
  .ui-nav__item.is-active:focus-visible { box-shadow: var(--ring); }
@@ -72,7 +71,7 @@
72
71
  .ui-nav__ic { display: inline-flex; flex: none; }
73
72
  .ui-nav__ic svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2.2; opacity: 0.72; }
74
73
  .ui-nav__item.is-active .ui-nav__ic svg,
75
- .ui-nav__item.is-current .ui-nav__ic svg { opacity: 1; stroke: var(--accent); }
74
+ .ui-nav__item.is-current .ui-nav__ic svg { opacity: 1; stroke: var(--accent); } /* motion: still — the glyph brightens with its row, whose own highlight already transitions */
76
75
  .ui-nav__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
77
76
 
78
77
  /* Destructive row (sign out, revoke). Quiet at rest, --pink once a pointer or
@@ -148,6 +147,12 @@
148
147
  border-left: 1px solid var(--border);
149
148
  }
150
149
  .ui-nav__sub[hidden] { display: none; }
150
+ /* An opened group's list fades in and drops --space-1 into place. wireNav() adds
151
+ the class when the reader opens it, never at first render. */
152
+ .ui-nav__sub.is-entering {
153
+ --m-dist: var(--space-1);
154
+ animation: m-slide-down var(--dur-fast) var(--ease-out) both;
155
+ }
151
156
  .ui-nav__item--sub { font-size: 14px; padding: 7px 12px; }
152
157
  /* No hairline on a nested current row — but only at rest. box-shadow carries
153
158
  both the hairline and the focus ring, so a rule about the resting look must
@@ -164,8 +169,7 @@
164
169
  .ui-nav--side.is-collapsed .ui-nav__cap,
165
170
  .ui-nav--side.is-collapsed .ui-nav__label,
166
171
  .ui-nav--side.is-collapsed .ui-nav__badge,
167
- .ui-nav--side.is-collapsed .ui-nav__caret,
168
- .ui-nav--side.is-collapsed .ui-nav__sub { display: none; }
172
+ .ui-nav--side.is-collapsed .ui-nav__caret { display: none; } /* motion: still — folding the rail is a layout change of the whole rail; animating these would reflow the page */
169
173
  .ui-nav--side.is-collapsed .ui-nav__item { justify-content: center; padding: 11px 0; gap: 0; }
170
174
  .ui-nav--side.is-collapsed .ui-nav__ic svg { width: 19px; height: 19px; stroke-width: 2; }
171
175
  .ui-nav--side.is-collapsed .ui-nav__item.is-active::before { left: 3px; }
@@ -0,0 +1,124 @@
1
+ /* ============================================================================
2
+ * Pagination — .ui-pager (variants: --steps / --numbered / --jump)
3
+ * --open total unknown: Prev and Next only, no last page to reach
4
+ * --single one page of content: the size control alone, no steps
5
+ * The controls are .ui-btn ghost/sm and the size control is a .ui-select, so
6
+ * everything here is layout and the two states those sheets do not own.
7
+ * ========================================================================== */
8
+
9
+ .ui-pager {
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ align-items: center;
13
+ gap: var(--space-3) var(--space-4);
14
+ font-size: var(--text-sm);
15
+ }
16
+
17
+ /* The status is the only thing anchored to the start of the strip: it is read,
18
+ not aimed at, and pushing the controls to the far end keeps the pointer's
19
+ target group in one place as the row count changes width. */
20
+ .ui-pager__status {
21
+ margin: 0 auto 0 0;
22
+ color: var(--muted);
23
+ font-variant-numeric: tabular-nums;
24
+ }
25
+
26
+ .ui-pager__size {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: var(--space-2);
30
+ }
31
+ .ui-pager__size-label { color: var(--muted); }
32
+
33
+ /* .ui-select is a form field sized for a form — full width, 12px/15px padding.
34
+ In a pager it sits in a row of sm buttons, so it takes their scale. Two things
35
+ travel with that: the chevron .ui-select paints is positioned from the right
36
+ edge, so the padding on that side has to stay clear of it, and the height is
37
+ declared so this control and the jump input beside it agree on one box. */
38
+ .ui-pager__size-select {
39
+ width: auto;
40
+ min-height: var(--space-8);
41
+ padding: var(--space-1) var(--space-6) var(--space-1) var(--space-2);
42
+ font-size: var(--text-sm);
43
+ border-radius: var(--radius-sm);
44
+ background-position: right var(--space-2) center;
45
+ }
46
+
47
+ .ui-pager__steps {
48
+ display: flex;
49
+ flex-wrap: wrap;
50
+ align-items: center;
51
+ gap: var(--space-1);
52
+ }
53
+
54
+ /* Page numbers are read as a row of equal cells, and .ui-btn--sm's padding makes
55
+ "1" narrower than "49" — so a strip re-flows under the pointer as the reader
56
+ walks into three-digit pages. The number is WCAG 2.5.8's 24px: an equalised
57
+ cell should not be narrower than a target is allowed to be. */
58
+ .ui-pager__page {
59
+ min-width: var(--space-6);
60
+ font-variant-numeric: tabular-nums;
61
+ }
62
+
63
+ /* The page you are on. Guarded, because this weighs the same as `.ui-btn:disabled`
64
+ and is imported after it: written plainly it would repaint the current page of
65
+ a `loading` pager as though it were live, which is the one thing the busy state
66
+ must not leave behind. Spelled `[disabled]` rather than `:disabled` — the same
67
+ selector for the markup this component emits, and the spelling that keeps a
68
+ rule about an ENABLED control out of the disabled-rule sweep in
69
+ stories/guidelines/accessibility-floor.test.js, which reads selector text. */
70
+ .ui-pager__page.is-current:not([disabled]) {
71
+ background: var(--surface-3);
72
+ border-color: var(--border);
73
+ color: var(--strong);
74
+ font-weight: var(--weight-semibold);
75
+ }
76
+
77
+ .ui-pager__gap {
78
+ padding: 0 var(--space-1);
79
+ color: var(--muted);
80
+ }
81
+
82
+ .ui-pager__jump {
83
+ display: inline-flex;
84
+ align-items: center;
85
+ gap: var(--space-2);
86
+ color: var(--muted);
87
+ padding: 0 var(--space-1);
88
+ }
89
+ /* Wide enough for four digits and the spinner a number input draws beside them;
90
+ in ch so it follows the type rather than a measured pixel. The height is
91
+ declared rather than left to the line box, because an <input> holds its value
92
+ in a property: it is the one control in the strip with no text of its own, and
93
+ nothing else gives it the 24px WCAG 2.5.8 asks of a pointer target. */
94
+ .ui-pager__jump-input {
95
+ width: 8ch;
96
+ min-height: var(--space-8);
97
+ padding: var(--space-1) var(--space-2);
98
+ font-size: var(--text-sm);
99
+ border-radius: var(--radius-sm);
100
+ text-align: center;
101
+ }
102
+
103
+ /* A pager directly after a table stands off it. The strip owns no margin of its
104
+ own — it is dropped under lists and cards too, and a component that carries
105
+ spacing everywhere is one every caller has to cancel somewhere — so the gap is
106
+ declared on the one adjacency the kit can see. `.rx-pager` carried a bare
107
+ `margin-top: 16px` for this, which is --space-4; the number moves to the scale
108
+ with it rather than travelling as a literal.
109
+ why: docs/specification.md#spacing-and-rhythm */
110
+ .ui-table + .ui-pager { margin-top: var(--space-4); }
111
+
112
+ /* A step given an `href` is an anchor, and a host stylesheet's `a:link` is
113
+ (0,1,1) — which outranks `.ui-btn--ghost` at (0,1,0) and paints the enabled
114
+ steps in the host's link colour while the disabled ends keep --disabled-ink-bare.
115
+ One strip, reading as two different controls. The kit has paid for this twice
116
+ already and both fixes are the same shape: see the (0,2,0) note on
117
+ `.ui-nav .ui-nav__item` in nav.css. Storybook ships no `a:link`, so the "Pages
118
+ as links" story cannot show it — which is why the rule is stated rather than
119
+ discovered.
120
+ why: docs/specification.md#pagination */
121
+ a.ui-pager__step,
122
+ a.ui-pager__page { color: var(--dim); }
123
+ a.ui-pager__step:hover,
124
+ a.ui-pager__page:hover { color: var(--strong); }
@@ -55,8 +55,9 @@
55
55
  .ui-sx__inner { position: relative; z-index: 1; }
56
56
  .ui-sx__content { min-width: 0; }
57
57
  .ui-sx__eyebrow {
58
- color: var(--green); font-size: 12px; font-weight: var(--weight-semibold);
59
- letter-spacing: .08em; text-transform: uppercase; margin-bottom: 10px;
58
+ /* rank: label */
59
+ color: var(--green); font-size: var(--text-sm); font-weight: var(--weight-medium);
60
+ margin-bottom: 10px;
60
61
  }
61
62
  .ui-sx__title {
62
63
  color: var(--strong); font-size: 22px; font-weight: var(--weight-semibold);
@@ -1,5 +1,5 @@
1
1
  /* ============================================================================
2
- * Table — .ui-table (borderless-body, hairline rows, uppercase head)
2
+ * Table — .ui-table (borderless-body, hairline rows, muted head)
3
3
  * Row modifiers: .is-dead (revoked/struck), right-aligned .ui-table__act
4
4
  * ========================================================================== */
5
5
 
@@ -10,11 +10,10 @@
10
10
  }
11
11
  .ui-table th {
12
12
  text-align: left;
13
- font-size: var(--text-xs);
14
- letter-spacing: 0.09em;
15
- text-transform: uppercase;
13
+ /* rank: label */
14
+ font-size: var(--text-sm);
15
+ font-weight: var(--weight-medium);
16
16
  color: var(--muted);
17
- font-weight: var(--weight-semibold);
18
17
  padding: 0 var(--space-4) var(--space-3) 0;
19
18
  border-bottom: 1px solid var(--border);
20
19
  }
@@ -26,6 +26,9 @@
26
26
 
27
27
  .ui-tabs__panels { padding-top: 20px; }
28
28
  .ui-tabs__panel[hidden] { display: none; }
29
+ /* The panel the reader switches to fades in, without travel. initTabs() adds the
30
+ class on a switch and never at first render; playEntrance() takes it off. */
31
+ .ui-tabs__panel.is-entering { animation: m-fade var(--dur-fast) var(--ease-out) both; }
29
32
  /* The panel is focusable (tabindex="0", see tabs.js) so a keyboard user can
30
33
  reach text-only content. Show the ring when they land on it. */
31
34
  .ui-tabs__panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 8px; }
@@ -0,0 +1,65 @@
1
+ /* ============================================================================
2
+ * Tooltip — .ui-tip, the readout that shows a value while a pointer rests on
3
+ * the mark holding it: a bar, a point on a sparkline, a cell in a heatmap.
4
+ * .ui-tip-host the box the readout is placed against
5
+ * .ui-tip the readout — __label, __value, __detail
6
+ * The readout is an overlay in every state. It is absolutely placed inside its
7
+ * host, so showing it, filling it and moving it change the size of nothing.
8
+ * why: docs/specification.md#the-hover-readout
9
+ * ========================================================================== */
10
+
11
+ .ui-tip-host { position: relative; }
12
+
13
+ .ui-tip {
14
+ /* One number for the mark-to-readout distance, read by both placements here
15
+ and by the wiring's flip test, so above and below cannot drift apart. */
16
+ --ui-tip-gap: 8px;
17
+ --ui-tip-bg: var(--surface-3);
18
+ position: absolute;
19
+ top: var(--ui-tip-y, 0px);
20
+ left: var(--ui-tip-x, 50%);
21
+ z-index: var(--z-dropdown);
22
+ translate: calc(-50% + var(--ui-tip-shift, 0px)) calc(-100% - var(--ui-tip-gap));
23
+ display: flex;
24
+ flex-direction: column;
25
+ width: max-content;
26
+ max-width: var(--prose-caption);
27
+ padding: var(--space-2) var(--space-3);
28
+ background: var(--ui-tip-bg);
29
+ border: 1px solid var(--border);
30
+ border-radius: var(--radius-sm);
31
+ box-shadow: var(--shadow-md);
32
+ font-family: var(--font-sans);
33
+ font-size: var(--text-xs);
34
+ line-height: 1.45;
35
+ color: var(--text);
36
+ /* The readout covers the marks beside the one it describes. Were it a hover
37
+ target it would take the pointer, uncover the mark, lose the pointer and
38
+ return — a flicker at pointer speed. */
39
+ pointer-events: none;
40
+ opacity: 0;
41
+ visibility: hidden;
42
+ transition:
43
+ opacity var(--dur-fast) var(--ease),
44
+ /* `linear`: visibility is discrete, the rule the dropdown panel states. */
45
+ visibility var(--dur-fast) linear;
46
+ }
47
+
48
+ /* Light is an all-white app, so the raised surface is white over a hairline,
49
+ the way a light card is. */
50
+ :root[data-theme="light"] .ui-tip { --ui-tip-bg: var(--surface); }
51
+
52
+ /* Below the mark: the wiring's flip when above would be clipped, or the
53
+ author's own choice. */
54
+ .ui-tip.is-below { translate: calc(-50% + var(--ui-tip-shift, 0px)) var(--ui-tip-gap); }
55
+
56
+ .ui-tip.is-open { opacity: 1; visibility: visible; }
57
+
58
+ .ui-tip__label { color: var(--muted); }
59
+ .ui-tip__value {
60
+ font-size: var(--text-sm);
61
+ font-weight: var(--weight-semibold);
62
+ color: var(--strong);
63
+ font-variant-numeric: tabular-nums;
64
+ }
65
+ .ui-tip__detail { color: var(--dim); font-variant-numeric: tabular-nums; }
@@ -164,10 +164,9 @@
164
164
  .vopt .vname { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
165
165
  .vopt .vmeta { font-size: 11px; color: var(--muted); margin-top: 2px; }
166
166
  .vopt .vbadge {
167
- font-size: 9.5px;
168
- letter-spacing: 0.12em;
169
- text-transform: uppercase;
170
- font-weight: 700;
167
+ /* rank: chip */
168
+ font-size: var(--text-xs);
169
+ font-weight: var(--weight-semibold);
171
170
  padding: 2px 7px;
172
171
  border-radius: 999px;
173
172
  margin-left: auto;
@@ -78,7 +78,7 @@
78
78
  --tracking-tight: -0.01em;
79
79
  --tracking-normal: 0;
80
80
  --tracking-wide: 0.04em;
81
- --tracking-caps: 0.14em;
81
+ --tracking-caps: 0.14em; /* nothing in the kit reads it since #268; consumer rules still may */
82
82
 
83
83
  /* -- Motion -------------------------------------------------------------
84
84
  * The kit's legacy --dur-* and --ease names alias onto the brand's
@@ -158,6 +158,11 @@
158
158
  --disabled-ink: var(--muted);
159
159
  --disabled-surface: var(--surface-2);
160
160
  --disabled-border: var(--border);
161
+ /* The ink of a disabled control that paints no box of its own — a ghost button. With
162
+ no surface beside it, it is read on whatever is behind it, so it is set to clear the
163
+ floor on the dullest ground there is (--surface-3). #273
164
+ why: docs/specification.md#colour-and-contrast */
165
+ --disabled-ink-bare: #a39eb7;
161
166
 
162
167
  /* Lifted from #9b5dff, which cleared the flat surfaces and failed on its own wash over
163
168
  a card; the value was already in the ramp. --ring is var(--accent) and follows by
@@ -208,8 +213,8 @@
208
213
  --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.5);
209
214
  /* Tight elevation for the active segmented pill — stays contained in its track. */
210
215
  --shadow-seg: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 4px rgba(0, 0, 0, 0.3);
211
- /* Resting elevation for a card. Dark cards are borderless the surface groups on
212
- its own so they cast nothing. */
216
+ /* A card's resting elevation. Nothing in the kit reads it since #284 made .ui-card
217
+ flat; it stays because it is published and a consumer may. Dark casts nothing. */
213
218
  --shadow-card: none;
214
219
  /* THE ONLY --ring in the kit — light and every data-accent sub-theme declare an
215
220
  --accent and inherit this line. Opaque because a translucent ring is a glow, and the
@@ -250,7 +255,7 @@
250
255
  --amber: #b5730a;
251
256
 
252
257
  /* A WHITE app: page and cards are both white, and cards are delineated by a hairline
253
- border + soft shadow (see card.css), not a grey canvas. */
258
+ border (see card.css), not a grey canvas or a shadow. */
254
259
  --bg: #ffffff;
255
260
  --bg-elevated: #ffffff;
256
261
  --surface: #ffffff;
@@ -271,6 +276,7 @@
271
276
  --disabled-ink: var(--muted);
272
277
  --disabled-surface: var(--surface-2);
273
278
  --disabled-border: var(--border);
279
+ --disabled-ink-bare: #585e6c;
274
280
 
275
281
  --accent: #6a2dcc;
276
282
  --accent-strong: #6a2dcc; /* already dark enough for white text */
@@ -288,8 +294,8 @@
288
294
  --glow-cyan: rgba(12, 143, 168, 0.1);
289
295
  --glow-pink: rgba(182, 51, 97, 0.1);
290
296
 
291
- /* Solid chip pairs for the white app. Each ink is deepened past its signal hue so 10px
292
- uppercase text clears WCAG AA on its own pale fill. */
297
+ /* Solid chip pairs for the white app. Each ink is deepened past its signal hue so 11px
298
+ chip text clears WCAG AA on its own pale fill. */
293
299
  --chip-success-ink: #1f7a38;
294
300
  --chip-success-fill: #dff3e4;
295
301
  --chip-warn-ink: #8a5e00;
@@ -318,8 +324,8 @@
318
324
  --shadow-lg: 0 18px 50px rgba(30, 30, 50, 0.16);
319
325
  /* Tight elevation for the active segmented pill — stays contained in its track. */
320
326
  --shadow-seg: 0 1px 2px rgba(30, 30, 50, 0.12), 0 2px 4px rgba(30, 30, 50, 0.1);
321
- /* A white card on a white page needs its own flatter-than-sm elevation: a hairline
322
- contact shadow plus a wide soft one (see card.css). */
327
+ /* A hairline contact shadow plus a wide soft one. Unread by the kit since #284 —
328
+ see the dark block. */
323
329
  --shadow-card: 0 1px 2px rgba(20, 25, 45, 0.04), 0 4px 14px rgba(20, 25, 45, 0.05);
324
330
  /* No --ring here. :root's is var(--accent), and light re-points --accent. */
325
331