@godxjp/ui 18.12.13 → 18.12.15
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/data-display/table.d.ts +34 -7
- package/dist/components/data-display/table.js +9 -4
- package/dist/props/vocabulary/data.prop.d.ts +8 -1
- package/dist/styles/shell-layout.css +50 -26
- package/dist/styles/table-layout.css +206 -1
- package/dist/tokens/components/shell.css +13 -0
- package/dist/tokens/components/table.css +12 -0
- package/dist/tokens/foundation.css +8 -0
- package/package.json +2 -2
|
@@ -32,12 +32,20 @@ export type TableProps = React.HTMLAttributes<HTMLTableElement> & {
|
|
|
32
32
|
* its rem floor (`--table-action-collection-*-width-floor`, ~5 CJK glyphs per line) and the
|
|
33
33
|
* table intentionally scrolls inside this wrapper — SC 1.4.10 permits one-dimensional scrolling
|
|
34
34
|
* of a data table; compressing further would shred CJK headers one character per line.
|
|
35
|
+
*
|
|
36
|
+
* `"stacked-record-collection"` (gh#293 restore — SCR-215) is for a wide, heterogeneous record
|
|
37
|
+
* table that CANNOT be squeezed into any fixed narrow-frame measure — an admin detail row with
|
|
38
|
+
* many disparate fields, not a dense queue. Below `collapseBelow` the `<thead>` hides and every
|
|
39
|
+
* `<tr>` becomes a bordered key-value card: each `TableCell`'s own `label` prop (its column's
|
|
40
|
+
* header text, repeated per cell since `<thead>` is gone) renders inline above the value. Above
|
|
41
|
+
* the step it renders as a byte-for-byte ordinary table — mark `label` on every `TableCell`.
|
|
35
42
|
*/
|
|
36
43
|
preset?: TablePresetProp;
|
|
37
44
|
/**
|
|
38
|
-
* Step at which `preset="action-collection"`
|
|
39
|
-
* the TABLE's own container (not the viewport), so a table
|
|
40
|
-
* page does. Defaults to `"sm"` (40rem). Ignored while
|
|
45
|
+
* Step at which `preset="action-collection"`/`"stacked-record-collection"` switch away from the
|
|
46
|
+
* ordinary table, measured against the TABLE's own container (not the viewport), so a table
|
|
47
|
+
* inside a rail collapses before the page does. Defaults to `"sm"` (40rem). Ignored while
|
|
48
|
+
* `preset` is `"default"`.
|
|
41
49
|
*/
|
|
42
50
|
collapseBelow?: BreakpointProp;
|
|
43
51
|
};
|
|
@@ -73,12 +81,20 @@ export declare const Table: React.ForwardRefExoticComponent<React.HTMLAttributes
|
|
|
73
81
|
* its rem floor (`--table-action-collection-*-width-floor`, ~5 CJK glyphs per line) and the
|
|
74
82
|
* table intentionally scrolls inside this wrapper — SC 1.4.10 permits one-dimensional scrolling
|
|
75
83
|
* of a data table; compressing further would shred CJK headers one character per line.
|
|
84
|
+
*
|
|
85
|
+
* `"stacked-record-collection"` (gh#293 restore — SCR-215) is for a wide, heterogeneous record
|
|
86
|
+
* table that CANNOT be squeezed into any fixed narrow-frame measure — an admin detail row with
|
|
87
|
+
* many disparate fields, not a dense queue. Below `collapseBelow` the `<thead>` hides and every
|
|
88
|
+
* `<tr>` becomes a bordered key-value card: each `TableCell`'s own `label` prop (its column's
|
|
89
|
+
* header text, repeated per cell since `<thead>` is gone) renders inline above the value. Above
|
|
90
|
+
* the step it renders as a byte-for-byte ordinary table — mark `label` on every `TableCell`.
|
|
76
91
|
*/
|
|
77
92
|
preset?: TablePresetProp;
|
|
78
93
|
/**
|
|
79
|
-
* Step at which `preset="action-collection"`
|
|
80
|
-
* the TABLE's own container (not the viewport), so a table
|
|
81
|
-
* page does. Defaults to `"sm"` (40rem). Ignored while
|
|
94
|
+
* Step at which `preset="action-collection"`/`"stacked-record-collection"` switch away from the
|
|
95
|
+
* ordinary table, measured against the TABLE's own container (not the viewport), so a table
|
|
96
|
+
* inside a rail collapses before the page does. Defaults to `"sm"` (40rem). Ignored while
|
|
97
|
+
* `preset` is `"default"`.
|
|
82
98
|
*/
|
|
83
99
|
collapseBelow?: BreakpointProp;
|
|
84
100
|
} & React.RefAttributes<HTMLTableElement>>;
|
|
@@ -94,6 +110,17 @@ export declare const TableRow: React.ForwardRefExoticComponent<React.HTMLAttribu
|
|
|
94
110
|
type TableCellPriority = {
|
|
95
111
|
priority?: TableColumnPriorityProp;
|
|
96
112
|
};
|
|
113
|
+
/**
|
|
114
|
+
* A `TableCell`'s own column label, read only by `Table preset="stacked-record-collection"`
|
|
115
|
+
* below its collapse step — where the real `<thead>` hides and this renders inline above the
|
|
116
|
+
* cell's value inside the stacked card, standing in for the header association that is no longer
|
|
117
|
+
* visually present. Rendered into the DOM unconditionally (so it exists for the preset's CSS to
|
|
118
|
+
* reveal) but visually hidden above the collapse step, where the real `<th>` already carries the
|
|
119
|
+
* label — an ordinary table with no `label` prop supplied gains no extra markup.
|
|
120
|
+
*/
|
|
121
|
+
type TableCellLabel = {
|
|
122
|
+
label?: React.ReactNode;
|
|
123
|
+
};
|
|
97
124
|
export declare const TableHead: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & TableCellPriority & React.RefAttributes<HTMLTableCellElement>>;
|
|
98
|
-
export declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<HTMLTableCellElement> & TableCellPriority & React.RefAttributes<HTMLTableCellElement>>;
|
|
125
|
+
export declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<HTMLTableCellElement> & TableCellPriority & TableCellLabel & React.RefAttributes<HTMLTableCellElement>>;
|
|
99
126
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { tableHeadHeightClass } from "../../lib/control-styles.js";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
@@ -23,7 +23,8 @@ const Table = React.forwardRef(
|
|
|
23
23
|
{
|
|
24
24
|
className: cn(
|
|
25
25
|
scrollable ? "relative w-full overflow-auto" : "relative w-full",
|
|
26
|
-
preset
|
|
26
|
+
preset === "action-collection" && "ui-table-collection",
|
|
27
|
+
preset === "stacked-record-collection" && "ui-table-stacked-collection"
|
|
27
28
|
),
|
|
28
29
|
"data-preset": preset === "default" ? void 0 : preset,
|
|
29
30
|
"data-collapse-below": preset === "default" ? void 0 : collapseBelow,
|
|
@@ -69,14 +70,18 @@ const TableHead = React.forwardRef(({ className, priority, ...props }, ref) => /
|
|
|
69
70
|
}
|
|
70
71
|
));
|
|
71
72
|
TableHead.displayName = "TableHead";
|
|
72
|
-
const TableCell = React.forwardRef(({ className, priority, ...props }, ref) => /* @__PURE__ */
|
|
73
|
+
const TableCell = React.forwardRef(({ className, priority, label, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
73
74
|
"td",
|
|
74
75
|
{
|
|
75
76
|
ref,
|
|
76
77
|
"data-slot": "table-cell",
|
|
77
78
|
"data-priority": priority,
|
|
78
79
|
className: cn(className),
|
|
79
|
-
...props
|
|
80
|
+
...props,
|
|
81
|
+
children: [
|
|
82
|
+
label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
|
|
83
|
+
children
|
|
84
|
+
]
|
|
80
85
|
}
|
|
81
86
|
));
|
|
82
87
|
TableCell.displayName = "TableCell";
|
|
@@ -81,8 +81,15 @@ export type StickyProp = boolean;
|
|
|
81
81
|
* the desktop intrinsic column widths are replaced by token-owned column-PRIORITY measures under
|
|
82
82
|
* `table-layout: fixed` and cells wrap, so every column — including the row actions — stays inside
|
|
83
83
|
* the initial narrow frame. The real `<table>` semantics are never rewritten.
|
|
84
|
+
*
|
|
85
|
+
* `"stacked-record-collection"` (gh#293 restore — SCR-215) is the canonical wide-record collection:
|
|
86
|
+
* a table whose column count/content cannot be squeezed into any fixed-measure narrow frame at all
|
|
87
|
+
* (an admin detail row with many heterogeneous fields). Below `collapseBelow` the header row hides
|
|
88
|
+
* and every `<tr>` becomes a bordered key-value CARD stack — each `TableCell`'s own `label` prop
|
|
89
|
+
* renders inline above its value, taking over the accessible-name role the (now hidden) `<th>`
|
|
90
|
+
* association would otherwise carry. Above the step it is a byte-for-byte ordinary table.
|
|
84
91
|
*/
|
|
85
|
-
export type TablePresetProp = "default" | "action-collection";
|
|
92
|
+
export type TablePresetProp = "default" | "action-collection" | "stacked-record-collection";
|
|
86
93
|
/**
|
|
87
94
|
* Relative importance of a table column, used by `preset="action-collection"` to allocate the
|
|
88
95
|
* narrow-frame measure. `"primary"` is the row's subject, `"secondary"` its object/target,
|
|
@@ -32,7 +32,14 @@
|
|
|
32
32
|
min-width: 0;
|
|
33
33
|
min-height: 0;
|
|
34
34
|
flex-direction: column;
|
|
35
|
-
|
|
35
|
+
/* Same ring-headroom contract as the topbar family (gh#291): nav rows are
|
|
36
|
+
* flush with the rail's inline edges, so a plain `hidden` clipped their
|
|
37
|
+
* focus ring on three sides. `clip` + margin (the margin is honoured only
|
|
38
|
+
* when BOTH axes clip) lets the ring paint over the rail border, while the
|
|
39
|
+
* rail still contains its content. Inner scroll regions are unaffected —
|
|
40
|
+
* `clip` creates no scroll container, exactly like `hidden`. */
|
|
41
|
+
overflow: clip;
|
|
42
|
+
overflow-clip-margin: var(--focus-ring-clip-margin);
|
|
36
43
|
border-inline-end: 1px solid hsl(var(--border));
|
|
37
44
|
background: hsl(var(--card));
|
|
38
45
|
/* Opt-in brand-chrome wash — invisible by default (--sidebar-gradient: none). */
|
|
@@ -47,7 +54,15 @@
|
|
|
47
54
|
* set to baseline; --scaling:1 alone is not enough — see foundation.css). */
|
|
48
55
|
display: flex;
|
|
49
56
|
min-width: 0;
|
|
50
|
-
|
|
57
|
+
/* Same both-axes-clip + margin contract as .ui-topbar (gh#291): Chromium
|
|
58
|
+
* honours overflow-clip-margin ONLY when BOTH axes are `clip` — a
|
|
59
|
+
* single-axis clip silently drops the margin, which would cut a flush
|
|
60
|
+
* control's ring whenever a theme sets --app-shell-bar-inset to 0. The 8px
|
|
61
|
+
* margin also covers the vertical ring of coarse-pointer 44px controls,
|
|
62
|
+
* which the 3.5rem coarse bar height already keeps inside the bar. Safari
|
|
63
|
+
* falls back to `visible` with the .ui-topbar family below. */
|
|
64
|
+
overflow: clip;
|
|
65
|
+
overflow-clip-margin: var(--focus-ring-clip-margin);
|
|
51
66
|
align-items: center;
|
|
52
67
|
gap: var(--app-shell-bar-gap);
|
|
53
68
|
padding-inline: var(--app-shell-bar-inset);
|
|
@@ -1271,19 +1286,19 @@
|
|
|
1271
1286
|
align-items: center;
|
|
1272
1287
|
gap: var(--topbar-gap);
|
|
1273
1288
|
padding-inline: var(--topbar-inset);
|
|
1274
|
-
/*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
* `auto
|
|
1280
|
-
*
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
*
|
|
1285
|
-
|
|
1286
|
-
overflow-clip-margin:
|
|
1289
|
+
/* Ring headroom contract (gh#291), measured empirically:
|
|
1290
|
+
* - Chromium honours overflow-clip-margin ONLY when BOTH axes are `clip`;
|
|
1291
|
+
* a single-axis clip silently ignores the margin, and a flush-edge
|
|
1292
|
+
* control's ring vanishes on the clipped axis.
|
|
1293
|
+
* - `hidden` can never work here (no clip-margin, and pairing it with
|
|
1294
|
+
* `visible` computes to `auto`, which still clips).
|
|
1295
|
+
* - The margin must be a bare var() — Chromium drops calc() at parse time.
|
|
1296
|
+
* So: clip BOTH axes and let the margin carry the ring on every side. The
|
|
1297
|
+
* gh#226 shrink/truncation contract is intact (content clips 8px outside
|
|
1298
|
+
* the box). Safari (clip yes, clip-margin no) falls back to `visible`
|
|
1299
|
+
* below. */
|
|
1300
|
+
overflow: clip;
|
|
1301
|
+
overflow-clip-margin: var(--focus-ring-clip-margin);
|
|
1287
1302
|
}
|
|
1288
1303
|
.ui-topbar-start,
|
|
1289
1304
|
.ui-topbar-center,
|
|
@@ -1292,17 +1307,26 @@
|
|
|
1292
1307
|
min-width: 0;
|
|
1293
1308
|
align-items: center;
|
|
1294
1309
|
gap: var(--topbar-gap);
|
|
1295
|
-
/*
|
|
1296
|
-
*
|
|
1297
|
-
*
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1310
|
+
/* Same both-axes-clip + margin contract as .ui-topbar above (gh#291): the
|
|
1311
|
+
* 8px margin covers the 3px ring on every side of a flush-edge control;
|
|
1312
|
+
* single-axis clip would silently drop the margin in Chromium. */
|
|
1313
|
+
overflow: clip;
|
|
1314
|
+
overflow-clip-margin: var(--focus-ring-clip-margin);
|
|
1315
|
+
}
|
|
1316
|
+
/* Safari implements `overflow: clip` but NOT overflow-clip-margin, so the
|
|
1317
|
+
* both-axes clip above would eat every flush-edge focus ring there with no
|
|
1318
|
+
* margin to save it. Trade slot containment for ring visibility on that
|
|
1319
|
+
* engine only — the .app-topbar horizontal clip still prevents bar blowout
|
|
1320
|
+
* and document scroll. */
|
|
1321
|
+
@supports not (overflow-clip-margin: 1px) {
|
|
1322
|
+
.app-sidebar,
|
|
1323
|
+
.app-topbar,
|
|
1324
|
+
.ui-topbar,
|
|
1325
|
+
.ui-topbar-start,
|
|
1326
|
+
.ui-topbar-center,
|
|
1327
|
+
.ui-topbar-end {
|
|
1328
|
+
overflow: visible;
|
|
1329
|
+
}
|
|
1306
1330
|
}
|
|
1307
1331
|
.ui-topbar-start {
|
|
1308
1332
|
flex: 0 1 auto;
|
|
@@ -119,7 +119,14 @@
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
.ui-data-table-surface {
|
|
122
|
-
|
|
122
|
+
/* `clip`, NOT `hidden` (gh#291 family): both clip the table to the rounded
|
|
123
|
+
* border, but `hidden` makes this box a SCROLL CONTAINER, which silently
|
|
124
|
+
* captured the sticky context of `stickyHeader` (default true) and of the
|
|
125
|
+
* pinned columns — they anchored to a box that never scrolls, so the header
|
|
126
|
+
* scrolled away with the body inside `.ui-data-table-scroll`. `clip` is not
|
|
127
|
+
* a scroll container, so sticky binds to the real scroll region and works.
|
|
128
|
+
* Measured: hidden → thead moved 300px per 300px scrolled; clip → 1px. */
|
|
129
|
+
overflow: clip;
|
|
123
130
|
/* Narrow-viewport legibility floor — a TOKEN, not the old `min-w-[640px]` literal (gh#253,
|
|
124
131
|
* rule #45). Cleared at the `sm` step below, and opted out of entirely by the collection
|
|
125
132
|
* preset, which owns its width through the column-priority measures. */
|
|
@@ -363,6 +370,29 @@
|
|
|
363
370
|
}
|
|
364
371
|
}
|
|
365
372
|
|
|
373
|
+
@layer components {
|
|
374
|
+
/* ── Table · `preset="stacked-record-collection"` (gh#293 restore — SCR-215) ─────────────────
|
|
375
|
+
* The canonical WIDE, heterogeneous record collection: a table whose column count/content
|
|
376
|
+
* cannot be squeezed into any fixed narrow-frame measure at all — an admin detail row with many
|
|
377
|
+
* disparate, free-text fields of unpredictable length, not a dense queue (contrast
|
|
378
|
+
* `action-collection` above, which keeps the real table and only re-sizes columns). Below
|
|
379
|
+
* `collapseBelow` the `<thead>` hides and every `<tr>` becomes a bordered key-value CARD: each
|
|
380
|
+
* `TableCell`'s own `label` (its column header text, carried per-cell since the `<th>`
|
|
381
|
+
* association is now hidden) renders inline above the value, taking over the accessible-name
|
|
382
|
+
* role. Above the step it is a byte-for-byte ordinary table. Measured against the TABLE'S OWN
|
|
383
|
+
* container, not the viewport, same as `action-collection`. */
|
|
384
|
+
.ui-table-stacked-collection {
|
|
385
|
+
container: ui-table-stacked-collection / inline-size;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Rendered into the DOM unconditionally so it exists for the container query below to reveal
|
|
389
|
+
* (see TableCell in table.tsx) but hidden above the collapse step, where the real `<th>` already
|
|
390
|
+
* carries the label — an ordinary table gains no visible extra markup. */
|
|
391
|
+
.ui-table-stacked-collection-label {
|
|
392
|
+
display: none;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
366
396
|
/* The compact tier lives in `godxjp-ui-responsive` — the LAST layer, declared after Tailwind in
|
|
367
397
|
* styles/base.css — not in `@layer components`. `<table>` carries `text-sm`, a Tailwind utility,
|
|
368
398
|
* and `utilities` outranks `components` by LAYER ORDER, so a `font-size:` re-point written here as
|
|
@@ -536,4 +566,179 @@
|
|
|
536
566
|
--table-action-collection-flex-width: var(--table-action-collection-flex-width-floor);
|
|
537
567
|
}
|
|
538
568
|
}
|
|
569
|
+
|
|
570
|
+
/* ── `preset="stacked-record-collection"` (gh#293 restore — SCR-215) ────────────────────────
|
|
571
|
+
* Below the step the `<thead>` hides and each `<tr>` becomes a bordered key-value card. This is
|
|
572
|
+
* a genuine layout-mode swap (`display: block`) rather than a measure re-point, because the
|
|
573
|
+
* whole point of this preset is fields too heterogeneous for ANY fixed column measure to hold —
|
|
574
|
+
* unlike `action-collection`'s fixed-layout column budget above. Above the step, none of this
|
|
575
|
+
* matches and the table renders exactly as an ordinary `<table>`. One block per canonical step,
|
|
576
|
+
* same sm/md/lg/xl scale as `action-collection`. */
|
|
577
|
+
@container ui-table-stacked-collection (width < 40rem) {
|
|
578
|
+
[data-collapse-below="sm"] [data-slot="table"] {
|
|
579
|
+
display: block;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
[data-collapse-below="sm"] [data-slot="table"] > thead {
|
|
583
|
+
display: none;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
[data-collapse-below="sm"] [data-slot="table"] > tbody {
|
|
587
|
+
display: block;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
[data-collapse-below="sm"] .ui-table-row {
|
|
591
|
+
display: block;
|
|
592
|
+
border: 1px solid hsl(var(--border));
|
|
593
|
+
border-radius: var(--radius-md);
|
|
594
|
+
padding: var(--table-stacked-collection-card-padding-y)
|
|
595
|
+
var(--table-stacked-collection-card-padding-x);
|
|
596
|
+
margin-block-end: var(--table-stacked-collection-card-gap);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
[data-collapse-below="sm"] .ui-table-row:last-child {
|
|
600
|
+
margin-block-end: 0;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
[data-collapse-below="sm"] [data-slot="table-cell"] {
|
|
604
|
+
display: block;
|
|
605
|
+
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
606
|
+
white-space: normal;
|
|
607
|
+
overflow-wrap: anywhere;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
[data-collapse-below="sm"] .ui-table-stacked-collection-label {
|
|
611
|
+
display: block;
|
|
612
|
+
font-size: var(--table-stacked-collection-label-font-size);
|
|
613
|
+
font-weight: var(--font-weight-medium);
|
|
614
|
+
color: hsl(var(--muted-foreground));
|
|
615
|
+
margin-block-end: var(--space-stack-xs);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
@container ui-table-stacked-collection (width < 48rem) {
|
|
620
|
+
[data-collapse-below="md"] [data-slot="table"] {
|
|
621
|
+
display: block;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
[data-collapse-below="md"] [data-slot="table"] > thead {
|
|
625
|
+
display: none;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
[data-collapse-below="md"] [data-slot="table"] > tbody {
|
|
629
|
+
display: block;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
[data-collapse-below="md"] .ui-table-row {
|
|
633
|
+
display: block;
|
|
634
|
+
border: 1px solid hsl(var(--border));
|
|
635
|
+
border-radius: var(--radius-md);
|
|
636
|
+
padding: var(--table-stacked-collection-card-padding-y)
|
|
637
|
+
var(--table-stacked-collection-card-padding-x);
|
|
638
|
+
margin-block-end: var(--table-stacked-collection-card-gap);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
[data-collapse-below="md"] .ui-table-row:last-child {
|
|
642
|
+
margin-block-end: 0;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
[data-collapse-below="md"] [data-slot="table-cell"] {
|
|
646
|
+
display: block;
|
|
647
|
+
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
648
|
+
white-space: normal;
|
|
649
|
+
overflow-wrap: anywhere;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
[data-collapse-below="md"] .ui-table-stacked-collection-label {
|
|
653
|
+
display: block;
|
|
654
|
+
font-size: var(--table-stacked-collection-label-font-size);
|
|
655
|
+
font-weight: var(--font-weight-medium);
|
|
656
|
+
color: hsl(var(--muted-foreground));
|
|
657
|
+
margin-block-end: var(--space-stack-xs);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
@container ui-table-stacked-collection (width < 64rem) {
|
|
662
|
+
[data-collapse-below="lg"] [data-slot="table"] {
|
|
663
|
+
display: block;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
[data-collapse-below="lg"] [data-slot="table"] > thead {
|
|
667
|
+
display: none;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
[data-collapse-below="lg"] [data-slot="table"] > tbody {
|
|
671
|
+
display: block;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
[data-collapse-below="lg"] .ui-table-row {
|
|
675
|
+
display: block;
|
|
676
|
+
border: 1px solid hsl(var(--border));
|
|
677
|
+
border-radius: var(--radius-md);
|
|
678
|
+
padding: var(--table-stacked-collection-card-padding-y)
|
|
679
|
+
var(--table-stacked-collection-card-padding-x);
|
|
680
|
+
margin-block-end: var(--table-stacked-collection-card-gap);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
[data-collapse-below="lg"] .ui-table-row:last-child {
|
|
684
|
+
margin-block-end: 0;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
[data-collapse-below="lg"] [data-slot="table-cell"] {
|
|
688
|
+
display: block;
|
|
689
|
+
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
690
|
+
white-space: normal;
|
|
691
|
+
overflow-wrap: anywhere;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
[data-collapse-below="lg"] .ui-table-stacked-collection-label {
|
|
695
|
+
display: block;
|
|
696
|
+
font-size: var(--table-stacked-collection-label-font-size);
|
|
697
|
+
font-weight: var(--font-weight-medium);
|
|
698
|
+
color: hsl(var(--muted-foreground));
|
|
699
|
+
margin-block-end: var(--space-stack-xs);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
@container ui-table-stacked-collection (width < 80rem) {
|
|
704
|
+
[data-collapse-below="xl"] [data-slot="table"] {
|
|
705
|
+
display: block;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
[data-collapse-below="xl"] [data-slot="table"] > thead {
|
|
709
|
+
display: none;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
[data-collapse-below="xl"] [data-slot="table"] > tbody {
|
|
713
|
+
display: block;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
[data-collapse-below="xl"] .ui-table-row {
|
|
717
|
+
display: block;
|
|
718
|
+
border: 1px solid hsl(var(--border));
|
|
719
|
+
border-radius: var(--radius-md);
|
|
720
|
+
padding: var(--table-stacked-collection-card-padding-y)
|
|
721
|
+
var(--table-stacked-collection-card-padding-x);
|
|
722
|
+
margin-block-end: var(--table-stacked-collection-card-gap);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
[data-collapse-below="xl"] .ui-table-row:last-child {
|
|
726
|
+
margin-block-end: 0;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
[data-collapse-below="xl"] [data-slot="table-cell"] {
|
|
730
|
+
display: block;
|
|
731
|
+
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
732
|
+
white-space: normal;
|
|
733
|
+
overflow-wrap: anywhere;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
[data-collapse-below="xl"] .ui-table-stacked-collection-label {
|
|
737
|
+
display: block;
|
|
738
|
+
font-size: var(--table-stacked-collection-label-font-size);
|
|
739
|
+
font-weight: var(--font-weight-medium);
|
|
740
|
+
color: hsl(var(--muted-foreground));
|
|
741
|
+
margin-block-end: var(--space-stack-xs);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
539
744
|
}
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
/* DXS application-shell geometry. These defaults mirror the checked-in
|
|
25
25
|
* Admin/Console hi-fi source while remaining themeable by consumers. */
|
|
26
26
|
--app-shell-bar-height: 3rem;
|
|
27
|
+
/* (the coarse-pointer override lives at the end of this file — Rule #24 grows
|
|
28
|
+
* controls to 44px, and a 48px bar cannot hold a 44px control plus its 3px
|
|
29
|
+
* focus ring at the very top of the viewport, where overflow cannot help.) */
|
|
27
30
|
/* Inline inset and slot gap of the AppShell top bar. `-compact` applies below the shell
|
|
28
31
|
* breakpoint (the docked sidebar is gone, so the bar tightens against the viewport edge). */
|
|
29
32
|
--app-shell-bar-inset: var(--space-4);
|
|
@@ -346,3 +349,13 @@
|
|
|
346
349
|
* page is the plain page canvas, not the app's `--muted` chrome. */
|
|
347
350
|
--centered-shell-landing-background: initial;
|
|
348
351
|
}
|
|
352
|
+
|
|
353
|
+
/* Rule #24 companion (gh#291): on coarse pointers --control-height grows to 2.75rem
|
|
354
|
+
* (44px tap floor), and the shell bar sits flush with the viewport top — a 3rem bar
|
|
355
|
+
* leaves the control's 3px focus ring painting ABOVE y=0, off-screen, which no
|
|
356
|
+
* overflow setting can recover. 3.5rem gives 6px of breathing per side. */
|
|
357
|
+
@media (pointer: coarse) {
|
|
358
|
+
:root {
|
|
359
|
+
--app-shell-bar-height: 3.5rem;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -136,3 +136,15 @@
|
|
|
136
136
|
* Japanese at the compact type tier) and the table scrolls instead of crushing. */
|
|
137
137
|
--table-action-collection-min-inline-size-compact: 0;
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
/* Table · stacked-record-collection preset (gh#293 restore — SCR-215) — the canonical WIDE,
|
|
141
|
+
* heterogeneous record collection. Below the collapse step every `<tr>` becomes a bordered
|
|
142
|
+
* key-value card; these tokens own the card's own geometry (unlike action-collection, there is no
|
|
143
|
+
* column-priority measure to retune — the whole row becomes one block). */
|
|
144
|
+
:root {
|
|
145
|
+
--table-stacked-collection-card-padding-y: var(--space-stack-sm);
|
|
146
|
+
--table-stacked-collection-card-padding-x: var(--space-inline-md);
|
|
147
|
+
--table-stacked-collection-card-gap: var(--space-stack-sm);
|
|
148
|
+
--table-stacked-collection-cell-padding-y: var(--space-stack-xs);
|
|
149
|
+
--table-stacked-collection-label-font-size: var(--font-size-xs);
|
|
150
|
+
}
|
|
@@ -153,6 +153,14 @@
|
|
|
153
153
|
* default re-resolves at the element that paints the ring while an explicit override still wins. */
|
|
154
154
|
--focus-ring-color: initial; /* default = the live --ring role */
|
|
155
155
|
--focus-ring-width: 2px;
|
|
156
|
+
/* Ring headroom for clipped chrome (`overflow-clip-margin` on the topbar family, gh#291).
|
|
157
|
+
* MUST stay a plain length consumed via a bare var(): Chromium rejects any calc() in
|
|
158
|
+
* overflow-clip-margin at parse time (even calc(2 * 2px)), silently dropping the
|
|
159
|
+
* declaration to 0. Value = max ring paint (3px open/focus) + rounding immunity:
|
|
160
|
+
* at 4px a flush-edge ring had only 1px of slack, which device-pixel rounding on
|
|
161
|
+
* non-retina (dpr 1) displays or fractional browser zoom could consume, shaving the
|
|
162
|
+
* ring's outer edge. 8px keeps ≥5px of slack under any rounding regime. */
|
|
163
|
+
--focus-ring-clip-margin: 8px;
|
|
156
164
|
/* REGION focus ring — the keyboard-scroll affordance on large scroll REGIONS (`.app-main`,
|
|
157
165
|
* gh#271/gh#276), separate from the control ring above. A control-strength 2px brand frame
|
|
158
166
|
* around the entire content area reads as a glitch to mouse-first users (`:focus-visible`
|