@apliteni/apliteni-ui 0.32.0 → 0.33.1
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/README.md +10 -6
- package/package.json +1 -1
- package/react/dist/index.css +2 -1
- package/src/components/dropdown.js +77 -30
- package/src/components/footer.js +6 -1
- package/src/components/nav.js +4 -3
- package/src/components/shell.js +197 -30
- package/src/components/success.js +12 -1
- package/src/styles/callout.css +8 -1
- package/src/styles/command-palette.css +9 -2
- package/src/styles/confirm.css +9 -2
- package/src/styles/drawer.css +25 -5
- package/src/styles/dropdown.css +22 -10
- package/src/styles/layout.css +207 -55
- package/src/styles/nav.css +88 -10
- package/src/styles/tooltip.css +4 -1
- package/src/styles/topbar.css +38 -5
- package/src/tokens/tokens.css +27 -6
package/src/styles/nav.css
CHANGED
|
@@ -9,12 +9,32 @@
|
|
|
9
9
|
.ui-nav :where(ul, ol) { list-style: none; margin: 0; padding: 0; } /* floor, not ceiling */
|
|
10
10
|
|
|
11
11
|
/* -- Sidebar rail -------------------------------------------------------- */
|
|
12
|
+
/* The rail's two widths, and the one place they are written. --ui-nav-col is the
|
|
13
|
+
open column. --ui-nav-strip is twice a row's own glyph centre — the row's
|
|
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.
|
|
20
|
+
Declared for the shell as well as the nav, because the shell's rail is this
|
|
21
|
+
nav with an inset around it, and two copies of 41 is the drift itself. */
|
|
22
|
+
.ui-nav--side,
|
|
23
|
+
.ui-app { --ui-nav-col: 216px; --ui-nav-strip: 41px; }
|
|
12
24
|
.ui-nav--side {
|
|
13
25
|
display: flex;
|
|
14
26
|
flex-direction: column;
|
|
15
27
|
gap: 4px;
|
|
16
|
-
width:
|
|
28
|
+
width: var(--ui-nav-col);
|
|
29
|
+
/* The width is the only property the fold travels. Nothing is clipped here:
|
|
30
|
+
inside the shell it is the rail that clips, and a clip of its own would have
|
|
31
|
+
been a second scroll box cutting the rows off at the rail's height. */
|
|
32
|
+
transition: width var(--dur-med) var(--ease);
|
|
17
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; }
|
|
18
38
|
.ui-nav__section + .ui-nav__section { margin-top: 14px; }
|
|
19
39
|
.ui-nav__list { display: flex; flex-direction: column; gap: 2px; }
|
|
20
40
|
.ui-nav__cap {
|
|
@@ -23,6 +43,9 @@
|
|
|
23
43
|
font-weight: var(--weight-medium);
|
|
24
44
|
color: var(--muted);
|
|
25
45
|
padding: 4px 12px 8px;
|
|
46
|
+
/* Goes on the labels' clock — a section heading is words, and the fold takes
|
|
47
|
+
every word on the rail together. */
|
|
48
|
+
transition: opacity var(--dur-fast) var(--ease);
|
|
26
49
|
}
|
|
27
50
|
|
|
28
51
|
/* Item row — link, group toggle, and leaf share the same skin */
|
|
@@ -72,7 +95,15 @@
|
|
|
72
95
|
.ui-nav__ic svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2.2; opacity: 0.72; }
|
|
73
96
|
.ui-nav__item.is-active .ui-nav__ic svg,
|
|
74
97
|
.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 */
|
|
75
|
-
.ui-nav__label {
|
|
98
|
+
.ui-nav__label {
|
|
99
|
+
flex: 1 1 auto; min-width: 0;
|
|
100
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
101
|
+
/* The words go before the closing edge reaches them, which is most of why the
|
|
102
|
+
fold is worth animating — a label cut through by that edge reads as the rail
|
|
103
|
+
eating it. --dur-fast against the width's --dur-med, as the reference times
|
|
104
|
+
its own. */
|
|
105
|
+
transition: opacity var(--dur-fast) var(--ease);
|
|
106
|
+
}
|
|
76
107
|
|
|
77
108
|
/* Destructive row (sign out, revoke). Quiet at rest, --pink once a pointer or
|
|
78
109
|
the keyboard reaches it — as .ui-btn--danger and .ui-dropdown__item do. */
|
|
@@ -111,6 +142,10 @@
|
|
|
111
142
|
line-height: 1;
|
|
112
143
|
background: var(--surface-3);
|
|
113
144
|
color: var(--dim);
|
|
145
|
+
/* The count fades with the words. It is never lost: sidebarNav() spells it
|
|
146
|
+
into the row's aria-label, so "Pending 3" is what a reader hears at either
|
|
147
|
+
width. */
|
|
148
|
+
transition: opacity var(--dur-fast) var(--ease);
|
|
114
149
|
}
|
|
115
150
|
.ui-nav__badge.is-accent { background: var(--glow-purple); color: var(--accent); }
|
|
116
151
|
.ui-nav__badge.is-live { background: var(--chip-success-fill); color: var(--chip-success-ink); }
|
|
@@ -135,7 +170,7 @@
|
|
|
135
170
|
border-right: 1.6px solid var(--muted);
|
|
136
171
|
border-bottom: 1.6px solid var(--muted);
|
|
137
172
|
transform: rotate(-45deg);
|
|
138
|
-
transition: transform var(--dur-fast) var(--ease);
|
|
173
|
+
transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
|
|
139
174
|
}
|
|
140
175
|
.ui-nav__group.is-open > .ui-nav__toggle .ui-nav__caret { transform: rotate(45deg); }
|
|
141
176
|
.ui-nav__sub {
|
|
@@ -164,16 +199,59 @@
|
|
|
164
199
|
/* Footer slot (divider + trailing links, e.g. sign-out) */
|
|
165
200
|
.ui-nav__foot { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
|
|
166
201
|
|
|
167
|
-
/*
|
|
168
|
-
|
|
202
|
+
/* A row with no glyph, on a rail folded to its glyphs, would be a blank target.
|
|
203
|
+
It gets a dot on the glyph column instead — out of flow, so the open rail's
|
|
204
|
+
labels stay where they are, and resting at nothing, so what the fold does is
|
|
205
|
+
raise it rather than conjure it. 18px is the row's own 12px padding plus half
|
|
206
|
+
a 17px glyph less half the dot: the column the glyph beside it stands on.
|
|
207
|
+
sidebarNav() takes `icon` as optional at every level, sub rows included. */
|
|
208
|
+
.ui-nav--side .ui-nav__item:not(:has(.ui-nav__ic))::after {
|
|
209
|
+
content: "";
|
|
210
|
+
position: absolute;
|
|
211
|
+
left: 18px; top: 50%;
|
|
212
|
+
width: 5px; height: 5px;
|
|
213
|
+
margin-top: -2.5px;
|
|
214
|
+
border-radius: 50%;
|
|
215
|
+
background: currentColor;
|
|
216
|
+
opacity: 0;
|
|
217
|
+
transition: opacity var(--dur-fast) var(--ease);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* The nested list's indent, which the strip has no room for. It travels with the
|
|
221
|
+
width rather than vanishing under it: the guide hairline thins to nothing and
|
|
222
|
+
the children walk back onto the glyph column their parent stands on. */
|
|
223
|
+
.ui-nav__sub {
|
|
224
|
+
transition: margin-inline-start var(--dur-med) var(--ease),
|
|
225
|
+
padding-inline-start var(--dur-med) var(--ease),
|
|
226
|
+
border-inline-start-width var(--dur-med) var(--ease);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Collapsed (icon-only) rail — the same fold the shell's rail makes, drawn once
|
|
230
|
+
rather than pressed: the column keeps its width and the nav clips to the
|
|
231
|
+
strip, so no row is laid out again and no glyph moves. A group's children stay
|
|
232
|
+
rows here, because wireNav() toggles the list's `hidden` attribute and nothing
|
|
233
|
+
else, so folding .ui-nav__sub away left the toggle announcing a list it could
|
|
234
|
+
not open. What goes is the indent and the words, and sidebarNav({ collapsed })
|
|
235
|
+
hands each row its name as a `title` so a pointer can still read it. The
|
|
236
|
+
shell's rail draws a chip of its own instead, on keyboard focus as well — see
|
|
237
|
+
layout.css. */
|
|
238
|
+
.ui-nav--side.is-collapsed {
|
|
239
|
+
width: var(--ui-nav-strip);
|
|
240
|
+
/* clip, not hidden: a standalone rail has nothing around it to clip for it,
|
|
241
|
+
and `hidden` would make this a scroll box in both axes and cut the rows off
|
|
242
|
+
at whatever height it was given. `clip` across leaves `visible` down alone,
|
|
243
|
+
which is the one pair that does. */
|
|
244
|
+
overflow-x: clip;
|
|
245
|
+
overflow-y: visible;
|
|
246
|
+
}
|
|
169
247
|
.ui-nav--side.is-collapsed .ui-nav__cap,
|
|
170
248
|
.ui-nav--side.is-collapsed .ui-nav__label,
|
|
171
249
|
.ui-nav--side.is-collapsed .ui-nav__badge,
|
|
172
|
-
.ui-nav--side.is-collapsed .ui-nav__caret {
|
|
173
|
-
.ui-nav--side.is-collapsed .ui-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.ui-nav--side.is-collapsed .ui-
|
|
250
|
+
.ui-nav--side.is-collapsed .ui-nav__caret { opacity: 0; pointer-events: none; }
|
|
251
|
+
.ui-nav--side.is-collapsed .ui-nav__sub {
|
|
252
|
+
margin-inline-start: 0; padding-inline-start: 0; border-inline-start-width: 0;
|
|
253
|
+
}
|
|
254
|
+
.ui-nav--side.is-collapsed .ui-nav__item:not(:has(.ui-nav__ic))::after { opacity: 0.62; }
|
|
177
255
|
|
|
178
256
|
/* -- Horizontal tabs ----------------------------------------------------- */
|
|
179
257
|
.ui-nav--tabs {
|
package/src/styles/tooltip.css
CHANGED
|
@@ -26,7 +26,10 @@
|
|
|
26
26
|
max-width: var(--prose-caption);
|
|
27
27
|
padding: var(--space-2) var(--space-3);
|
|
28
28
|
background: var(--ui-tip-bg);
|
|
29
|
-
|
|
29
|
+
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
30
|
+
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
31
|
+
border: 1px solid var(--border-strong);
|
|
32
|
+
box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
|
|
30
33
|
border-radius: var(--radius-sm);
|
|
31
34
|
font-family: var(--font-sans);
|
|
32
35
|
font-size: var(--text-xs);
|
package/src/styles/topbar.css
CHANGED
|
@@ -123,11 +123,18 @@
|
|
|
123
123
|
left: 0;
|
|
124
124
|
min-width: 266px;
|
|
125
125
|
background: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
|
|
126
|
-
|
|
126
|
+
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
127
|
+
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
128
|
+
border: 1px solid var(--border-strong);
|
|
129
|
+
box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
|
|
127
130
|
border-radius: 16px;
|
|
128
131
|
padding: 6px;
|
|
129
132
|
opacity: 0;
|
|
130
133
|
visibility: hidden;
|
|
134
|
+
/* Drawn for the whole of the fade out, so the rows do not vanish mid-fade — and a box
|
|
135
|
+
that is drawn is a box that is hit. The open rule takes this back.
|
|
136
|
+
why: docs/specification.md#the-dropdown-panel */
|
|
137
|
+
pointer-events: none;
|
|
131
138
|
transform: translateY(-6px);
|
|
132
139
|
/* Named properties, not the bare shorthand: `transition: 0.18s` is `all`, and `all`
|
|
133
140
|
includes visibility — held at the OLD value for the whole duration, so the menu is
|
|
@@ -138,7 +145,20 @@
|
|
|
138
145
|
visibility var(--dur-med) linear;
|
|
139
146
|
z-index: var(--z-dropdown);
|
|
140
147
|
}
|
|
141
|
-
|
|
148
|
+
/* Open, the menu is clickable and visible AT ONCE. Both menus in this file are
|
|
149
|
+
`wireDropdown()` in bespoke clothes — same hooks, same keyboard, same fade — so they
|
|
150
|
+
owe a panel's two rules as much as `.ui-dropdown__panel` does: `visibility` off the
|
|
151
|
+
open transition, because the frame the open class lands is the frame the wiring moves
|
|
152
|
+
focus onto a row in and a browser will not focus inside a hidden box; and
|
|
153
|
+
`pointer-events` back on, because the closed rule turned it off.
|
|
154
|
+
why: docs/specification.md#the-dropdown-panel */
|
|
155
|
+
.vsw.open .vsw__menu {
|
|
156
|
+
opacity: 1;
|
|
157
|
+
visibility: visible;
|
|
158
|
+
pointer-events: auto;
|
|
159
|
+
transform: translateY(0);
|
|
160
|
+
transition-property: opacity, transform;
|
|
161
|
+
}
|
|
142
162
|
.vopt {
|
|
143
163
|
display: flex;
|
|
144
164
|
gap: 11px;
|
|
@@ -160,7 +180,8 @@
|
|
|
160
180
|
transition: background var(--dur-fast) var(--ease);
|
|
161
181
|
}
|
|
162
182
|
/* The menu is raised, so a hovered row takes the step ABOVE it — see
|
|
163
|
-
src/styles/dropdown.css:
|
|
183
|
+
src/styles/dropdown.css:144 `.ui-dropdown__item:hover`.
|
|
184
|
+
why: docs/specification.md#elevation */
|
|
164
185
|
.vopt:hover { background: var(--surface-3); }
|
|
165
186
|
.vopt .vname { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
166
187
|
.vopt .vmeta { font-size: 11px; color: var(--muted); margin-top: 2px; }
|
|
@@ -205,11 +226,15 @@
|
|
|
205
226
|
right: 0; top: 44px;
|
|
206
227
|
width: 252px;
|
|
207
228
|
background: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
|
|
208
|
-
|
|
229
|
+
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
230
|
+
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
231
|
+
border: 1px solid var(--border-strong);
|
|
232
|
+
box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
|
|
209
233
|
border-radius: 14px;
|
|
210
234
|
overflow: hidden;
|
|
211
235
|
opacity: 0;
|
|
212
236
|
visibility: hidden;
|
|
237
|
+
pointer-events: none; /* see .vsw__menu above */
|
|
213
238
|
transform: translateY(-6px);
|
|
214
239
|
/* Named properties — see .vsw__menu above. */
|
|
215
240
|
transition:
|
|
@@ -218,7 +243,15 @@
|
|
|
218
243
|
visibility var(--dur-med) linear;
|
|
219
244
|
z-index: var(--z-dropdown);
|
|
220
245
|
}
|
|
221
|
-
.
|
|
246
|
+
/* Clickable and visible at once — see .vsw.open .vsw__menu above. The row this one
|
|
247
|
+
costs is `.aout`: a stray click in the fade out ends the reader's session. */
|
|
248
|
+
.acct.open .amenu {
|
|
249
|
+
opacity: 1;
|
|
250
|
+
visibility: visible;
|
|
251
|
+
pointer-events: auto;
|
|
252
|
+
transform: translateY(0);
|
|
253
|
+
transition-property: opacity, transform;
|
|
254
|
+
}
|
|
222
255
|
.amenu .ahead { padding: 13px 15px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 11px; }
|
|
223
256
|
.amenu .ahead .avatar { cursor: default; }
|
|
224
257
|
.amenu .ahead .aw { min-width: 0; display: flex; flex-direction: column; gap: 1px; line-height: 1.35; }
|
package/src/tokens/tokens.css
CHANGED
|
@@ -133,9 +133,10 @@
|
|
|
133
133
|
--pink: #e97ca5;
|
|
134
134
|
--amber: #ffcf6a;
|
|
135
135
|
|
|
136
|
-
/* The elevation ladder, bottom to top.
|
|
137
|
-
with
|
|
138
|
-
|
|
136
|
+
/* The elevation ladder, bottom to top. A surface says how high it is with its step and
|
|
137
|
+
with the hairline around it, and --muted caps how far the ladder can go. Nothing casts
|
|
138
|
+
below the floating step; the floating step itself adds --elev-drop under its inner
|
|
139
|
+
line and nothing else in the kit does. why: docs/specification.md#elevation */
|
|
139
140
|
--bg: #0e0d14;
|
|
140
141
|
--surface-2: #161520; /* SUNKEN — fields, tracks, disabled, code */
|
|
141
142
|
--surface: #211e2d; /* the card */
|
|
@@ -214,9 +215,10 @@
|
|
|
214
215
|
--signal-solid-info: var(--cyan);
|
|
215
216
|
--signal-solid-neutral: var(--muted);
|
|
216
217
|
|
|
217
|
-
/* DEPRECATED since #295:
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
/* DEPRECATED since #295: no surface below the floating step casts, and the floating
|
|
219
|
+
step reads --elev-drop rather than any of these. Published still, so a consumer
|
|
220
|
+
reading one gets nothing rather than an unresolved var(), and a consumer who wants a
|
|
221
|
+
cast shadow sets them. Nothing in src/ reads them.
|
|
220
222
|
|
|
221
223
|
A transparent shadow, not `none`, because these are read in a LIST. The kit's own
|
|
222
224
|
pre-0.32 pattern was `box-shadow: var(--shadow-lg), var(--ring)`, and `none` is only
|
|
@@ -239,6 +241,18 @@
|
|
|
239
241
|
--shadow-ink: #000000;
|
|
240
242
|
--sheen: #ffffff;
|
|
241
243
|
|
|
244
|
+
/* The drops of the floating treatment, in Primer's --shadow-floating-* order:
|
|
245
|
+
the inner half of the two-step edge, then these. The line is NOT in this
|
|
246
|
+
token and cannot be — a var() inside a custom property is substituted on the
|
|
247
|
+
element that DECLARES it, so an --elev-edge read here resolves at :root and
|
|
248
|
+
nothing below could re-point it. A floating surface writes the pair itself:
|
|
249
|
+
box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
|
|
250
|
+
Dark spends 62% / 50% of the ink and reaches 1.20 at the drop's core, having
|
|
251
|
+
nowhere to go on a near-black page. why: docs/specification.md#elevation */
|
|
252
|
+
--elev-drop:
|
|
253
|
+
0 14px 30px -12px color-mix(in srgb, var(--shadow-ink) 62%, transparent),
|
|
254
|
+
0 3px 9px -4px color-mix(in srgb, var(--shadow-ink) 50%, transparent);
|
|
255
|
+
|
|
242
256
|
/* Backdrop that dims the page behind an overlay (drawer, modal, composer). */
|
|
243
257
|
--scrim: rgba(0, 0, 0, 0.58);
|
|
244
258
|
|
|
@@ -345,6 +359,13 @@
|
|
|
345
359
|
--shadow-ink: #1e1e32;
|
|
346
360
|
--sheen: #ffffff;
|
|
347
361
|
|
|
362
|
+
/* 18% / 10% against dark's 62% / 50%. Light's ink is #1e1e32 on a card at
|
|
363
|
+
#f8f9fc, and 18% is what puts the drop core at #d1d2d8 — 1.44, the strongest
|
|
364
|
+
separation either theme gets. why: docs/specification.md#elevation */
|
|
365
|
+
--elev-drop:
|
|
366
|
+
0 14px 30px -12px color-mix(in srgb, var(--shadow-ink) 18%, transparent),
|
|
367
|
+
0 3px 9px -4px color-mix(in srgb, var(--shadow-ink) 10%, transparent);
|
|
368
|
+
|
|
348
369
|
--scrim: rgba(20, 22, 40, 0.38);
|
|
349
370
|
|
|
350
371
|
--grad-from: var(--purple-light);
|