@tensor_1/tokens 2.45.1 → 2.47.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.
- package/build/css/components.css +1 -1
- package/build/css/styles.css +1 -1
- package/build/css/tokens.css +12 -0
- package/build/ts/tokens.d.ts +1 -1
- package/build/ts/tokens.js +24 -0
- package/package.json +2 -2
- package/styles/components/app-shell.css +3 -3
- package/styles/components/arrival.css +7 -6
- package/styles/components/avatar.css +2 -1
- package/styles/components/busy-region.css +47 -0
- package/styles/components/button.css +36 -6
- package/styles/components/card.css +4 -2
- package/styles/components/flow.css +4 -4
- package/styles/components/heartbeat.css +7 -2
- package/styles/components/inline-edit.css +2 -1
- package/styles/components/input.css +1 -1
- package/styles/components/kanban.css +2 -3
- package/styles/components/meter.css +5 -1
- package/styles/components/org-chart.css +1 -1
- package/styles/components/progress.css +8 -2
- package/styles/components/radio.css +1 -1
- package/styles/components/rich-text.css +4 -2
- package/styles/components/save-status.css +2 -2
- package/styles/components/select.css +1 -1
- package/styles/components/sidebar.css +17 -9
- package/styles/components/spinner.css +3 -1
- package/styles/components/states.css +2 -1
- package/styles/components/table.css +28 -11
- package/styles/components/textarea.css +1 -1
- package/styles/components/toast.css +6 -1
- package/styles/components/tooltip.css +2 -1
- package/styles/components/view-menu.css +4 -2
- package/styles/motion.css +29 -6
- package/tokens/base/effect.json +17 -2
package/build/css/tokens.css
CHANGED
|
@@ -116,6 +116,18 @@
|
|
|
116
116
|
--uix-dur: 160ms;
|
|
117
117
|
--uix-dur-slow: 240ms;
|
|
118
118
|
--uix-dur-slower: 320ms;
|
|
119
|
+
--uix-dur-exit-fast: 80ms;
|
|
120
|
+
--uix-dur-exit: 110ms;
|
|
121
|
+
--uix-dur-exit-slow: 160ms;
|
|
122
|
+
--uix-dur-highlight: 2400ms;
|
|
123
|
+
--uix-delay-tooltip: 400ms;
|
|
124
|
+
--uix-delay-tooltip-skip: 300ms;
|
|
125
|
+
--uix-loop-spin: 600ms;
|
|
126
|
+
--uix-loop-progress: 1200ms;
|
|
127
|
+
--uix-loop-shimmer: 1400ms;
|
|
128
|
+
--uix-loop-ping: 1600ms;
|
|
129
|
+
--uix-loop-blink: 1100ms;
|
|
130
|
+
--uix-loop-pulse: 2000ms;
|
|
119
131
|
--uix-lift: 4px;
|
|
120
132
|
--uix-z-raised: 1;
|
|
121
133
|
--uix-z-sticky: 3;
|
package/build/ts/tokens.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* GENERATED — do not edit. */
|
|
2
|
-
export type UixTokenName = "bg-app" | "bg-subtle" | "bg-hover" | "bg-active" | "surface" | "surface-2" | "surface-3" | "border" | "border-strong" | "text" | "text-hushed" | "text-muted" | "text-reverse" | "text-hushed-reverse" | "accent" | "accent-dark" | "accent-light" | "accent-hover" | "accent-fg" | "link" | "accent-text" | "ring" | "brand-muted" | "success" | "success-fg" | "success-bg" | "success-text" | "warning" | "warning-fg" | "warning-bg" | "warning-text" | "warning-border" | "info" | "info-fg" | "info-bg" | "info-text" | "danger" | "danger-fg" | "danger-bg" | "danger-border" | "danger-text" | "amber" | "amber-text" | "amber-bg" | "attention" | "attention-bg" | "attention-text" | "attention-solid" | "overdue" | "overdue-bg" | "overdue-text" | "overdue-solid" | "sev-4" | "sev-4-bg" | "sev-4-text" | "sev-5" | "sev-5-bg" | "sev-5-text" | "success-solid" | "warning-solid" | "info-solid" | "danger-solid" | "neutral-solid" | "neutral-text" | "neutral-bg" | "neutral-border" | "chart-1" | "chart-2" | "chart-3" | "chart-4" | "chart-5" | "chart-6" | "chart-7" | "chart-8" | "chart-neutral" | "chart-grid" | "chart-axis" | "chart-reference" | "chart-zone-warning" | "chart-zone-danger" | "chart-forecast-band" | "chart-event" | "chart-partial" | "chart-comparison" | "row" | "row-alt" | "row-pinned-bg" | "row-selected-bg" | "scrollbar-thumb" | "scrollbar-thumb-hover" | "scrollbar-track" | "scrim" | "scrim-strong" | "print-ink" | "print-ink-quiet" | "print-paper" | "print-paper-quiet" | "print-line" | "print-danger" | "shadow-sm" | "shadow-md" | "shadow-popover" | "shadow-overlay" | "highlight-top" | "ease-out" | "ease-out-strong" | "ease-in" | "ease-in-out" | "ease-spring" | "dur-fast" | "dur" | "dur-slow" | "dur-slower" | "lift" | "z-raised" | "z-sticky" | "z-dropdown" | "z-overlay" | "z-tooltip" | "z-toast" | "radius-xs" | "radius-sm" | "radius-md" | "radius-lg" | "radius-xl" | "radius-pill" | "row-h" | "row-h-compact" | "row-h-comfortable" | "control-h" | "sidebar-w" | "sidebar-w-rail" | "topbar-h" | "scrollbar-size" | "icon-sm" | "icon-md" | "icon-lg" | "peek-w" | "col-w-xs" | "col-w-sm" | "col-w-md" | "col-w-lg" | "col-w-xl" | "col-title-min" | "space-0" | "space-1" | "space-2" | "space-3" | "space-4" | "space-5" | "space-6" | "space-7" | "space-8" | "space-9" | "space-10" | "space-11" | "space-12" | "font-sans" | "font-heading" | "font-mono" | "text-display" | "leading-display" | "text-data-hero" | "leading-data-hero" | "text-h2" | "leading-h2" | "text-h3" | "leading-h3" | "text-body" | "leading-body" | "text-meta" | "leading-meta" | "text-eyebrow" | "leading-eyebrow" | "tracking-tight" | "tracking-eyebrow";
|
|
2
|
+
export type UixTokenName = "bg-app" | "bg-subtle" | "bg-hover" | "bg-active" | "surface" | "surface-2" | "surface-3" | "border" | "border-strong" | "text" | "text-hushed" | "text-muted" | "text-reverse" | "text-hushed-reverse" | "accent" | "accent-dark" | "accent-light" | "accent-hover" | "accent-fg" | "link" | "accent-text" | "ring" | "brand-muted" | "success" | "success-fg" | "success-bg" | "success-text" | "warning" | "warning-fg" | "warning-bg" | "warning-text" | "warning-border" | "info" | "info-fg" | "info-bg" | "info-text" | "danger" | "danger-fg" | "danger-bg" | "danger-border" | "danger-text" | "amber" | "amber-text" | "amber-bg" | "attention" | "attention-bg" | "attention-text" | "attention-solid" | "overdue" | "overdue-bg" | "overdue-text" | "overdue-solid" | "sev-4" | "sev-4-bg" | "sev-4-text" | "sev-5" | "sev-5-bg" | "sev-5-text" | "success-solid" | "warning-solid" | "info-solid" | "danger-solid" | "neutral-solid" | "neutral-text" | "neutral-bg" | "neutral-border" | "chart-1" | "chart-2" | "chart-3" | "chart-4" | "chart-5" | "chart-6" | "chart-7" | "chart-8" | "chart-neutral" | "chart-grid" | "chart-axis" | "chart-reference" | "chart-zone-warning" | "chart-zone-danger" | "chart-forecast-band" | "chart-event" | "chart-partial" | "chart-comparison" | "row" | "row-alt" | "row-pinned-bg" | "row-selected-bg" | "scrollbar-thumb" | "scrollbar-thumb-hover" | "scrollbar-track" | "scrim" | "scrim-strong" | "print-ink" | "print-ink-quiet" | "print-paper" | "print-paper-quiet" | "print-line" | "print-danger" | "shadow-sm" | "shadow-md" | "shadow-popover" | "shadow-overlay" | "highlight-top" | "ease-out" | "ease-out-strong" | "ease-in" | "ease-in-out" | "ease-spring" | "dur-fast" | "dur" | "dur-slow" | "dur-slower" | "dur-exit-fast" | "dur-exit" | "dur-exit-slow" | "dur-highlight" | "delay-tooltip" | "delay-tooltip-skip" | "loop-spin" | "loop-progress" | "loop-shimmer" | "loop-ping" | "loop-blink" | "loop-pulse" | "lift" | "z-raised" | "z-sticky" | "z-dropdown" | "z-overlay" | "z-tooltip" | "z-toast" | "radius-xs" | "radius-sm" | "radius-md" | "radius-lg" | "radius-xl" | "radius-pill" | "row-h" | "row-h-compact" | "row-h-comfortable" | "control-h" | "sidebar-w" | "sidebar-w-rail" | "topbar-h" | "scrollbar-size" | "icon-sm" | "icon-md" | "icon-lg" | "peek-w" | "col-w-xs" | "col-w-sm" | "col-w-md" | "col-w-lg" | "col-w-xl" | "col-title-min" | "space-0" | "space-1" | "space-2" | "space-3" | "space-4" | "space-5" | "space-6" | "space-7" | "space-8" | "space-9" | "space-10" | "space-11" | "space-12" | "font-sans" | "font-heading" | "font-mono" | "text-display" | "leading-display" | "text-data-hero" | "leading-data-hero" | "text-h2" | "leading-h2" | "text-h3" | "leading-h3" | "text-body" | "leading-body" | "text-meta" | "leading-meta" | "text-eyebrow" | "leading-eyebrow" | "tracking-tight" | "tracking-eyebrow";
|
|
3
3
|
export declare const cssVar: Record<UixTokenName, string>;
|
|
4
4
|
export declare const light: Record<UixTokenName, string>;
|
|
5
5
|
export declare const dark: Partial<Record<UixTokenName, string>>;
|
package/build/ts/tokens.js
CHANGED
|
@@ -117,6 +117,18 @@ export const cssVar = {
|
|
|
117
117
|
"dur": "var(--uix-dur)",
|
|
118
118
|
"dur-slow": "var(--uix-dur-slow)",
|
|
119
119
|
"dur-slower": "var(--uix-dur-slower)",
|
|
120
|
+
"dur-exit-fast": "var(--uix-dur-exit-fast)",
|
|
121
|
+
"dur-exit": "var(--uix-dur-exit)",
|
|
122
|
+
"dur-exit-slow": "var(--uix-dur-exit-slow)",
|
|
123
|
+
"dur-highlight": "var(--uix-dur-highlight)",
|
|
124
|
+
"delay-tooltip": "var(--uix-delay-tooltip)",
|
|
125
|
+
"delay-tooltip-skip": "var(--uix-delay-tooltip-skip)",
|
|
126
|
+
"loop-spin": "var(--uix-loop-spin)",
|
|
127
|
+
"loop-progress": "var(--uix-loop-progress)",
|
|
128
|
+
"loop-shimmer": "var(--uix-loop-shimmer)",
|
|
129
|
+
"loop-ping": "var(--uix-loop-ping)",
|
|
130
|
+
"loop-blink": "var(--uix-loop-blink)",
|
|
131
|
+
"loop-pulse": "var(--uix-loop-pulse)",
|
|
120
132
|
"lift": "var(--uix-lift)",
|
|
121
133
|
"z-raised": "var(--uix-z-raised)",
|
|
122
134
|
"z-sticky": "var(--uix-z-sticky)",
|
|
@@ -296,6 +308,18 @@ export const light = {
|
|
|
296
308
|
"dur": "160ms",
|
|
297
309
|
"dur-slow": "240ms",
|
|
298
310
|
"dur-slower": "320ms",
|
|
311
|
+
"dur-exit-fast": "80ms",
|
|
312
|
+
"dur-exit": "110ms",
|
|
313
|
+
"dur-exit-slow": "160ms",
|
|
314
|
+
"dur-highlight": "2400ms",
|
|
315
|
+
"delay-tooltip": "400ms",
|
|
316
|
+
"delay-tooltip-skip": "300ms",
|
|
317
|
+
"loop-spin": "600ms",
|
|
318
|
+
"loop-progress": "1200ms",
|
|
319
|
+
"loop-shimmer": "1400ms",
|
|
320
|
+
"loop-ping": "1600ms",
|
|
321
|
+
"loop-blink": "1100ms",
|
|
322
|
+
"loop-pulse": "2000ms",
|
|
299
323
|
"lift": "4px",
|
|
300
324
|
"z-raised": "1",
|
|
301
325
|
"z-sticky": "3",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tensor_1/tokens",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.47.0",
|
|
4
4
|
"description": "UIx v2 design tokens — the --uix-* contract for house products (Tensor, POSx, SHOPx). One DTCG source -> CSS variables, Tailwind theme, and typed TS constants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"build:styles": "node scripts/build-styles.mjs",
|
|
48
48
|
"build": "npm run build:tokens && npm run build:themes && npm run build:styles",
|
|
49
49
|
"test:parity": "node scripts/check-parity.mjs",
|
|
50
|
-
"test:contract": "node scripts/check-contract.mjs",
|
|
50
|
+
"test:contract": "node scripts/check-contract.mjs && node scripts/check-motion.mjs",
|
|
51
51
|
"docs:serve": "serve -l 4178 ../..",
|
|
52
52
|
"size:css": "node scripts/size-report.mjs --check",
|
|
53
53
|
"size:css:update": "node scripts/size-report.mjs --update",
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
grid-template-rows: var(--uix-topbar-h) 1fr;
|
|
8
8
|
height: 100%; min-height: 360px;
|
|
9
9
|
border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden;
|
|
10
|
-
transition:
|
|
10
|
+
/* No transition: collapsing the nav is frequent, so the tracks switch instantly (grid tracks never animate). */
|
|
11
11
|
}
|
|
12
|
-
.uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; visibility: visible;
|
|
12
|
+
.uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; visibility: visible; }
|
|
13
13
|
.uix-shell__topbar { grid-column: 2; display: flex; align-items: center; gap: var(--uix-space-3); padding: 0 var(--uix-space-6); background: var(--uix-bg-app); border-bottom: 1px solid var(--uix-border); }
|
|
14
14
|
.uix-shell__main { grid-column: 2; overflow: auto; padding: var(--uix-space-7); background: var(--uix-bg-app); }
|
|
15
15
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
.uix-shell[data-nav="rail"], .uix-shell[data-collapsed] { grid-template-columns: var(--uix-sidebar-w-rail) 1fr; }
|
|
20
20
|
.uix-shell[data-nav="hidden"] { grid-template-columns: 0 1fr; }
|
|
21
21
|
/* the 0-width column still renders its links — visibility removes them from the tab
|
|
22
|
-
order / accessibility tree
|
|
22
|
+
order / accessibility tree (UIX-A11Y-2) */
|
|
23
23
|
.uix-shell[data-nav="hidden"] .uix-shell__sidebar { visibility: hidden; }
|
|
24
24
|
|
|
25
25
|
/* ── focus / immersive mode ───────────────────────────────────────────────────
|
|
@@ -6,23 +6,24 @@
|
|
|
6
6
|
.uix-arrival {
|
|
7
7
|
border-radius: var(--uix-radius-md);
|
|
8
8
|
scroll-margin-block: var(--uix-space-10);
|
|
9
|
-
animation: uix-arrival
|
|
9
|
+
animation: uix-arrival var(--uix-dur-highlight) var(--uix-ease-out) both;
|
|
10
10
|
}
|
|
11
11
|
@keyframes uix-arrival {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/* the outline carries the tint past the element's edge; only its colour fades */
|
|
13
|
+
0%, 40% { background-color: var(--uix-brand-muted); outline: var(--uix-space-2) solid var(--uix-brand-muted); outline-offset: 0; }
|
|
14
|
+
100% { background-color: transparent; outline: var(--uix-space-2) solid transparent; outline-offset: 0; }
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
/* no fade: a steady outline for
|
|
17
|
+
/* no fade: a steady outline for the highlight time, then nothing */
|
|
17
18
|
@keyframes uix-arrival-static {
|
|
18
19
|
0% { outline: 2px solid var(--uix-ring); outline-offset: var(--uix-space-1); }
|
|
19
20
|
100% { outline: 2px solid transparent; outline-offset: var(--uix-space-1); }
|
|
20
21
|
}
|
|
21
22
|
@media (prefers-reduced-motion: reduce) {
|
|
22
|
-
.uix-arrival { animation: uix-arrival-static
|
|
23
|
+
.uix-arrival { animation: uix-arrival-static var(--uix-dur-highlight) step-end both; }
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
@media (forced-colors: active) {
|
|
26
|
-
.uix-arrival { animation: uix-arrival-static
|
|
27
|
+
.uix-arrival { animation: uix-arrival-static var(--uix-dur-highlight) step-end both; }
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
.uix-avatar--editable { cursor: pointer; }
|
|
31
31
|
.uix-avatar__edit { position: absolute; inset: 0; display: grid; place-items: center; background: var(--uix-scrim); color: var(--uix-text-reverse); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
|
|
32
32
|
.uix-avatar__edit svg { width: 45%; height: 45%; }
|
|
33
|
-
.uix-avatar--editable:
|
|
33
|
+
.uix-avatar--editable:focus-visible .uix-avatar__edit { opacity: 1; }
|
|
34
|
+
@media (hover: hover) and (pointer: fine) { .uix-avatar--editable:hover .uix-avatar__edit { opacity: 1; } }
|
|
34
35
|
.uix-avatar--empty { background: var(--uix-bg-subtle); border: 1.5px dashed var(--uix-border-strong); color: var(--uix-text-muted); }
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* uix busy region — keep what is on screen while it is fetched again (HAR-2582, motion
|
|
2
|
+
standard §2.5). A refetch dims the content under an indeterminate bar along the top instead
|
|
3
|
+
of swapping it for skeletons, so nothing the person was looking at vanishes. The React
|
|
4
|
+
BusyBar sets [data-shown] after 300 ms and holds it 500 ms; the parent reads it with :has(),
|
|
5
|
+
so `BusyRegion` and `TableWrap refreshing` stay server components. Depends only on --uix-*
|
|
6
|
+
tokens. */
|
|
7
|
+
@layer uix.components {
|
|
8
|
+
.uix-busy-region { position: relative; }
|
|
9
|
+
.uix-busy-region__content { transition: opacity var(--uix-dur-exit) var(--uix-ease-out); }
|
|
10
|
+
.uix-busy-region:has(> .uix-busy-bar[data-shown]) > .uix-busy-region__content { opacity: .6; transition-duration: var(--uix-dur); }
|
|
11
|
+
|
|
12
|
+
.uix-busy-bar {
|
|
13
|
+
position: absolute; inset-block-start: 0; inset-inline: 0; z-index: var(--uix-z-sticky);
|
|
14
|
+
display: block; height: 2px; overflow: hidden; pointer-events: none;
|
|
15
|
+
opacity: 0; transition: opacity var(--uix-dur-exit) var(--uix-ease-out);
|
|
16
|
+
}
|
|
17
|
+
.uix-busy-bar[data-shown] { opacity: 1; transition-duration: var(--uix-dur); }
|
|
18
|
+
.uix-busy-bar::before {
|
|
19
|
+
content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; width: 40%;
|
|
20
|
+
background: var(--uix-accent); transform: translateX(-100%);
|
|
21
|
+
}
|
|
22
|
+
/* constant motion is linear (§2.4) */
|
|
23
|
+
.uix-busy-bar[data-shown]::before { animation: uix-busy-sweep var(--uix-loop-progress) linear infinite; }
|
|
24
|
+
@keyframes uix-busy-sweep { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
|
|
25
|
+
/* right to left: the stripe starts at the right (inline-start) edge and sweeps leftwards */
|
|
26
|
+
@keyframes uix-busy-sweep-rtl { from { transform: translateX(100%); } to { transform: translateX(-250%); } }
|
|
27
|
+
.uix-busy-bar[data-shown]:dir(rtl)::before { animation-name: uix-busy-sweep-rtl; }
|
|
28
|
+
|
|
29
|
+
/* Reduced motion: no sweep; the full bar pulses (the kit's uix-pulse), so "still working" survives (§2.7). */
|
|
30
|
+
@media (prefers-reduced-motion: reduce) {
|
|
31
|
+
.uix-busy-bar::before { width: 100%; transform: none; }
|
|
32
|
+
/* !important: the kit's reduced-motion policy ends keyframes at once; a still-working signal opts back in */
|
|
33
|
+
.uix-busy-bar[data-shown]::before, .uix-busy-bar[data-shown]:dir(rtl)::before { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
|
|
34
|
+
}
|
|
35
|
+
@media (forced-colors: active) {
|
|
36
|
+
.uix-busy-bar::before { background: Highlight; }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* A refreshing table: the bar sticks to the top of the scrolling wrap (over the sticky
|
|
40
|
+
header) and takes no room: it is 0 tall and draws its 2 px stripe below its own edge. It
|
|
41
|
+
clips sideways only (overflow-x: clip), so the sweep never widens the wrap's scroll area.
|
|
42
|
+
The rows dim; the header stays. */
|
|
43
|
+
.uix-table-wrap > .uix-busy-bar { position: sticky; inset-inline-start: 0; height: 0; overflow-x: clip; overflow-y: visible; z-index: calc(var(--uix-z-sticky) + 1); }
|
|
44
|
+
.uix-table-wrap > .uix-busy-bar::before { inset-block: 0 auto; height: 2px; }
|
|
45
|
+
.uix-table-wrap > .uix-table > tbody { transition: opacity var(--uix-dur-exit) var(--uix-ease-out); }
|
|
46
|
+
.uix-table-wrap:has(> .uix-busy-bar[data-shown]) > .uix-table > tbody { opacity: .6; transition-duration: var(--uix-dur); }
|
|
47
|
+
}
|
|
@@ -52,19 +52,49 @@
|
|
|
52
52
|
.uix-btn--wrap.uix-btn--lg:not(.uix-btn--icon) { min-height: 44px; }
|
|
53
53
|
.uix-btn--wrap.uix-btn--link { min-height: 0; padding-block: 0; }
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
/* Pending (React `loading`, HAR-2580): the button stops taking presses at once but looks the
|
|
56
|
+
same for the first 300 ms; a fast action shows nothing new. It keeps full colour while it
|
|
57
|
+
works (a spinner, never a greyed-out control), which overrides the aria-disabled dim. */
|
|
58
|
+
.uix-btn[data-pending], .uix-btn:has(> [data-uix-btn-busy]) { opacity: 1; pointer-events: none; }
|
|
59
|
+
|
|
60
|
+
/* The spinner: `data-loading` (plain markup, shows at once) or React's delayed busy marker. */
|
|
61
|
+
.uix-btn:has(> [data-uix-btn-busy]), .uix-btn[data-loading] { color: transparent !important; position: relative; pointer-events: none; }
|
|
56
62
|
/* The label is hidden (color: transparent), so the ring cannot inherit
|
|
57
63
|
currentColor from the button; each variant names its own foreground.
|
|
58
64
|
TENSOR RX-125 (UIX-01): the ring was on-accent for every variant, so a
|
|
59
65
|
loading secondary/outline/ghost button rendered blank. */
|
|
60
|
-
.uix-btn[data-loading]::after {
|
|
66
|
+
.uix-btn:has(> [data-uix-btn-busy])::after, .uix-btn[data-loading]::after {
|
|
61
67
|
content: ""; position: absolute; width: 1em; height: 1em;
|
|
62
68
|
border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
|
|
63
|
-
color: var(--uix-text); animation: uix-spin
|
|
69
|
+
color: var(--uix-text); animation: uix-spin var(--uix-loop-spin) linear infinite;
|
|
64
70
|
}
|
|
65
|
-
.uix-btn
|
|
66
|
-
.uix-btn--
|
|
67
|
-
.uix-btn--
|
|
71
|
+
@media (prefers-reduced-motion: reduce) { .uix-btn:has(> [data-uix-btn-busy])::after, .uix-btn[data-loading]::after { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; } }
|
|
72
|
+
.uix-btn--primary:has(> [data-uix-btn-busy])::after, .uix-btn--primary[data-loading]::after { color: var(--uix-accent-fg); }
|
|
73
|
+
.uix-btn--danger:has(> [data-uix-btn-busy])::after, .uix-btn--danger[data-loading]::after { color: var(--uix-danger-fg); }
|
|
74
|
+
.uix-btn--link:has(> [data-uix-btn-busy])::after, .uix-btn--link[data-loading]::after { color: var(--uix-link); }
|
|
75
|
+
/* The result face hides with the label while the spinner shows. */
|
|
76
|
+
.uix-btn:has(> [data-uix-btn-busy]) .uix-btn__result { visibility: hidden; }
|
|
77
|
+
|
|
78
|
+
/* Result (React `result`, HAR-2581): the label and both result wordings share one grid cell,
|
|
79
|
+
so the button is always as wide as the widest and nothing beside it moves. A result
|
|
80
|
+
crossfades in over the label (opacity only), holds, and fades back. Text and icon carry
|
|
81
|
+
the meaning; colour only tints the icon. */
|
|
82
|
+
.uix-btn__face { display: inline-grid; justify-items: center; align-items: center; }
|
|
83
|
+
.uix-btn__face > * { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: .5em; transition: opacity var(--uix-dur) var(--uix-ease-out); }
|
|
84
|
+
.uix-btn__result { opacity: 0; transition-duration: var(--uix-dur-exit); }
|
|
85
|
+
.uix-btn__face[data-result] > .uix-btn__label { opacity: 0; transition-duration: var(--uix-dur-exit-fast); }
|
|
86
|
+
.uix-btn__face[data-result="success"] > [data-kind="success"],
|
|
87
|
+
.uix-btn__face[data-result="error"] > [data-kind="error"] { opacity: 1; transition-duration: var(--uix-dur); }
|
|
88
|
+
.uix-btn--secondary .uix-btn__result[data-kind="success"] svg,
|
|
89
|
+
.uix-btn--outline .uix-btn__result[data-kind="success"] svg,
|
|
90
|
+
.uix-btn--ghost .uix-btn__result[data-kind="success"] svg { color: var(--uix-success-text); }
|
|
91
|
+
.uix-btn--secondary .uix-btn__result[data-kind="error"] svg,
|
|
92
|
+
.uix-btn--outline .uix-btn__result[data-kind="error"] svg,
|
|
93
|
+
.uix-btn--ghost .uix-btn__result[data-kind="error"] svg { color: var(--uix-danger-text); }
|
|
94
|
+
.uix-btn--wrap .uix-btn__face > * { white-space: normal; }
|
|
95
|
+
.uix-btn--xs .uix-btn__face > * { gap: .25em; }
|
|
96
|
+
/* An icon-only button keeps its square: the result is the mark alone (the words are spoken). */
|
|
97
|
+
.uix-btn--icon .uix-btn__result-text { display: none; }
|
|
68
98
|
|
|
69
99
|
/* attached group */
|
|
70
100
|
.uix-btn-group { display: inline-flex; }
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
.uix-card__body { padding: var(--uix-space-6); }
|
|
9
9
|
/* wraps at 320 px (WCAG 1.4.10) */
|
|
10
10
|
.uix-card__footer { padding: var(--uix-space-4) var(--uix-space-6); border-top: 1px solid var(--uix-border); display: flex; flex-wrap: wrap; gap: var(--uix-space-2); justify-content: flex-end; }
|
|
11
|
-
.uix-card--interactive { display: block; color: inherit; text-decoration: none; cursor: pointer; transition: border-color var(--uix-dur-fast) var(--uix-ease-out),
|
|
12
|
-
|
|
11
|
+
.uix-card--interactive { display: block; color: inherit; text-decoration: none; cursor: pointer; transition: border-color var(--uix-dur-fast) var(--uix-ease-out), transform var(--uix-dur-fast) var(--uix-ease-out); }
|
|
12
|
+
/* The shadow steps (box-shadow never animates); the lift is hover-only, and keyboard focus gets no movement. */
|
|
13
|
+
.uix-card--interactive:focus-visible { border-color: var(--uix-border-strong); box-shadow: var(--uix-shadow-md); text-decoration: none; }
|
|
14
|
+
@media (hover: hover) and (pointer: fine) { .uix-card--interactive:hover { border-color: var(--uix-border-strong); box-shadow: var(--uix-shadow-md); text-decoration: none; transform: translateY(-1px); } }
|
|
13
15
|
.uix-card--interactive:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
|
|
14
16
|
.uix-collapsible { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); background: var(--uix-surface); }
|
|
15
17
|
.uix-collapsible__summary { display: flex; align-items: center; justify-content: space-between; gap: var(--uix-space-3); padding: var(--uix-space-4) var(--uix-space-5); cursor: pointer; list-style: none; }
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
.uix-node--active, .uix-node--running { box-shadow: var(--uix-shadow-sm), 0 0 0 3px var(--tone-bg); }
|
|
68
68
|
|
|
69
69
|
/* running node spins its icon */
|
|
70
|
-
.uix-node--running .uix-node__icon svg { animation: uix-flow-spin
|
|
70
|
+
.uix-node--running .uix-node__icon svg { animation: uix-flow-spin var(--uix-loop-spin) linear infinite; }
|
|
71
71
|
|
|
72
72
|
/* ---- decision / diamond ---- */
|
|
73
73
|
.uix-node--decision {
|
|
@@ -175,8 +175,7 @@
|
|
|
175
175
|
border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md);
|
|
176
176
|
background: var(--uix-surface); color: var(--uix-text);
|
|
177
177
|
font-size: var(--uix-text-meta); cursor: grab; box-shadow: var(--uix-shadow-sm);
|
|
178
|
-
transition:
|
|
179
|
-
transform var(--uix-dur-fast) var(--uix-ease-out);
|
|
178
|
+
transition: transform var(--uix-dur-fast) var(--uix-ease-out);
|
|
180
179
|
}
|
|
181
180
|
.uix-flow__chip svg { width: var(--uix-icon-sm); height: var(--uix-icon-sm); color: var(--uix-text-muted); flex: none; }
|
|
182
181
|
.uix-flow__chip:active { cursor: grabbing; }
|
|
@@ -210,7 +209,8 @@
|
|
|
210
209
|
@keyframes uix-flow-march { to { stroke-dashoffset: -18; } }
|
|
211
210
|
|
|
212
211
|
@media (prefers-reduced-motion: reduce) {
|
|
213
|
-
|
|
212
|
+
/* a running node keeps showing it runs: the icon breathes instead of turning */
|
|
213
|
+
.uix-node--running .uix-node__icon svg { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
|
|
214
214
|
.uix-flow:hover .uix-flow__edge,
|
|
215
215
|
.uix-flow:focus-within .uix-flow__edge { animation: none; }
|
|
216
216
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
/* uix heartbeat / live status indicator — a pulsing ping.
|
|
1
|
+
/* uix heartbeat / live status indicator — a pulsing ping. Under reduced motion the ping (it grows) goes
|
|
2
|
+
and the dot itself breathes, so "live" is still visible. */
|
|
2
3
|
@layer uix.components {
|
|
3
4
|
.uix-heartbeat { position: relative; display: inline-grid; place-items: center; width: 8px; height: 8px; flex: none; }
|
|
4
5
|
.uix-heartbeat__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--uix-success); z-index: var(--uix-z-raised); }
|
|
5
|
-
.uix-heartbeat__ping { position: absolute; inset: 0; border-radius: 50%; background: var(--uix-success); animation: uix-ping
|
|
6
|
+
.uix-heartbeat__ping { position: absolute; inset: 0; border-radius: 50%; background: var(--uix-success); animation: uix-ping var(--uix-loop-ping) var(--uix-ease-out) infinite; }
|
|
6
7
|
@keyframes uix-ping { 0% { transform: scale(1); opacity: .55; } 100% { transform: scale(2.8); opacity: 0; } }
|
|
7
8
|
.uix-heartbeat--warning .uix-heartbeat__dot, .uix-heartbeat--warning .uix-heartbeat__ping { background: var(--uix-warning); }
|
|
8
9
|
.uix-heartbeat--danger .uix-heartbeat__dot, .uix-heartbeat--danger .uix-heartbeat__ping { background: var(--uix-danger); }
|
|
9
10
|
.uix-heartbeat--idle .uix-heartbeat__dot { background: var(--uix-text-muted); }
|
|
10
11
|
.uix-heartbeat--idle .uix-heartbeat__ping { display: none; }
|
|
12
|
+
@media (prefers-reduced-motion: reduce) {
|
|
13
|
+
.uix-heartbeat__ping { display: none; }
|
|
14
|
+
.uix-heartbeat:not(.uix-heartbeat--idle) .uix-heartbeat__dot { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
|
|
15
|
+
}
|
|
11
16
|
.uix-live { display: inline-flex; align-items: center; gap: var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-text-hushed); }
|
|
12
17
|
}
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
.uix-inline-edit__placeholder { color: var(--uix-text-muted); }
|
|
20
20
|
/* 75% at rest keeps the pencil above 3:1 (the same floor as the view menu's quiet controls). */
|
|
21
21
|
.uix-inline-edit__icon { display: inline-flex; flex: none; color: var(--uix-text-muted); opacity: .75; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
|
|
22
|
-
.uix-inline-edit__view:
|
|
22
|
+
.uix-inline-edit__view:focus-visible .uix-inline-edit__icon { opacity: 1; }
|
|
23
|
+
@media (hover: hover) and (pointer: fine) { .uix-inline-edit__view:hover .uix-inline-edit__icon { opacity: 1; } }
|
|
23
24
|
.uix-inline-edit__editor { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--uix-space-2); flex: 1; min-width: 0; }
|
|
24
25
|
.uix-inline-edit__control { flex: 1 1 12rem; min-width: 0; }
|
|
25
26
|
.uix-inline-edit__control > * { width: 100%; }
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
height: var(--uix-control-h); width: 100%;
|
|
21
21
|
padding: 0 var(--uix-space-3); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md);
|
|
22
22
|
background: var(--uix-surface); color: var(--uix-text); font: inherit; font-size: var(--uix-text-body);
|
|
23
|
-
transition: border-color var(--uix-dur-fast) var(--uix-ease-out)
|
|
23
|
+
transition: border-color var(--uix-dur-fast) var(--uix-ease-out);
|
|
24
24
|
}
|
|
25
25
|
.uix-input::placeholder { color: var(--uix-text-muted); }
|
|
26
26
|
.uix-input:hover { border-color: var(--uix-border-strong); }
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
.uix-kanban__head { display: flex; align-items: center; gap: var(--uix-space-2); padding: var(--uix-space-3) var(--uix-space-4); font-weight: 600; font-size: var(--uix-text-meta); }
|
|
6
6
|
.uix-kanban__count { margin-left: auto; color: var(--uix-text-muted); font-weight: 500; }
|
|
7
7
|
.uix-kanban__body { padding: 0 var(--uix-space-3) var(--uix-space-3); display: flex; flex-direction: column; gap: var(--uix-space-2); overflow-y: auto; }
|
|
8
|
-
.uix-kanban__card { background: var(--uix-surface); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); padding: var(--uix-space-3); box-shadow: var(--uix-shadow-sm); cursor: grab; transition:
|
|
9
|
-
.uix-kanban__card:hover { box-shadow: var(--uix-shadow-popover); }
|
|
10
|
-
@media (hover: hover) and (pointer: fine) { .uix-kanban__card:hover { transform: translateY(calc(-1 * var(--uix-lift))); } }
|
|
8
|
+
.uix-kanban__card { background: var(--uix-surface); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); padding: var(--uix-space-3); box-shadow: var(--uix-shadow-sm); cursor: grab; transition: transform var(--uix-dur-fast) var(--uix-ease-out); }
|
|
9
|
+
@media (hover: hover) and (pointer: fine) { .uix-kanban__card:hover { box-shadow: var(--uix-shadow-popover); transform: translateY(calc(-1 * var(--uix-lift))); } }
|
|
11
10
|
.uix-kanban__card:active { cursor: grabbing; }
|
|
12
11
|
.uix-kanban__card-title { font-weight: 500; font-size: var(--uix-text-body); margin-bottom: var(--uix-space-2); }
|
|
13
12
|
.uix-kanban__card-meta { display: flex; align-items: center; gap: var(--uix-space-2); }
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/* uix meter / utilization bar (threshold tones) — depends only on --uix-* tokens. */
|
|
2
2
|
@layer uix.components {
|
|
3
3
|
.uix-meter { height: 8px; background: var(--uix-bg-active); border-radius: var(--uix-radius-pill); overflow: hidden; }
|
|
4
|
-
|
|
4
|
+
/* --val (0–1) slides a full-width fill into the clipped track: transform, never width (see progress.css).
|
|
5
|
+
A legacy inline `width: n%` still works: --val then defaults to 1 and nothing slides. */
|
|
6
|
+
.uix-meter__fill { width: 100%; height: 100%; border-radius: inherit; background: var(--uix-success);
|
|
7
|
+
transform: translateX(calc((var(--val, 1) - 1) * 100%)); transition: transform var(--uix-dur) var(--uix-ease-out); }
|
|
8
|
+
.uix-meter__fill:dir(rtl) { transform: translateX(calc((1 - var(--val, 1)) * 100%)); }
|
|
5
9
|
.uix-meter__fill[data-tone="warning"] { background: var(--uix-warning); }
|
|
6
10
|
.uix-meter__fill[data-tone="danger"] { background: var(--uix-danger); }
|
|
7
11
|
.uix-meter__fill[data-tone="attention"] { background: var(--uix-attention); }
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md);
|
|
91
91
|
background: var(--uix-surface); color: var(--uix-text); box-shadow: var(--uix-shadow-sm);
|
|
92
92
|
text-align: left; cursor: pointer;
|
|
93
|
-
transition: border-color var(--uix-dur-fast) var(--uix-ease-out)
|
|
93
|
+
transition: border-color var(--uix-dur-fast) var(--uix-ease-out);
|
|
94
94
|
}
|
|
95
95
|
.uix-org-chart__item > .uix-org-chart__node:hover { border-color: var(--uix-border-strong); }
|
|
96
96
|
.uix-org-chart__item[aria-selected="true"] > .uix-org-chart__node {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/* uix progress bar + ring — depends only on --uix-* tokens. */
|
|
2
2
|
@layer uix.components {
|
|
3
3
|
.uix-progress { height: 8px; background: var(--uix-bg-active); border-radius: var(--uix-radius-pill); overflow: hidden; }
|
|
4
|
-
|
|
4
|
+
/* --val (0–1) slides a full-width bar into the clipped track: transform, never width, and the rounded
|
|
5
|
+
leading end survives. A legacy inline `width: n%` still works (--val then defaults to 1, no slide). */
|
|
6
|
+
.uix-progress__bar { width: 100%; height: 100%; background: var(--uix-accent); border-radius: inherit;
|
|
7
|
+
transform: translateX(calc((var(--val, 1) - 1) * 100%)); transition: transform var(--uix-dur) var(--uix-ease-out); }
|
|
8
|
+
.uix-progress__bar:dir(rtl) { transform: translateX(calc((1 - var(--val, 1)) * 100%)); }
|
|
5
9
|
.uix-progress--indeterminate { position: relative; }
|
|
6
|
-
.uix-progress--indeterminate .uix-progress__bar { width: 40%; animation: uix-progress-slide
|
|
10
|
+
.uix-progress--indeterminate .uix-progress__bar { width: 40%; animation: uix-progress-slide var(--uix-loop-progress) var(--uix-ease-in-out) infinite; }
|
|
7
11
|
@keyframes uix-progress-slide { 0% { transform: translateX(-110%); } 100% { transform: translateX(280%); } }
|
|
12
|
+
/* reduced motion: the bar fills the track and breathes instead of sweeping */
|
|
13
|
+
@media (prefers-reduced-motion: reduce) { .uix-progress--indeterminate .uix-progress__bar { width: 100%; animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; } }
|
|
8
14
|
|
|
9
15
|
.uix-ring { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
|
|
10
16
|
background: conic-gradient(var(--uix-accent) calc(var(--val, .66) * 360deg), var(--uix-bg-active) 0); }
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
.uix-radio-card {
|
|
29
29
|
position: relative; display: flex; flex-direction: column; gap: var(--uix-space-3); min-width: 0; padding: var(--uix-space-4);
|
|
30
30
|
border: 1px solid var(--uix-border-strong); border-radius: var(--uix-radius-lg); background: var(--uix-surface); color: var(--uix-text); cursor: pointer;
|
|
31
|
-
transition: border-color var(--uix-dur-fast) var(--uix-ease-out)
|
|
31
|
+
transition: border-color var(--uix-dur-fast) var(--uix-ease-out);
|
|
32
32
|
}
|
|
33
33
|
.uix-radio-card > input { position: absolute; opacity: 0; width: 1px; height: 1px; }
|
|
34
34
|
.uix-radio-card:hover { border-color: var(--uix-text-muted); }
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
.uix-rich-text {
|
|
6
6
|
display: flex; flex-direction: column; min-width: 0;
|
|
7
7
|
border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); background: var(--uix-surface);
|
|
8
|
-
transition: border-color var(--uix-dur-fast) var(--uix-ease-out)
|
|
8
|
+
transition: border-color var(--uix-dur-fast) var(--uix-ease-out);
|
|
9
9
|
}
|
|
10
10
|
.uix-rich-text:hover { border-color: var(--uix-border-strong); }
|
|
11
11
|
.uix-rich-text:focus-within { border-color: var(--uix-ring); box-shadow: 0 0 0 3px var(--uix-brand-muted); }
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
.uix-rich-text__content .ProseMirror-gapcursor { display: none; position: absolute; margin: 0; pointer-events: none; }
|
|
67
67
|
.uix-rich-text__content .ProseMirror-gapcursor::after {
|
|
68
68
|
content: ""; display: block; position: absolute; top: -2px; width: 20px; border-top: 1px solid var(--uix-text);
|
|
69
|
-
animation: uix-rich-text-caret
|
|
69
|
+
animation: uix-rich-text-caret var(--uix-loop-blink) steps(2, start) infinite;
|
|
70
70
|
}
|
|
71
71
|
.uix-rich-text__content.ProseMirror-focused .ProseMirror-gapcursor { display: block; }
|
|
72
72
|
.uix-rich-text__content.ProseMirror-hideselection *::selection { background: transparent; }
|
|
@@ -181,5 +181,7 @@
|
|
|
181
181
|
|
|
182
182
|
@media (prefers-reduced-motion: reduce) {
|
|
183
183
|
.uix-rich-text, .uix-rich-text__tool { transition: none; }
|
|
184
|
+
/* a steady gap cursor: no blink */
|
|
185
|
+
.uix-rich-text__content .ProseMirror-gapcursor::after { animation: none; }
|
|
184
186
|
}
|
|
185
187
|
}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
.uix-save-status__icon { width: var(--uix-space-2); height: var(--uix-space-2); flex-shrink: 0; border-radius: var(--uix-radius-pill); }
|
|
8
8
|
.uix-save-status[data-state="idle"] .uix-save-status__icon { display: none; }
|
|
9
9
|
|
|
10
|
-
.uix-save-status[data-state="saving"] .uix-save-status__icon { border: 1px solid var(--uix-border-strong); border-top-color: transparent; animation: uix-spin var(--uix-
|
|
10
|
+
.uix-save-status[data-state="saving"] .uix-save-status__icon { border: 1px solid var(--uix-border-strong); border-top-color: transparent; animation: uix-spin var(--uix-loop-spin) linear infinite; }
|
|
11
11
|
.uix-save-status[data-state="saved"] .uix-save-status__icon { background: var(--uix-success); }
|
|
12
12
|
.uix-save-status[data-state="failed"] { color: var(--uix-danger-text); }
|
|
13
13
|
.uix-save-status[data-state="failed"] .uix-save-status__icon { background: var(--uix-danger); }
|
|
14
14
|
|
|
15
15
|
@media (prefers-reduced-motion: reduce) {
|
|
16
|
-
.uix-save-status[data-state="saving"] .uix-save-status__icon { animation:
|
|
16
|
+
.uix-save-status[data-state="saving"] .uix-save-status__icon { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
background-color: var(--uix-surface); color: var(--uix-text); font: inherit; font-size: var(--uix-text-body); cursor: pointer;
|
|
9
9
|
background-repeat: no-repeat; background-position: right 12px center;
|
|
10
10
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23737373' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
|
11
|
-
transition: border-color var(--uix-dur-fast) var(--uix-ease-out)
|
|
11
|
+
transition: border-color var(--uix-dur-fast) var(--uix-ease-out);
|
|
12
12
|
}
|
|
13
13
|
.uix-select:hover { border-color: var(--uix-border-strong); }
|
|
14
14
|
.uix-select:focus { outline: none; border-color: var(--uix-ring); box-shadow: 0 0 0 3px var(--uix-brand-muted); }
|
|
@@ -40,11 +40,16 @@
|
|
|
40
40
|
.uix-navitem[aria-current="page"] .uix-navitem__desc { color: var(--uix-text-hushed); }
|
|
41
41
|
/* on the active tint, muted badge dips below AA — hushed composites darker on the tint */
|
|
42
42
|
.uix-navitem[aria-current="page"] .uix-navitem__badge { color: var(--uix-text-hushed); }
|
|
43
|
-
.uix-navitem__star { position: relative; display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs);
|
|
43
|
+
.uix-navitem__star { position: relative; display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
|
|
44
44
|
/* invisible halo → 24px effective target with zero visual change (UIX-A11Y-2) */
|
|
45
45
|
.uix-navitem__star::before { content: ""; position: absolute; inset: -1px; }
|
|
46
46
|
.uix-navitem__star svg { width: 15px; height: 15px; }
|
|
47
|
-
|
|
47
|
+
/* Hidden until hover only where hover exists; a touch screen always shows the star. */
|
|
48
|
+
@media (hover: hover) and (pointer: fine) {
|
|
49
|
+
.uix-navitem__star { opacity: 0; }
|
|
50
|
+
.uix-navitem:hover .uix-navitem__star { opacity: 1; }
|
|
51
|
+
}
|
|
52
|
+
.uix-navitem:focus-within .uix-navitem__star, .uix-navitem__star:focus-visible { opacity: 1; }
|
|
48
53
|
.uix-navitem__star[data-on] { opacity: 1; color: var(--uix-warning); }
|
|
49
54
|
.uix-navitem__star[data-on] svg { fill: currentColor; }
|
|
50
55
|
|
|
@@ -64,9 +69,12 @@
|
|
|
64
69
|
margin-left: auto; display: inline-flex; height: 20px; width: 20px; flex-shrink: 0;
|
|
65
70
|
align-items: center; justify-content: center; border: 0; border-radius: calc(var(--uix-radius-xs) / 2);
|
|
66
71
|
background: transparent; cursor: pointer; color: var(--uix-text-muted);
|
|
67
|
-
|
|
72
|
+
transition: opacity var(--uix-dur-fast) var(--uix-ease-out);
|
|
73
|
+
}
|
|
74
|
+
@media (hover: hover) and (pointer: fine) {
|
|
75
|
+
.uix-favourites__menu-trigger { opacity: 0; }
|
|
76
|
+
.uix-favourites__row:hover .uix-favourites__menu-trigger { opacity: 1; }
|
|
68
77
|
}
|
|
69
|
-
.uix-favourites__row:hover .uix-favourites__menu-trigger,
|
|
70
78
|
.uix-favourites__row:focus-within .uix-favourites__menu-trigger,
|
|
71
79
|
.uix-favourites__menu-trigger[aria-expanded="true"] { opacity: 1; }
|
|
72
80
|
.uix-favourites__backdrop { position: fixed; inset: 0; cursor: default; background: transparent; z-index: calc(var(--uix-z-tooltip) + 10); }
|
|
@@ -91,12 +99,12 @@
|
|
|
91
99
|
.uix-navgroup__trigger .uix-navgroup__chevron { margin-left: auto; transition: transform var(--uix-dur) var(--uix-ease-out); }
|
|
92
100
|
.uix-navgroup__trigger[aria-expanded="false"] .uix-navgroup__chevron { transform: rotate(-90deg); }
|
|
93
101
|
.uix-navgroup__chevron { width: var(--uix-icon-sm); height: var(--uix-icon-sm); }
|
|
94
|
-
|
|
102
|
+
/* A nav group opens and closes instantly: it is toggled many times a day, and grid tracks never
|
|
103
|
+
animate. The chevron still turns, so the change is visible. */
|
|
104
|
+
.uix-navgroup__panel { display: grid; grid-template-rows: 1fr; }
|
|
95
105
|
.uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel { grid-template-rows: 0fr; }
|
|
96
|
-
/* visibility keeps the 0fr-collapsed links out of the tab order / accessibility tree
|
|
97
|
-
|
|
98
|
-
visibility snaps back to visible instantly on expand, so nothing visibly glitches. */
|
|
99
|
-
.uix-navgroup__panel > div { overflow: hidden; visibility: visible; transition: visibility var(--uix-dur) var(--uix-ease-out); }
|
|
106
|
+
/* visibility keeps the 0fr-collapsed links out of the tab order / accessibility tree (UIX-A11Y-2) */
|
|
107
|
+
.uix-navgroup__panel > div { overflow: hidden; visibility: visible; }
|
|
100
108
|
.uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel > div { visibility: hidden; }
|
|
101
109
|
.uix-subitem { padding-left: var(--uix-space-5); }
|
|
102
110
|
.uix-subitem .uix-navitem__label::before { content: ""; display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--uix-text-muted); margin-right: var(--uix-space-3); vertical-align: middle; }
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* uix spinner + progress overlay — depends only on --uix-* tokens. */
|
|
2
2
|
@layer uix.components {
|
|
3
|
-
.uix-spinner { width: 20px; height: 20px; border: 2px solid var(--uix-border-strong); border-right-color: transparent; border-radius: 50%; display: inline-block; animation: uix-spin
|
|
3
|
+
.uix-spinner { width: 20px; height: 20px; border: 2px solid var(--uix-border-strong); border-right-color: transparent; border-radius: 50%; display: inline-block; animation: uix-spin var(--uix-loop-spin) linear infinite; }
|
|
4
|
+
/* reduced motion: the ring stops turning and breathes instead, so "still working" survives */
|
|
5
|
+
@media (prefers-reduced-motion: reduce) { .uix-spinner { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; } }
|
|
4
6
|
.uix-spinner--accent { border-color: var(--uix-accent); border-right-color: transparent; }
|
|
5
7
|
.uix-spinner--lg { width: 32px; height: 32px; border-width: 3px; }
|
|
6
8
|
/* HAR-1606: inline, beside a file name or inside a 24 px toggle; the 2 px stroke is kept. */
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
.uix-empty__icon--warning { background: var(--uix-warning-bg); color: var(--uix-warning-text); }
|
|
14
14
|
.uix-stack--compact { gap: var(--uix-space-2); }
|
|
15
15
|
|
|
16
|
-
.uix-skeleton { background: linear-gradient(90deg, var(--uix-bg-subtle) 25%, var(--uix-bg-hover) 50%, var(--uix-bg-subtle) 75%); background-size: 200% 100%; animation: uix-shimmer
|
|
16
|
+
.uix-skeleton { background: linear-gradient(90deg, var(--uix-bg-subtle) 25%, var(--uix-bg-hover) 50%, var(--uix-bg-subtle) 75%); background-size: 200% 100%; animation: uix-shimmer var(--uix-loop-shimmer) linear infinite; border-radius: var(--uix-radius-sm); }
|
|
17
|
+
@media (prefers-reduced-motion: reduce) { .uix-skeleton { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; } }
|
|
17
18
|
.uix-skeleton--text { height: 12px; border-radius: var(--uix-radius-pill); }
|
|
18
19
|
.uix-skeleton--circle { border-radius: 50%; }
|
|
19
20
|
.uix-operation { display: grid; gap: var(--uix-space-3); padding: var(--uix-space-4); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); background: var(--uix-surface); }
|