@godxjp/ui 18.15.3 → 19.0.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/app/date-format-labels.d.ts +1 -1
- package/dist/app/time-format-labels.d.ts +1 -1
- package/dist/components/data-display/badge.d.ts +1 -1
- package/dist/components/data-display/card.d.ts +4 -13
- package/dist/components/data-display/card.js +2 -15
- package/dist/components/data-display/data-table.d.ts +3 -8
- package/dist/components/data-display/data-table.js +106 -68
- package/dist/components/data-display/descriptions.js +34 -5
- package/dist/components/data-display/empty-state.js +1 -1
- package/dist/components/data-display/permission-matrix.js +7 -7
- package/dist/components/data-display/popover.js +2 -9
- package/dist/components/data-display/qr-code.d.ts +1 -1
- package/dist/components/data-display/scroll-area.d.ts +3 -1
- package/dist/components/data-display/scroll-area.js +150 -16
- package/dist/components/data-display/table.js +12 -3
- package/dist/components/data-entry/branch-scope-picker.js +4 -4
- package/dist/components/data-entry/calendar.js +15 -24
- package/dist/components/data-entry/cascader.js +67 -71
- package/dist/components/data-entry/checkbox.js +9 -1
- package/dist/components/data-entry/command.d.ts +6 -6
- package/dist/components/data-entry/date-picker.js +28 -15
- package/dist/components/data-entry/date-range-picker.js +10 -10
- package/dist/components/data-entry/form-field.js +7 -3
- package/dist/components/data-entry/index.d.ts +2 -1
- package/dist/components/data-entry/input.js +8 -19
- package/dist/components/data-entry/label.js +4 -2
- package/dist/components/data-entry/month-picker.js +16 -15
- package/dist/components/data-entry/month-range-picker.js +17 -16
- package/dist/components/data-entry/radio.js +6 -1
- package/dist/components/data-entry/search-select.js +29 -29
- package/dist/components/data-entry/select.js +15 -18
- package/dist/components/data-entry/switch.js +7 -1
- package/dist/components/data-entry/textarea.d.ts +56 -0
- package/dist/components/data-entry/textarea.js +103 -40
- package/dist/components/data-entry/time-picker.js +52 -52
- package/dist/components/data-entry/toggle-group.d.ts +1 -0
- package/dist/components/data-entry/toggle.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +14 -15
- package/dist/components/data-entry/tree-select.js +16 -22
- package/dist/components/data-entry/upload-crop-dialog.js +4 -4
- package/dist/components/data-entry/upload.d.ts +1 -1
- package/dist/components/data-entry/upload.js +46 -46
- package/dist/components/feedback/alert.js +7 -14
- package/dist/components/feedback/dialog.d.ts +23 -32
- package/dist/components/feedback/dialog.js +16 -13
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +14 -14
- package/dist/components/feedback/skeleton.js +13 -10
- package/dist/components/feedback/sonner.d.ts +1 -1
- package/dist/components/feedback/sonner.js +17 -8
- package/dist/components/feedback/tooltip.js +1 -1
- package/dist/components/general/activity.d.ts +44 -0
- package/dist/components/general/activity.js +65 -0
- package/dist/components/general/button.d.ts +2 -2
- package/dist/components/general/button.js +11 -24
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/layout/app-shell.js +5 -3
- package/dist/components/layout/auth-divider.d.ts +9 -2
- package/dist/components/layout/auth-divider.js +7 -11
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +32 -20
- package/dist/components/layout/resizable.d.ts +12 -12
- package/dist/components/layout/separator.d.ts +1 -0
- package/dist/components/layout/service-role-panel.js +47 -42
- package/dist/components/layout/sidebar.js +13 -1
- package/dist/components/layout/split-pane.d.ts +12 -1
- package/dist/components/layout/split-pane.js +13 -4
- package/dist/components/navigation/app-setting-picker.js +5 -14
- package/dist/components/navigation/dropdown-menu.js +10 -16
- package/dist/components/navigation/menubar.d.ts +3 -6
- package/dist/components/navigation/pagination-utils.d.ts +15 -2
- package/dist/components/navigation/pagination-utils.js +27 -21
- package/dist/components/navigation/pagination.d.ts +4 -4
- package/dist/components/navigation/pagination.js +2 -2
- package/dist/components/navigation/steps.js +31 -67
- package/dist/components/navigation/tabs.js +17 -5
- package/dist/components/query/infinite-query-state.js +2 -2
- package/dist/components/ui/accordion.d.ts +1 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +29 -10
- package/dist/components/ui/input-otp.d.ts +8 -6
- package/dist/components/ui/rating.js +1 -1
- package/dist/components/ui/separator.d.ts +27 -2
- package/dist/components/ui/separator.js +42 -11
- package/dist/components/ui/toggle-group.d.ts +15 -5
- package/dist/components/ui/toggle-group.js +43 -18
- package/dist/components/ui/toggle.d.ts +66 -5
- package/dist/components/ui/toggle.js +64 -9
- package/dist/i18n/messages/en.json +8 -0
- package/dist/i18n/messages/ja.json +8 -0
- package/dist/i18n/messages/vi.json +8 -0
- package/dist/lib/control-styles.d.ts +14 -0
- package/dist/lib/control-styles.js +2 -0
- package/dist/props/components/data-display.prop.d.ts +85 -3
- package/dist/props/components/data-entry.prop.d.ts +17 -0
- package/dist/props/components/general.prop.d.ts +52 -1
- package/dist/props/components/layout.prop.d.ts +137 -2
- package/dist/props/registry.d.ts +116 -5
- package/dist/props/registry.js +165 -4
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/interaction.prop.d.ts +15 -0
- package/dist/props/vocabulary/layout.prop.d.ts +8 -0
- package/dist/styles/alert-layout.css +69 -3
- package/dist/styles/badge-layout.css +2 -2
- package/dist/styles/base.css +6 -0
- package/dist/styles/card-layout.css +27 -7
- package/dist/styles/control.css +1150 -29
- package/dist/styles/data-display-layout.css +185 -11
- package/dist/styles/data-entry-layout.css +352 -1
- package/dist/styles/density.css +2 -2
- package/dist/styles/dialog-layout.css +203 -4
- package/dist/styles/focus-ring.css +155 -0
- package/dist/styles/form-layout.css +50 -5
- package/dist/styles/index.css +1 -0
- package/dist/styles/layout.css +412 -23
- package/dist/styles/motion.css +178 -0
- package/dist/styles/navigation-layout.css +398 -22
- package/dist/styles/shell-layout.css +137 -39
- package/dist/styles/table-layout.css +153 -22
- package/dist/styles/toggle.css +59 -0
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/activity.css +64 -0
- package/dist/tokens/components/badge.css +7 -0
- package/dist/tokens/components/card.css +14 -10
- package/dist/tokens/components/chart.css +1 -1
- package/dist/tokens/components/control.css +358 -8
- package/dist/tokens/components/data-display.css +75 -0
- package/dist/tokens/components/data-entry.css +25 -0
- package/dist/tokens/components/descriptions.css +22 -0
- package/dist/tokens/components/feedback.css +143 -4
- package/dist/tokens/components/form.css +16 -0
- package/dist/tokens/components/legal-document.css +5 -1
- package/dist/tokens/components/navigation.css +109 -0
- package/dist/tokens/components/scroll-area.css +21 -0
- package/dist/tokens/components/separator.css +52 -0
- package/dist/tokens/components/shell.css +132 -20
- package/dist/tokens/components/table.css +52 -3
- package/dist/tokens/components/toggle.css +82 -0
- package/dist/tokens/components/upload.css +107 -0
- package/dist/tokens/foundation.css +171 -10
- package/dist/tokens/semantic/layout.css +120 -1
- package/package.json +84 -68
- package/scripts/ui-audit.mjs +51 -2
|
@@ -73,19 +73,19 @@
|
|
|
73
73
|
* Tokenised (rule #44) so a service theme can re-tune it without forking CSS.
|
|
74
74
|
* The slot padding compensation in card-layout.css subtracts the same token,
|
|
75
75
|
* so content stays aligned on the shell whatever the rail width. */
|
|
76
|
-
--card-accent-rail-width:
|
|
76
|
+
--card-accent-rail-width: var(--stroke-2xl);
|
|
77
77
|
/* Accent placement `perimeter` (gh#12) — the FULL attention border. Two knobs so a service can
|
|
78
78
|
* tune the edge weight and the outer ring independently; the defaults reproduce the optical
|
|
79
79
|
* weight of `variant="featured"` (1px border + 1px ring) in the card's own semantic accent tone
|
|
80
80
|
* instead of --primary. Structural 1px literals, like the base card hairline. */
|
|
81
|
-
--card-accent-perimeter-width:
|
|
82
|
-
--card-accent-perimeter-ring-width:
|
|
81
|
+
--card-accent-perimeter-width: var(--stroke-hairline);
|
|
82
|
+
--card-accent-perimeter-ring-width: var(--stroke-hairline);
|
|
83
83
|
/* `variant="featured"` edge — role-mirror knob (docs/TOKENS.md). `initial` so the --primary
|
|
84
84
|
* default resolves at the CALL SITE and a scoped [data-tenant]/.dark override of --primary
|
|
85
85
|
* reaches it; a service points it anywhere (e.g. var(--attention)) to retint every featured card
|
|
86
86
|
* at once. Default = hsl(var(--primary)). */
|
|
87
87
|
--card-featured-border-color: initial;
|
|
88
|
-
--card-featured-ring-width:
|
|
88
|
+
--card-featured-ring-width: var(--stroke-hairline);
|
|
89
89
|
--stat-card-label-font-size: var(--font-size-xs);
|
|
90
90
|
--stat-card-label-font-weight: var(--font-weight-medium);
|
|
91
91
|
--stat-card-label-letter-spacing: 0.04em;
|
|
@@ -94,8 +94,8 @@
|
|
|
94
94
|
--stat-card-value-font-weight: var(--font-weight-semibold);
|
|
95
95
|
--stat-card-hint-font-size: var(--font-size-xs);
|
|
96
96
|
--stat-card-gap: var(--space-stack-xs);
|
|
97
|
-
--stat-card-icon-size:
|
|
98
|
-
--stat-card-icon-glyph-size:
|
|
97
|
+
--stat-card-icon-size: var(--icon-size-2xl);
|
|
98
|
+
--stat-card-icon-glyph-size: var(--icon-size-lg);
|
|
99
99
|
--stat-card-icon-radius: var(--radius-md);
|
|
100
100
|
/* Medallion tint — soft brand wash + brand glyph by default; a service retints by overriding
|
|
101
101
|
* --primary or these tokens directly (rule #44/#45). `initial` so the --primary default
|
|
@@ -108,10 +108,14 @@
|
|
|
108
108
|
* Internal rhythm of a launcher tile: one gap knob drives the vertical stack AND the
|
|
109
109
|
* icon↔title↔status row, so a service theme retunes the whole tile density once. */
|
|
110
110
|
--card-service-launcher-space-gap: var(--space-stack-sm);
|
|
111
|
-
/* Semantic icon surface
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
/* Semantic icon surface — 36px, the `--icon-size-2xl` step, multiplied by --scaling so the
|
|
112
|
+
* medallion still breathes with its sibling controls (the gh#328 rule: an icon that wants
|
|
113
|
+
* density says so itself). It read `var(--control-height-lg)` until gh#324: a CONTROL tier is
|
|
114
|
+
* the wrong axis for an icon box, and the bug was visible — `@media (pointer: coarse)` lifts
|
|
115
|
+
* the control ladder to the 44px tap floor, so on every touch device the medallion silently
|
|
116
|
+
* inflated to 48px while the glyph inside it stayed 20px. */
|
|
117
|
+
--card-service-launcher-icon-size: calc(var(--icon-size-2xl) * var(--scaling));
|
|
118
|
+
--card-service-launcher-icon-glyph-size: calc(var(--icon-size-lg) * var(--scaling));
|
|
115
119
|
--card-service-launcher-icon-radius: var(--radius-md);
|
|
116
120
|
/* Available-service medallion tint. `initial` (role-mirror rule, docs/TOKENS.md) so the role
|
|
117
121
|
* defaults resolve at the CALL SITE and a scoped [data-tenant]/.dark override reaches them.
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
/* Ceiling on a single mark so a 3-point trend does not render slabs. */
|
|
26
26
|
--chart-trend-bar-max-width: 1.5rem;
|
|
27
27
|
/* Floor so a zero/absent value still reads as a plotted category rather than a hole. */
|
|
28
|
-
--chart-trend-bar-min-height:
|
|
28
|
+
--chart-trend-bar-min-height: var(--stroke-md);
|
|
29
29
|
/* Muted mark fill — role-mirror knob, declared `initial` so the role default re-resolves
|
|
30
30
|
* at the CALL SITE under `.dark` / `[data-tenant]` (docs/TOKENS.md · "Role-mirror knobs
|
|
31
31
|
* MUST be `initial`"). Default = hsl(var(--muted-foreground) / 0.75), which clears the
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* Control primitive tokens: heights, horizontal padding, adjacent control sizes. */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
-
--control-height-compact:
|
|
5
|
-
--control-height-default:
|
|
6
|
-
--control-height-comfortable:
|
|
4
|
+
--control-height-compact: var(--band-height-sm);
|
|
5
|
+
--control-height-default: var(--band-height-md);
|
|
6
|
+
--control-height-comfortable: var(--band-height-xl);
|
|
7
7
|
--control-padding-x-compact: var(--space-2);
|
|
8
8
|
--control-padding-x-default: var(--space-3);
|
|
9
9
|
--control-padding-x-comfortable: var(--space-4);
|
|
@@ -27,12 +27,24 @@
|
|
|
27
27
|
* once instead of each component hard-coding Tailwind utilities. Defaults preserve
|
|
28
28
|
* the historical look (font-size-base, 1px border, shadow-xs). */
|
|
29
29
|
--control-font-size: var(--font-size-base);
|
|
30
|
-
--control-border-width:
|
|
30
|
+
--control-border-width: var(--stroke-hairline);
|
|
31
31
|
--control-shadow: var(--shadow-xs);
|
|
32
|
-
--control-icon-size: calc(
|
|
33
|
-
--control-icon-size-sm: calc(
|
|
32
|
+
--control-icon-size: calc(var(--icon-size-md) * var(--scaling));
|
|
33
|
+
--control-icon-size-sm: calc(var(--icon-size-sm) * var(--scaling));
|
|
34
34
|
--control-focus-ring-width: var(--focus-ring-width);
|
|
35
35
|
|
|
36
|
+
/* Ring knobs for the two controls that need a softer, heavier mark than the
|
|
37
|
+
* global default — both are filled surfaces where a hard 2px ring reads as a
|
|
38
|
+
* second border. Values preserve the look these controls always had; they are
|
|
39
|
+
* knobs now instead of hand-written box-shadows (styles/focus-ring.css). */
|
|
40
|
+
--toggle-focus-ring-width: var(--stroke-lg);
|
|
41
|
+
--toggle-focus-ring-alpha: 0.35;
|
|
42
|
+
--time-input-focus-ring-width: var(--stroke-lg);
|
|
43
|
+
--time-input-focus-ring-alpha: 0.3;
|
|
44
|
+
|
|
45
|
+
/* Outline-form gaps — marks where a radius-hugging ring would touch the glyph. */
|
|
46
|
+
--rating-focus-ring-offset: 2px;
|
|
47
|
+
|
|
36
48
|
--checkbox-size: calc(1rem * var(--scaling));
|
|
37
49
|
--checkbox-size-compact: 0.875rem;
|
|
38
50
|
--checkbox-size-comfortable: 1.125rem;
|
|
@@ -94,8 +106,16 @@
|
|
|
94
106
|
--slider-track-background: initial;
|
|
95
107
|
--slider-range-background: initial;
|
|
96
108
|
|
|
109
|
+
/* Switch OFF track fill (gh#315) — `initial`, default hsl(var(--input)). Its own knob so a
|
|
110
|
+
* service can quieten the off-track without dragging the --input control-boundary role back
|
|
111
|
+
* below the WCAG SC 1.4.11 floor (rule #45); whatever you set still owes 3:1 against the page
|
|
112
|
+
* and against the thumb (--background), or "off" stops being a visible state. */
|
|
113
|
+
--switch-unchecked-background: initial;
|
|
114
|
+
|
|
115
|
+
/* ColorPicker — width of the hex text field beside the swatch. */
|
|
97
116
|
--color-picker-input-width: 6.5rem;
|
|
98
117
|
|
|
118
|
+
/* Command / CommandPalette — list height, inner paddings and the palette's own box. */
|
|
99
119
|
--command-list-max-height: min(300px, 50vh);
|
|
100
120
|
--command-input-padding-x: var(--space-3);
|
|
101
121
|
--command-group-padding: var(--space-1);
|
|
@@ -107,6 +127,9 @@
|
|
|
107
127
|
--command-palette-hint-padding-y: var(--space-2);
|
|
108
128
|
--command-palette-hint-padding-x: var(--space-4);
|
|
109
129
|
--command-palette-hint-gap: var(--space-4);
|
|
130
|
+
|
|
131
|
+
/* SearchInput — the inset the leading/trailing icons sit at, and the field padding derived
|
|
132
|
+
* from it so the text never runs under an icon. */
|
|
110
133
|
--search-input-edge-inset: var(--space-3);
|
|
111
134
|
--search-input-start-padding: calc(
|
|
112
135
|
var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap)
|
|
@@ -115,6 +138,8 @@
|
|
|
115
138
|
var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap)
|
|
116
139
|
);
|
|
117
140
|
|
|
141
|
+
/* The --font-size-xs tier, spelled once per control that reads it, so a service can retune a
|
|
142
|
+
* single one of them without moving the whole scale. */
|
|
118
143
|
--choice-description-font-size: var(--font-size-xs);
|
|
119
144
|
--color-picker-hex-font-size: var(--font-size-xs);
|
|
120
145
|
--command-group-heading-font-size: var(--font-size-xs);
|
|
@@ -127,9 +152,334 @@
|
|
|
127
152
|
/* Rule #24 — on touch devices (coarse pointer) interactive controls keep a ≥44px tap target
|
|
128
153
|
* regardless of density; desktop (fine pointer) keeps the compact heights above. --control-height
|
|
129
154
|
* resolves through these via var(), so inputs/buttons/selects/table rows all bump together. */
|
|
155
|
+
/* Control-family tokens added for #319.
|
|
156
|
+
*
|
|
157
|
+
* These MUST live in a plain :root, not inside the @media (pointer: coarse) block below —
|
|
158
|
+
* bare declarations in a conditional group rule are invalid CSS and the parser drops them
|
|
159
|
+
* silently. They spent this whole refactor dead for exactly that reason: the guards read the
|
|
160
|
+
* file textually, so check-token-tiers and the geometry ratchet both passed while every one of
|
|
161
|
+
* these resolved to nothing. */
|
|
162
|
+
:root {
|
|
163
|
+
/* TRAILING AFFIX — the clear ✕ / chevron overlay a select-family trigger parks at its inline
|
|
164
|
+
* end. Select, SearchSelect and TagInput each hard-coded the same `end-2 size-6 rounded-sm
|
|
165
|
+
* opacity-50` stack independently (#319), so a service retuning affix weight had to chase the
|
|
166
|
+
* literal through several components. One shared set of knobs instead — this is a CONTROL-level
|
|
167
|
+
* concern, not a per-component one. */
|
|
168
|
+
--control-affix-inset-inline-end: var(--space-2);
|
|
169
|
+
--control-affix-action-size: 1.5rem;
|
|
170
|
+
--control-affix-action-radius: var(--radius-sm);
|
|
171
|
+
--control-affix-icon-size: var(--icon-size-md);
|
|
172
|
+
/* Resting weight of an affix glyph — it must read as secondary until hovered/focused. */
|
|
173
|
+
--control-affix-rest-alpha: 0.5;
|
|
174
|
+
/* Room a trigger reserves so its label never runs under the affix. */
|
|
175
|
+
/* 2.25rem — the room a single trailing affix needs. Written as a raw rem because the
|
|
176
|
+
* literal it replaced (`pe-9`) is a flat Tailwind step, not a density-scaled one. */
|
|
177
|
+
--control-trigger-space-inline-end: 2.25rem;
|
|
178
|
+
|
|
179
|
+
/* INSIDE-FIELD AFFIX — the leading/trailing controls Input and TimePicker render WITHIN the
|
|
180
|
+
* field box, as opposed to the overlay affix (--control-affix-*) that Select and SearchSelect
|
|
181
|
+
* park on top of a trigger. Both carried the identical literal stack (#319). Because these sit
|
|
182
|
+
* on the field's own surface rather than over it, they rest a touch heavier than the overlay
|
|
183
|
+
* pair — that difference is the reason the two sets stay separate. */
|
|
184
|
+
--control-inline-affix-size: 1.25rem;
|
|
185
|
+
--control-inline-affix-icon-size: var(--control-affix-icon-size);
|
|
186
|
+
--control-inline-affix-space-gap: var(--space-1);
|
|
187
|
+
--control-inline-affix-inset-inline: var(--space-2);
|
|
188
|
+
--control-inline-affix-rest-alpha: 0.7;
|
|
189
|
+
/* Inline room the field reserves so its text never runs under a single affix. */
|
|
190
|
+
--control-inline-affix-space-inline-end: 2.25rem;
|
|
191
|
+
/* Input centres its affix on the field's single line; a textarea has no single line to centre
|
|
192
|
+
* on, so its clear control parks at the top-end corner instead. */
|
|
193
|
+
--textarea-clear-inset-block-start: var(--space-2);
|
|
194
|
+
/* MULTILINE BOX — the block padding of `.ui-control-multiline` (Textarea). It was a bare
|
|
195
|
+
* `--space-2` inside the padding shorthand, which made it unreachable for a service that runs a
|
|
196
|
+
* denser composer, AND it is the constant the auto-grow row maths has to add back, so the two
|
|
197
|
+
* had to read the same knob or drift (#45). */
|
|
198
|
+
--control-multiline-padding-block: var(--space-2);
|
|
199
|
+
/* TEXTAREA AUTO-GROW (gh#310) — `autoGrow` grows the box with its content between a floor and a
|
|
200
|
+
* ceiling expressed in TEXT ROWS. Rows, not pixels, because a row count survives a density
|
|
201
|
+
* change and a `--font-size-base` retheme where a px ceiling would silently stop matching the
|
|
202
|
+
* visible line count. Defaults reproduce today's geometry when `autoGrow` is absent (#44). */
|
|
203
|
+
/* The unit a "row" is measured in. `initial` on purpose: the call site reads
|
|
204
|
+
* `var(--textarea-autogrow-line-height, var(--line-height-normal))`, so a service that retunes
|
|
205
|
+
* the multiline line-height for CJK legibility retunes the ceiling with it (#46). Unitless —
|
|
206
|
+
* it is multiplied by `--control-font-size`. */
|
|
207
|
+
--textarea-autogrow-line-height: initial;
|
|
208
|
+
/* Floor of the grown box, in text rows. The `minRows` prop overrides per instance — the same
|
|
209
|
+
* theme-global / prop-local priority as `--form-label-width` vs `labelWidth`. The floor is
|
|
210
|
+
* additionally clamped up to `--control-height` so a resting one-row composer still lines up
|
|
211
|
+
* with the Input / Button beside it instead of undercutting the control tier. */
|
|
212
|
+
--textarea-autogrow-min-height-rows: 1;
|
|
213
|
+
/* Ceiling of the grown box, in text rows; past it the control scrolls internally instead of
|
|
214
|
+
* pushing the page. `maxRows={0}` sets this to `infinity` for an unbounded box. */
|
|
215
|
+
--textarea-autogrow-max-height-rows: 8;
|
|
216
|
+
/* The non-text part of the box the row maths must add back: block padding + border, both
|
|
217
|
+
* edges. `.ui-textarea-autogrow--ghost` re-declares it without the border, because the ghost
|
|
218
|
+
* variant drops its own chrome. */
|
|
219
|
+
--textarea-autogrow-box-inset: calc(
|
|
220
|
+
(var(--control-multiline-padding-block) + var(--control-border-width)) * 2
|
|
221
|
+
);
|
|
222
|
+
/* A field parking TWO inline affixes (TimePicker's clear+clock, DatePicker's clear+calendar)
|
|
223
|
+
* reserves a wider end than the single-affix case. */
|
|
224
|
+
--control-inline-affix-pair-space-inline-end: 3.5rem;
|
|
225
|
+
/* COMPOSITE FIELD — the bordered box that wraps two inputs plus a separator (date/month
|
|
226
|
+
* range pickers) or one input plus affixes. Shared so the four range/picker fields cannot
|
|
227
|
+
* drift into four slightly different boxes. */
|
|
228
|
+
--control-composite-field-space-gap: var(--space-2);
|
|
229
|
+
/* The <input type=file> button is a browser-owned box we restyle; it sits one tier below the
|
|
230
|
+
* field so it reads as a control INSIDE the control. */
|
|
231
|
+
--input-file-button-height: var(--band-height-sm);
|
|
232
|
+
--input-file-button-font-size: var(--font-size-sm);
|
|
233
|
+
|
|
234
|
+
/* SEARCH-SELECT — the Popover+Command combobox. Its panel geometry was baked onto the
|
|
235
|
+
* component as arbitrary values (`max-w-[min(32rem,calc(100vw-1.5rem))]`), so a service could
|
|
236
|
+
* not widen the panel or change the viewport gutter without forking. */
|
|
237
|
+
--search-select-panel-max-width: 32rem;
|
|
238
|
+
--search-select-panel-viewport-inset: var(--space-6);
|
|
239
|
+
--search-select-list-space-inset: var(--space-1);
|
|
240
|
+
--search-select-footer-space-inset: var(--space-1);
|
|
241
|
+
--search-select-option-space-gap: var(--space-2);
|
|
242
|
+
--search-select-option-font-size: var(--font-size-sm);
|
|
243
|
+
--search-select-option-sublabel-font-size: var(--font-size-xs);
|
|
244
|
+
--search-select-status-space-inline: var(--space-2);
|
|
245
|
+
--search-select-status-space-block: var(--space-3);
|
|
246
|
+
/* Empty/error states sit alone in the panel, so they get a taller, centred block. */
|
|
247
|
+
--search-select-placeholder-space-block: var(--space-6);
|
|
248
|
+
--search-select-status-font-size: var(--font-size-sm);
|
|
249
|
+
--search-select-spinner-size: 1rem;
|
|
250
|
+
|
|
251
|
+
/* CASCADER — column browser + flat search list. Its option rows, column widths and panel
|
|
252
|
+
* paddings were literals on the component (#319), so a service could not widen a column to fit
|
|
253
|
+
* longer JA labels or tighten the row rhythm without forking. */
|
|
254
|
+
--cascader-column-min-width: 9rem;
|
|
255
|
+
--cascader-columns-max-height: min(280px, 50vh);
|
|
256
|
+
--cascader-list-max-height: min(300px, 50vh);
|
|
257
|
+
--cascader-panel-space-inset: var(--space-1);
|
|
258
|
+
--cascader-option-space-inline: var(--space-3);
|
|
259
|
+
--cascader-option-space-block: var(--space-2);
|
|
260
|
+
--cascader-option-space-gap: var(--space-1);
|
|
261
|
+
--cascader-option-font-size: var(--font-size-sm);
|
|
262
|
+
--cascader-option-icon-size: var(--icon-size-md);
|
|
263
|
+
/* The flat search result row is denser than a column row — it has no chevron to balance. */
|
|
264
|
+
--cascader-result-space-inline: var(--space-2);
|
|
265
|
+
--cascader-result-space-block: 0.375rem;
|
|
266
|
+
--cascader-result-radius: var(--radius-sm);
|
|
267
|
+
--cascader-result-icon-space-inline-end: var(--space-2);
|
|
268
|
+
--cascader-empty-space-block: var(--space-6);
|
|
269
|
+
|
|
270
|
+
/* SELECT — the Radix listbox surface. Its popup shares the menu row rhythm (--menu-item-*),
|
|
271
|
+
* so only what is genuinely its own lives here (#319). */
|
|
272
|
+
--select-content-max-height: 24rem;
|
|
273
|
+
--select-scroll-button-space-block: var(--space-1);
|
|
274
|
+
/* Select rows sit slightly wider than a menu row: a listbox has no leading icon column to
|
|
275
|
+
* absorb the optical inset, so 2.5 reads level with a menu's 2 + icon. */
|
|
276
|
+
--select-item-space-inline: 0.625rem;
|
|
277
|
+
|
|
278
|
+
/* TIME PICKER — scroll columns of hour/minute/second plus an inline affix pair. All of its
|
|
279
|
+
* geometry was literal on the component (#319): a service could not shorten the column, widen
|
|
280
|
+
* the panel for a 12-hour layout, or retune the row rhythm without forking. */
|
|
281
|
+
--time-picker-column-height: 13rem;
|
|
282
|
+
--time-picker-panel-width: 9rem;
|
|
283
|
+
/* 12-hour mode adds an AM/PM column, so the panel is wider. */
|
|
284
|
+
--time-picker-panel-width-12h: 13rem;
|
|
285
|
+
--time-picker-heading-space-inline: var(--space-1);
|
|
286
|
+
--time-picker-heading-space-block: 0.375rem;
|
|
287
|
+
--time-picker-heading-font-size: var(--font-size-xs);
|
|
288
|
+
--time-picker-column-space-inset: var(--space-1);
|
|
289
|
+
--time-picker-option-space-block: 0.375rem;
|
|
290
|
+
--time-picker-option-radius: var(--radius-md);
|
|
291
|
+
--time-picker-option-font-size: var(--font-size-sm);
|
|
292
|
+
--time-picker-footer-space-inset: var(--space-2);
|
|
293
|
+
|
|
294
|
+
--time-picker-affix-space-gap: var(--control-inline-affix-space-gap);
|
|
295
|
+
|
|
296
|
+
/* TREE SELECT — a Select whose panel holds a tree. Its rows, indent and toggle were literal
|
|
297
|
+
* on the component, and the depth indent was a magic expression in JSX
|
|
298
|
+
* (`depth * 1.25 + 0.5` rem) that no theme could reach at all (#319). */
|
|
299
|
+
--tree-select-list-max-height: min(300px, 50vh);
|
|
300
|
+
--tree-select-row-space-block: 0.375rem;
|
|
301
|
+
--tree-select-row-space-inline-end: var(--space-2);
|
|
302
|
+
--tree-select-row-radius: var(--radius-sm);
|
|
303
|
+
--tree-select-row-font-size: var(--font-size-sm);
|
|
304
|
+
/* Indent = base + depth × step. A denser service dials the step down without touching JSX. */
|
|
305
|
+
--tree-select-depth-space-base: var(--space-2);
|
|
306
|
+
--tree-select-depth-space-step: 1.25rem;
|
|
307
|
+
--tree-select-toggle-size: 1.25rem;
|
|
308
|
+
--tree-select-toggle-space-inline-end: var(--space-1);
|
|
309
|
+
--tree-select-label-space-gap: var(--space-2);
|
|
310
|
+
--tree-select-empty-space-block: var(--space-6);
|
|
311
|
+
|
|
312
|
+
/* CALENDAR — the react-day-picker grid. Day/weekday cells already size from --control-height
|
|
313
|
+
* (the system control tier), but the frame around them — root inset, month gaps, nav offset,
|
|
314
|
+
* grid rhythm — was literal on the component (#319), so a service could not tighten the
|
|
315
|
+
* calendar to its own density without forking the classNames map. */
|
|
316
|
+
--calendar-space-inset: var(--space-3);
|
|
317
|
+
--calendar-month-space-gap: var(--space-4);
|
|
318
|
+
--calendar-caption-space-inline: var(--space-8);
|
|
319
|
+
--calendar-caption-font-size: var(--font-size-sm);
|
|
320
|
+
--calendar-nav-space-block-start: var(--space-3);
|
|
321
|
+
--calendar-nav-space-inline: var(--space-1);
|
|
322
|
+
/* Nav chevrons read as secondary until hovered — they frame the month, they are not the point. */
|
|
323
|
+
--calendar-nav-rest-alpha: 0.7;
|
|
324
|
+
--calendar-grid-space-block-start: var(--space-4);
|
|
325
|
+
--calendar-week-space-block-start: var(--space-2);
|
|
326
|
+
--calendar-weekday-font-size: var(--font-size-xs);
|
|
327
|
+
--calendar-weekday-radius: var(--radius-md);
|
|
328
|
+
--calendar-day-font-size: var(--font-size-sm);
|
|
329
|
+
--calendar-day-radius: var(--radius-md);
|
|
330
|
+
--calendar-chevron-size: var(--icon-size-md);
|
|
331
|
+
|
|
332
|
+
/* TRANSFER — the two-pane list mover. Pane height, header rhythm and row density were literal
|
|
333
|
+
* on the component (#319), so a service could not fit the panes to its own page grid or
|
|
334
|
+
* tighten the row for a dense admin table without forking. */
|
|
335
|
+
--transfer-pane-min-height: 14rem;
|
|
336
|
+
--transfer-pane-radius: var(--radius-md);
|
|
337
|
+
--transfer-panes-space-gap: var(--space-3);
|
|
338
|
+
--transfer-header-space-inline: var(--space-3);
|
|
339
|
+
--transfer-header-space-block: var(--space-2);
|
|
340
|
+
--transfer-header-font-size: var(--font-size-sm);
|
|
341
|
+
--transfer-header-space-gap: var(--space-2);
|
|
342
|
+
--transfer-search-space-inset: var(--space-2);
|
|
343
|
+
--transfer-list-space-inset: var(--space-1);
|
|
344
|
+
--transfer-row-space-inline: var(--space-2);
|
|
345
|
+
--transfer-row-space-block: var(--space-2);
|
|
346
|
+
--transfer-row-space-gap: var(--space-2);
|
|
347
|
+
--transfer-row-radius: var(--radius-sm);
|
|
348
|
+
--transfer-row-font-size: var(--font-size-sm);
|
|
349
|
+
/* The checkbox is top-aligned against a two-line row, so it needs a hair of optical offset to
|
|
350
|
+
* sit level with the first line's cap height rather than its box. */
|
|
351
|
+
--transfer-row-check-space-block-start: 0.125rem;
|
|
352
|
+
--transfer-row-description-font-size: var(--font-size-xs);
|
|
353
|
+
--transfer-empty-space-block: var(--space-8);
|
|
354
|
+
--transfer-actions-space-gap: var(--space-2);
|
|
355
|
+
--transfer-action-icon-size: var(--icon-size-md);
|
|
356
|
+
|
|
357
|
+
/* MONTH PICKER — shared by MonthPicker and MonthRangePicker, which render the same year-nav +
|
|
358
|
+
* 3-column month grid. Both carried an identical copy of every literal (#319); one set of knobs
|
|
359
|
+
* now drives both, so they cannot drift apart the way Select and DropdownMenu once did. */
|
|
360
|
+
--month-picker-panel-space-inset: var(--space-3);
|
|
361
|
+
--month-picker-grid-space-block-start: var(--space-3);
|
|
362
|
+
--month-picker-grid-space-gap: var(--space-1);
|
|
363
|
+
--month-picker-cell-space-inline: var(--space-4);
|
|
364
|
+
--month-picker-nav-font-size: var(--font-size-sm);
|
|
365
|
+
/* Year-nav chevrons read as secondary until hovered — same treatment as the Calendar nav, so
|
|
366
|
+
* the two panels stay visually consistent when either is retuned. */
|
|
367
|
+
--month-picker-nav-rest-alpha: var(--calendar-nav-rest-alpha);
|
|
368
|
+
--month-picker-icon-size: var(--icon-size-md);
|
|
369
|
+
--month-picker-separator-icon-size: var(--icon-size-sm);
|
|
370
|
+
|
|
371
|
+
/* BUTTON size-xs box + the count pill (#319, reconciled in #316).
|
|
372
|
+
*
|
|
373
|
+
* `size="xs"` now reads the tier, like every other control in the library. It used to be
|
|
374
|
+
* `calc(var(--control-height) - 0.75rem)` = 1.25rem, which sat 4px BELOW `--control-height-xs`
|
|
375
|
+
* (1.5rem) that `size="icon-xs"` already used — the same tier name, two heights, so an xs
|
|
376
|
+
* Button never lined up with the xs control beside it. It was also the exact shape this repo's
|
|
377
|
+
* own rule forbids: an ad-hoc `calc(var(--control-height) ± length)` silently re-derives a tier
|
|
378
|
+
* and drifts from its siblings (the bug that made Pagination's size-changer taller than its
|
|
379
|
+
* page buttons), and being a raw length rather than a `--scaling`-multiplied step, it did not
|
|
380
|
+
* move with density while the tier did.
|
|
381
|
+
*
|
|
382
|
+
* What settled it was not consistency but MEASUREMENT: an xs Button rendered 20px tall, under
|
|
383
|
+
* the 24x24 CSS px that WCAG 2.2 SC 2.5.8 (Target Size, Minimum) requires, while icon-xs beside
|
|
384
|
+
* it rendered 24px and passed. So this is an accessibility fix that happens to also remove an
|
|
385
|
+
* inconsistency, not a visual preference. It is a real visual change on the most-used component
|
|
386
|
+
* in the library (20px -> 24px), and it stays a knob: a service that wants the old box sets
|
|
387
|
+
* --button-xs-height back. */
|
|
388
|
+
--button-xs-height: var(--control-height-xs);
|
|
389
|
+
--button-xs-space-inline: var(--space-2);
|
|
390
|
+
--button-xs-space-gap: var(--space-1);
|
|
391
|
+
--button-xs-font-size: var(--font-size-xs);
|
|
392
|
+
--button-xs-icon-size: var(--icon-size-xs);
|
|
393
|
+
/* Icon-adjacent padding: a button whose only child is an icon needs less inline room than one
|
|
394
|
+
* carrying a label, or the glyph floats in a too-wide box. One knob per size tier. */
|
|
395
|
+
--button-icon-space-inline-md: var(--space-3);
|
|
396
|
+
--button-icon-space-inline-sm: 0.625rem;
|
|
397
|
+
--button-icon-space-inline-lg: var(--space-4);
|
|
398
|
+
--button-icon-space-inline-xs: 0.375rem;
|
|
399
|
+
--button-space-block: var(--space-2);
|
|
400
|
+
/* Count pill — a borderless counter that reads on the button's own surface. */
|
|
401
|
+
/* OTP separator glyph. Was a bare 1rem in styles/control.css, so the two-tier contract had no
|
|
402
|
+
* tier-2 route here at all: a consumer wanting a different separator could only use !important
|
|
403
|
+
* or fork the stylesheet. Same value, now reachable. */
|
|
404
|
+
/* The OTP blinking caret. The ratchet catches it because the selector says "caret", but it is a
|
|
405
|
+
* text CURSOR, not a chevron: a 1px bar as tall as the digit's line box. Its width belongs to
|
|
406
|
+
* the stroke scale; its height belongs to neither the icon nor the band scale, so it is declared
|
|
407
|
+
* rather than forced onto one.
|
|
408
|
+
* scale-exempt: text-caret height, tracks the OTP digit's line box, not an icon or a band */
|
|
409
|
+
--otp-caret-block-size: 1rem;
|
|
410
|
+
--otp-caret-inline-size: var(--stroke-hairline);
|
|
411
|
+
--otp-separator-icon-size: var(--icon-size-md);
|
|
412
|
+
|
|
413
|
+
--button-count-min-width: var(--space-4);
|
|
414
|
+
--button-count-space-inline: var(--space-1);
|
|
415
|
+
--button-count-font-size: var(--font-size-xs);
|
|
416
|
+
|
|
417
|
+
/* Count pill · COLOUR (gh#320). The pill used to tint itself translucently over whatever the
|
|
418
|
+
* button's surface happened to be (`bg-primary-foreground/15`, `bg-foreground/8`), which means
|
|
419
|
+
* its contrast was a FUNCTION of that surface — and five of those combinations measured below
|
|
420
|
+
* the 4.5:1 that WCAG 2.2 SC 1.4.3 requires of small text:
|
|
421
|
+
*
|
|
422
|
+
* default (light) 3.88 · destructive (dark) 4.29
|
|
423
|
+
* outline family (light, at rest) 4.32 · outline family (light, hover) 3.64
|
|
424
|
+
* outline family (dark, hover) 3.68
|
|
425
|
+
*
|
|
426
|
+
* The hover rows are the reason a static sweep never caught this: `--accent` only appears under
|
|
427
|
+
* the cursor, so no screenshot of a resting page contains the failing state. Same shape as
|
|
428
|
+
* gh#299 and gh#315 — a value that passes on the surface someone happened to check.
|
|
429
|
+
*
|
|
430
|
+
* The fix is the one gh#312 already validated on Toggle: OPAQUE role fills, which make the pill's
|
|
431
|
+
* contrast independent of the button's variant AND of hover. Each filled variant uses its own
|
|
432
|
+
* label pair SWAPPED, so the pill is exactly as legible as the label beside it and cannot be less
|
|
433
|
+
* legible under any theme that keeps that button readable at all:
|
|
434
|
+
*
|
|
435
|
+
* default --primary on --primary-foreground 5.04 light · 7.07 dark
|
|
436
|
+
* destructive --destructive on --destructive-foreground 6.10 light · 5.53 dark
|
|
437
|
+
* secondary --secondary on --secondary-foreground 14.25 light · 12.40 dark
|
|
438
|
+
* outline family --foreground on --muted 14.25 light · 12.40 dark
|
|
439
|
+
*
|
|
440
|
+
* The outline family's `--muted` fill is 1.09:1 against the button's own ground, so at rest the
|
|
441
|
+
* counter still reads as quiet text rather than a badge (#44) — it is legibility of the DIGITS
|
|
442
|
+
* that went up, not loudness of the pill.
|
|
443
|
+
*
|
|
444
|
+
* All eight are role-mirror knobs: `initial` at :root with the role default at the CALL SITE, so
|
|
445
|
+
* a scoped [data-tenant]/.dark override of the role still reaches them (docs/TOKENS.md ·
|
|
446
|
+
* "Role-mirror knobs MUST be `initial`"). */
|
|
447
|
+
--button-count-background: initial;
|
|
448
|
+
--button-count-color: initial;
|
|
449
|
+
--button-count-default-background: initial;
|
|
450
|
+
--button-count-default-color: initial;
|
|
451
|
+
--button-count-destructive-background: initial;
|
|
452
|
+
--button-count-destructive-color: initial;
|
|
453
|
+
--button-count-secondary-background: initial;
|
|
454
|
+
--button-count-secondary-color: initial;
|
|
455
|
+
|
|
456
|
+
/* LABEL — the Label primitive's own box and type (#319). Every one of these was a Tailwind
|
|
457
|
+
* literal baked into label.tsx (`text-sm leading-none flex items-center gap-2`), so a service
|
|
458
|
+
* whose form grid wanted a smaller/denser label had to hand-write font-size on every call site
|
|
459
|
+
* (which is exactly why --form-label-font-size had to be invented as a per-instance escape).
|
|
460
|
+
* They live under the `control` prefix because Label is a control-family primitive and
|
|
461
|
+
* src/tokens/components/ has no `label` file of its own.
|
|
462
|
+
*
|
|
463
|
+
* Defaults reproduce today's rendering exactly:
|
|
464
|
+
* font-size ← `text-sm` → --text-sm → var(--font-size-sm)
|
|
465
|
+
* line-height ← `leading-none` → 1 (leading-none beats text-sm's companion line-height) */
|
|
466
|
+
--control-label-font-size: var(--font-size-sm);
|
|
467
|
+
--control-label-line-height: 1;
|
|
468
|
+
/* Label → addon/required-marker gap. A RAW rem, deliberately NOT var(--space-2): the `gap-2` it
|
|
469
|
+
* replaces reads Tailwind's own --spacing grid, which this repo does NOT density-scale, so a
|
|
470
|
+
* --space-* default would silently resize every label row under a compact/comfortable density.
|
|
471
|
+
* A service that WANTS it to follow density points the knob at var(--space-2) itself. */
|
|
472
|
+
--control-label-space-gap: 0.5rem;
|
|
473
|
+
/* Weight of a label whose `peer` control is disabled. Deliberately its OWN knob rather than the
|
|
474
|
+
* global --disabled-opacity (0.5): a label must stay READABLE next to a disabled control — it is
|
|
475
|
+
* still the field's accessible name — so it rests one step heavier than the control it names.
|
|
476
|
+
* Default = the historical `peer-disabled:opacity-70`. */
|
|
477
|
+
--control-label-disabled-alpha: 0.7;
|
|
478
|
+
}
|
|
479
|
+
|
|
130
480
|
@media (pointer: coarse) {
|
|
131
481
|
:root {
|
|
132
|
-
--control-height-compact:
|
|
133
|
-
--control-height-default:
|
|
482
|
+
--control-height-compact: var(--band-height-xl);
|
|
483
|
+
--control-height-default: var(--band-height-xl);
|
|
134
484
|
}
|
|
135
485
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/* Data-display component tokens — small-by-design text knobs (rule #45/#46). */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
+
/* Accordion chevron and Carousel arrow. Both were bare 1rem literals in
|
|
5
|
+
* data-display-layout.css — glyphs with no tier-2 route, invisible to the icon ratchet because
|
|
6
|
+
* neither selector contains the word "icon". */
|
|
7
|
+
--accordion-chevron-size: var(--icon-size-md);
|
|
8
|
+
--carousel-arrow-icon-size: var(--icon-size-md);
|
|
9
|
+
|
|
10
|
+
/* Outline-form ring gaps — a hugging ring would touch these marks
|
|
11
|
+
* (styles/focus-ring.css). */
|
|
12
|
+
--accordion-focus-ring-offset: 2px;
|
|
13
|
+
--carousel-dot-focus-ring-offset: 2px;
|
|
4
14
|
--progress-label-font-size: var(--font-size-xs);
|
|
5
15
|
--tree-item-title-font-size: var(--font-size-xs);
|
|
6
16
|
--tree-item-description-font-size: var(--font-size-xs);
|
|
@@ -40,6 +50,46 @@
|
|
|
40
50
|
--avatar-tinted-foreground: initial;
|
|
41
51
|
--avatar-tinted-glyph-size: var(--control-icon-size);
|
|
42
52
|
|
|
53
|
+
/* PRESENCE INDICATOR — `<Avatar presence="online|away|busy|offline">` (gh#309): the realtime
|
|
54
|
+
reachability dot pinned to the block-end/inline-end corner of the mark. Every constant below is
|
|
55
|
+
a knob (rule #45) and the separator ring is chrome that reads a token (rule #44), because the
|
|
56
|
+
hand-rolled workaround this replaces —
|
|
57
|
+
`bg-green-500 ring-2 ring-background -end-0.5 -bottom-0.5` on a wrapper span — bakes four
|
|
58
|
+
service-tunable constants and a raw palette colour into a consumer page.
|
|
59
|
+
|
|
60
|
+
--avatar-presence-size is a PROPORTION of the mark, not a px step. One value therefore tracks
|
|
61
|
+
EVERY avatar the system paints — the --control-height default box, a `size-12` call site, the
|
|
62
|
+
--avatar-square-size entity mark, --org-switcher-avatar-size (1.75rem), --upload-avatar-size
|
|
63
|
+
(6rem), the 36px ListRow density="compact" leading mark — instead of freezing one diameter that
|
|
64
|
+
is a boulder on a 24px mark and a speck on a 96px one. --avatar-presence-min-size is the
|
|
65
|
+
legibility floor for the smallest marks; --avatar-presence-inset lets a service pull the dot
|
|
66
|
+
further into a round mark than into a square one.
|
|
67
|
+
|
|
68
|
+
--avatar-presence-ring-color and the four state colours are ROLE-MIRROR knobs: declared
|
|
69
|
+
`initial` here so the --background / --success / --warning / --destructive / --muted-foreground
|
|
70
|
+
defaults resolve at the CALL SITE and a scoped [data-tenant] / .dark override of the ROLE still
|
|
71
|
+
reaches them (docs/TOKENS.md · "Role-mirror knobs MUST be `initial`"). Binding them to the role
|
|
72
|
+
here would freeze the ring light-mode-white on a dark avatar.
|
|
73
|
+
|
|
74
|
+
Presence is never colour-alone (WCAG 1.4.1): the colour rides with a SHAPE — filled · half
|
|
75
|
+
filled · barred · hollow — and a localized sr-only string, so --avatar-presence-stroke-width and
|
|
76
|
+
--avatar-presence-bar-* are part of the accessible encoding, not decoration.
|
|
77
|
+
|
|
78
|
+
Defaults = 30% of the mark, floor 0.5rem · flush with the mark's corner · 2px separator ring in
|
|
79
|
+
--background · 1.5px state stroke · a 56%-wide, 1.5px dnd bar. */
|
|
80
|
+
--avatar-presence-size: 30%;
|
|
81
|
+
--avatar-presence-min-size: var(--space-2);
|
|
82
|
+
--avatar-presence-inset: 0;
|
|
83
|
+
--avatar-presence-ring-width: var(--stroke-md);
|
|
84
|
+
--avatar-presence-stroke-width: var(--stroke-sm);
|
|
85
|
+
--avatar-presence-bar-inline-size: 56%;
|
|
86
|
+
--avatar-presence-bar-block-size: var(--stroke-sm);
|
|
87
|
+
--avatar-presence-ring-color: initial;
|
|
88
|
+
--avatar-presence-online-color: initial;
|
|
89
|
+
--avatar-presence-away-color: initial;
|
|
90
|
+
--avatar-presence-busy-color: initial;
|
|
91
|
+
--avatar-presence-offline-color: initial;
|
|
92
|
+
|
|
43
93
|
/* Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme.
|
|
44
94
|
Track reads --secondary, fill reads --success; a service re-tones once.
|
|
45
95
|
Defaults = hsl(var(--secondary)) track · hsl(var(--success)) fill. */
|
|
@@ -65,4 +115,29 @@
|
|
|
65
115
|
--qr-code-size-sm: 8rem;
|
|
66
116
|
--qr-code-size-md: 10rem;
|
|
67
117
|
--qr-code-size-lg: 12.5rem;
|
|
118
|
+
|
|
119
|
+
/* SCROLL AREA — the custom scrollbar rail. `.ui-scroll-area-*` did not exist at all: the whole
|
|
120
|
+
* rail shipped as Tailwind literals on the component (`w-2.5 p-px` / `h-2.5 p-px`,
|
|
121
|
+
* `rounded-full`), so a service could not widen the bar for a touch/coarse-pointer console or
|
|
122
|
+
* square the thumb to match a sharp-cornered theme without forking ScrollArea (rule #45).
|
|
123
|
+
* --scroll-area-bar-size is a RAW rem on purpose: it replaces a FLAT Tailwind step (2.5 = 10px),
|
|
124
|
+
* not a --space-* step, so binding it to the density-scaled scale would silently change today's
|
|
125
|
+
* rendering under a non-default --scaling. Defaults reproduce the previous rail exactly. */
|
|
126
|
+
--scroll-area-bar-size: 0.625rem;
|
|
127
|
+
/* Hairline inset that keeps the thumb off the rail edge — a service running a thicker bar
|
|
128
|
+
* usually wants a proportionally larger gutter here. */
|
|
129
|
+
--scroll-area-bar-padding: 1px;
|
|
130
|
+
--scroll-area-thumb-radius: var(--radius-pill);
|
|
131
|
+
|
|
132
|
+
/* PERMISSION MATRIX — the sticky-first-column grid. Nothing here was themeable: the class
|
|
133
|
+
* `.ui-permission-matrix` existed as a bare hook with no CSS rule at all, so every constant
|
|
134
|
+
* lived on the component (#319). A JA/VI service whose role names run longer than the English
|
|
135
|
+
* ones could not widen the label column without forking. */
|
|
136
|
+
--permission-matrix-label-width: 16rem;
|
|
137
|
+
--permission-matrix-role-space-gap: var(--space-1);
|
|
138
|
+
--permission-matrix-name-space-gap: 0.375rem;
|
|
139
|
+
--permission-matrix-cell-icon-size: var(--control-icon-size);
|
|
140
|
+
/* Floor for the scrolling body — below this the columns collapse into unreadable slivers, so
|
|
141
|
+
* the table scrolls instead. Mirrors --table-surface-min-inline-size on DataTable. */
|
|
142
|
+
--permission-matrix-min-width: 48rem;
|
|
68
143
|
}
|
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
/* Data-entry component tokens — small-by-design text knobs (rule #45/#46). */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
+
|
|
4
5
|
--password-strength-score-font-size: var(--font-size-xs);
|
|
5
6
|
--password-strength-checklist-font-size: var(--font-size-xs);
|
|
7
|
+
|
|
8
|
+
/* BranchScopePicker (gh#319). `.ui-branch-scope-picker` was a bare hook with no rule anywhere:
|
|
9
|
+
* every measure lived as a Tailwind literal on the component, so a service could only retune
|
|
10
|
+
* the control by forking it (#45).
|
|
11
|
+
*
|
|
12
|
+
* All four are FLAT rems, not `--space-*` aliases, on purpose: the literals they replace read
|
|
13
|
+
* Tailwind's own `--spacing` grid, which this package never remaps and which does NOT move with
|
|
14
|
+
* the density axis. Aliasing them to `--space-3`/`--space-2`/`--space-1` would silently start
|
|
15
|
+
* scaling the control inside a `.ui-density-*` subtree — a visual change, not a refactor. */
|
|
16
|
+
/* Stack rhythm between the mode radios, the subset box and the error line (was `gap-3`). */
|
|
17
|
+
--branch-scope-picker-gap: 0.75rem;
|
|
18
|
+
/* Read-only summary: the wrapped run of branch Badges (was `gap-1.5`). */
|
|
19
|
+
--branch-scope-picker-badges-gap: 0.375rem;
|
|
20
|
+
/* The `mode="selected"` subset box — its inner stack rhythm and the inset that clears its
|
|
21
|
+
* indent rule (was `gap-2` / `ps-4`). */
|
|
22
|
+
--branch-scope-picker-subset-gap: 0.5rem;
|
|
23
|
+
--branch-scope-picker-subset-padding-inline: 1rem;
|
|
24
|
+
/* The indent rule itself is CHROME (#44), so it is a knob: a service that wants the flat
|
|
25
|
+
* treatment sets it to 0 rather than forking the component. Default = today's `border-s-2`. */
|
|
26
|
+
--branch-scope-picker-subset-border-width: var(--stroke-md);
|
|
27
|
+
/* Bounded height of the scrollable branch list (was `max-h-64`). Flat by design: the box is a
|
|
28
|
+
* keyboard-reachable scroll region whose job is to cap the control's measure, so it must not
|
|
29
|
+
* grow with density and push the surrounding form off a 390px frame. */
|
|
30
|
+
--branch-scope-picker-list-max-height: 16rem;
|
|
6
31
|
}
|
|
@@ -11,4 +11,26 @@
|
|
|
11
11
|
* block above an editable field on the same card) retunes this to `var(--space-4)` to match
|
|
12
12
|
* Form's own field-to-field rhythm instead of the two blocks reading as visually unrelated. */
|
|
13
13
|
--descriptions-row-gap: var(--space-3);
|
|
14
|
+
/* Column-to-column gap of the <dl> grid (#319). Was a hardcoded `gap-x-6`, the one axis of the
|
|
15
|
+
* grid rhythm a service could NOT reach while --descriptions-row-gap was already a knob — so a
|
|
16
|
+
* 2/3-column detail block could be retuned vertically but never horizontally.
|
|
17
|
+
* A RAW rem, deliberately NOT var(--space-6): `gap-x-6` reads Tailwind's own --spacing grid,
|
|
18
|
+
* which this repo does NOT density-scale, so a --space-* default would silently rescale the
|
|
19
|
+
* column gap under a compact/comfortable density. Point it at var(--space-6) to opt in. */
|
|
20
|
+
--descriptions-column-gap: 1.5rem;
|
|
21
|
+
/* Label → value gap inside ONE item when layout="horizontal" (was `gap-x-3`). Pairs with
|
|
22
|
+
* --descriptions-label-width: a service that narrows the label column usually wants to close
|
|
23
|
+
* this gap in the same step. Raw rem for the same --spacing reason as above. */
|
|
24
|
+
--descriptions-label-gap: 0.75rem;
|
|
25
|
+
/* VALUE TYPOGRAPHY (gh#294 + #319). `FormField staticText` renders its read-only value with the
|
|
26
|
+
* SAME typography as a <dd> so a static Form row and a Descriptions value are indistinguishable
|
|
27
|
+
* when mixed on one card. That contract used to be two copies of the literal `text-sm` plus a
|
|
28
|
+
* comment asking future editors to keep them in sync; both call sites now read these tokens, so
|
|
29
|
+
* the mirror is mechanical and a service retunes BOTH from one place. */
|
|
30
|
+
--descriptions-value-font-size: var(--font-size-sm);
|
|
31
|
+
/* Companion to --descriptions-value-font-size (the gh#260 bug). The `text-sm` utility this
|
|
32
|
+
* replaces ALSO set a line-height, via Tailwind's default `--text-sm--line-height`
|
|
33
|
+
* (= calc(1.25 / 0.875)); the theme remaps --text-sm but never that companion. Without this the
|
|
34
|
+
* value would silently inherit ambient leading instead of its own 20px line box. */
|
|
35
|
+
--descriptions-value-line-height: calc(1.25 / 0.875);
|
|
14
36
|
}
|