@ponchia/ui 0.3.0 → 0.3.2
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 +43 -61
- package/behaviors/index.d.ts +46 -0
- package/behaviors/index.js +575 -6
- package/classes/index.d.ts +53 -1
- package/classes/index.js +58 -4
- package/classes/vscode.css-custom-data.json +407 -0
- package/css/app.css +8 -48
- package/css/base.css +0 -1
- package/css/dots.css +25 -1
- package/css/feedback.css +87 -2
- package/css/forms.css +126 -0
- package/css/overlay.css +64 -1
- package/css/primitives.css +252 -4
- package/css/site.css +16 -2
- package/css/table.css +59 -0
- package/css/tokens.css +69 -21
- package/dist/bronto.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/site.css +1 -1
- package/dist/css/table.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/package.json +13 -7
- package/tokens/index.d.ts +2 -2
- package/tokens/index.js +45 -14
- package/tokens/index.json +90 -28
- package/tokens/tokens.dtcg.json +219 -14
package/css/forms.css
CHANGED
|
@@ -92,6 +92,108 @@
|
|
|
92
92
|
color: var(--danger);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/* --- Input group: prefix/suffix affix around a control --- */
|
|
96
|
+
.ui-input-group {
|
|
97
|
+
display: flex;
|
|
98
|
+
isolation: isolate;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.ui-input-group > .ui-input,
|
|
102
|
+
.ui-input-group > .ui-select {
|
|
103
|
+
border-radius: 0;
|
|
104
|
+
flex: 1;
|
|
105
|
+
margin-inline-start: -1px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.ui-input-group > :first-child {
|
|
109
|
+
border-start-start-radius: var(--radius-md);
|
|
110
|
+
border-end-start-radius: var(--radius-md);
|
|
111
|
+
margin-inline-start: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.ui-input-group > :last-child {
|
|
115
|
+
border-start-end-radius: var(--radius-md);
|
|
116
|
+
border-end-end-radius: var(--radius-md);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.ui-input-group > .ui-input:focus-visible {
|
|
120
|
+
z-index: 1; /* keep the focus ring above the adjacent addon border */
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ui-input-group__addon {
|
|
124
|
+
align-items: center;
|
|
125
|
+
background: var(--panel-soft);
|
|
126
|
+
border: 1px solid var(--line);
|
|
127
|
+
color: var(--text-dim);
|
|
128
|
+
display: flex;
|
|
129
|
+
font-size: var(--text-sm);
|
|
130
|
+
padding-inline: var(--space-sm);
|
|
131
|
+
white-space: nowrap;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* --- File input --- */
|
|
135
|
+
.ui-file {
|
|
136
|
+
color: var(--text-soft);
|
|
137
|
+
font-size: var(--text-sm);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.ui-file::file-selector-button {
|
|
141
|
+
background: var(--panel-soft);
|
|
142
|
+
border: 1px solid var(--line-strong);
|
|
143
|
+
border-radius: var(--radius-md);
|
|
144
|
+
color: var(--text);
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
font: inherit;
|
|
147
|
+
margin-inline-end: var(--space-sm);
|
|
148
|
+
padding: 0.5rem 0.85rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.ui-file::file-selector-button:hover {
|
|
152
|
+
border-color: var(--accent);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* --- Range --- */
|
|
156
|
+
.ui-range {
|
|
157
|
+
accent-color: var(--accent);
|
|
158
|
+
inline-size: 100%;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.ui-range:focus-visible {
|
|
162
|
+
outline: 2px solid var(--focus-ring);
|
|
163
|
+
outline-offset: 4px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* --- Error summary: one focusable, assertive list of form errors --- */
|
|
167
|
+
.ui-error-summary {
|
|
168
|
+
border: 1px solid var(--danger);
|
|
169
|
+
border-radius: var(--radius-md);
|
|
170
|
+
color: var(--text);
|
|
171
|
+
padding: var(--space-md);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.ui-error-summary[hidden] {
|
|
175
|
+
display: none;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.ui-error-summary__title {
|
|
179
|
+
color: var(--danger);
|
|
180
|
+
font-family: var(--display);
|
|
181
|
+
font-size: var(--text-sm);
|
|
182
|
+
font-weight: 700;
|
|
183
|
+
letter-spacing: var(--tracking-wide);
|
|
184
|
+
margin: 0 0 var(--space-xs);
|
|
185
|
+
text-transform: uppercase;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.ui-error-summary__list {
|
|
189
|
+
margin: 0;
|
|
190
|
+
padding-inline-start: var(--space-md);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.ui-error-summary__list a {
|
|
194
|
+
color: var(--danger);
|
|
195
|
+
}
|
|
196
|
+
|
|
95
197
|
/* Search field with leading dot. */
|
|
96
198
|
.ui-search {
|
|
97
199
|
align-items: center;
|
|
@@ -187,6 +289,30 @@
|
|
|
187
289
|
outline-offset: 2px;
|
|
188
290
|
}
|
|
189
291
|
|
|
292
|
+
/* ARIA contract: `.ui-switch` is a visually-styled checkbox. Author
|
|
293
|
+
`role="switch"` on the `<input>` so AT announces "switch, on/off"
|
|
294
|
+
rather than "checkbox, checked" — the native `checked` state then
|
|
295
|
+
drives `aria-checked` automatically, so no JS is required. In
|
|
296
|
+
forced-colors mode the colour cues are dropped by the OS, so convey
|
|
297
|
+
on/off with system-colour border + thumb instead. */
|
|
298
|
+
@media (forced-colors: active) {
|
|
299
|
+
.ui-switch__track {
|
|
300
|
+
border-color: ButtonBorder;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.ui-switch__thumb {
|
|
304
|
+
background: ButtonText;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.ui-switch input:checked + .ui-switch__track {
|
|
308
|
+
border-color: Highlight;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.ui-switch input:checked + .ui-switch__track .ui-switch__thumb {
|
|
312
|
+
background: Highlight;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
190
316
|
/* Checkbox / radio — square accent. */
|
|
191
317
|
.ui-check {
|
|
192
318
|
align-items: center;
|
package/css/overlay.css
CHANGED
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
position: absolute;
|
|
118
118
|
inset-inline-end: 0;
|
|
119
119
|
inset-block-start: calc(100% + 0.4rem);
|
|
120
|
-
z-index:
|
|
120
|
+
z-index: var(--z-overlay);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.ui-menu__label {
|
|
@@ -172,6 +172,69 @@
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
/* --- Combobox: an input with a filtered listbox popup (APG pattern,
|
|
176
|
+
wired by initCombobox). Reuses the menu surface tokens. --- */
|
|
177
|
+
.ui-combobox {
|
|
178
|
+
display: inline-block;
|
|
179
|
+
min-inline-size: 14rem;
|
|
180
|
+
position: relative;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.ui-combobox__input {
|
|
184
|
+
inline-size: 100%;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ui-combobox__list {
|
|
188
|
+
background: var(--panel-strong);
|
|
189
|
+
border: 1px solid var(--line-strong);
|
|
190
|
+
border-radius: var(--radius-md);
|
|
191
|
+
box-shadow: var(--shadow-raised);
|
|
192
|
+
display: grid;
|
|
193
|
+
gap: 1px;
|
|
194
|
+
list-style: none;
|
|
195
|
+
margin: 0;
|
|
196
|
+
max-block-size: 16rem;
|
|
197
|
+
overflow-y: auto;
|
|
198
|
+
padding: 0.3rem;
|
|
199
|
+
position: absolute;
|
|
200
|
+
inset-block-start: calc(100% + 0.4rem);
|
|
201
|
+
inset-inline: 0;
|
|
202
|
+
z-index: var(--z-overlay);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.ui-combobox__list[hidden] {
|
|
206
|
+
display: none;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.ui-combobox__option {
|
|
210
|
+
border-radius: var(--radius-sm);
|
|
211
|
+
color: var(--text-soft);
|
|
212
|
+
cursor: pointer;
|
|
213
|
+
font-family: var(--mono);
|
|
214
|
+
font-size: var(--text-sm);
|
|
215
|
+
padding: 0.5rem 0.55rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ui-combobox__option[hidden] {
|
|
219
|
+
display: none;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.ui-combobox__option.is-active,
|
|
223
|
+
.ui-combobox__option[aria-selected='true'] {
|
|
224
|
+
background: var(--bg-accent);
|
|
225
|
+
color: var(--text);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.ui-combobox__empty {
|
|
229
|
+
color: var(--text-dim);
|
|
230
|
+
font-size: var(--text-2xs);
|
|
231
|
+
padding: 0.5rem 0.55rem;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.ui-combobox__empty[hidden] {
|
|
235
|
+
display: none;
|
|
236
|
+
}
|
|
237
|
+
|
|
175
238
|
/* --- Mobile: modal becomes a bottom sheet, drawer goes full-width --- */
|
|
176
239
|
|
|
177
240
|
@media (max-width: 560px) {
|
package/css/primitives.css
CHANGED
|
@@ -27,6 +27,75 @@
|
|
|
27
27
|
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min, 16rem)), 1fr));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/* Every-Layout set — the layouts consumers otherwise hand-roll. All
|
|
31
|
+
intrinsic (no media queries): they respond to content + available
|
|
32
|
+
space, so they work the same in a viewport or a container. */
|
|
33
|
+
|
|
34
|
+
/* Sidebar + main; the sidebar is its natural width, main takes the
|
|
35
|
+
rest, and they stack once main would go below --sidebar-min. */
|
|
36
|
+
.ui-sidebar {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-wrap: wrap;
|
|
39
|
+
gap: var(--sidebar-gap, var(--space-md));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ui-sidebar > :first-child {
|
|
43
|
+
flex-basis: var(--sidebar-width, 16rem);
|
|
44
|
+
flex-grow: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ui-sidebar > :last-child {
|
|
48
|
+
flex-basis: 0;
|
|
49
|
+
flex-grow: 999;
|
|
50
|
+
min-inline-size: var(--sidebar-min, 60%);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* All children in one row until they no longer fit --switcher-min,
|
|
54
|
+
then all switch to a column together (no half-states). */
|
|
55
|
+
.ui-switcher {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
gap: var(--switcher-gap, var(--space-md));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.ui-switcher > * {
|
|
62
|
+
flex-basis: calc((var(--switcher-min, 24rem) - 100%) * 999);
|
|
63
|
+
flex-grow: 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Centered measure-bounded column. */
|
|
67
|
+
.ui-center {
|
|
68
|
+
box-sizing: content-box;
|
|
69
|
+
margin-inline: auto;
|
|
70
|
+
max-inline-size: var(--center-max, 64rem);
|
|
71
|
+
padding-inline: var(--center-gutter, var(--space-md));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Intrinsic aspect-ratio box; the media child fills it. */
|
|
75
|
+
.ui-ratio {
|
|
76
|
+
aspect-ratio: var(--ratio, 16 / 9);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ui-ratio > * {
|
|
80
|
+
block-size: 100%;
|
|
81
|
+
inline-size: 100%;
|
|
82
|
+
object-fit: cover;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Opt-in containment: add .ui-cq to a wrapper to make descendant
|
|
86
|
+
.ui-grid / .ui-app-metrics adapt to THIS box, not the viewport
|
|
87
|
+
(island-safe). Inert until applied, so existing layouts/baselines
|
|
88
|
+
are unaffected. */
|
|
89
|
+
.ui-cq {
|
|
90
|
+
container: var(--cq-name, bronto) / inline-size;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@container bronto (max-width: 34rem) {
|
|
94
|
+
.ui-grid {
|
|
95
|
+
--grid-min: 100%;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
30
99
|
/* --- Surfaces --- */
|
|
31
100
|
|
|
32
101
|
.ui-surface,
|
|
@@ -59,6 +128,13 @@
|
|
|
59
128
|
border-color: var(--accent);
|
|
60
129
|
}
|
|
61
130
|
|
|
131
|
+
/* Interactive cards usually wrap a single link; keyboard users get no
|
|
132
|
+
hover, so surface the focused state on the card itself (not pointer-
|
|
133
|
+
gated — lives outside the @media (hover) block below). */
|
|
134
|
+
.ui-card--interactive:focus-within {
|
|
135
|
+
border-color: var(--line-strong);
|
|
136
|
+
}
|
|
137
|
+
|
|
62
138
|
.ui-card__head,
|
|
63
139
|
.ui-panel__head {
|
|
64
140
|
align-items: flex-start;
|
|
@@ -73,6 +149,95 @@
|
|
|
73
149
|
margin: 0;
|
|
74
150
|
}
|
|
75
151
|
|
|
152
|
+
/* --- Stat / metric tile — shell-agnostic ---
|
|
153
|
+
The canonical metric primitive. `.ui-app-metric*` / `.ui-app-metrics`
|
|
154
|
+
are permanent aliases grouped here so the admin shell keeps working
|
|
155
|
+
with byte-identical output (no baseline drift). */
|
|
156
|
+
|
|
157
|
+
.ui-statgrid,
|
|
158
|
+
.ui-app-metrics {
|
|
159
|
+
display: grid;
|
|
160
|
+
gap: var(--space-md);
|
|
161
|
+
grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Inside an opt-in .ui-cq container, collapse to one column when the
|
|
165
|
+
container (not the viewport) is narrow — keeps tiles usable in a slim
|
|
166
|
+
panel. Inert without .ui-cq, so baselines are unaffected. */
|
|
167
|
+
@container bronto (max-width: 30rem) {
|
|
168
|
+
.ui-statgrid,
|
|
169
|
+
.ui-app-metrics {
|
|
170
|
+
grid-template-columns: 1fr;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.ui-stat,
|
|
175
|
+
.ui-app-metric {
|
|
176
|
+
background: var(--panel);
|
|
177
|
+
border: 1px solid var(--line);
|
|
178
|
+
border-radius: var(--radius-md);
|
|
179
|
+
display: grid;
|
|
180
|
+
gap: 0.4rem;
|
|
181
|
+
padding: var(--space-md);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ui-stat__label,
|
|
185
|
+
.ui-app-metric__label {
|
|
186
|
+
color: var(--text-dim);
|
|
187
|
+
font-family: var(--mono);
|
|
188
|
+
font-size: var(--text-2xs);
|
|
189
|
+
letter-spacing: var(--tracking-wide);
|
|
190
|
+
text-transform: uppercase;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.ui-stat__value,
|
|
194
|
+
.ui-app-metric__value {
|
|
195
|
+
color: var(--text);
|
|
196
|
+
font-family: var(--display);
|
|
197
|
+
font-size: 1.9rem;
|
|
198
|
+
font-variant-numeric: tabular-nums;
|
|
199
|
+
letter-spacing: 0.01em;
|
|
200
|
+
line-height: 1;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.ui-stat__delta,
|
|
204
|
+
.ui-app-metric__delta {
|
|
205
|
+
font-family: var(--mono);
|
|
206
|
+
font-size: var(--text-xs);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.ui-stat__delta.is-pos,
|
|
210
|
+
.ui-app-metric__delta.is-pos {
|
|
211
|
+
color: var(--success);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.ui-stat__delta.is-neg,
|
|
215
|
+
.ui-app-metric__delta.is-neg {
|
|
216
|
+
color: var(--danger);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* --- Numeric value vocabulary ---
|
|
220
|
+
The same tabular/aligned/tone intent the table has shipped since
|
|
221
|
+
0.1.0, but freed from `.ui-table` so cards, stats and inline figures
|
|
222
|
+
share one P&L vocabulary. Token-identical to the table's is-num/
|
|
223
|
+
is-pos/is-neg (which stay table-local). */
|
|
224
|
+
.ui-num {
|
|
225
|
+
font-variant-numeric: tabular-nums;
|
|
226
|
+
text-align: end;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.ui-num--pos {
|
|
230
|
+
color: var(--success);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.ui-num--neg {
|
|
234
|
+
color: var(--danger);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.ui-num--muted {
|
|
238
|
+
color: var(--text-dim);
|
|
239
|
+
}
|
|
240
|
+
|
|
76
241
|
/* --- Eyebrow / section label — dot-matrix face --- */
|
|
77
242
|
|
|
78
243
|
.ui-eyebrow {
|
|
@@ -91,6 +256,12 @@
|
|
|
91
256
|
color: var(--text-dim);
|
|
92
257
|
}
|
|
93
258
|
|
|
259
|
+
/* Dense contexts (cards, table toolbars) — restores the size step that
|
|
260
|
+
0.2.2 had as eyebrow--tight. Composes with --muted. */
|
|
261
|
+
.ui-eyebrow--sm {
|
|
262
|
+
font-size: var(--text-2xs);
|
|
263
|
+
}
|
|
264
|
+
|
|
94
265
|
/* --- Buttons --- */
|
|
95
266
|
|
|
96
267
|
.ui-button {
|
|
@@ -153,6 +324,32 @@
|
|
|
153
324
|
transform: translateY(1px);
|
|
154
325
|
}
|
|
155
326
|
|
|
327
|
+
/* Async/pending state — set aria-busy="true" (and disable) on submit.
|
|
328
|
+
A leading ring spinner is injected with no extra markup; the label
|
|
329
|
+
stays for context. Inert until aria-busy is set, so default buttons
|
|
330
|
+
and visual baselines are unaffected. */
|
|
331
|
+
.ui-button[aria-busy='true'] {
|
|
332
|
+
cursor: progress;
|
|
333
|
+
pointer-events: none;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.ui-button[aria-busy='true']::before {
|
|
337
|
+
animation: uiSpin 0.6s linear infinite;
|
|
338
|
+
block-size: 0.9em;
|
|
339
|
+
border: 2px solid currentcolor;
|
|
340
|
+
border-block-start-color: transparent;
|
|
341
|
+
border-radius: var(--radius-pill);
|
|
342
|
+
content: '';
|
|
343
|
+
flex: none;
|
|
344
|
+
inline-size: 0.9em;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
@media (prefers-reduced-motion: reduce) {
|
|
348
|
+
.ui-button[aria-busy='true']::before {
|
|
349
|
+
animation-duration: 1.4s;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
156
353
|
/* --- Link --- */
|
|
157
354
|
|
|
158
355
|
.ui-link {
|
|
@@ -166,14 +363,26 @@
|
|
|
166
363
|
text-decoration-color var(--duration-fast) var(--ease-standard);
|
|
167
364
|
}
|
|
168
365
|
|
|
169
|
-
.ui-link--arrow
|
|
366
|
+
.ui-link--arrow,
|
|
367
|
+
.ui-link--cta {
|
|
170
368
|
align-items: center;
|
|
171
369
|
display: inline-flex;
|
|
172
370
|
gap: 0.4rem;
|
|
173
371
|
text-decoration: none;
|
|
174
372
|
}
|
|
175
373
|
|
|
176
|
-
|
|
374
|
+
/* CTA: the eyebrow-faced action link (accent · display · uppercase),
|
|
375
|
+
composed from the same tokens as .ui-eyebrow + the arrow glyph. */
|
|
376
|
+
.ui-link--cta {
|
|
377
|
+
color: var(--accent-text);
|
|
378
|
+
font-family: var(--display);
|
|
379
|
+
font-weight: 700;
|
|
380
|
+
letter-spacing: var(--tracking-wide);
|
|
381
|
+
text-transform: uppercase;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.ui-link--arrow::after,
|
|
385
|
+
.ui-link--cta::after {
|
|
177
386
|
border-inline-end: 1px solid currentColor;
|
|
178
387
|
border-block-start: 1px solid currentColor;
|
|
179
388
|
content: '';
|
|
@@ -250,6 +459,42 @@
|
|
|
250
459
|
border-color: color-mix(in srgb, var(--danger) 40%, var(--line));
|
|
251
460
|
}
|
|
252
461
|
|
|
462
|
+
/* Idle / unknown — the honest "no signal yet" tone (distinct from the
|
|
463
|
+
default tinted badge). Token-safe; no new hue. */
|
|
464
|
+
.ui-badge--muted {
|
|
465
|
+
background: transparent;
|
|
466
|
+
border-color: var(--line);
|
|
467
|
+
color: var(--text-dim);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Leading state dot — composes with any tone modifier; the dot takes
|
|
471
|
+
the tone via currentColor-adjacent text, but stays neutral-strong so
|
|
472
|
+
it reads on the soft tint (same WCAG rationale as the tone note). */
|
|
473
|
+
.ui-badge--dot::before {
|
|
474
|
+
background: var(--text-soft);
|
|
475
|
+
border-radius: 50%;
|
|
476
|
+
content: '';
|
|
477
|
+
flex: 0 0 auto;
|
|
478
|
+
block-size: 0.4rem;
|
|
479
|
+
inline-size: 0.4rem;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.ui-badge--accent.ui-badge--dot::before {
|
|
483
|
+
background: var(--accent);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.ui-badge--success.ui-badge--dot::before {
|
|
487
|
+
background: var(--success);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.ui-badge--warning.ui-badge--dot::before {
|
|
491
|
+
background: var(--warning);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.ui-badge--danger.ui-badge--dot::before {
|
|
495
|
+
background: var(--danger);
|
|
496
|
+
}
|
|
497
|
+
|
|
253
498
|
/* --- Key/value list --- */
|
|
254
499
|
|
|
255
500
|
.ui-key-value {
|
|
@@ -289,6 +534,7 @@
|
|
|
289
534
|
}
|
|
290
535
|
|
|
291
536
|
.ui-card--interactive:hover {
|
|
537
|
+
box-shadow: var(--shadow-raised);
|
|
292
538
|
transform: translateY(-2px);
|
|
293
539
|
}
|
|
294
540
|
|
|
@@ -313,11 +559,13 @@
|
|
|
313
559
|
text-decoration-color: var(--accent);
|
|
314
560
|
}
|
|
315
561
|
|
|
316
|
-
.ui-link--arrow:hover::after
|
|
562
|
+
.ui-link--arrow:hover::after,
|
|
563
|
+
.ui-link--cta:hover::after {
|
|
317
564
|
transform: translateX(0.14rem) rotate(45deg);
|
|
318
565
|
}
|
|
319
566
|
|
|
320
|
-
[dir='rtl'] .ui-link--arrow:hover::after
|
|
567
|
+
[dir='rtl'] .ui-link--arrow:hover::after,
|
|
568
|
+
[dir='rtl'] .ui-link--cta:hover::after {
|
|
321
569
|
transform: translateX(-0.14rem) rotate(45deg);
|
|
322
570
|
}
|
|
323
571
|
|
package/css/site.css
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
max-inline-size: var(--container-narrow, 44rem);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/* App / marketing shells run wider than the 72rem reading measure.
|
|
25
|
+
Override the cap per-consumer via --container-wide. */
|
|
26
|
+
.ui-container--wide {
|
|
27
|
+
max-inline-size: var(--container-wide, 82rem);
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
/* --- Skip link — first focusable, jumps to main --- */
|
|
25
31
|
|
|
26
32
|
.ui-skiplink {
|
|
@@ -32,7 +38,7 @@
|
|
|
32
38
|
inset-inline-start: var(--space-md);
|
|
33
39
|
padding: 0.7rem 1rem;
|
|
34
40
|
position: fixed;
|
|
35
|
-
z-index:
|
|
41
|
+
z-index: var(--z-toast);
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
.ui-skiplink:focus {
|
|
@@ -51,6 +57,14 @@
|
|
|
51
57
|
padding-block: var(--space-sm);
|
|
52
58
|
}
|
|
53
59
|
|
|
60
|
+
/* Structural sticky only — the floating-card skin (radius/shadow/panel
|
|
61
|
+
bg) is consumer identity, not a framework concern; layer it yourself. */
|
|
62
|
+
.ui-siteheader--sticky {
|
|
63
|
+
position: sticky;
|
|
64
|
+
inset-block-start: 0;
|
|
65
|
+
z-index: var(--z-sticky);
|
|
66
|
+
}
|
|
67
|
+
|
|
54
68
|
.ui-siteheader__brand {
|
|
55
69
|
align-items: center;
|
|
56
70
|
color: var(--text);
|
|
@@ -182,7 +196,7 @@
|
|
|
182
196
|
min-inline-size: 12rem;
|
|
183
197
|
padding: 0.4rem;
|
|
184
198
|
position: absolute;
|
|
185
|
-
z-index:
|
|
199
|
+
z-index: var(--z-overlay);
|
|
186
200
|
}
|
|
187
201
|
|
|
188
202
|
/* Below the breakpoint the inline nav collapses into the menu. */
|
package/css/table.css
CHANGED
|
@@ -100,3 +100,62 @@
|
|
|
100
100
|
padding: 2rem;
|
|
101
101
|
text-align: center;
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
/* --- Sortable headers (wired by initTableSort) --- */
|
|
105
|
+
.ui-table__sort {
|
|
106
|
+
align-items: center;
|
|
107
|
+
background: none;
|
|
108
|
+
border: 0;
|
|
109
|
+
color: inherit;
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
display: flex;
|
|
112
|
+
font: inherit;
|
|
113
|
+
gap: 0.4rem;
|
|
114
|
+
letter-spacing: inherit;
|
|
115
|
+
padding: 0;
|
|
116
|
+
text-transform: inherit;
|
|
117
|
+
inline-size: 100%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.ui-table__sort::after {
|
|
121
|
+
content: '↕';
|
|
122
|
+
opacity: 0.4;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ui-table th[aria-sort='ascending'] .ui-table__sort::after {
|
|
126
|
+
content: '↑';
|
|
127
|
+
opacity: 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ui-table th[aria-sort='descending'] .ui-table__sort::after {
|
|
131
|
+
content: '↓';
|
|
132
|
+
opacity: 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* --- Row selection --- */
|
|
136
|
+
.ui-table__select {
|
|
137
|
+
inline-size: 1px; /* shrink-to-fit checkbox column */
|
|
138
|
+
white-space: nowrap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ui-table--selectable tbody tr[aria-selected='true'] td {
|
|
142
|
+
background: var(--bg-accent);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* --- Bulk-action toolbar --- */
|
|
146
|
+
.ui-table__toolbar {
|
|
147
|
+
align-items: center;
|
|
148
|
+
border: 1px solid var(--line);
|
|
149
|
+
border-block-end: 0;
|
|
150
|
+
border-start-start-radius: var(--radius-md);
|
|
151
|
+
border-start-end-radius: var(--radius-md);
|
|
152
|
+
display: flex;
|
|
153
|
+
gap: var(--space-sm);
|
|
154
|
+
padding: var(--space-sm) var(--space-md);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* --- Loading state: set aria-busy + .ui-table--loading on the wrap --- */
|
|
158
|
+
.ui-table--loading {
|
|
159
|
+
opacity: 0.6;
|
|
160
|
+
pointer-events: none;
|
|
161
|
+
}
|