@adea-ai/ui 0.71.6 → 0.72.1
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/theme/theme-picker.d.ts.map +1 -1
- package/dist/components/theme/theme-picker.js +2 -2
- package/dist/components/theme/theme-picker.js.map +1 -1
- package/dist/components/ui/button/button.js +1 -1
- package/dist/components/ui/button/button.js.map +1 -1
- package/dist/components/ui/checkbox/checkbox.d.ts +2 -0
- package/dist/components/ui/checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/ui/checkbox/checkbox.js +52 -13
- package/dist/components/ui/checkbox/checkbox.js.map +1 -1
- package/dist/components/ui/radio-group/radio-group.d.ts +2 -1
- package/dist/components/ui/radio-group/radio-group.d.ts.map +1 -1
- package/dist/components/ui/radio-group/radio-group.js +46 -13
- package/dist/components/ui/radio-group/radio-group.js.map +1 -1
- package/dist/components/ui/switch/switch.d.ts +2 -0
- package/dist/components/ui/switch/switch.d.ts.map +1 -1
- package/dist/components/ui/switch/switch.js +51 -12
- package/dist/components/ui/switch/switch.js.map +1 -1
- package/dist/lib/themes.d.ts +3 -0
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +6 -7
- package/dist/lib/themes.js.map +1 -1
- package/dist/lib/tokens.d.ts.map +1 -1
- package/dist/lib/tokens.js +14 -2
- package/dist/lib/tokens.js.map +1 -1
- package/dist/r/appearance-editor.json +1 -1
- package/dist/r/lib.json +1 -1
- package/dist/r/registry.json +2 -2
- package/dist/r/src/components/theme/theme-picker.tsx +5 -2
- package/dist/r/src/components/ui/button/button.tsx +1 -1
- package/dist/r/src/components/ui/checkbox/checkbox.tsx +34 -9
- package/dist/r/src/components/ui/radio-group/radio-group.tsx +22 -5
- package/dist/r/src/components/ui/switch/switch.tsx +34 -9
- package/dist/r/src/lib/themes.ts +18 -7
- package/dist/r/src/lib/tokens.ts +15 -2
- package/dist/r/src/styles/theme.css +6 -0
- package/package.json +2 -2
- package/registry.json +2 -2
- package/src/components/theme/theme-picker.tsx +5 -2
- package/src/components/ui/button/button.tsx +1 -1
- package/src/components/ui/checkbox/checkbox.tsx +34 -9
- package/src/components/ui/radio-group/radio-group.tsx +22 -5
- package/src/components/ui/switch/switch.tsx +34 -9
- package/src/lib/themes.ts +18 -7
- package/src/lib/tokens.ts +15 -2
- package/src/styles/theme.css +6 -0
|
@@ -21,6 +21,8 @@ export type SwitchProps = Omit<ComponentProps<typeof KobalteSwitch>, 'children'>
|
|
|
21
21
|
thumbClass?: string
|
|
22
22
|
labelClass?: string
|
|
23
23
|
descriptionClass?: string
|
|
24
|
+
label?: JSX.Element
|
|
25
|
+
description?: JSX.Element
|
|
24
26
|
/**
|
|
25
27
|
* Replaces the control and label. Omit it to get the default control beside
|
|
26
28
|
* `label` and `description`; supply it to compose the parts yourself.
|
|
@@ -36,16 +38,30 @@ export function Switch(props: SwitchProps) {
|
|
|
36
38
|
'labelClass',
|
|
37
39
|
'descriptionClass',
|
|
38
40
|
'children',
|
|
41
|
+
'label',
|
|
42
|
+
'description',
|
|
39
43
|
'aria-label',
|
|
40
44
|
'aria-labelledby',
|
|
45
|
+
'aria-describedby',
|
|
46
|
+
'aria-invalid',
|
|
47
|
+
'aria-busy',
|
|
48
|
+
'title',
|
|
41
49
|
])
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
|
-
<KobalteSwitch
|
|
52
|
+
<KobalteSwitch
|
|
53
|
+
title={local.title}
|
|
54
|
+
class={cn('group/switch flex items-center gap-2.5', local.class)}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
45
57
|
{/* The name belongs on the input; see Checkbox for why. */}
|
|
46
58
|
<KobalteSwitch.Input
|
|
47
59
|
aria-label={local['aria-label']}
|
|
48
60
|
aria-labelledby={local['aria-labelledby']}
|
|
61
|
+
aria-describedby={local['aria-describedby']}
|
|
62
|
+
aria-invalid={local['aria-invalid']}
|
|
63
|
+
aria-busy={local['aria-busy']}
|
|
64
|
+
title={local.title}
|
|
49
65
|
/>
|
|
50
66
|
<KobalteSwitch.Control
|
|
51
67
|
class={cn(
|
|
@@ -67,14 +83,23 @@ export function Switch(props: SwitchProps) {
|
|
|
67
83
|
)}
|
|
68
84
|
/>
|
|
69
85
|
</KobalteSwitch.Control>
|
|
70
|
-
{local.children ??
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
{local.children ??
|
|
87
|
+
(local.label || local.description ? (
|
|
88
|
+
<div class="grid gap-0.5">
|
|
89
|
+
{local.label ? (
|
|
90
|
+
<KobalteSwitch.Label class={cn('text-sm leading-none font-medium', local.labelClass)}>
|
|
91
|
+
{local.label}
|
|
92
|
+
</KobalteSwitch.Label>
|
|
93
|
+
) : null}
|
|
94
|
+
{local.description ? (
|
|
95
|
+
<KobalteSwitch.Description
|
|
96
|
+
class={cn('text-muted-foreground text-sm', local.descriptionClass)}
|
|
97
|
+
>
|
|
98
|
+
{local.description}
|
|
99
|
+
</KobalteSwitch.Description>
|
|
100
|
+
) : null}
|
|
101
|
+
</div>
|
|
102
|
+
) : null)}
|
|
78
103
|
</KobalteSwitch>
|
|
79
104
|
)
|
|
80
105
|
}
|
package/dist/r/src/lib/themes.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
chartSeries,
|
|
40
40
|
getAccent,
|
|
41
41
|
hasTheme,
|
|
42
|
+
shadcnDestructiveProjection,
|
|
42
43
|
statusForeground,
|
|
43
44
|
tint,
|
|
44
45
|
primaryHover,
|
|
@@ -78,6 +79,9 @@ export type ThemeColors = {
|
|
|
78
79
|
destructive: string
|
|
79
80
|
destructiveForeground: string
|
|
80
81
|
destructiveSubtle: string
|
|
82
|
+
/** Contrast-safe solid-action presentation, derived from the canonical error role. */
|
|
83
|
+
destructiveAction: string
|
|
84
|
+
destructiveActionForeground: string
|
|
81
85
|
success: string
|
|
82
86
|
successForeground: string
|
|
83
87
|
successSubtle: string
|
|
@@ -170,10 +174,12 @@ export type ThemeVariant = {
|
|
|
170
174
|
/**
|
|
171
175
|
* Canonical role → this system's `ThemeColors` key.
|
|
172
176
|
*
|
|
173
|
-
* Read by {@link toVariant}.
|
|
174
|
-
*
|
|
177
|
+
* Read by {@link toVariant}. The two derived destructive-action presentation values
|
|
178
|
+
* are intentionally excluded; the shared Themes adapter owns their color math.
|
|
175
179
|
*/
|
|
176
|
-
|
|
180
|
+
type ThemeRole = Exclude<keyof ThemeColors, 'destructiveAction' | 'destructiveActionForeground'>
|
|
181
|
+
|
|
182
|
+
const ROLE_FOR: Readonly<Record<ThemeRole, keyof AdeaThemeRecord['colors']>> = {
|
|
177
183
|
background: 'background',
|
|
178
184
|
foreground: 'text',
|
|
179
185
|
card: 'surface',
|
|
@@ -216,14 +222,17 @@ const ROLE_FOR: Readonly<Record<keyof ThemeColors, keyof AdeaThemeRecord['colors
|
|
|
216
222
|
/** Builds the design system's view of one catalogue entry. */
|
|
217
223
|
function toVariant(theme: AdeaThemeRecord): ThemeVariant {
|
|
218
224
|
const colors = {} as ThemeColors
|
|
219
|
-
for (const key of Object.keys(ROLE_FOR) as
|
|
225
|
+
for (const key of Object.keys(ROLE_FOR) as ThemeRole[]) {
|
|
220
226
|
colors[key] = theme.colors[ROLE_FOR[key]]
|
|
221
227
|
}
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
228
|
+
// Keep the semantic foreground paired with the canonical error role. Filled
|
|
229
|
+
// destructive actions use the distinct projection below so their /90 hover state
|
|
230
|
+
// remains readable without changing icons, borders, or tinted status surfaces.
|
|
225
231
|
colors.destructiveForeground = statusForeground(theme, 'error')
|
|
226
232
|
colors.destructiveSubtle = tint(theme.colors.error, theme.colors.background)
|
|
233
|
+
const destructiveAction = shadcnDestructiveProjection(theme)
|
|
234
|
+
colors.destructiveAction = destructiveAction.fill
|
|
235
|
+
colors.destructiveActionForeground = destructiveAction.foreground
|
|
227
236
|
colors.successForeground = statusForeground(theme, 'success')
|
|
228
237
|
colors.successSubtle = tint(theme.colors.success, theme.colors.background)
|
|
229
238
|
colors.warningForeground = statusForeground(theme, 'warning')
|
|
@@ -397,6 +406,8 @@ export function themeCssVariables(theme: ThemeVariant): Record<string, string> {
|
|
|
397
406
|
'--destructive': c.destructive,
|
|
398
407
|
'--destructive-foreground': c.destructiveForeground,
|
|
399
408
|
'--destructive-subtle': c.destructiveSubtle,
|
|
409
|
+
'--destructive-action': c.destructiveAction,
|
|
410
|
+
'--destructive-action-foreground': c.destructiveActionForeground,
|
|
400
411
|
'--success': c.success,
|
|
401
412
|
'--success-foreground': c.successForeground,
|
|
402
413
|
'--success-subtle': c.successSubtle,
|
package/dist/r/src/lib/tokens.ts
CHANGED
|
@@ -184,13 +184,14 @@ export const colorTokens: TokenDefinition[] = [
|
|
|
184
184
|
name: 'destructive',
|
|
185
185
|
kind: 'color',
|
|
186
186
|
themed: true,
|
|
187
|
-
description: '
|
|
187
|
+
description: 'The canonical error hue for semantic status indicators and tinted notices.',
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
190
|
name: 'destructive-foreground',
|
|
191
191
|
kind: 'color',
|
|
192
192
|
themed: true,
|
|
193
|
-
description:
|
|
193
|
+
description:
|
|
194
|
+
'Text on the canonical error hue; solid actions use `destructive-action-foreground`.',
|
|
194
195
|
},
|
|
195
196
|
{
|
|
196
197
|
name: 'destructive-subtle',
|
|
@@ -198,6 +199,18 @@ export const colorTokens: TokenDefinition[] = [
|
|
|
198
199
|
themed: true,
|
|
199
200
|
description: 'Opaque destructive tint against the canvas; subtle labels use foreground.',
|
|
200
201
|
},
|
|
202
|
+
{
|
|
203
|
+
name: 'destructive-action',
|
|
204
|
+
kind: 'color',
|
|
205
|
+
themed: true,
|
|
206
|
+
description: 'Contrast-safe solid fill for destructive actions, derived from the error role.',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'destructive-action-foreground',
|
|
210
|
+
kind: 'color',
|
|
211
|
+
themed: true,
|
|
212
|
+
description: 'Text on the destructive action fill and its 90% hover composition.',
|
|
213
|
+
},
|
|
201
214
|
{ name: 'success', kind: 'color', themed: true, description: 'A completed or healthy state.' },
|
|
202
215
|
{ name: 'success-foreground', kind: 'color', themed: true, description: 'Label on `success`.' },
|
|
203
216
|
{
|
|
@@ -81,6 +81,8 @@
|
|
|
81
81
|
/* Status fills; solid labels and subtle surfaces come from the catalogue. */
|
|
82
82
|
--destructive: oklch(0.4705 0.1626 25.78);
|
|
83
83
|
--destructive-foreground: oklch(0.933 0.016 261.79);
|
|
84
|
+
--destructive-action: oklch(0.4705 0.1626 25.78);
|
|
85
|
+
--destructive-action-foreground: oklch(0.933 0.016 261.79);
|
|
84
86
|
--success: oklch(0.4311 0.1809 145.62);
|
|
85
87
|
--success-foreground: oklch(0.933 0.016 261.79);
|
|
86
88
|
--warning: oklch(0.4556 0.1401 79.91);
|
|
@@ -216,6 +218,8 @@
|
|
|
216
218
|
/* Status fills; solid labels and subtle surfaces come from the catalogue. */
|
|
217
219
|
--destructive: oklch(0.7345 0.1626 25.78);
|
|
218
220
|
--destructive-foreground: oklch(0.1918 0.0238 265.37);
|
|
221
|
+
--destructive-action: oklch(0.7345 0.1626 25.78);
|
|
222
|
+
--destructive-action-foreground: oklch(0.1918 0.0238 265.37);
|
|
219
223
|
--success: oklch(0.6951 0.1809 145.62);
|
|
220
224
|
--success-foreground: oklch(0.1918 0.0238 265.37);
|
|
221
225
|
--warning: oklch(0.7196 0.1401 79.91);
|
|
@@ -730,6 +734,8 @@
|
|
|
730
734
|
--color-destructive: var(--destructive);
|
|
731
735
|
--color-destructive-foreground: var(--destructive-foreground);
|
|
732
736
|
--color-destructive-subtle: var(--destructive-subtle);
|
|
737
|
+
--color-destructive-action: var(--destructive-action);
|
|
738
|
+
--color-destructive-action-foreground: var(--destructive-action-foreground);
|
|
733
739
|
--color-success: var(--success);
|
|
734
740
|
--color-success-foreground: var(--success-foreground);
|
|
735
741
|
--color-success-subtle: var(--success-subtle);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adea-ai/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.1",
|
|
4
4
|
"description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adea",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"check:packed-paste-model": "node scripts/check-packed-paste-model.mjs"
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"@adea-ai/themes": "^0.6.
|
|
109
|
+
"@adea-ai/themes": "^0.6.2",
|
|
110
110
|
"@corvu/calendar": "^0.1.2",
|
|
111
111
|
"@corvu/drawer": "^0.2.4",
|
|
112
112
|
"@corvu/otp-field": "^0.1.4",
|
package/registry.json
CHANGED
|
@@ -1670,7 +1670,7 @@
|
|
|
1670
1670
|
"title": "Appearance Editor",
|
|
1671
1671
|
"description": "",
|
|
1672
1672
|
"dependencies": [
|
|
1673
|
-
"@adea-ai/themes@^0.6.
|
|
1673
|
+
"@adea-ai/themes@^0.6.2",
|
|
1674
1674
|
"@kobalte/core@^0.13.14",
|
|
1675
1675
|
"lucide-solid@^1.48.0"
|
|
1676
1676
|
],
|
|
@@ -2064,7 +2064,7 @@
|
|
|
2064
2064
|
"title": "Class-name and token helpers",
|
|
2065
2065
|
"description": "The private helpers the components import: the class-name merge, the variant recipes, the token manifest and the theme bridge. Installed automatically as a peer of any component that needs it.",
|
|
2066
2066
|
"dependencies": [
|
|
2067
|
-
"@adea-ai/themes@^0.6.
|
|
2067
|
+
"@adea-ai/themes@^0.6.2",
|
|
2068
2068
|
"class-variance-authority@^0.7.1",
|
|
2069
2069
|
"clsx@^2.1.1",
|
|
2070
2070
|
"tailwind-merge@^3.7.0"
|
|
@@ -47,7 +47,7 @@ export function ThemeSwatch(props: ThemeSwatchProps) {
|
|
|
47
47
|
colors().card,
|
|
48
48
|
colors().primary,
|
|
49
49
|
colors().accent,
|
|
50
|
-
colors().
|
|
50
|
+
colors().destructiveAction,
|
|
51
51
|
]}
|
|
52
52
|
>
|
|
53
53
|
{(color) => (
|
|
@@ -109,7 +109,10 @@ export function ThemePreview(props: ThemePreviewProps) {
|
|
|
109
109
|
<div class="h-1 w-16 rounded-full" style={{ 'background-color': c().mutedForeground }} />
|
|
110
110
|
<div class="mt-auto flex items-center gap-1">
|
|
111
111
|
<span class="h-3 w-9 rounded-sm" style={{ 'background-color': c().primary }} />
|
|
112
|
-
<span
|
|
112
|
+
<span
|
|
113
|
+
class="h-3 w-6 rounded-sm"
|
|
114
|
+
style={{ 'background-color': c().destructiveAction }}
|
|
115
|
+
/>
|
|
113
116
|
<span class="h-3 w-6 rounded-sm" style={{ 'background-color': c().secondary }} />
|
|
114
117
|
</div>
|
|
115
118
|
</div>
|
|
@@ -29,7 +29,7 @@ export const buttonVariants = cva(
|
|
|
29
29
|
secondary: 'bg-secondary text-secondary-foreground hover:bg-surface-hover',
|
|
30
30
|
/** For the action that destroys something. Never the default. */
|
|
31
31
|
destructive:
|
|
32
|
-
'bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive-subtle',
|
|
32
|
+
'bg-destructive-action text-destructive-action-foreground hover:bg-destructive-action/90 focus-visible:ring-destructive-subtle',
|
|
33
33
|
/** A bordered button for a surface that already has a fill. */
|
|
34
34
|
outline:
|
|
35
35
|
'border border-border bg-transparent text-foreground hover:bg-surface-hover hover:border-input',
|
|
@@ -21,6 +21,8 @@ export type CheckboxProps = Omit<ComponentProps<typeof KobalteCheckbox>, 'childr
|
|
|
21
21
|
controlClass?: string
|
|
22
22
|
labelClass?: string
|
|
23
23
|
descriptionClass?: string
|
|
24
|
+
label?: JSX.Element
|
|
25
|
+
description?: JSX.Element
|
|
24
26
|
/**
|
|
25
27
|
* Replaces the control and label. Omit it to get the default control beside
|
|
26
28
|
* `label` and `description`; supply it to compose the parts yourself.
|
|
@@ -35,13 +37,23 @@ export function Checkbox(props: CheckboxProps) {
|
|
|
35
37
|
'labelClass',
|
|
36
38
|
'descriptionClass',
|
|
37
39
|
'children',
|
|
40
|
+
'label',
|
|
41
|
+
'description',
|
|
38
42
|
'indeterminate',
|
|
39
43
|
'aria-label',
|
|
40
44
|
'aria-labelledby',
|
|
45
|
+
'aria-describedby',
|
|
46
|
+
'aria-invalid',
|
|
47
|
+
'aria-busy',
|
|
48
|
+
'title',
|
|
41
49
|
])
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
|
-
<KobalteCheckbox
|
|
52
|
+
<KobalteCheckbox
|
|
53
|
+
title={local.title}
|
|
54
|
+
class={cn('group/checkbox flex items-start gap-2.5', local.class)}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
45
57
|
{/*
|
|
46
58
|
* The name goes on the input, which is what carries the value and takes
|
|
47
59
|
* focus. On the Root it would land on a plain div and name nothing — the
|
|
@@ -50,6 +62,10 @@ export function Checkbox(props: CheckboxProps) {
|
|
|
50
62
|
<KobalteCheckbox.Input
|
|
51
63
|
aria-label={local['aria-label']}
|
|
52
64
|
aria-labelledby={local['aria-labelledby']}
|
|
65
|
+
aria-describedby={local['aria-describedby']}
|
|
66
|
+
aria-invalid={local['aria-invalid']}
|
|
67
|
+
aria-busy={local['aria-busy']}
|
|
68
|
+
title={local.title}
|
|
53
69
|
/>
|
|
54
70
|
<KobalteCheckbox.Control
|
|
55
71
|
class={cn(
|
|
@@ -67,14 +83,23 @@ export function Checkbox(props: CheckboxProps) {
|
|
|
67
83
|
{local.indeterminate ? <Minus class="size-3" /> : <Check class="size-3" />}
|
|
68
84
|
</KobalteCheckbox.Indicator>
|
|
69
85
|
</KobalteCheckbox.Control>
|
|
70
|
-
{local.children ??
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
{local.children ??
|
|
87
|
+
(local.label || local.description ? (
|
|
88
|
+
<div class="grid gap-0.5">
|
|
89
|
+
{local.label ? (
|
|
90
|
+
<KobalteCheckbox.Label class={cn('text-sm font-medium', local.labelClass)}>
|
|
91
|
+
{local.label}
|
|
92
|
+
</KobalteCheckbox.Label>
|
|
93
|
+
) : null}
|
|
94
|
+
{local.description ? (
|
|
95
|
+
<KobalteCheckbox.Description
|
|
96
|
+
class={cn('text-muted-foreground text-sm', local.descriptionClass)}
|
|
97
|
+
>
|
|
98
|
+
{local.description}
|
|
99
|
+
</KobalteCheckbox.Description>
|
|
100
|
+
) : null}
|
|
101
|
+
</div>
|
|
102
|
+
) : null)}
|
|
78
103
|
</KobalteCheckbox>
|
|
79
104
|
)
|
|
80
105
|
}
|
|
@@ -25,7 +25,8 @@ export type RadioGroupItemProps = ComponentProps<typeof KobalteRadioGroup.Item>
|
|
|
25
25
|
controlClass?: string
|
|
26
26
|
/**
|
|
27
27
|
* The option's visible label. A radio with no accessible name is unreachable
|
|
28
|
-
* by a screen reader and by voice control, so supply this
|
|
28
|
+
* by a screen reader and by voice control, so supply this, a labelled child,
|
|
29
|
+
* `aria-label`, or `aria-labelledby`.
|
|
29
30
|
*/
|
|
30
31
|
label?: string
|
|
31
32
|
description?: string
|
|
@@ -38,14 +39,28 @@ export function RadioGroupItem(props: RadioGroupItemProps) {
|
|
|
38
39
|
'label',
|
|
39
40
|
'description',
|
|
40
41
|
'children',
|
|
42
|
+
'aria-label',
|
|
43
|
+
'aria-labelledby',
|
|
44
|
+
'aria-describedby',
|
|
45
|
+
'aria-invalid',
|
|
46
|
+
'aria-busy',
|
|
47
|
+
'title',
|
|
41
48
|
])
|
|
42
49
|
|
|
43
50
|
return (
|
|
44
51
|
<KobalteRadioGroup.Item
|
|
52
|
+
title={local.title}
|
|
45
53
|
class={cn('group/radio flex items-start gap-2.5', local.class)}
|
|
46
54
|
{...rest}
|
|
47
55
|
>
|
|
48
|
-
<KobalteRadioGroup.ItemInput
|
|
56
|
+
<KobalteRadioGroup.ItemInput
|
|
57
|
+
aria-label={local['aria-label']}
|
|
58
|
+
aria-labelledby={local['aria-labelledby']}
|
|
59
|
+
aria-describedby={local['aria-describedby']}
|
|
60
|
+
aria-invalid={local['aria-invalid']}
|
|
61
|
+
aria-busy={local['aria-busy']}
|
|
62
|
+
title={local.title}
|
|
63
|
+
/>
|
|
49
64
|
<KobalteRadioGroup.ItemControl
|
|
50
65
|
class={cn(
|
|
51
66
|
'border-input bg-transparent flex size-4 shrink-0 items-center justify-center rounded-full border',
|
|
@@ -63,9 +78,11 @@ export function RadioGroupItem(props: RadioGroupItemProps) {
|
|
|
63
78
|
</KobalteRadioGroup.ItemControl>
|
|
64
79
|
{local.children ?? (
|
|
65
80
|
<div class="grid gap-0.5 leading-none">
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
{local.label ? (
|
|
82
|
+
<KobalteRadioGroup.ItemLabel class="text-sm font-medium">
|
|
83
|
+
{local.label}
|
|
84
|
+
</KobalteRadioGroup.ItemLabel>
|
|
85
|
+
) : null}
|
|
69
86
|
{local.description ? (
|
|
70
87
|
<KobalteRadioGroup.ItemDescription class="text-muted-foreground text-sm">
|
|
71
88
|
{local.description}
|
|
@@ -21,6 +21,8 @@ export type SwitchProps = Omit<ComponentProps<typeof KobalteSwitch>, 'children'>
|
|
|
21
21
|
thumbClass?: string
|
|
22
22
|
labelClass?: string
|
|
23
23
|
descriptionClass?: string
|
|
24
|
+
label?: JSX.Element
|
|
25
|
+
description?: JSX.Element
|
|
24
26
|
/**
|
|
25
27
|
* Replaces the control and label. Omit it to get the default control beside
|
|
26
28
|
* `label` and `description`; supply it to compose the parts yourself.
|
|
@@ -36,16 +38,30 @@ export function Switch(props: SwitchProps) {
|
|
|
36
38
|
'labelClass',
|
|
37
39
|
'descriptionClass',
|
|
38
40
|
'children',
|
|
41
|
+
'label',
|
|
42
|
+
'description',
|
|
39
43
|
'aria-label',
|
|
40
44
|
'aria-labelledby',
|
|
45
|
+
'aria-describedby',
|
|
46
|
+
'aria-invalid',
|
|
47
|
+
'aria-busy',
|
|
48
|
+
'title',
|
|
41
49
|
])
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
|
-
<KobalteSwitch
|
|
52
|
+
<KobalteSwitch
|
|
53
|
+
title={local.title}
|
|
54
|
+
class={cn('group/switch flex items-center gap-2.5', local.class)}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
45
57
|
{/* The name belongs on the input; see Checkbox for why. */}
|
|
46
58
|
<KobalteSwitch.Input
|
|
47
59
|
aria-label={local['aria-label']}
|
|
48
60
|
aria-labelledby={local['aria-labelledby']}
|
|
61
|
+
aria-describedby={local['aria-describedby']}
|
|
62
|
+
aria-invalid={local['aria-invalid']}
|
|
63
|
+
aria-busy={local['aria-busy']}
|
|
64
|
+
title={local.title}
|
|
49
65
|
/>
|
|
50
66
|
<KobalteSwitch.Control
|
|
51
67
|
class={cn(
|
|
@@ -67,14 +83,23 @@ export function Switch(props: SwitchProps) {
|
|
|
67
83
|
)}
|
|
68
84
|
/>
|
|
69
85
|
</KobalteSwitch.Control>
|
|
70
|
-
{local.children ??
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
{local.children ??
|
|
87
|
+
(local.label || local.description ? (
|
|
88
|
+
<div class="grid gap-0.5">
|
|
89
|
+
{local.label ? (
|
|
90
|
+
<KobalteSwitch.Label class={cn('text-sm leading-none font-medium', local.labelClass)}>
|
|
91
|
+
{local.label}
|
|
92
|
+
</KobalteSwitch.Label>
|
|
93
|
+
) : null}
|
|
94
|
+
{local.description ? (
|
|
95
|
+
<KobalteSwitch.Description
|
|
96
|
+
class={cn('text-muted-foreground text-sm', local.descriptionClass)}
|
|
97
|
+
>
|
|
98
|
+
{local.description}
|
|
99
|
+
</KobalteSwitch.Description>
|
|
100
|
+
) : null}
|
|
101
|
+
</div>
|
|
102
|
+
) : null)}
|
|
78
103
|
</KobalteSwitch>
|
|
79
104
|
)
|
|
80
105
|
}
|
package/src/lib/themes.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
chartSeries,
|
|
40
40
|
getAccent,
|
|
41
41
|
hasTheme,
|
|
42
|
+
shadcnDestructiveProjection,
|
|
42
43
|
statusForeground,
|
|
43
44
|
tint,
|
|
44
45
|
primaryHover,
|
|
@@ -78,6 +79,9 @@ export type ThemeColors = {
|
|
|
78
79
|
destructive: string
|
|
79
80
|
destructiveForeground: string
|
|
80
81
|
destructiveSubtle: string
|
|
82
|
+
/** Contrast-safe solid-action presentation, derived from the canonical error role. */
|
|
83
|
+
destructiveAction: string
|
|
84
|
+
destructiveActionForeground: string
|
|
81
85
|
success: string
|
|
82
86
|
successForeground: string
|
|
83
87
|
successSubtle: string
|
|
@@ -170,10 +174,12 @@ export type ThemeVariant = {
|
|
|
170
174
|
/**
|
|
171
175
|
* Canonical role → this system's `ThemeColors` key.
|
|
172
176
|
*
|
|
173
|
-
* Read by {@link toVariant}.
|
|
174
|
-
*
|
|
177
|
+
* Read by {@link toVariant}. The two derived destructive-action presentation values
|
|
178
|
+
* are intentionally excluded; the shared Themes adapter owns their color math.
|
|
175
179
|
*/
|
|
176
|
-
|
|
180
|
+
type ThemeRole = Exclude<keyof ThemeColors, 'destructiveAction' | 'destructiveActionForeground'>
|
|
181
|
+
|
|
182
|
+
const ROLE_FOR: Readonly<Record<ThemeRole, keyof AdeaThemeRecord['colors']>> = {
|
|
177
183
|
background: 'background',
|
|
178
184
|
foreground: 'text',
|
|
179
185
|
card: 'surface',
|
|
@@ -216,14 +222,17 @@ const ROLE_FOR: Readonly<Record<keyof ThemeColors, keyof AdeaThemeRecord['colors
|
|
|
216
222
|
/** Builds the design system's view of one catalogue entry. */
|
|
217
223
|
function toVariant(theme: AdeaThemeRecord): ThemeVariant {
|
|
218
224
|
const colors = {} as ThemeColors
|
|
219
|
-
for (const key of Object.keys(ROLE_FOR) as
|
|
225
|
+
for (const key of Object.keys(ROLE_FOR) as ThemeRole[]) {
|
|
220
226
|
colors[key] = theme.colors[ROLE_FOR[key]]
|
|
221
227
|
}
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
228
|
+
// Keep the semantic foreground paired with the canonical error role. Filled
|
|
229
|
+
// destructive actions use the distinct projection below so their /90 hover state
|
|
230
|
+
// remains readable without changing icons, borders, or tinted status surfaces.
|
|
225
231
|
colors.destructiveForeground = statusForeground(theme, 'error')
|
|
226
232
|
colors.destructiveSubtle = tint(theme.colors.error, theme.colors.background)
|
|
233
|
+
const destructiveAction = shadcnDestructiveProjection(theme)
|
|
234
|
+
colors.destructiveAction = destructiveAction.fill
|
|
235
|
+
colors.destructiveActionForeground = destructiveAction.foreground
|
|
227
236
|
colors.successForeground = statusForeground(theme, 'success')
|
|
228
237
|
colors.successSubtle = tint(theme.colors.success, theme.colors.background)
|
|
229
238
|
colors.warningForeground = statusForeground(theme, 'warning')
|
|
@@ -397,6 +406,8 @@ export function themeCssVariables(theme: ThemeVariant): Record<string, string> {
|
|
|
397
406
|
'--destructive': c.destructive,
|
|
398
407
|
'--destructive-foreground': c.destructiveForeground,
|
|
399
408
|
'--destructive-subtle': c.destructiveSubtle,
|
|
409
|
+
'--destructive-action': c.destructiveAction,
|
|
410
|
+
'--destructive-action-foreground': c.destructiveActionForeground,
|
|
400
411
|
'--success': c.success,
|
|
401
412
|
'--success-foreground': c.successForeground,
|
|
402
413
|
'--success-subtle': c.successSubtle,
|
package/src/lib/tokens.ts
CHANGED
|
@@ -184,13 +184,14 @@ export const colorTokens: TokenDefinition[] = [
|
|
|
184
184
|
name: 'destructive',
|
|
185
185
|
kind: 'color',
|
|
186
186
|
themed: true,
|
|
187
|
-
description: '
|
|
187
|
+
description: 'The canonical error hue for semantic status indicators and tinted notices.',
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
190
|
name: 'destructive-foreground',
|
|
191
191
|
kind: 'color',
|
|
192
192
|
themed: true,
|
|
193
|
-
description:
|
|
193
|
+
description:
|
|
194
|
+
'Text on the canonical error hue; solid actions use `destructive-action-foreground`.',
|
|
194
195
|
},
|
|
195
196
|
{
|
|
196
197
|
name: 'destructive-subtle',
|
|
@@ -198,6 +199,18 @@ export const colorTokens: TokenDefinition[] = [
|
|
|
198
199
|
themed: true,
|
|
199
200
|
description: 'Opaque destructive tint against the canvas; subtle labels use foreground.',
|
|
200
201
|
},
|
|
202
|
+
{
|
|
203
|
+
name: 'destructive-action',
|
|
204
|
+
kind: 'color',
|
|
205
|
+
themed: true,
|
|
206
|
+
description: 'Contrast-safe solid fill for destructive actions, derived from the error role.',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'destructive-action-foreground',
|
|
210
|
+
kind: 'color',
|
|
211
|
+
themed: true,
|
|
212
|
+
description: 'Text on the destructive action fill and its 90% hover composition.',
|
|
213
|
+
},
|
|
201
214
|
{ name: 'success', kind: 'color', themed: true, description: 'A completed or healthy state.' },
|
|
202
215
|
{ name: 'success-foreground', kind: 'color', themed: true, description: 'Label on `success`.' },
|
|
203
216
|
{
|
package/src/styles/theme.css
CHANGED
|
@@ -81,6 +81,8 @@
|
|
|
81
81
|
/* Status fills; solid labels and subtle surfaces come from the catalogue. */
|
|
82
82
|
--destructive: oklch(0.4705 0.1626 25.78);
|
|
83
83
|
--destructive-foreground: oklch(0.933 0.016 261.79);
|
|
84
|
+
--destructive-action: oklch(0.4705 0.1626 25.78);
|
|
85
|
+
--destructive-action-foreground: oklch(0.933 0.016 261.79);
|
|
84
86
|
--success: oklch(0.4311 0.1809 145.62);
|
|
85
87
|
--success-foreground: oklch(0.933 0.016 261.79);
|
|
86
88
|
--warning: oklch(0.4556 0.1401 79.91);
|
|
@@ -216,6 +218,8 @@
|
|
|
216
218
|
/* Status fills; solid labels and subtle surfaces come from the catalogue. */
|
|
217
219
|
--destructive: oklch(0.7345 0.1626 25.78);
|
|
218
220
|
--destructive-foreground: oklch(0.1918 0.0238 265.37);
|
|
221
|
+
--destructive-action: oklch(0.7345 0.1626 25.78);
|
|
222
|
+
--destructive-action-foreground: oklch(0.1918 0.0238 265.37);
|
|
219
223
|
--success: oklch(0.6951 0.1809 145.62);
|
|
220
224
|
--success-foreground: oklch(0.1918 0.0238 265.37);
|
|
221
225
|
--warning: oklch(0.7196 0.1401 79.91);
|
|
@@ -730,6 +734,8 @@
|
|
|
730
734
|
--color-destructive: var(--destructive);
|
|
731
735
|
--color-destructive-foreground: var(--destructive-foreground);
|
|
732
736
|
--color-destructive-subtle: var(--destructive-subtle);
|
|
737
|
+
--color-destructive-action: var(--destructive-action);
|
|
738
|
+
--color-destructive-action-foreground: var(--destructive-action-foreground);
|
|
733
739
|
--color-success: var(--success);
|
|
734
740
|
--color-success-foreground: var(--success-foreground);
|
|
735
741
|
--color-success-subtle: var(--success-subtle);
|