@godxjp/ui 18.15.4 → 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 +25 -8
- 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
|
@@ -61,6 +61,125 @@
|
|
|
61
61
|
background: var(--avatar-background, hsl(var(--muted)));
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/* PRESENCE (gh#309) — the realtime reachability dot on the mark itself.
|
|
65
|
+
*
|
|
66
|
+
* Opt-in ONLY: with no `presence` prop the avatar emits neither the attribute nor the node, so
|
|
67
|
+
* every existing call site keeps today's DOM and today's clip. WITH it the ROOT stops clipping —
|
|
68
|
+
* the dot straddles the mark's edge, which is exactly why a consumer could never place it from
|
|
69
|
+
* outside — and the clip moves down onto the image/fallback, which is where it was doing the real
|
|
70
|
+
* work. `border-radius: inherit` keeps that clip correct for both shapes: --radius-pill for a
|
|
71
|
+
* person, --avatar-square-radius for an entity mark. */
|
|
72
|
+
.ui-avatar[data-presence] {
|
|
73
|
+
overflow: visible;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.ui-avatar[data-presence] > .ui-avatar-image,
|
|
77
|
+
.ui-avatar[data-presence] > .ui-avatar-fallback {
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
border-radius: inherit;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* NEVER COLOUR-ALONE (WCAG 1.4.1). Three independent encodings ride together: the localized
|
|
83
|
+
* sr-only string inside this span, a semantic ROLE colour, and a SHAPE — filled · half-filled ·
|
|
84
|
+
* barred · hollow — so the four states stay apart in greyscale, for a deuteranope, and under
|
|
85
|
+
* forced colors. `box-sizing: border-box` makes --avatar-presence-size the OUTER diameter, so the
|
|
86
|
+
* state stroke never changes the dot's footprint between states.
|
|
87
|
+
*
|
|
88
|
+
* The dot is a state, not an event: nothing here animates, so there is nothing for
|
|
89
|
+
* prefers-reduced-motion to switch off. Presence is deliberately NOT a live region either — a
|
|
90
|
+
* roster of 40 avatars resyncing over a socket would flood a screen reader; announcing a CHANGE is
|
|
91
|
+
* the consumer's call, in the consumer's own live region. */
|
|
92
|
+
[data-slot="avatar-presence"] {
|
|
93
|
+
position: absolute;
|
|
94
|
+
inset-block-end: var(--avatar-presence-inset);
|
|
95
|
+
inset-inline-end: var(--avatar-presence-inset);
|
|
96
|
+
display: block;
|
|
97
|
+
box-sizing: border-box;
|
|
98
|
+
inline-size: var(--avatar-presence-size);
|
|
99
|
+
block-size: var(--avatar-presence-size);
|
|
100
|
+
min-inline-size: var(--avatar-presence-min-size);
|
|
101
|
+
min-block-size: var(--avatar-presence-min-size);
|
|
102
|
+
border: var(--avatar-presence-stroke-width) solid transparent;
|
|
103
|
+
border-radius: var(--radius-pill);
|
|
104
|
+
background-origin: border-box;
|
|
105
|
+
/* Separator ring — chrome, therefore a knob (#44). It is what keeps the dot legible over a busy
|
|
106
|
+
* photo; a service that puts the avatar on a coloured surface retunes the colour once. */
|
|
107
|
+
box-shadow: 0 0 0 var(--avatar-presence-ring-width)
|
|
108
|
+
hsl(var(--avatar-presence-ring-color, var(--background)));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ONLINE — a SOLID disc. */
|
|
112
|
+
[data-slot="avatar-presence"][data-presence="online"] {
|
|
113
|
+
border-color: hsl(var(--avatar-presence-online-color, var(--success)));
|
|
114
|
+
background-color: hsl(var(--avatar-presence-online-color, var(--success)));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* AWAY — a HALF-FILLED disc (block-end half), the one silhouette that survives greyscale next to
|
|
118
|
+
* both the solid and the hollow states. */
|
|
119
|
+
[data-slot="avatar-presence"][data-presence="away"] {
|
|
120
|
+
border-color: hsl(var(--avatar-presence-away-color, var(--warning)));
|
|
121
|
+
background-color: hsl(var(--avatar-presence-ring-color, var(--background)));
|
|
122
|
+
background-image: linear-gradient(
|
|
123
|
+
to bottom,
|
|
124
|
+
transparent 0 50%,
|
|
125
|
+
hsl(var(--avatar-presence-away-color, var(--warning))) 50%
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* BUSY (do-not-disturb) — a solid disc CUT by a horizontal bar. */
|
|
130
|
+
[data-slot="avatar-presence"][data-presence="busy"] {
|
|
131
|
+
border-color: hsl(var(--avatar-presence-busy-color, var(--destructive)));
|
|
132
|
+
background-color: hsl(var(--avatar-presence-busy-color, var(--destructive)));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* `inset: 0; margin: auto` centres the bar in BOTH axes with no translate, so it stays centred
|
|
136
|
+
* under dir="rtl" (a start-anchored `translate(-50%)` would slide it off-centre when the inline
|
|
137
|
+
* axis flips). */
|
|
138
|
+
[data-slot="avatar-presence"][data-presence="busy"]::before {
|
|
139
|
+
content: "";
|
|
140
|
+
position: absolute;
|
|
141
|
+
inset: 0;
|
|
142
|
+
margin: auto;
|
|
143
|
+
inline-size: var(--avatar-presence-bar-inline-size);
|
|
144
|
+
block-size: var(--avatar-presence-bar-block-size);
|
|
145
|
+
border-radius: var(--radius-pill);
|
|
146
|
+
background: hsl(var(--avatar-presence-ring-color, var(--background)));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* OFFLINE — a HOLLOW ring. Distinct from an ABSENT `presence`, which draws nothing at all: absent
|
|
150
|
+
* means "this entity has no presence concept" (an organization mark), offline means "known to be
|
|
151
|
+
* unreachable" — the same distinction ListRow draws between an omitted and a `false` `unread`. */
|
|
152
|
+
[data-slot="avatar-presence"][data-presence="offline"] {
|
|
153
|
+
border-color: hsl(var(--avatar-presence-offline-color, var(--muted-foreground)));
|
|
154
|
+
background-color: hsl(var(--avatar-presence-ring-color, var(--background)));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* FORCED COLORS — the UA replaces author colours, and box-shadow is dropped outright, so the
|
|
158
|
+
* separator ring would vanish into the mark and all four states would collapse to one swatch.
|
|
159
|
+
* System-colour keywords ARE honoured inside this block, so re-draw the ring as an outline and
|
|
160
|
+
* re-state each silhouette in Canvas / CanvasText: the shape encoding survives, which is the half
|
|
161
|
+
* of WCAG 1.4.1 that a colour-only dot loses here first. */
|
|
162
|
+
@media (forced-colors: active) {
|
|
163
|
+
[data-slot="avatar-presence"] {
|
|
164
|
+
border-color: CanvasText;
|
|
165
|
+
background-color: CanvasText;
|
|
166
|
+
background-image: none;
|
|
167
|
+
outline: var(--avatar-presence-ring-width) solid Canvas;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
[data-slot="avatar-presence"][data-presence="away"] {
|
|
171
|
+
background-image: linear-gradient(to bottom, Canvas 0 50%, CanvasText 50%);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
[data-slot="avatar-presence"][data-presence="offline"] {
|
|
175
|
+
background-color: Canvas;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
[data-slot="avatar-presence"][data-presence="busy"]::before {
|
|
179
|
+
background: Canvas;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
64
183
|
.ui-progress {
|
|
65
184
|
display: flex;
|
|
66
185
|
flex-direction: column;
|
|
@@ -305,8 +424,6 @@
|
|
|
305
424
|
text-decoration: underline;
|
|
306
425
|
}
|
|
307
426
|
.ui-accordion-trigger:focus-visible {
|
|
308
|
-
outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
|
|
309
|
-
outline-offset: 2px;
|
|
310
427
|
border-radius: var(--radius-sm);
|
|
311
428
|
}
|
|
312
429
|
.ui-accordion-trigger:disabled,
|
|
@@ -316,8 +433,8 @@
|
|
|
316
433
|
pointer-events: none;
|
|
317
434
|
}
|
|
318
435
|
.ui-accordion-chevron {
|
|
319
|
-
width:
|
|
320
|
-
height:
|
|
436
|
+
width: var(--accordion-chevron-size);
|
|
437
|
+
height: var(--accordion-chevron-size);
|
|
321
438
|
color: hsl(var(--muted-foreground));
|
|
322
439
|
transition: transform 0.2s ease;
|
|
323
440
|
flex-shrink: 0;
|
|
@@ -397,8 +514,8 @@
|
|
|
397
514
|
}
|
|
398
515
|
|
|
399
516
|
.ui-carousel-arrow {
|
|
400
|
-
width:
|
|
401
|
-
height:
|
|
517
|
+
width: var(--carousel-arrow-icon-size);
|
|
518
|
+
height: var(--carousel-arrow-icon-size);
|
|
402
519
|
}
|
|
403
520
|
|
|
404
521
|
/* Dot indicators — horizontal, centered row of round dots; the active one fills + widens. */
|
|
@@ -431,11 +548,6 @@
|
|
|
431
548
|
background: hsl(var(--primary));
|
|
432
549
|
}
|
|
433
550
|
|
|
434
|
-
.ui-carousel-dot:focus-visible {
|
|
435
|
-
outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
|
|
436
|
-
outline-offset: 2px;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
551
|
/* Vertical orientation — stack the dots into a column beside the track. */
|
|
440
552
|
.ui-carousel[data-orientation="vertical"] .ui-carousel-dots {
|
|
441
553
|
flex-direction: column;
|
|
@@ -642,3 +754,65 @@
|
|
|
642
754
|
inline-size: var(--qr-code-size-lg);
|
|
643
755
|
}
|
|
644
756
|
}
|
|
757
|
+
|
|
758
|
+
@layer components {
|
|
759
|
+
/* PERMISSION MATRIX — `.ui-permission-matrix` was a bare hook with no rule anywhere, so every
|
|
760
|
+
* constant sat on the component (#319). */
|
|
761
|
+
.ui-permission-matrix-table {
|
|
762
|
+
min-inline-size: var(--permission-matrix-min-width);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/* Sticky first column: the scrolling grid passes UNDER it, so it needs an opaque ground.
|
|
766
|
+
* Scoped through the matrix root because `[data-slot="table-head"]` sets its own background at
|
|
767
|
+
* the same specificity — an unscoped rule would win only by import order, which is not a
|
|
768
|
+
* property worth depending on. */
|
|
769
|
+
.ui-permission-matrix .ui-permission-matrix-pin {
|
|
770
|
+
position: sticky;
|
|
771
|
+
inset-inline-start: 0;
|
|
772
|
+
/* Above the scrolling cells, below any portaled overlay (--overlay-z-index). */
|
|
773
|
+
z-index: 20;
|
|
774
|
+
background-color: inherit;
|
|
775
|
+
border-inline-end: 1px solid hsl(var(--border));
|
|
776
|
+
inline-size: var(--permission-matrix-label-width);
|
|
777
|
+
min-inline-size: var(--permission-matrix-label-width);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.ui-permission-matrix-role {
|
|
781
|
+
display: inline-flex;
|
|
782
|
+
align-items: center;
|
|
783
|
+
gap: var(--permission-matrix-role-space-gap);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.ui-permission-matrix-name {
|
|
787
|
+
display: inline-flex;
|
|
788
|
+
align-items: center;
|
|
789
|
+
gap: var(--permission-matrix-name-space-gap);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.ui-permission-matrix-cell-icon {
|
|
793
|
+
inline-size: var(--permission-matrix-cell-icon-size);
|
|
794
|
+
block-size: var(--permission-matrix-cell-icon-size);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
@layer components {
|
|
799
|
+
/* SCROLL AREA — the custom scrollbar rail (#319). There was no `.ui-scroll*` rule anywhere: the
|
|
800
|
+
* rail's whole geometry lived on the component as Tailwind literals, so a service could not
|
|
801
|
+
* retune it. Logical sizing (inline-/block-size) keeps the rail correct in RTL and in vertical
|
|
802
|
+
* writing modes; the thumb radius is a knob so a sharp-cornered theme squares it once. */
|
|
803
|
+
.ui-scroll-area-bar {
|
|
804
|
+
padding: var(--scroll-area-bar-padding);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.ui-scroll-area-bar--vertical {
|
|
808
|
+
inline-size: var(--scroll-area-bar-size);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.ui-scroll-area-bar--horizontal {
|
|
812
|
+
block-size: var(--scroll-area-bar-size);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.ui-scroll-area-thumb {
|
|
816
|
+
border-radius: var(--scroll-area-thumb-radius);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
@@ -84,7 +84,6 @@
|
|
|
84
84
|
|
|
85
85
|
.ui-time-input:focus-visible {
|
|
86
86
|
border-color: hsl(var(--focus-ring-color, var(--ring)));
|
|
87
|
-
box-shadow: 0 0 0 3px hsl(var(--focus-ring-color, var(--ring)) / 0.3);
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
.ui-time-input[aria-invalid="true"] {
|
|
@@ -162,3 +161,355 @@
|
|
|
162
161
|
color: hsl(var(--destructive));
|
|
163
162
|
}
|
|
164
163
|
}
|
|
164
|
+
|
|
165
|
+
@layer components {
|
|
166
|
+
/* UPLOAD — five variants (dropzone · button · picture · picture-card · avatar) that used to
|
|
167
|
+
* carry their entire box as Tailwind literals on the component: 66 of them, the worst file in
|
|
168
|
+
* the library (#319). A service could not resize the avatar, dial back the dropzone's generous
|
|
169
|
+
* inset, or align the file row to its own grid without forking. Every constant is now a knob
|
|
170
|
+
* (rule #45); colour scrims are role-mirror knobs resolved at the CALL SITE so a scoped
|
|
171
|
+
* [data-tenant]/.dark override reaches them (docs/TOKENS.md). */
|
|
172
|
+
|
|
173
|
+
.ui-upload-dropzone {
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
padding: var(--upload-dropzone-space-inset);
|
|
176
|
+
border-radius: var(--upload-dropzone-radius);
|
|
177
|
+
border: var(--upload-dropzone-border-width) dashed hsl(var(--border));
|
|
178
|
+
text-align: center;
|
|
179
|
+
transition: border-color 150ms ease;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.ui-upload-dropzone[data-drag-active] {
|
|
183
|
+
border-color: hsl(var(--primary));
|
|
184
|
+
background-color: hsl(var(--primary) / 0.05);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ui-upload-dropzone:not([data-drag-active]):hover {
|
|
188
|
+
border-color: hsl(var(--primary) / 0.5);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.ui-upload-dropzone-icon {
|
|
192
|
+
display: block;
|
|
193
|
+
margin-inline: auto;
|
|
194
|
+
inline-size: var(--upload-dropzone-icon-size);
|
|
195
|
+
block-size: var(--upload-dropzone-icon-size);
|
|
196
|
+
color: hsl(var(--muted-foreground));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.ui-upload-dropzone-hint {
|
|
200
|
+
margin-block-start: var(--upload-dropzone-hint-space-block-start);
|
|
201
|
+
font-size: var(--upload-dropzone-hint-font-size);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.ui-upload-dropzone-meta {
|
|
205
|
+
margin-block-start: var(--upload-dropzone-meta-space-block-start);
|
|
206
|
+
font-size: var(--upload-dropzone-meta-font-size);
|
|
207
|
+
color: hsl(var(--muted-foreground));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.ui-upload-grid {
|
|
211
|
+
display: flex;
|
|
212
|
+
flex-wrap: wrap;
|
|
213
|
+
gap: var(--upload-tile-space-gap);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.ui-upload-tile {
|
|
217
|
+
position: relative;
|
|
218
|
+
inline-size: var(--upload-tile-size);
|
|
219
|
+
block-size: var(--upload-tile-size);
|
|
220
|
+
overflow: hidden;
|
|
221
|
+
border-radius: var(--upload-tile-radius);
|
|
222
|
+
border: 1px solid hsl(var(--border));
|
|
223
|
+
background-color: hsl(var(--muted));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.ui-upload-tile-add {
|
|
227
|
+
display: flex;
|
|
228
|
+
flex-direction: column;
|
|
229
|
+
align-items: center;
|
|
230
|
+
justify-content: center;
|
|
231
|
+
inline-size: var(--upload-tile-size);
|
|
232
|
+
block-size: var(--upload-tile-size);
|
|
233
|
+
border-radius: var(--upload-tile-radius);
|
|
234
|
+
border: 1px dashed hsl(var(--border));
|
|
235
|
+
color: hsl(var(--muted-foreground));
|
|
236
|
+
transition:
|
|
237
|
+
border-color 150ms ease,
|
|
238
|
+
color 150ms ease;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.ui-upload-tile-add:hover {
|
|
242
|
+
border-color: hsl(var(--primary));
|
|
243
|
+
color: hsl(var(--primary));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.ui-upload-tile-add-icon {
|
|
247
|
+
inline-size: var(--upload-tile-icon-size);
|
|
248
|
+
block-size: var(--upload-tile-icon-size);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.ui-upload-tile-add-label {
|
|
252
|
+
margin-block-start: var(--upload-tile-label-space-block-start);
|
|
253
|
+
font-size: var(--upload-tile-label-font-size);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* Busy scrim — one share of the surface role, resolved here so a scoped theme reaches it. */
|
|
257
|
+
.ui-upload-overlay {
|
|
258
|
+
position: absolute;
|
|
259
|
+
inset: 0;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
justify-content: center;
|
|
263
|
+
background-color: var(
|
|
264
|
+
--upload-overlay-background,
|
|
265
|
+
color-mix(in srgb, hsl(var(--background)) var(--upload-overlay-alpha), transparent)
|
|
266
|
+
);
|
|
267
|
+
font-size: var(--upload-tile-overlay-font-size);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.ui-upload-tile-placeholder {
|
|
271
|
+
display: flex;
|
|
272
|
+
inline-size: 100%;
|
|
273
|
+
block-size: 100%;
|
|
274
|
+
align-items: center;
|
|
275
|
+
justify-content: center;
|
|
276
|
+
font-size: var(--upload-tile-overlay-font-size);
|
|
277
|
+
color: hsl(var(--muted-foreground));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.ui-upload-tile-remove {
|
|
281
|
+
position: absolute;
|
|
282
|
+
inset-block-start: var(--upload-remove-offset);
|
|
283
|
+
inset-inline-end: var(--upload-remove-offset);
|
|
284
|
+
padding: calc(var(--upload-remove-space-inset) / 2);
|
|
285
|
+
border-radius: var(--radius-pill);
|
|
286
|
+
background-color: hsl(var(--background) / 0.9);
|
|
287
|
+
box-shadow: var(--shadow-sm);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.ui-upload-tile-remove:hover {
|
|
291
|
+
background-color: hsl(var(--destructive));
|
|
292
|
+
color: hsl(var(--destructive-foreground));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.ui-upload-remove-icon {
|
|
296
|
+
inline-size: var(--upload-remove-icon-size);
|
|
297
|
+
block-size: var(--upload-remove-icon-size);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.ui-upload-picture {
|
|
301
|
+
max-inline-size: var(--upload-picture-max-width);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.ui-upload-picture-frame {
|
|
305
|
+
position: relative;
|
|
306
|
+
overflow: hidden;
|
|
307
|
+
border-radius: var(--upload-picture-radius);
|
|
308
|
+
border: 1px solid hsl(var(--border));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.ui-upload-picture-img {
|
|
312
|
+
inline-size: 100%;
|
|
313
|
+
max-block-size: var(--upload-picture-preview-max-height);
|
|
314
|
+
object-fit: cover;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.ui-upload-picture-overlay {
|
|
318
|
+
font-size: var(--upload-picture-overlay-font-size);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.ui-upload-picture-badge {
|
|
322
|
+
position: absolute;
|
|
323
|
+
inset-block-start: var(--upload-picture-badge-offset);
|
|
324
|
+
inset-inline-start: var(--upload-picture-badge-offset);
|
|
325
|
+
padding-inline: var(--upload-picture-badge-space-inline);
|
|
326
|
+
padding-block: var(--upload-picture-badge-space-block);
|
|
327
|
+
border-radius: var(--upload-picture-badge-radius);
|
|
328
|
+
background-color: hsl(var(--warning));
|
|
329
|
+
color: hsl(var(--warning-foreground));
|
|
330
|
+
font-size: var(--upload-picture-badge-font-size);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.ui-upload-picture-empty {
|
|
334
|
+
display: flex;
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
align-items: center;
|
|
337
|
+
justify-content: center;
|
|
338
|
+
inline-size: 100%;
|
|
339
|
+
block-size: var(--upload-picture-empty-height);
|
|
340
|
+
border-radius: var(--upload-picture-radius);
|
|
341
|
+
border: 1px dashed hsl(var(--border));
|
|
342
|
+
color: hsl(var(--muted-foreground));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.ui-upload-picture-empty:hover {
|
|
346
|
+
border-color: hsl(var(--primary));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.ui-upload-picture-empty-label {
|
|
350
|
+
margin-block-start: var(--upload-picture-empty-label-space-block-start);
|
|
351
|
+
font-size: var(--upload-picture-empty-label-font-size);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.ui-upload-avatar {
|
|
355
|
+
position: relative;
|
|
356
|
+
inline-size: var(--upload-avatar-size);
|
|
357
|
+
block-size: var(--upload-avatar-size);
|
|
358
|
+
overflow: hidden;
|
|
359
|
+
border-radius: var(--radius-pill);
|
|
360
|
+
border: var(--upload-avatar-border-width) solid hsl(var(--border));
|
|
361
|
+
background-color: hsl(var(--muted));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.ui-upload-avatar[data-pending-delete] {
|
|
365
|
+
opacity: var(--upload-avatar-pending-delete-alpha);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.ui-upload-avatar-image {
|
|
369
|
+
inline-size: 100%;
|
|
370
|
+
block-size: 100%;
|
|
371
|
+
object-fit: cover;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.ui-upload-avatar-placeholder {
|
|
375
|
+
display: flex;
|
|
376
|
+
inline-size: 100%;
|
|
377
|
+
block-size: 100%;
|
|
378
|
+
align-items: center;
|
|
379
|
+
justify-content: center;
|
|
380
|
+
color: hsl(var(--muted-foreground));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* Sits ON the photo, so the wash is a fixed dark scrim rather than a surface role — it must
|
|
384
|
+
* stay legible over an arbitrary user image in either theme. */
|
|
385
|
+
.ui-upload-avatar-change {
|
|
386
|
+
position: absolute;
|
|
387
|
+
inset-inline: 0;
|
|
388
|
+
inset-block-end: 0;
|
|
389
|
+
padding-block: var(--upload-avatar-change-space-block);
|
|
390
|
+
background-color: var(--upload-avatar-change-background);
|
|
391
|
+
color: var(--upload-avatar-change-foreground);
|
|
392
|
+
text-align: center;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.ui-upload-avatar-remove {
|
|
396
|
+
position: absolute;
|
|
397
|
+
inset-block-start: calc(var(--upload-remove-offset) * -1);
|
|
398
|
+
inset-inline-end: calc(var(--upload-remove-offset) * -1);
|
|
399
|
+
padding: var(--upload-remove-space-inset);
|
|
400
|
+
border-radius: var(--radius-pill);
|
|
401
|
+
border: 1px solid hsl(var(--border));
|
|
402
|
+
background-color: hsl(var(--background));
|
|
403
|
+
box-shadow: var(--shadow-sm);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.ui-upload-avatar-remove:hover {
|
|
407
|
+
background-color: hsl(var(--destructive));
|
|
408
|
+
color: hsl(var(--destructive-foreground));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.ui-upload-draft-undo {
|
|
412
|
+
display: flex;
|
|
413
|
+
flex-wrap: wrap;
|
|
414
|
+
align-items: center;
|
|
415
|
+
gap: var(--upload-draft-space-gap);
|
|
416
|
+
padding-inline: var(--upload-draft-space-inline);
|
|
417
|
+
padding-block: var(--upload-draft-space-block);
|
|
418
|
+
border-radius: var(--upload-draft-radius);
|
|
419
|
+
border: 1px dashed hsl(var(--destructive) / 0.4);
|
|
420
|
+
background-color: hsl(var(--destructive) / 0.05);
|
|
421
|
+
font-size: var(--upload-draft-font-size);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.ui-upload-draft-hint {
|
|
425
|
+
display: flex;
|
|
426
|
+
flex-wrap: wrap;
|
|
427
|
+
align-items: center;
|
|
428
|
+
gap: var(--upload-draft-space-gap);
|
|
429
|
+
font-size: var(--upload-draft-font-size);
|
|
430
|
+
color: hsl(var(--muted-foreground));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.ui-upload-draft-icon {
|
|
434
|
+
margin-inline-end: calc(var(--upload-draft-space-gap) / 2);
|
|
435
|
+
inline-size: var(--upload-draft-icon-size);
|
|
436
|
+
block-size: var(--upload-draft-icon-size);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.ui-upload-row {
|
|
440
|
+
display: flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
gap: var(--upload-row-space-gap);
|
|
443
|
+
padding-inline: var(--upload-row-space-inline);
|
|
444
|
+
padding-block: var(--upload-row-space-block);
|
|
445
|
+
border-radius: var(--upload-row-radius);
|
|
446
|
+
border: 1px solid hsl(var(--border));
|
|
447
|
+
font-size: var(--upload-row-font-size);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.ui-upload-row-main {
|
|
451
|
+
min-inline-size: 0;
|
|
452
|
+
flex: 1 1 0%;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.ui-upload-row-icon {
|
|
456
|
+
inline-size: var(--upload-row-icon-size);
|
|
457
|
+
block-size: var(--upload-row-icon-size);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.ui-upload-trigger-icon {
|
|
461
|
+
inline-size: var(--upload-row-icon-size);
|
|
462
|
+
block-size: var(--upload-row-icon-size);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.ui-upload-trigger-icon[data-with-label] {
|
|
466
|
+
margin-inline-end: var(--space-2);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Disabled affordances share the one system alpha rather than a per-variant literal. */
|
|
470
|
+
.ui-upload-dropzone[data-disabled],
|
|
471
|
+
.ui-upload-tile-add[data-disabled],
|
|
472
|
+
.ui-upload-avatar[data-disabled] {
|
|
473
|
+
pointer-events: none;
|
|
474
|
+
opacity: var(--disabled-opacity);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ── BranchScopePicker (gh#319) ────────────────────────────────────────────────
|
|
478
|
+
* `.ui-branch-scope-picker` shipped as a bare hook: the class existed but no rule did, so all
|
|
479
|
+
* of the control's geometry sat on the component as Tailwind literals. It composes RadioGroup +
|
|
480
|
+
* CheckboxGroup + SearchInput and has no field box of its own, so none of the control-affix
|
|
481
|
+
* machinery applies — these four rules are the whole surface. Every measure is a documented
|
|
482
|
+
* token (#45); see tokens/components/data-entry.css for why each default is a flat rem. */
|
|
483
|
+
.ui-branch-scope-picker {
|
|
484
|
+
display: flex;
|
|
485
|
+
flex-direction: column;
|
|
486
|
+
gap: var(--branch-scope-picker-gap);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.ui-branch-scope-picker-badges {
|
|
490
|
+
display: flex;
|
|
491
|
+
flex-wrap: wrap;
|
|
492
|
+
gap: var(--branch-scope-picker-badges-gap);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* The `mode="selected"` subset, indented under its radio by a rule on the inline-start edge.
|
|
496
|
+
* Logical properties throughout, so the indent flips with the writing direction (the utilities
|
|
497
|
+
* this replaces, `border-s-2 ps-4`, already did). The colour is left to the global
|
|
498
|
+
* `* { border-color: hsl(var(--border)) }` so a scoped [data-tenant]/.dark override of
|
|
499
|
+
* `--border` still reaches it. */
|
|
500
|
+
.ui-branch-scope-picker-subset {
|
|
501
|
+
display: flex;
|
|
502
|
+
flex-direction: column;
|
|
503
|
+
gap: var(--branch-scope-picker-subset-gap);
|
|
504
|
+
padding-inline-start: var(--branch-scope-picker-subset-padding-inline);
|
|
505
|
+
border-inline-start-width: var(--branch-scope-picker-subset-border-width);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* A bounded scroll region — the component gives it `tabIndex={0}` + a group name so it stays
|
|
509
|
+
* keyboard-reachable (WCAG 2.1.1 / axe scrollable-region-focusable) even when every checkbox
|
|
510
|
+
* in it is disabled. The cap is the token; the overflow is not negotiable. */
|
|
511
|
+
.ui-branch-scope-picker-list {
|
|
512
|
+
max-block-size: var(--branch-scope-picker-list-max-height);
|
|
513
|
+
overflow-y: auto;
|
|
514
|
+
}
|
|
515
|
+
}
|
package/dist/styles/density.css
CHANGED
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
--control-height-sm: calc(var(--control-height) - calc(0.25rem * var(--scaling)));
|
|
62
62
|
--control-height-lg: calc(var(--control-height) + calc(0.25rem * var(--scaling)));
|
|
63
63
|
--control-height-xs: calc(var(--control-height) - calc(0.5rem * var(--scaling)));
|
|
64
|
-
--control-icon-size: calc(
|
|
65
|
-
--control-icon-size-sm: calc(
|
|
64
|
+
--control-icon-size: calc(var(--icon-size-md) * var(--scaling));
|
|
65
|
+
--control-icon-size-sm: calc(var(--icon-size-sm) * var(--scaling));
|
|
66
66
|
--control-padding-x: var(--space-3);
|
|
67
67
|
--control-gap: var(--space-2);
|
|
68
68
|
--control-gap-sm: var(--space-1);
|