@godxjp/ui 18.5.0 → 18.7.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/dist/components/charts/compact-bar-trend.d.ts +2 -1
- package/dist/components/charts/index.d.ts +4 -1
- package/dist/components/data-display/data-table.d.ts +25 -4
- package/dist/components/data-display/data-table.js +13 -2
- package/dist/components/data-display/empty-state.js +1 -1
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/list-row.d.ts +19 -0
- package/dist/components/data-display/list-row.js +2 -0
- package/dist/components/data-display/qr-code.d.ts +1 -1
- package/dist/components/data-display/table.d.ts +47 -2
- package/dist/components/data-display/table.js +29 -4
- package/dist/components/data-entry/command.d.ts +10 -10
- package/dist/components/data-entry/index.d.ts +1 -0
- package/dist/components/data-entry/input-otp.d.ts +1 -0
- package/dist/components/feedback/alert.d.ts +20 -2
- package/dist/components/feedback/alert.js +11 -1
- package/dist/components/feedback/dialog.d.ts +14 -1
- package/dist/components/feedback/dialog.js +4 -0
- package/dist/components/feedback/index.d.ts +3 -3
- package/dist/components/feedback/index.js +5 -1
- package/dist/components/general/logo.d.ts +7 -1
- package/dist/components/general/logo.js +1 -1
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +55 -46
- package/dist/components/layout/auth-account-summary.d.ts +5 -0
- package/dist/components/layout/auth-account-summary.js +31 -0
- package/dist/components/layout/auth-shell.d.ts +5 -2
- package/dist/components/layout/centered-shell.d.ts +1 -1
- package/dist/components/layout/centered-shell.js +28 -19
- package/dist/components/layout/error-surface.d.ts +35 -0
- package/dist/components/layout/error-surface.js +155 -0
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +4 -0
- package/dist/components/layout/index.d.ts +7 -0
- package/dist/components/layout/index.js +6 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +23 -41
- package/dist/components/layout/page-header.d.ts +22 -0
- package/dist/components/layout/page-header.js +89 -0
- package/dist/components/navigation/filter-bar.d.ts +2 -2
- package/dist/components/navigation/filter-bar.js +44 -1
- package/dist/components/navigation/index.d.ts +1 -1
- package/dist/components/navigation/steps.js +38 -19
- package/dist/components/navigation/tabs.js +12 -3
- package/dist/components/ui/avatar.d.ts +2 -1
- package/dist/components/ui/avatar.js +2 -1
- package/dist/components/ui/input-otp.d.ts +4 -1
- package/dist/components/ui/input-otp.js +2 -1
- package/dist/components/ui/toggle-group.d.ts +7 -4
- package/dist/components/ui/toggle-group.js +32 -21
- package/dist/email/brand-mark.d.ts +21 -5
- package/dist/email/brand-mark.js +5 -0
- package/dist/email/color.d.ts +2 -1
- package/dist/email/geometry.d.ts +9 -1
- package/dist/email/geometry.js +1 -0
- package/dist/email/index.d.ts +6 -1
- package/dist/email/index.js +6 -0
- package/dist/email/inline-style.d.ts +7 -5
- package/dist/email/inline-style.js +5 -0
- package/dist/email/tokens.generated.d.ts +40 -20
- package/dist/email/tokens.generated.js +40 -20
- package/dist/email/urgency.d.ts +22 -0
- package/dist/email/urgency.js +14 -0
- package/dist/i18n/messages/en.json +26 -1
- package/dist/i18n/messages/ja.json +23 -1
- package/dist/i18n/messages/vi.json +23 -1
- package/dist/props/components/data-display.prop.d.ts +63 -1
- package/dist/props/components/data-entry.prop.d.ts +6 -0
- package/dist/props/components/feedback.prop.d.ts +6 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +244 -4
- package/dist/props/components/navigation.prop.d.ts +57 -1
- package/dist/props/registry.d.ts +205 -5
- package/dist/props/registry.js +270 -6
- package/dist/props/vocabulary/data.prop.d.ts +27 -0
- package/dist/props/vocabulary/index.d.ts +3 -3
- package/dist/props/vocabulary/interaction.prop.d.ts +19 -2
- package/dist/props/vocabulary/layout.prop.d.ts +41 -7
- package/dist/styles/alert-layout.css +36 -0
- package/dist/styles/control.css +28 -0
- package/dist/styles/data-display-layout.css +26 -0
- package/dist/styles/layout.css +212 -0
- package/dist/styles/logo-layout.css +42 -9
- package/dist/styles/navigation-layout.css +109 -0
- package/dist/styles/shell-layout.css +336 -0
- package/dist/styles/table-layout.css +164 -1
- package/dist/theme/dxs.canonical.css +5 -4
- package/dist/tokens/axes.css +4 -3
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/data-display.css +13 -0
- package/dist/tokens/components/email.css +43 -16
- package/dist/tokens/components/error-surface.css +36 -0
- package/dist/tokens/components/feedback.css +20 -0
- package/dist/tokens/components/list-row.css +20 -0
- package/dist/tokens/components/logo.css +52 -10
- package/dist/tokens/components/navigation.css +41 -0
- package/dist/tokens/components/shell.css +109 -0
- package/dist/tokens/components/table.css +45 -0
- package/dist/tokens/foundation.css +26 -0
- package/dist/tokens/semantic/layout.css +38 -0
- package/package.json +8 -2
|
@@ -49,6 +49,45 @@
|
|
|
49
49
|
scrollbar-width: thin;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/* Tabs `line` — the ACTIVE decoration is a token-owned bar and nothing else (gh#248). It is
|
|
53
|
+
* deliberately painted here (not as an `after:*` utility) so it stays independent of the
|
|
54
|
+
* `:focus-visible` ring utilities: "selected" and "keyboard-focused" are two different states and
|
|
55
|
+
* must remain visually distinct (WCAG 2.4.7). Logical insets keep the vertical rail on the
|
|
56
|
+
* inline-END edge under dir="rtl" too. */
|
|
57
|
+
[data-slot="tabs-list"][data-variant="line"] [data-slot="tabs-trigger"]::after {
|
|
58
|
+
content: "";
|
|
59
|
+
position: absolute;
|
|
60
|
+
background: var(--tabs-indicator-background, hsl(var(--primary)));
|
|
61
|
+
opacity: 0;
|
|
62
|
+
transition: opacity var(--duration-fast) var(--ease-standard);
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[data-slot="tabs-list"][data-variant="line"][data-orientation="horizontal"]
|
|
67
|
+
[data-slot="tabs-trigger"]::after {
|
|
68
|
+
inset-inline: 0;
|
|
69
|
+
inset-block-end: calc(-1 * var(--tabs-indicator-offset));
|
|
70
|
+
block-size: var(--tabs-indicator-size);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[data-slot="tabs-list"][data-variant="line"][data-orientation="vertical"]
|
|
74
|
+
[data-slot="tabs-trigger"]::after {
|
|
75
|
+
inset-block: 0;
|
|
76
|
+
inset-inline-end: calc(-1 * var(--tabs-indicator-offset));
|
|
77
|
+
inline-size: var(--tabs-indicator-size);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
[data-slot="tabs-list"][data-variant="line"]
|
|
81
|
+
[data-slot="tabs-trigger"][data-state="active"]::after {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (prefers-reduced-motion: reduce) {
|
|
86
|
+
[data-slot="tabs-list"][data-variant="line"] [data-slot="tabs-trigger"]::after {
|
|
87
|
+
transition: none;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
52
91
|
.ui-context-menu-content {
|
|
53
92
|
z-index: 50;
|
|
54
93
|
min-width: 10rem;
|
|
@@ -320,3 +359,73 @@
|
|
|
320
359
|
transform-origin: center;
|
|
321
360
|
}
|
|
322
361
|
}
|
|
362
|
+
|
|
363
|
+
@layer components {
|
|
364
|
+
.ui-steps-inline {
|
|
365
|
+
display: flex;
|
|
366
|
+
width: 100%;
|
|
367
|
+
flex-wrap: wrap;
|
|
368
|
+
align-items: center;
|
|
369
|
+
justify-content: center;
|
|
370
|
+
gap: var(--steps-inline-gap);
|
|
371
|
+
font-size: var(--steps-inline-font-size);
|
|
372
|
+
line-height: var(--line-height-tight);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.ui-steps-inline-item {
|
|
376
|
+
display: inline-flex;
|
|
377
|
+
min-width: 0;
|
|
378
|
+
flex: 0 1 auto;
|
|
379
|
+
align-items: center;
|
|
380
|
+
gap: var(--steps-inline-gap);
|
|
381
|
+
text-align: start;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.ui-steps-inline-control {
|
|
385
|
+
display: inline-flex;
|
|
386
|
+
min-width: 0;
|
|
387
|
+
align-items: center;
|
|
388
|
+
gap: var(--steps-inline-item-gap);
|
|
389
|
+
border-radius: var(--radius-sm);
|
|
390
|
+
outline: none;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
button.ui-steps-inline-control:focus-visible {
|
|
394
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.ui-steps-inline-index {
|
|
398
|
+
flex: none;
|
|
399
|
+
font-variant-numeric: tabular-nums;
|
|
400
|
+
font-weight: var(--font-weight-bold);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.ui-steps-inline-title {
|
|
404
|
+
min-width: 0;
|
|
405
|
+
overflow-wrap: anywhere;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.ui-steps-inline-item[data-status="finish"] .ui-steps-inline-control {
|
|
409
|
+
color: hsl(var(--primary));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.ui-steps-inline-item[data-status="process"] .ui-steps-inline-control {
|
|
413
|
+
color: hsl(var(--foreground));
|
|
414
|
+
font-weight: var(--font-weight-medium);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.ui-steps-inline-item[data-status="error"] .ui-steps-inline-control {
|
|
418
|
+
color: hsl(var(--destructive));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.ui-steps-inline-item[data-status="wait"] .ui-steps-inline-control,
|
|
422
|
+
.ui-steps-inline-separator {
|
|
423
|
+
color: hsl(var(--muted-foreground));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.ui-steps-inline-separator {
|
|
427
|
+
width: var(--steps-inline-separator-size);
|
|
428
|
+
height: var(--steps-inline-separator-size);
|
|
429
|
+
flex: none;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
@@ -147,6 +147,51 @@
|
|
|
147
147
|
gap: var(--auth-shell-card-stack-gap);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/* Login is an anchored three-part composition: AuthIdentity · Card · AuthFooter. The fixed
|
|
151
|
+
* identity track absorbs absent, one-line and wrapped two-line requester states while its
|
|
152
|
+
* content remains visually adjacent to the Card. This keeps real requester data intact without
|
|
153
|
+
* allowing its line count to move the canonical SCR-001 card anchor (gh#237). */
|
|
154
|
+
.ui-auth-shell[data-preset="login"] {
|
|
155
|
+
--auth-shell-card-max-width: var(--auth-shell-login-card-max-width);
|
|
156
|
+
--auth-shell-main-align: flex-start;
|
|
157
|
+
--auth-shell-main-padding: var(--auth-shell-login-flow-offset-block)
|
|
158
|
+
var(--auth-shell-login-main-padding-inline) var(--auth-shell-login-main-padding-block-end);
|
|
159
|
+
--auth-shell-card-stack-gap: var(--auth-shell-login-card-stack-gap);
|
|
160
|
+
--auth-shell-card-padding-block-compact: var(--auth-shell-login-card-padding-block-compact);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-shell-card {
|
|
164
|
+
display: grid;
|
|
165
|
+
grid-template-rows: var(--auth-shell-login-identity-slot-block-size) auto auto;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-shell-card > .ui-auth-identity,
|
|
169
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-shell-card > :has(> .ui-auth-identity) {
|
|
170
|
+
min-width: 0;
|
|
171
|
+
min-height: 0;
|
|
172
|
+
block-size: var(--auth-shell-login-identity-slot-block-size);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-shell-card > .ui-auth-identity,
|
|
176
|
+
.ui-auth-shell[data-preset="login"]
|
|
177
|
+
.ui-auth-shell-card
|
|
178
|
+
> :has(> .ui-auth-identity)
|
|
179
|
+
> .ui-auth-identity {
|
|
180
|
+
height: 100%;
|
|
181
|
+
justify-content: flex-end;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-requester {
|
|
185
|
+
max-width: 100%;
|
|
186
|
+
justify-content: center;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.ui-auth-shell[data-preset="login"] .ui-auth-requester > :last-child {
|
|
190
|
+
min-width: 0;
|
|
191
|
+
overflow-wrap: anywhere;
|
|
192
|
+
text-align: center;
|
|
193
|
+
}
|
|
194
|
+
|
|
150
195
|
.ui-auth-shell[data-preset="device-authorization"] {
|
|
151
196
|
--auth-shell-card-max-width: var(--auth-shell-device-card-max-width);
|
|
152
197
|
--auth-shell-main-padding: var(--auth-shell-device-main-padding);
|
|
@@ -167,6 +212,30 @@
|
|
|
167
212
|
--auth-shell-main-padding: var(--auth-shell-recovery-main-padding);
|
|
168
213
|
}
|
|
169
214
|
|
|
215
|
+
/* Registration preset (gh#256) — the sign-up measure. `flex-start` is the load-bearing line: a
|
|
216
|
+
* registration card is the tallest surface in the hosted-identity set, and a vertically CENTRED
|
|
217
|
+
* tall card overflows ABOVE the scroll origin on a short viewport, putting its first field out of
|
|
218
|
+
* reach. Start-aligned, the block-start inset is ordinary page padding the user scrolls past, and
|
|
219
|
+
* the block-end inset is the footer clearance the form keeps at the end of a long scroll. */
|
|
220
|
+
.ui-auth-shell[data-preset="registration"] {
|
|
221
|
+
--auth-shell-card-max-width: var(--auth-shell-registration-card-max-width);
|
|
222
|
+
--auth-shell-main-align: flex-start;
|
|
223
|
+
--auth-shell-main-padding: var(--auth-shell-registration-main-padding-block-start)
|
|
224
|
+
var(--auth-shell-registration-main-padding-inline)
|
|
225
|
+
var(--auth-shell-registration-main-padding-block-end);
|
|
226
|
+
--auth-shell-card-stack-gap: var(--auth-shell-registration-card-stack-gap);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Fixed identity track — the mechanism `login` proved (gh#237), applied to the identity block
|
|
230
|
+
* wherever it sits in the column rather than through a grid row, so the preset does not constrain
|
|
231
|
+
* how many sections the page stacks. Content aligns to the slot END, so absent / one-line /
|
|
232
|
+
* wrapped two-line identity copy changes only the empty space ABOVE it and never moves the card
|
|
233
|
+
* off its canonical anchor. */
|
|
234
|
+
.ui-auth-shell[data-preset="registration"] .ui-auth-shell-card > .ui-auth-identity {
|
|
235
|
+
block-size: var(--auth-shell-registration-identity-slot-block-size);
|
|
236
|
+
justify-content: flex-end;
|
|
237
|
+
}
|
|
238
|
+
|
|
170
239
|
.ui-auth-identity {
|
|
171
240
|
display: flex;
|
|
172
241
|
flex-direction: column;
|
|
@@ -197,6 +266,52 @@
|
|
|
197
266
|
height: var(--auth-requester-glyph-size);
|
|
198
267
|
}
|
|
199
268
|
|
|
269
|
+
.ui-auth-account-summary {
|
|
270
|
+
display: flex;
|
|
271
|
+
min-height: var(--auth-account-summary-min-height);
|
|
272
|
+
flex-wrap: wrap;
|
|
273
|
+
align-items: center;
|
|
274
|
+
gap: var(--auth-account-summary-gap);
|
|
275
|
+
padding: var(--auth-account-summary-padding);
|
|
276
|
+
border-radius: var(--radius-md);
|
|
277
|
+
background: hsl(var(--muted));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.ui-auth-account-identity {
|
|
281
|
+
display: flex;
|
|
282
|
+
min-width: min(100%, var(--auth-account-summary-identity-min-width));
|
|
283
|
+
flex: 1 1 var(--auth-account-summary-identity-min-width);
|
|
284
|
+
align-items: center;
|
|
285
|
+
gap: var(--auth-account-summary-gap);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.ui-auth-account-avatar {
|
|
289
|
+
width: var(--auth-account-summary-avatar-size);
|
|
290
|
+
height: var(--auth-account-summary-avatar-size);
|
|
291
|
+
flex: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.ui-auth-account-fallback-icon {
|
|
295
|
+
width: var(--auth-account-summary-avatar-glyph-size);
|
|
296
|
+
height: var(--auth-account-summary-avatar-glyph-size);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.ui-auth-account-email {
|
|
300
|
+
min-width: 0;
|
|
301
|
+
overflow: hidden;
|
|
302
|
+
color: hsl(var(--foreground));
|
|
303
|
+
font-size: var(--auth-account-summary-email-font-size);
|
|
304
|
+
/* Declares its own line box because it CLIPS — see gh#254. */
|
|
305
|
+
line-height: var(--auth-account-summary-email-line-height);
|
|
306
|
+
font-weight: var(--font-weight-medium);
|
|
307
|
+
text-overflow: ellipsis;
|
|
308
|
+
white-space: nowrap;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.ui-auth-account-summary > [data-slot="button"] {
|
|
312
|
+
margin-inline-start: auto;
|
|
313
|
+
}
|
|
314
|
+
|
|
200
315
|
.ui-auth-legal-footer {
|
|
201
316
|
display: flex;
|
|
202
317
|
flex-wrap: wrap;
|
|
@@ -277,6 +392,12 @@
|
|
|
277
392
|
--auth-shell-main-padding: var(--auth-shell-canonical-main-padding-mobile);
|
|
278
393
|
}
|
|
279
394
|
|
|
395
|
+
.ui-auth-shell[data-preset="login"] {
|
|
396
|
+
--auth-shell-main-padding: var(--auth-shell-login-flow-offset-block-mobile)
|
|
397
|
+
var(--auth-shell-login-main-padding-inline-mobile)
|
|
398
|
+
var(--auth-shell-login-main-padding-block-end);
|
|
399
|
+
}
|
|
400
|
+
|
|
280
401
|
/* Declared after the canonical mobile inset so a preset's mobile gutter wins at equal
|
|
281
402
|
* specificity: device-authorization = 5px inline (card x=5, width=380 at 390px);
|
|
282
403
|
* context-selection = edge-to-edge (0 inline). */
|
|
@@ -294,6 +415,16 @@
|
|
|
294
415
|
.ui-auth-shell[data-preset="account-recovery"] {
|
|
295
416
|
--auth-shell-main-padding: var(--auth-shell-recovery-main-padding-mobile);
|
|
296
417
|
}
|
|
418
|
+
|
|
419
|
+
/* registration = 15px inline at 390 (card x=15, width=360 — the same page rhythm as Login, so
|
|
420
|
+
* sign-in → sign-up never jumps on a phone). The block insets tighten but the footer clearance
|
|
421
|
+
* stays deliberately larger than the block-start inset: at 390 the form is at its tallest and
|
|
422
|
+
* the consent/legal footer must not sit flush against the submit button. */
|
|
423
|
+
.ui-auth-shell[data-preset="registration"] {
|
|
424
|
+
--auth-shell-main-padding: var(--auth-shell-registration-main-padding-block-start-mobile)
|
|
425
|
+
var(--auth-shell-registration-main-padding-inline-mobile)
|
|
426
|
+
var(--auth-shell-registration-main-padding-block-end-mobile);
|
|
427
|
+
}
|
|
297
428
|
}
|
|
298
429
|
|
|
299
430
|
/*
|
|
@@ -479,6 +610,33 @@
|
|
|
479
610
|
.app-mobile-nav-trigger {
|
|
480
611
|
display: inline-flex;
|
|
481
612
|
}
|
|
613
|
+
|
|
614
|
+
/* Some approved application contracts retain their navigation rail at narrow widths. This is
|
|
615
|
+
* an explicit AppShell mode, never a consumer media-query fork: the same sidebar node, footer,
|
|
616
|
+
* active items and token-owned rail width remain in the canonical two-track grid. */
|
|
617
|
+
.app-root[data-responsive-navigation="docked"] {
|
|
618
|
+
grid-template-areas:
|
|
619
|
+
"sidebar topbar"
|
|
620
|
+
"sidebar main"
|
|
621
|
+
"sidebar footer";
|
|
622
|
+
grid-template-columns: var(--app-shell-sidebar-width) minmax(0, 1fr);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.app-root[data-responsive-navigation="docked"][data-collapsed="true"] {
|
|
626
|
+
grid-template-columns: var(--app-shell-rail-width) minmax(0, 1fr);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.app-root[data-responsive-navigation="docked"] > .app-sidebar {
|
|
630
|
+
display: flex;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.app-root[data-responsive-navigation="docked"] > .app-topbar {
|
|
634
|
+
padding-inline: var(--app-shell-bar-inset);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.app-root[data-responsive-navigation="docked"] .app-mobile-nav-trigger {
|
|
638
|
+
display: none;
|
|
639
|
+
}
|
|
482
640
|
}
|
|
483
641
|
|
|
484
642
|
.sb-root {
|
|
@@ -781,6 +939,10 @@
|
|
|
781
939
|
min-width: 0;
|
|
782
940
|
flex: 1;
|
|
783
941
|
overflow: hidden;
|
|
942
|
+
/* gh#254 — MUST NOT inherit the row's `line-height: 1`. This element clips, so its line box is
|
|
943
|
+
* its clip box, and a 1em box is shorter than the font's ascent+descent: every descender and
|
|
944
|
+
* Vietnamese tone mark below the baseline gets sheared off. Knob, not constant (rule #45). */
|
|
945
|
+
line-height: var(--sidebar-nav-item-line-height);
|
|
784
946
|
text-overflow: ellipsis;
|
|
785
947
|
white-space: nowrap;
|
|
786
948
|
}
|
|
@@ -1093,6 +1255,16 @@
|
|
|
1093
1255
|
.ui-topbar-start {
|
|
1094
1256
|
flex: 0 1 auto;
|
|
1095
1257
|
}
|
|
1258
|
+
.ui-topbar-start > :last-child {
|
|
1259
|
+
max-width: 100%;
|
|
1260
|
+
min-width: 0;
|
|
1261
|
+
flex: 0 1 auto;
|
|
1262
|
+
overflow: hidden;
|
|
1263
|
+
/* Declares its own line box because it CLIPS — see gh#254. */
|
|
1264
|
+
line-height: var(--topbar-start-truncate-line-height);
|
|
1265
|
+
text-overflow: ellipsis;
|
|
1266
|
+
white-space: nowrap;
|
|
1267
|
+
}
|
|
1096
1268
|
.ui-topbar-center {
|
|
1097
1269
|
flex: 1 1 0%;
|
|
1098
1270
|
justify-content: center;
|
|
@@ -1103,6 +1275,17 @@
|
|
|
1103
1275
|
margin-inline-start: auto;
|
|
1104
1276
|
}
|
|
1105
1277
|
|
|
1278
|
+
/* COLLISION CONTRACT (gh#244) — with a docked 16rem sidebar, 901–1100px viewports do not have
|
|
1279
|
+
* enough room for a breadcrumb/title, full search trigger and end utilities. The center slot is
|
|
1280
|
+
* optional by definition, so remove it before it can cover either owned edge. This also gives
|
|
1281
|
+
* phones the same deterministic allocation. A consumer with a real compact center presentation
|
|
1282
|
+
* can opt it back in through the public token instead of a page-local media query. */
|
|
1283
|
+
@media (width <= 68.75rem) {
|
|
1284
|
+
.ui-topbar-center {
|
|
1285
|
+
display: var(--topbar-center-compact-display);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1106
1289
|
.tb-chip {
|
|
1107
1290
|
display: inline-flex;
|
|
1108
1291
|
max-width: 15rem;
|
|
@@ -1156,6 +1339,10 @@
|
|
|
1156
1339
|
min-width: 0;
|
|
1157
1340
|
overflow: hidden;
|
|
1158
1341
|
font-weight: 500;
|
|
1342
|
+
/* gh#254 — same trap as `.sb-label`: this clips, so it must own a line box tall enough for the
|
|
1343
|
+
* font's descenders. `.tb-chip` uses `font: inherit`, so without this the chip would shear its
|
|
1344
|
+
* glyphs the moment a service set a tight line-height on the bar. */
|
|
1345
|
+
line-height: 1.5;
|
|
1159
1346
|
text-overflow: ellipsis;
|
|
1160
1347
|
white-space: nowrap;
|
|
1161
1348
|
}
|
|
@@ -1286,3 +1473,152 @@
|
|
|
1286
1473
|
transition: none;
|
|
1287
1474
|
}
|
|
1288
1475
|
}
|
|
1476
|
+
|
|
1477
|
+
/*
|
|
1478
|
+
* ERROR SURFACE — the 403 / 404 / 500 / 503 exception surface (gh#221, gh#251).
|
|
1479
|
+
*
|
|
1480
|
+
* Geometry is PACKAGE-OWNED at 1440 / 1024 / 390: a consumer never writes `min-h-dvh`, a
|
|
1481
|
+
* flex-centring class or a media query for an error page. In `system` mode the viewport centring
|
|
1482
|
+
* comes from `CenteredShell align="center"` (which the component renders itself); this block owns
|
|
1483
|
+
* the surface block that is identical in BOTH modes — measure, rhythm, metadata list.
|
|
1484
|
+
*
|
|
1485
|
+
* The narrow step is a CONTAINER query, not a viewport one (the SplitPane precedent, gh#165): the
|
|
1486
|
+
* surface reads its OWN width, so it compacts correctly whether the shrinking came from a 390px
|
|
1487
|
+
* phone or from an application shell whose sidebar is expanded on a laptop.
|
|
1488
|
+
*/
|
|
1489
|
+
@layer components {
|
|
1490
|
+
.ui-error-surface {
|
|
1491
|
+
container: error-surface / inline-size;
|
|
1492
|
+
display: flex;
|
|
1493
|
+
width: 100%;
|
|
1494
|
+
max-width: var(--error-surface-max-width);
|
|
1495
|
+
flex-direction: column;
|
|
1496
|
+
align-items: center;
|
|
1497
|
+
/* Logical, so the surface stays centred and its text start-aligns correctly under `dir="rtl"`. */
|
|
1498
|
+
margin-inline: auto;
|
|
1499
|
+
gap: var(--error-surface-gap);
|
|
1500
|
+
padding-block: var(--error-surface-padding-block);
|
|
1501
|
+
text-align: center;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
.ui-error-surface-brand {
|
|
1505
|
+
display: flex;
|
|
1506
|
+
justify-content: center;
|
|
1507
|
+
padding-block-end: var(--error-surface-brand-gap);
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
/* The EmptyState body already owns its own vertical rhythm and description measure
|
|
1511
|
+
* (--empty-state-*); the surface only removes the duplicated block padding so the two spacing
|
|
1512
|
+
* systems do not stack into a hole between the status code and the icon. */
|
|
1513
|
+
.ui-error-surface .ui-error-surface-body {
|
|
1514
|
+
width: 100%;
|
|
1515
|
+
padding-block: 0;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
.ui-error-surface-status {
|
|
1519
|
+
margin: 0;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
.ui-error-surface-meta {
|
|
1523
|
+
display: flex;
|
|
1524
|
+
width: 100%;
|
|
1525
|
+
flex-direction: column;
|
|
1526
|
+
gap: var(--error-surface-meta-gap);
|
|
1527
|
+
/* Chrome is a token, default quiet (rule #44) — `none` unless a service opts in. */
|
|
1528
|
+
border-block-start: var(--error-surface-meta-border);
|
|
1529
|
+
padding-block-start: var(--error-surface-meta-padding-block);
|
|
1530
|
+
margin: 0;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
.ui-error-surface-meta-row {
|
|
1534
|
+
display: flex;
|
|
1535
|
+
flex-wrap: wrap;
|
|
1536
|
+
justify-content: center;
|
|
1537
|
+
gap: var(--error-surface-meta-row-gap);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
.ui-error-surface-meta-row > dd {
|
|
1541
|
+
margin-inline-start: 0;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
.ui-error-surface-progress {
|
|
1545
|
+
width: 100%;
|
|
1546
|
+
max-width: var(--error-surface-progress-max-width);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/*
|
|
1550
|
+
* NARROW STEP (the 390 case). Reclaim vertical space and stop a long ja / vi metadata row from
|
|
1551
|
+
* wrapping into a ragged two-column shape: each label stacks over its value, centred.
|
|
1552
|
+
*/
|
|
1553
|
+
@container error-surface (width < 30rem) {
|
|
1554
|
+
.ui-error-surface {
|
|
1555
|
+
padding-block: var(--error-surface-padding-block-compact);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
.ui-error-surface-meta-row {
|
|
1559
|
+
flex-direction: column;
|
|
1560
|
+
gap: 0;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
@layer components {
|
|
1566
|
+
/* ── CenteredShell · `preset="public-landing"` (gh#252) ──────────────────────────────────────
|
|
1567
|
+
* A PUBLIC landing page (marketing header · hero · sections · legal footer) is a COMPOSITION,
|
|
1568
|
+
* not a framework component (docs/COMPOSITION-VS-COMPONENT.md: Hero / Navbar / Footer / Pricing
|
|
1569
|
+
* all FAIL the Framework-Component Test). What the consumer must NOT own is the SHELL geometry —
|
|
1570
|
+
* the content measure, the header/footer measure alignment, the section rhythm and the flat
|
|
1571
|
+
* public-surface chrome. This preset owns all of it through `--centered-shell-landing-*` knobs,
|
|
1572
|
+
* so a landing composes real primitives with ZERO page-local CSS and zero descendant selectors.
|
|
1573
|
+
*
|
|
1574
|
+
* `preset="default"` emits NO `data-preset` attribute at all, so none of this can match and every
|
|
1575
|
+
* existing CenteredShell keeps its exact box (the gh#231 inert-default contract). */
|
|
1576
|
+
.ui-centered-shell[data-preset="public-landing"] {
|
|
1577
|
+
--centered-shell-main-padding: var(--centered-shell-landing-main-padding-block)
|
|
1578
|
+
var(--centered-shell-landing-inset-inline);
|
|
1579
|
+
/* The hero title is a real `Heading level={1}`; the preset re-points the h1 tier the same way
|
|
1580
|
+
* `.ui-auth-shell` re-points it — never a consumer font-size. */
|
|
1581
|
+
--heading-h1: var(--centered-shell-landing-heading-size);
|
|
1582
|
+
/* Flat public surface: every Card in the subtree loses its elevation from ONE knob instead of
|
|
1583
|
+
* a consumer `.landing .card { box-shadow: none }` descendant selector. */
|
|
1584
|
+
--card-shadow: var(--centered-shell-landing-card-shadow);
|
|
1585
|
+
background: hsl(var(--centered-shell-landing-background, var(--background)));
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
.ui-centered-shell[data-preset="public-landing"] .ui-centered-shell-column {
|
|
1589
|
+
display: flex;
|
|
1590
|
+
max-width: var(--centered-shell-landing-max-width);
|
|
1591
|
+
flex-direction: column;
|
|
1592
|
+
/* Section rhythm — the consumer stacks plain `<section>` layout elements and never sets a gap. */
|
|
1593
|
+
gap: var(--centered-shell-landing-section-gap);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/* Header and footer share the column's measure WITHOUT a consumer max-width wrapper: the inline
|
|
1597
|
+
* padding is the page gutter until the viewport is wider than the measure, then it grows so the
|
|
1598
|
+
* bar content starts on exactly the same inline edge as the centred column. */
|
|
1599
|
+
.ui-centered-shell[data-preset="public-landing"] .ui-centered-shell-bar,
|
|
1600
|
+
.ui-centered-shell[data-preset="public-landing"] .ui-centered-shell-footer {
|
|
1601
|
+
padding-inline: max(
|
|
1602
|
+
var(--centered-shell-landing-inset-inline),
|
|
1603
|
+
calc((100% - var(--centered-shell-landing-max-width)) / 2)
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
.ui-centered-shell[data-preset="public-landing"] .ui-centered-shell-footer {
|
|
1608
|
+
padding-block: var(--centered-shell-landing-footer-padding-block);
|
|
1609
|
+
text-align: start;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
/* Compact step (the 390px acceptance width sits here): the gutter, the section rhythm and the
|
|
1613
|
+
* hero tier switch to their compact knobs. One media query, owned by the package. */
|
|
1614
|
+
@media (width < 40rem) {
|
|
1615
|
+
.ui-centered-shell[data-preset="public-landing"] {
|
|
1616
|
+
--centered-shell-landing-inset-inline: var(--centered-shell-landing-inset-inline-compact);
|
|
1617
|
+
--centered-shell-landing-main-padding-block: var(
|
|
1618
|
+
--centered-shell-landing-main-padding-block-compact
|
|
1619
|
+
);
|
|
1620
|
+
--centered-shell-landing-section-gap: var(--centered-shell-landing-section-gap-compact);
|
|
1621
|
+
--centered-shell-landing-heading-size: var(--centered-shell-landing-heading-size-compact);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|