@attrus-ds/core 0.1.0 → 0.2.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/README.md +80 -8
- package/dist/css/components/buttons.css +1 -1
- package/dist/css/components/combobox.css +17 -1
- package/dist/css/components/inputs.css +3 -55
- package/dist/css/components/overlays.css +28 -59
- package/dist/css/components/primitives.css +10 -1
- package/dist/css/components/sidebar.css +3 -3
- package/dist/css/components/smart-search.css +91 -0
- package/dist/css/components/table.css +10 -8
- package/dist/css/components/tabs.css +2 -2
- package/dist/css/components/toast.css +4 -0
- package/dist/css/components/tooltip.css +5 -0
- package/dist/css/index.css +1 -0
- package/dist/css/tokens.css +100 -96
- package/dist/react/AppSidebar/AppSidebar.d.ts +50 -0
- package/dist/react/AppSidebar/AppSidebar.tsx +197 -0
- package/dist/react/AppTopbar/AppTopbar.d.ts +58 -0
- package/dist/react/AppTopbar/AppTopbar.tsx +203 -0
- package/dist/react/Atoms/Atoms.d.ts +149 -0
- package/dist/react/Atoms/Atoms.tsx +407 -0
- package/dist/react/Button/Button.d.ts +25 -0
- package/dist/react/Button/Button.tsx +83 -0
- package/dist/react/Callout/Callout.d.ts +29 -0
- package/dist/react/Callout/Callout.tsx +98 -0
- package/dist/react/Card/Card.d.ts +38 -0
- package/dist/react/Card/Card.tsx +93 -0
- package/dist/react/Combobox/Combobox.d.ts +52 -0
- package/dist/react/Combobox/Combobox.tsx +254 -0
- package/dist/react/DataTable/DataTable.d.ts +81 -0
- package/dist/react/DataTable/DataTable.tsx +308 -0
- package/dist/react/Drawer/Drawer.d.ts +35 -0
- package/dist/react/Drawer/Drawer.tsx +226 -0
- package/dist/react/Input/Input.d.ts +155 -0
- package/dist/react/Input/Input.tsx +478 -0
- package/dist/react/Modal/Modal.d.ts +27 -0
- package/dist/react/Modal/Modal.tsx +173 -0
- package/dist/react/NumberInput/NumberInput.d.ts +25 -0
- package/dist/react/NumberInput/NumberInput.tsx +117 -0
- package/dist/react/Pill/Pill.d.ts +31 -0
- package/dist/react/Pill/Pill.tsx +104 -0
- package/dist/react/SearchPill/SearchPill.d.ts +14 -0
- package/dist/react/SearchPill/SearchPill.tsx +40 -0
- package/dist/react/SmartSearch/SmartSearch.d.ts +65 -0
- package/dist/react/SmartSearch/SmartSearch.tsx +271 -0
- package/dist/react/Stepper/Stepper.d.ts +25 -0
- package/dist/react/Stepper/Stepper.tsx +94 -0
- package/dist/react/Tabs/Tabs.d.ts +32 -0
- package/dist/react/Tabs/Tabs.tsx +147 -0
- package/dist/react/Toast/Toast.d.ts +30 -0
- package/dist/react/Toast/Toast.tsx +94 -0
- package/dist/react/Tooltip/Tooltip.d.ts +23 -0
- package/dist/react/Tooltip/Tooltip.tsx +80 -0
- package/dist/react/ZeroState/ZeroState.d.ts +17 -0
- package/dist/react/ZeroState/ZeroState.tsx +45 -0
- package/dist/react/index.ts +35 -0
- package/dist/tokens/attrus-tokens.flat.json +1 -1
- package/dist/tokens/attrus-tokens.json +1 -1
- package/package.json +20 -2
package/README.md
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# @attrus-ds/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The **ATTRUS / Cabiros** design system, packaged for npm.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
The CSS is the single visual source of truth — design tokens, component styles,
|
|
6
|
+
brand assets and self-hosted fonts. On top of that, an **optional typed React
|
|
7
|
+
layer** ships as source (TSX + `.d.ts`) under `@attrus-ds/core/react`; it only
|
|
8
|
+
composes the canonical class names, so the CSS-only / markup path stays fully
|
|
9
|
+
valid. No application screens are included.
|
|
8
10
|
|
|
9
11
|
What's inside:
|
|
10
12
|
|
|
11
13
|
- **Design tokens** — colors, typography, spacing, radii, shadows, motion, data-viz (CSS custom properties + JSON).
|
|
12
|
-
- **Component styles** — ready-to-use CSS for buttons, inputs, tables, pills, tabs, cards, callouts, overlays and more.
|
|
14
|
+
- **Component styles** — ready-to-use CSS for buttons, inputs, tables, pills, tabs, cards, callouts, overlays, smart-search and more.
|
|
15
|
+
- **React components** — 20 typed wrappers (Button, Pill, Card, DataTable, Combobox, SmartSearch, Modal, Drawer, AppSidebar…), shipped as source under `@attrus-ds/core/react`. `react` is an optional peer dependency.
|
|
13
16
|
- **Brand assets** — logos, icons and country flags (SVG).
|
|
14
17
|
- **Fonts** — Lato and JetBrains Mono, self-hosted (`.woff2`, no CDN).
|
|
15
18
|
|
|
@@ -74,8 +77,38 @@ import "@attrus-ds/core/components/table.css";
|
|
|
74
77
|
Available component stylesheets:
|
|
75
78
|
|
|
76
79
|
`buttons` · `callout` · `cards` · `combobox` · `empty-states` · `inputs` ·
|
|
77
|
-
`number-input` · `overlays` · `primitives` · `sidebar` · `
|
|
78
|
-
`stepper` · `table` · `tabs` · `toast` · `tooltip` · `topbar`
|
|
80
|
+
`number-input` · `overlays` · `primitives` · `sidebar` · `smart-search` ·
|
|
81
|
+
`status-pills` · `stepper` · `table` · `tabs` · `toast` · `tooltip` · `topbar`
|
|
82
|
+
|
|
83
|
+
### React components
|
|
84
|
+
|
|
85
|
+
The typed React layer is shipped as TSX source under `@attrus-ds/core/react`.
|
|
86
|
+
Your bundler/toolchain compiles it; `react` (>= 18) is an optional peer
|
|
87
|
+
dependency. Import the styles once at your app root, then the components:
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
import "@attrus-ds/core/css"; // styles (once, at the root)
|
|
91
|
+
import { Button, Pill, DataTable } from "@attrus-ds/core/react";
|
|
92
|
+
|
|
93
|
+
export function Example() {
|
|
94
|
+
return <Button variant="primary" size="sm">New transaction</Button>;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Each component is also importable on its own path:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
import { Button } from "@attrus-ds/core/react/Button/Button";
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The CSS stays the single visual source of truth — these wrappers add a typed API
|
|
105
|
+
and compose the same canonical classes (`.btn btn-primary`, `.pill success`, …),
|
|
106
|
+
so plain HTML consumers and React consumers render identically.
|
|
107
|
+
|
|
108
|
+
Component roster: `Button` · `Pill` · `Callout` · `Tabs` · `Input` ·
|
|
109
|
+
`SearchPill` · `Card` · `DataTable` · `Atoms` (Money/Metric/Avatar/Eyebrow/Flag/
|
|
110
|
+
Divider…) · `Stepper` · `NumberInput` · `Combobox` · `SmartSearch` · `Toast` ·
|
|
111
|
+
`Tooltip` · `ZeroState` · `Modal` · `Drawer` · `AppSidebar` · `AppTopbar`.
|
|
79
112
|
|
|
80
113
|
### Fonts
|
|
81
114
|
|
|
@@ -108,8 +141,31 @@ for additive changes, `major` for breaking token/API changes.
|
|
|
108
141
|
|
|
109
142
|
## Local development
|
|
110
143
|
|
|
144
|
+
Source lives under `src/`, organized by concern:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
src/
|
|
148
|
+
├── index.css # dev entry — fonts + tokens + typography + components
|
|
149
|
+
├── tokens/ # design tokens, split by concern (3-layer architecture)
|
|
150
|
+
│ ├── index.css # barrel (cascade order)
|
|
151
|
+
│ ├── palette.css # layer 1 — raw, theme-agnostic primitives
|
|
152
|
+
│ ├── color-semantic.css # layer 2 — semantic color roles (components consume these)
|
|
153
|
+
│ ├── gradients.css · data-viz.css · glass.css
|
|
154
|
+
│ ├── radius.css · elevation.css · spacing.css · iconography.css · motion.css
|
|
155
|
+
│ ├── typography.css # type scale / weights / line-height / tracking tokens
|
|
156
|
+
│ └── theme-dark.css # [data-theme="dark"] semantic overrides
|
|
157
|
+
├── typography/index.css # ready-to-use type classes + text utilities
|
|
158
|
+
├── components/ # one stylesheet per component domain (+ index.css barrel)
|
|
159
|
+
└── react/ # typed React layer — one folder per component
|
|
160
|
+
├── index.ts # barrel re-exporting every component
|
|
161
|
+
└── <Name>/<Name>.tsx + <Name>.d.ts
|
|
162
|
+
```
|
|
163
|
+
|
|
111
164
|
The published artifact is assembled into `dist/` by a dependency-free Node
|
|
112
|
-
script
|
|
165
|
+
script (`scripts/build.mjs`). The token partials are concatenated into a single
|
|
166
|
+
`dist/css/tokens.css`, the component CSS is copied per-file, and the React
|
|
167
|
+
sources are copied verbatim to `dist/react/` (no compilation — consumers build
|
|
168
|
+
them), so consumer import paths are unchanged.
|
|
113
169
|
|
|
114
170
|
```bash
|
|
115
171
|
npm install
|
|
@@ -117,6 +173,22 @@ npm run build # writes dist/
|
|
|
117
173
|
npm pack # inspect the tarball before publishing
|
|
118
174
|
```
|
|
119
175
|
|
|
176
|
+
### Components showcase
|
|
177
|
+
|
|
178
|
+
`preview/components.html` is the design-system home — a navigable index of foundations, components, brand assets and package entry points (same structure as the Cabiros `design-system.html`).
|
|
179
|
+
|
|
180
|
+
Each component has a dedicated spec page under `preview/` (e.g. `buttons.html`, `inputs.html`) with anatomy, variants, states, composition, don'ts, accessibility and token tables.
|
|
181
|
+
|
|
182
|
+
`preview/gallery.html` is a compact live-specimen reference — useful for quick visual checks, but not the full documentation.
|
|
183
|
+
|
|
184
|
+
Build first, then open the home page in a browser:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm run build
|
|
188
|
+
node scripts/port-preview.mjs # re-sync spec pages from cabiros when upstream changes
|
|
189
|
+
# then open preview/components.html
|
|
190
|
+
```
|
|
191
|
+
|
|
120
192
|
## License
|
|
121
193
|
|
|
122
194
|
See [LICENSE](LICENSE). Bundled fonts (Lato, JetBrains Mono) are distributed
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
border-color: var(--color-feedback-danger-border);
|
|
207
207
|
}
|
|
208
208
|
.btn-danger-outline:hover { background: var(--color-feedback-danger-background); border-color: var(--color-danger-500); }
|
|
209
|
-
.btn-danger-outline:active { background: color-mix(in srgb, var(--color-feedback-danger-background)
|
|
209
|
+
.btn-danger-outline:active { background: color-mix(in srgb, var(--color-feedback-danger-background) 85%, var(--color-danger-500)); }
|
|
210
210
|
.btn-danger-outline:focus-visible { box-shadow: var(--shadow-focus-danger); }
|
|
211
211
|
|
|
212
212
|
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
background: var(--color-background-hover);
|
|
172
172
|
}
|
|
173
173
|
.combobox-option.is-selected {
|
|
174
|
-
background: var(--color-
|
|
174
|
+
background: var(--color-background-selected);
|
|
175
175
|
color: var(--color-foreground-accent);
|
|
176
176
|
font-weight: var(--w-semibold);
|
|
177
177
|
}
|
|
@@ -296,6 +296,22 @@
|
|
|
296
296
|
box-shadow: 0 0 0 3px var(--color-feedback-danger-background);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
|
|
300
|
+
/* ----------------------------------------------------------------
|
|
301
|
+
LISTING POPOVER EXTRAS — optional rows inside the popover:
|
|
302
|
+
filter-chip row (below search), results meta (above list),
|
|
303
|
+
foot meta (below list). Exposed via Combobox props
|
|
304
|
+
`filters` / `meta` / `footMeta`.
|
|
305
|
+
---------------------------------------------------------------- */
|
|
306
|
+
.combobox-filters { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-3); border-bottom: 1px solid var(--color-border-subtle); }
|
|
307
|
+
.combobox-filter-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px var(--space-3); background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-pill); font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: var(--w-medium); color: var(--color-foreground-secondary); cursor: pointer; transition: var(--transition-fast); }
|
|
308
|
+
.combobox-filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); color: var(--color-foreground-default); }
|
|
309
|
+
.combobox-filter-chip.is-active { background: var(--color-background-selected); border-color: var(--color-brand-secondary-200); color: var(--color-foreground-brand); font-weight: var(--w-semibold); }
|
|
310
|
+
.combobox-filter-chip .count { font-family: var(--font-mono); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
|
|
311
|
+
.combobox-filter-chip.is-active .count { color: var(--color-brand-secondary-600); }
|
|
312
|
+
.combobox-meta { padding: var(--space-2) var(--space-3) var(--space-1); font-size: var(--fs-xxs); font-weight: var(--w-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); border-bottom: 1px solid var(--color-border-subtle); }
|
|
313
|
+
.combobox-foot-meta { padding: var(--space-2) var(--space-3); font-size: var(--fs-xs); color: var(--color-foreground-muted); border-top: 1px solid var(--color-border-subtle); }
|
|
314
|
+
|
|
299
315
|
/* Reduced motion */
|
|
300
316
|
@media (prefers-reduced-motion: reduce) {
|
|
301
317
|
.combobox-chevron { transition: none; }
|
|
@@ -455,59 +455,7 @@ textarea.input.input-lg { height: auto; min-height: 120px; padding: var(--space-
|
|
|
455
455
|
}
|
|
456
456
|
|
|
457
457
|
|
|
458
|
-
/*
|
|
459
|
-
10. NUMBER INPUT (with +/- buttons)
|
|
460
|
-
---------------------------------------------------------------- */
|
|
461
|
-
.number-input {
|
|
462
|
-
display: inline-flex;
|
|
463
|
-
align-items: stretch;
|
|
464
|
-
height: 40px;
|
|
465
|
-
border: 1px solid var(--color-border-default);
|
|
466
|
-
border-radius: var(--radius-sm);
|
|
467
|
-
background: var(--color-background-surface);
|
|
468
|
-
overflow: hidden;
|
|
469
|
-
transition:
|
|
470
|
-
border-color var(--transition-fast),
|
|
471
|
-
box-shadow var(--transition-fast);
|
|
472
|
-
}
|
|
473
|
-
.number-input:focus-within {
|
|
474
|
-
border-color: var(--color-border-focus);
|
|
475
|
-
box-shadow: var(--shadow-focus);
|
|
476
|
-
}
|
|
477
|
-
.number-input button {
|
|
478
|
-
width: 36px;
|
|
479
|
-
border: 0;
|
|
480
|
-
background: var(--color-background-subtle);
|
|
481
|
-
color: var(--color-foreground-default);
|
|
482
|
-
cursor: pointer;
|
|
483
|
-
display: inline-flex;
|
|
484
|
-
align-items: center;
|
|
485
|
-
justify-content: center;
|
|
486
|
-
font-family: var(--font-sans);
|
|
487
|
-
font-size: var(--fs-md);
|
|
488
|
-
font-weight: var(--w-semibold);
|
|
489
|
-
transition: background var(--transition-fast);
|
|
490
|
-
}
|
|
491
|
-
.number-input button:hover { background: var(--color-background-hover); }
|
|
492
|
-
.number-input button:active { background: var(--color-background-press); }
|
|
493
|
-
.number-input button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
494
|
-
.number-input button.minus { border-right: 1px solid var(--color-border-default); }
|
|
495
|
-
.number-input button.plus { border-left: 1px solid var(--color-border-default); }
|
|
496
|
-
.number-input > input {
|
|
497
|
-
width: 64px;
|
|
498
|
-
border: 0;
|
|
499
|
-
outline: none;
|
|
500
|
-
text-align: center;
|
|
501
|
-
font-family: var(--font-mono);
|
|
502
|
-
font-size: var(--fs-md);
|
|
503
|
-
font-weight: var(--w-semibold);
|
|
504
|
-
background: transparent;
|
|
505
|
-
color: var(--color-foreground-default);
|
|
506
|
-
-moz-appearance: textfield;
|
|
507
|
-
}
|
|
508
|
-
.number-input > input::-webkit-outer-spin-button,
|
|
509
|
-
.number-input > input::-webkit-inner-spin-button { appearance: none; margin: 0; }
|
|
510
|
-
|
|
458
|
+
/* (NUMBER INPUT moved to number-input.css — canonical single source) */
|
|
511
459
|
|
|
512
460
|
/* ----------------------------------------------------------------
|
|
513
461
|
11. OTP — one-time password digit cells
|
|
@@ -927,12 +875,12 @@ textarea.input.input-lg { height: auto; min-height: 120px; padding: var(--space-
|
|
|
927
875
|
}
|
|
928
876
|
.slider::-webkit-slider-runnable-track {
|
|
929
877
|
height: 4px;
|
|
930
|
-
background: var(--color-
|
|
878
|
+
background: var(--color-border-default);
|
|
931
879
|
border-radius: var(--radius-pill);
|
|
932
880
|
}
|
|
933
881
|
.slider::-moz-range-track {
|
|
934
882
|
height: 4px;
|
|
935
|
-
background: var(--color-
|
|
883
|
+
background: var(--color-border-default);
|
|
936
884
|
border-radius: var(--radius-pill);
|
|
937
885
|
}
|
|
938
886
|
.slider::-webkit-slider-thumb {
|
|
@@ -186,76 +186,27 @@
|
|
|
186
186
|
opacity var(--duration-slower) var(--ease-standard);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
/* Right (default).
|
|
190
|
-
--drawer-w drives both the width AND stack offsets so size variants
|
|
191
|
-
automatically scale the stacking math. --drawer-offset shifts the panel
|
|
192
|
-
inward when stacked behind another drawer. */
|
|
189
|
+
/* Right (default). --drawer-w drives the width per size variant. */
|
|
193
190
|
.drawer-right {
|
|
194
|
-
--drawer-w: min(440px, 90vw);
|
|
195
|
-
--drawer-offset: 0px;
|
|
191
|
+
--drawer-w: min(440px, 90vw); /* @kind spacing */
|
|
196
192
|
top: 0; right: 0; bottom: 0;
|
|
197
193
|
width: var(--drawer-w);
|
|
198
194
|
border-top-left-radius: var(--radius-xs);
|
|
199
195
|
border-bottom-left-radius: var(--radius-xs);
|
|
200
196
|
transform: translateX(100%);
|
|
201
197
|
}
|
|
202
|
-
.drawer-right.is-open { transform: translateX(
|
|
198
|
+
.drawer-right.is-open { transform: translateX(0); }
|
|
203
199
|
|
|
204
200
|
/* Left */
|
|
205
201
|
.drawer-left {
|
|
206
|
-
--drawer-w: min(320px, 85vw);
|
|
207
|
-
--drawer-offset: 0px;
|
|
202
|
+
--drawer-w: min(320px, 85vw); /* @kind spacing */
|
|
208
203
|
top: 0; left: 0; bottom: 0;
|
|
209
204
|
width: var(--drawer-w);
|
|
210
205
|
border-top-right-radius: var(--radius-xs);
|
|
211
206
|
border-bottom-right-radius: var(--radius-xs);
|
|
212
207
|
transform: translateX(-100%);
|
|
213
208
|
}
|
|
214
|
-
.drawer-left.is-open { transform: translateX(
|
|
215
|
-
|
|
216
|
-
/* =================== STACKED DRAWERS ===================
|
|
217
|
-
Open a second drawer alongside the first instead of replacing it.
|
|
218
|
-
--drawer-stack = how many slots inward to shift; 0 = frontmost panel.
|
|
219
|
-
Slot width derived from --drawer-w so size variants stack correctly.
|
|
220
|
-
Cap at 3 stacked panels for screens ≥1280px; 2 below.
|
|
221
|
-
Usage: <aside class="drawer drawer-right drawer-md" data-stack="1"> */
|
|
222
|
-
.drawer-right[data-stack="1"], .drawer-left[data-stack="1"] { --drawer-offset: var(--drawer-w); }
|
|
223
|
-
.drawer-right[data-stack="2"], .drawer-left[data-stack="2"] { --drawer-offset: calc(var(--drawer-w) * 2); }
|
|
224
|
-
.drawer-right[data-stack="3"], .drawer-left[data-stack="3"] { --drawer-offset: calc(var(--drawer-w) * 3); }
|
|
225
|
-
|
|
226
|
-
/* Stacked panels lose their inner radius — they butt up against a sibling.
|
|
227
|
-
Separator is placed on the edge that TOUCHES the adjacent panel.
|
|
228
|
-
`:has(~)` only matches FOLLOWING siblings, so we apply rules from the
|
|
229
|
-
panel that comes EARLIER in the DOM (the back panel, which is rendered
|
|
230
|
-
before the front panel in modal-drawer.html). */
|
|
231
|
-
|
|
232
|
-
/* Back panel (stack ≥ 1): when followed by an open front panel,
|
|
233
|
-
only flatten the INNER edge (right side) and add separator there.
|
|
234
|
-
Outer edge (left side) keeps the rounded corners. */
|
|
235
|
-
.drawer-right[data-stack]:not([data-stack="0"]).is-open:has(~ .drawer-right[data-stack="0"].is-open) {
|
|
236
|
-
border-top-right-radius: 0;
|
|
237
|
-
border-bottom-right-radius: 0;
|
|
238
|
-
border-right: 2px solid var(--color-border-default);
|
|
239
|
-
}
|
|
240
|
-
.drawer-left[data-stack]:not([data-stack="0"]).is-open:has(~ .drawer-left[data-stack="0"].is-open) {
|
|
241
|
-
border-top-left-radius: 0;
|
|
242
|
-
border-bottom-left-radius: 0;
|
|
243
|
-
border-left: 2px solid var(--color-border-default);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* Front panel (stack=0): when PRECEDED by an open back panel, flatten
|
|
247
|
-
the inner-side radius and add the matching separator. Use the parent's
|
|
248
|
-
`:has` to detect the configuration, then target the front. */
|
|
249
|
-
:has(> .drawer-right[data-stack]:not([data-stack="0"]).is-open) > .drawer-right[data-stack="0"].is-open {
|
|
250
|
-
border-top-left-radius: 0;
|
|
251
|
-
border-bottom-left-radius: 0;
|
|
252
|
-
border-left: 2px solid var(--color-border-default);
|
|
253
|
-
}
|
|
254
|
-
:has(> .drawer-left[data-stack]:not([data-stack="0"]).is-open) > .drawer-left[data-stack="0"].is-open {
|
|
255
|
-
border-top-right-radius: 0;
|
|
256
|
-
border-bottom-right-radius: 0;
|
|
257
|
-
border-right: 2px solid var(--color-border-default);
|
|
258
|
-
}
|
|
209
|
+
.drawer-left.is-open { transform: translateX(0); }
|
|
259
210
|
|
|
260
211
|
/* Bottom */
|
|
261
212
|
.drawer-bottom {
|
|
@@ -267,11 +218,11 @@
|
|
|
267
218
|
}
|
|
268
219
|
.drawer-bottom.is-open { transform: translateY(0); }
|
|
269
220
|
|
|
270
|
-
/* Drawer sizes (right/left) — feed --drawer-w so
|
|
271
|
-
.drawer-sm { --drawer-w: min(360px, 90vw); width: var(--drawer-w); }
|
|
272
|
-
.drawer-md { --drawer-w: min(440px, 90vw); width: var(--drawer-w); }
|
|
273
|
-
.drawer-lg { --drawer-w: min(560px, 92vw); width: var(--drawer-w); }
|
|
274
|
-
.drawer-xl { --drawer-w: min(720px, 94vw); width: var(--drawer-w); }
|
|
221
|
+
/* Drawer sizes (right/left) — feed --drawer-w so widths scale per variant */
|
|
222
|
+
.drawer-sm { --drawer-w: min(360px, 90vw); /* @kind spacing */ width: var(--drawer-w); }
|
|
223
|
+
.drawer-md { --drawer-w: min(440px, 90vw); /* @kind spacing */ width: var(--drawer-w); }
|
|
224
|
+
.drawer-lg { --drawer-w: min(560px, 92vw); /* @kind spacing */ width: var(--drawer-w); }
|
|
225
|
+
.drawer-xl { --drawer-w: min(720px, 94vw); /* @kind spacing */ width: var(--drawer-w); }
|
|
275
226
|
|
|
276
227
|
/* Drawer parts (mirror modal vocabulary).
|
|
277
228
|
Header and footer are STICKY with a liquid-glass background: body
|
|
@@ -326,6 +277,24 @@
|
|
|
326
277
|
transition: var(--transition-fast);
|
|
327
278
|
}
|
|
328
279
|
.drawer-close:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
|
|
280
|
+
|
|
281
|
+
/* Footer aux — left-side total/note when the footer is space-between (footerAux prop) */
|
|
282
|
+
.drawer-footer-aux { font-size: var(--fs-xs); color: var(--color-foreground-muted); min-width: 0; }
|
|
283
|
+
|
|
284
|
+
/* Mobile: footer actions stack full-width (doc §Header & Footer, variant 7) */
|
|
285
|
+
@media (max-width: 560px) {
|
|
286
|
+
.drawer-footer { flex-direction: column; align-items: stretch; gap: var(--space-2); padding-bottom: max(var(--space-4), env(safe-area-inset-bottom)); }
|
|
287
|
+
.drawer-footer .btn { width: 100%; justify-content: center; }
|
|
288
|
+
.drawer-footer-aux { text-align: center; margin-bottom: var(--space-1); }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Dense header — tight chrome for utility drawers (filters) */
|
|
292
|
+
.drawer-header.is-dense { padding: var(--space-3) var(--space-4); }
|
|
293
|
+
.drawer-header.is-dense .drawer-title { font-size: var(--fs-md); }
|
|
294
|
+
|
|
295
|
+
/* Header with a second control row (search pill, tabs) */
|
|
296
|
+
.drawer-header.has-extra { flex-wrap: wrap; }
|
|
297
|
+
.drawer-header > .drawer-header-extra { flex-basis: 100%; min-width: 0; }
|
|
329
298
|
.drawer-close:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
330
299
|
.drawer-close i, .drawer-close svg { width: 18px; height: 18px; stroke-width: var(--icon-stroke); }
|
|
331
300
|
|
|
@@ -177,6 +177,8 @@
|
|
|
177
177
|
color: var(--color-foreground-secondary);
|
|
178
178
|
margin-top: var(--space-1);
|
|
179
179
|
}
|
|
180
|
+
/* Bare stat — figure block without tile chrome, for use inside a Card */
|
|
181
|
+
.stat.is-bare { background: none; border: 0; padding: 0; border-radius: 0; }
|
|
180
182
|
|
|
181
183
|
/* Compact variant — for sidebars / dense headers */
|
|
182
184
|
.stat-compact {
|
|
@@ -275,13 +277,20 @@
|
|
|
275
277
|
}
|
|
276
278
|
.filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
|
|
277
279
|
.filter-chip:active { background: var(--color-background-press); }
|
|
280
|
+
/* Selected (aria-pressed via FilterChip TSX) — same active treatment as combobox filter chips */
|
|
281
|
+
.filter-chip[aria-pressed="true"] {
|
|
282
|
+
background: var(--color-background-selected);
|
|
283
|
+
border-color: var(--color-brand-secondary-200);
|
|
284
|
+
color: var(--color-foreground-brand);
|
|
285
|
+
font-weight: var(--w-semibold);
|
|
286
|
+
}
|
|
278
287
|
.filter-chip .chip-chevron { opacity: .55; }
|
|
279
288
|
|
|
280
289
|
/* =================== PROGRESS BAR =================== */
|
|
281
290
|
/* Slim track + fill. Width of fill is data-driven (set inline). */
|
|
282
291
|
.progress {
|
|
283
292
|
height: var(--progress-h, 6px);
|
|
284
|
-
background: var(--progress-track, var(--color-
|
|
293
|
+
background: var(--progress-track, var(--color-border-default));
|
|
285
294
|
border-radius: var(--radius-pill);
|
|
286
295
|
position: relative;
|
|
287
296
|
overflow: hidden;
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
}
|
|
75
75
|
.sb-item:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
|
|
76
76
|
.sb-item.active {
|
|
77
|
-
background: var(--color-
|
|
78
|
-
color: var(--color-brand
|
|
77
|
+
background: var(--color-background-selected);
|
|
78
|
+
color: var(--color-foreground-brand);
|
|
79
79
|
font-weight: var(--w-semibold);
|
|
80
80
|
}
|
|
81
81
|
.sb-item.active::before {
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
}
|
|
169
169
|
.sb-children .sb-subitem:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
|
|
170
170
|
.sb-children .sb-subitem:hover::before { opacity: 1; background: var(--color-foreground-muted); }
|
|
171
|
-
.sb-children .sb-subitem.active { color: var(--color-brand
|
|
171
|
+
.sb-children .sb-subitem.active { color: var(--color-foreground-brand); font-weight: var(--w-semibold); background: var(--color-background-selected); }
|
|
172
172
|
.sb-children .sb-subitem.active::before { background: var(--color-brand-secondary-500); opacity: 1; }
|
|
173
173
|
.sb-children .sb-subitem .count, .sb-children .sb-subitem .sb-count {
|
|
174
174
|
margin-left: auto;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
SMART SEARCH — global command palette (⌘K) shell
|
|
3
|
+
Promoted from combobox.html §03 (2026-06-11): the 8 canonical
|
|
4
|
+
states (inactive · active · word · similar · id · partial-id ·
|
|
5
|
+
no-results · loading · error) compose from these pieces.
|
|
6
|
+
Consumed by the SmartSearch TSX component.
|
|
7
|
+
============================================================ */
|
|
8
|
+
/* Smart-search combobox */
|
|
9
|
+
.ss { width: 100%; max-width: 380px; background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); overflow: hidden; font-size: var(--fs-sm); }
|
|
10
|
+
.ss-input { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-border-subtle); }
|
|
11
|
+
.ss-input.ss-input-flat { border-bottom: 0; }
|
|
12
|
+
.ss-input svg, .ss-input i { width: var(--icon-sm); height: var(--icon-sm); stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); flex-shrink: 0; }
|
|
13
|
+
.ss-input input { flex: 1; border: 0; outline: 0; background: transparent; font: inherit; color: var(--color-foreground-default); }
|
|
14
|
+
.ss-input input::placeholder { color: var(--color-foreground-placeholder); }
|
|
15
|
+
.ss-clear { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border: 0; padding: 0; border-radius: var(--radius-pill); background: transparent; color: var(--color-foreground-muted); cursor: pointer; }
|
|
16
|
+
.ss-clear:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
|
|
17
|
+
.ss-clear svg, .ss-clear i { width: 12px; height: 12px; }
|
|
18
|
+
|
|
19
|
+
.ss-section { padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--color-border-subtle); }
|
|
20
|
+
.ss-section:last-of-type { border-bottom: 0; }
|
|
21
|
+
.ss-section-label { font-size: var(--fs-xxs); font-weight: var(--w-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); padding: 0 var(--space-2); margin-bottom: var(--space-2); }
|
|
22
|
+
|
|
23
|
+
/* Suggestion chips (active state) */
|
|
24
|
+
.ss-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 0 var(--space-2); }
|
|
25
|
+
.ss-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px var(--space-3); background: var(--color-background-canvas); border: 1px solid var(--color-border-default); border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: var(--w-medium); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); }
|
|
26
|
+
.ss-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
|
|
27
|
+
.ss-chip svg, .ss-chip i { width: 11px; height: 11px; stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); }
|
|
28
|
+
|
|
29
|
+
/* List rows */
|
|
30
|
+
.ss-list { list-style: none; margin: 0; padding: 0; }
|
|
31
|
+
.ss-list-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); cursor: pointer; transition: var(--transition-fast); }
|
|
32
|
+
.ss-list-item:hover, .ss-list-item.is-active { background: var(--color-background-hover); }
|
|
33
|
+
.ss-list-item .icon-leading { width: 28px; height: 28px; border-radius: var(--radius-sm); background: var(--color-background-canvas); display: inline-flex; align-items: center; justify-content: center; color: var(--color-foreground-secondary); flex-shrink: 0; }
|
|
34
|
+
.ss-list-item .icon-leading svg, .ss-list-item .icon-leading i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
|
|
35
|
+
.ss-list-item .icon-leading.brand { background: var(--color-brand-secondary-50); color: var(--color-brand-secondary-700); }
|
|
36
|
+
.ss-list-item .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
|
|
37
|
+
.ss-list-item .text .label { font-size: var(--fs-sm); font-weight: var(--w-semibold); color: var(--color-foreground-default); }
|
|
38
|
+
.ss-list-item .text .meta { font-size: var(--fs-xs); color: var(--color-foreground-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
39
|
+
.ss-list-item .icon-trailing { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; flex-shrink: 0; color: var(--color-foreground-muted); }
|
|
40
|
+
.ss-list-item .icon-trailing svg, .ss-list-item .icon-trailing i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
|
|
41
|
+
|
|
42
|
+
/* Recent searches — clock icon + dim text */
|
|
43
|
+
.ss-recent .ss-list-item .icon-leading { background: transparent; border: 0; width: 18px; height: 18px; }
|
|
44
|
+
.ss-recent .ss-list-item .icon-leading svg, .ss-recent .ss-list-item .icon-leading i { width: 13px; height: 13px; color: var(--color-foreground-muted); }
|
|
45
|
+
.ss-recent .ss-list-item .text .label { font-weight: var(--w-regular); color: var(--color-foreground-secondary); }
|
|
46
|
+
|
|
47
|
+
/* Empty/result label */
|
|
48
|
+
.ss-result-label { padding: 0 var(--space-2) var(--space-2); }
|
|
49
|
+
.ss-result-label .l { font-size: var(--fs-xxs); font-weight: var(--w-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); }
|
|
50
|
+
.ss-no-result { padding: 0 var(--space-2); font-size: var(--fs-sm); color: var(--color-foreground-muted); }
|
|
51
|
+
.ss-no-result strong { color: var(--color-foreground-default); font-weight: var(--w-semibold); }
|
|
52
|
+
|
|
53
|
+
/* Tip / hint card (similar match suggestion, ID format hint) */
|
|
54
|
+
.ss-hint { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); background: var(--color-background-subtle); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); margin: var(--space-3) var(--space-2) 0; }
|
|
55
|
+
.ss-hint .icon-leading { color: var(--color-foreground-muted); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; }
|
|
56
|
+
.ss-hint .icon-leading svg, .ss-hint .icon-leading i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
|
|
57
|
+
.ss-hint .body { font-size: var(--fs-sm); color: var(--color-foreground-secondary); line-height: var(--lh-relaxed); }
|
|
58
|
+
.ss-hint .body strong { color: var(--color-foreground-default); font-weight: var(--w-semibold); }
|
|
59
|
+
.ss-hint .body code { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--color-foreground-accent); background: color-mix(in srgb, var(--color-brand-secondary-500) 12%, transparent); padding: 1px var(--space-2); border-radius: var(--radius-xs); }
|
|
60
|
+
|
|
61
|
+
/* ID type-picker buttons */
|
|
62
|
+
.ss-typebtns { display: flex; flex-direction: column; gap: var(--space-2); padding: 0 var(--space-2); }
|
|
63
|
+
.ss-typebtn { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-3); background: var(--color-background-canvas); border: 1px solid var(--color-border-default); border-radius: var(--radius-sm); font-size: var(--fs-sm); font-weight: var(--w-medium); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); text-align: left; width: 100%; }
|
|
64
|
+
.ss-typebtn:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
|
|
65
|
+
.ss-typebtn svg, .ss-typebtn i { width: 16px; height: 16px; stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); }
|
|
66
|
+
.ss-typebtn .grow { flex: 1; }
|
|
67
|
+
.ss-typebtn .chev { color: var(--color-foreground-muted); }
|
|
68
|
+
|
|
69
|
+
/* Loading skeleton + spinner illustration */
|
|
70
|
+
.ss-skeleton { padding: var(--space-3) var(--space-2); display: flex; flex-direction: column; gap: var(--space-3); }
|
|
71
|
+
.ss-skel-row { display: flex; align-items: center; gap: var(--space-3); }
|
|
72
|
+
.ss-skel-circle { width: 28px; height: 28px; border-radius: var(--radius-sm); background: var(--color-border-default); flex-shrink: 0; }
|
|
73
|
+
.ss-skel-bars { flex: 1; display: flex; flex-direction: column; gap: 5px; }
|
|
74
|
+
.ss-skel-bar { height: 8px; border-radius: var(--radius-xs); background: var(--color-border-default); }
|
|
75
|
+
.ss-skel-bar.short { width: 40%; }
|
|
76
|
+
.ss-skel-bar.long { width: 70%; }
|
|
77
|
+
.ss-skel-shimmer { background: linear-gradient(90deg, var(--color-border-default) 0%, var(--color-border-subtle) 50%, var(--color-border-default) 100%); background-size: 200% 100%; animation: skel 1.4s linear infinite; }
|
|
78
|
+
@keyframes skel { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
|
|
79
|
+
|
|
80
|
+
.ss-illo { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); padding: var(--space-7) var(--space-5); text-align: center; }
|
|
81
|
+
.ss-illo svg.illustration { width: 84px; height: 60px; }
|
|
82
|
+
.ss-illo .title { font-size: var(--fs-md); font-weight: var(--w-semibold); color: var(--color-foreground-default); }
|
|
83
|
+
.ss-illo .body { font-size: var(--fs-xs); color: var(--color-foreground-muted); max-width: 32ch; line-height: var(--lh-relaxed); }
|
|
84
|
+
|
|
85
|
+
/* Footer with keyboard shortcuts */
|
|
86
|
+
.ss-foot { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-2) var(--space-3); background: var(--color-background-subtle); border-top: 1px solid var(--color-border-subtle); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
|
|
87
|
+
.ss-foot .kbd-group { display: inline-flex; align-items: center; gap: 4px; }
|
|
88
|
+
kbd.ss-kbd { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 4px; background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-xs); font-family: var(--font-mono); font-size: 10px; font-weight: var(--w-semibold); color: var(--color-foreground-secondary); }
|
|
89
|
+
.ss-foot .sep { width: 1px; height: 12px; background: var(--color-border-default); }
|
|
90
|
+
|
|
91
|
+
|
|
@@ -138,9 +138,9 @@
|
|
|
138
138
|
.dt-pagination .page-btn:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
|
|
139
139
|
.dt-pagination .page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
140
140
|
.dt-pagination .page-btn.is-current {
|
|
141
|
-
background: var(--color-brand-accent-
|
|
142
|
-
border-color: var(--color-brand-accent-
|
|
143
|
-
color: var(--color-
|
|
141
|
+
background: color-mix(in srgb, var(--color-brand-accent-500) 14%, transparent);
|
|
142
|
+
border-color: color-mix(in srgb, var(--color-brand-accent-500) 36%, transparent);
|
|
143
|
+
color: var(--color-foreground-accent);
|
|
144
144
|
}
|
|
145
145
|
.dt-pagination .page-btn > i, .dt-pagination .page-btn > svg,
|
|
146
146
|
.dt-pagination .page-btn > svg { width: 12px; height: 12px; stroke-width: var(--icon-stroke); }
|
|
@@ -218,8 +218,8 @@
|
|
|
218
218
|
.dt tbody tr.is-muted td,
|
|
219
219
|
.dt tbody tr.is-muted .dt-cell-stack > .sub { opacity: 0.55; }
|
|
220
220
|
|
|
221
|
-
.dt tbody tr.is-error { background: color-mix(in srgb, var(--color-danger-
|
|
222
|
-
.dt tbody tr.is-error:hover { background:
|
|
221
|
+
.dt tbody tr.is-error { background: color-mix(in srgb, var(--color-feedback-danger-background) 60%, transparent); }
|
|
222
|
+
.dt tbody tr.is-error:hover { background: var(--color-feedback-danger-background); }
|
|
223
223
|
|
|
224
224
|
|
|
225
225
|
/* ----------------------------------------------------------------
|
|
@@ -437,11 +437,13 @@
|
|
|
437
437
|
display: inline-block;
|
|
438
438
|
height: 12px;
|
|
439
439
|
border-radius: var(--radius-2xs);
|
|
440
|
+
/* theme-aware: border tokens are light-gray hairlines in light and
|
|
441
|
+
white-alpha in dark — raw neutral-50/100 read near-white on ink */
|
|
440
442
|
background:
|
|
441
443
|
linear-gradient(90deg,
|
|
442
|
-
var(--color-
|
|
443
|
-
var(--color-
|
|
444
|
-
var(--color-
|
|
444
|
+
var(--color-border-default) 0%,
|
|
445
|
+
var(--color-border-subtle) 40%,
|
|
446
|
+
var(--color-border-default) 80%);
|
|
445
447
|
background-size: 480px 100%;
|
|
446
448
|
animation: dt-shimmer 1.4s var(--ease-linear) infinite;
|
|
447
449
|
}
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
}
|
|
84
84
|
.tab[aria-selected="true"] .tab-count,
|
|
85
85
|
.tab.is-active .tab-count {
|
|
86
|
-
background: var(--color-brand-accent-
|
|
87
|
-
color: var(--color-
|
|
86
|
+
background: color-mix(in srgb, var(--color-brand-accent-500) 16%, transparent);
|
|
87
|
+
color: var(--color-foreground-accent);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/* Pill tabs — alternative for compact, segmented contexts */
|
|
@@ -130,6 +130,10 @@
|
|
|
130
130
|
to { transform: scaleX(0); }
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/* Auto-dismiss must pause while the user inspects (doc a11y contract) */
|
|
134
|
+
.toast:hover .toast-progress::after,
|
|
135
|
+
.toast:focus-within .toast-progress::after { animation-play-state: paused; }
|
|
136
|
+
|
|
133
137
|
/* ============================================================
|
|
134
138
|
VARIANTS — semantic
|
|
135
139
|
============================================================ */
|
|
@@ -220,6 +220,11 @@
|
|
|
220
220
|
line-height: 1;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/* Esc suppression — hide while focus stays on the target (doc a11y contract).
|
|
224
|
+
The TSX toggles .is-suppressed on Escape; clears on blur / mouse re-enter. */
|
|
225
|
+
.tooltip-target.is-suppressed > .tooltip,
|
|
226
|
+
.tooltip-target.is-suppressed > .tooltip-rich { opacity: 0; pointer-events: none; }
|
|
227
|
+
|
|
223
228
|
/* Reduced motion */
|
|
224
229
|
@media (prefers-reduced-motion: reduce) {
|
|
225
230
|
.tooltip { transition: opacity var(--duration-instant) linear; transform: none !important; transition-delay: 0s !important; }
|
package/dist/css/index.css
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
@import "./components/overlays.css";
|
|
15
15
|
@import "./components/primitives.css";
|
|
16
16
|
@import "./components/sidebar.css";
|
|
17
|
+
@import "./components/smart-search.css";
|
|
17
18
|
@import "./components/status-pills.css";
|
|
18
19
|
@import "./components/stepper.css";
|
|
19
20
|
@import "./components/table.css";
|