@firecms/ui 3.3.0-canary.2064433 → 3.3.0-canary.289082f
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/Card.d.ts +2 -3
- package/dist/components/Checkbox.d.ts +2 -1
- package/dist/components/Chip.d.ts +5 -1
- package/dist/components/Dialog.d.ts +2 -1
- package/dist/components/FilterChip.d.ts +34 -0
- package/dist/components/IconButton.d.ts +1 -0
- package/dist/components/Popover.d.ts +3 -1
- package/dist/components/Select.d.ts +1 -1
- package/dist/components/TextField.d.ts +2 -2
- package/dist/components/index.d.ts +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useDebounceCallback.d.ts +13 -0
- package/dist/index.es.js +982 -530
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +981 -529
- package/dist/index.umd.js.map +1 -1
- package/dist/{index.css → src/index.css} +43 -32
- package/dist/styles.d.ts +1 -1
- package/package.json +6 -6
- package/src/components/Alert.tsx +7 -7
- package/src/components/Avatar.tsx +1 -1
- package/src/components/BooleanSwitch.tsx +6 -3
- package/src/components/Button.tsx +17 -13
- package/src/components/Card.tsx +3 -1
- package/src/components/CenteredView.tsx +1 -1
- package/src/components/Checkbox.tsx +10 -4
- package/src/components/Chip.tsx +70 -11
- package/src/components/Collapse.tsx +2 -0
- package/src/components/Dialog.tsx +8 -5
- package/src/components/ExpandablePanel.tsx +3 -2
- package/src/components/FilterChip.tsx +79 -0
- package/src/components/IconButton.tsx +11 -6
- package/src/components/InfoLabel.tsx +1 -1
- package/src/components/InputLabel.tsx +2 -2
- package/src/components/Label.tsx +1 -1
- package/src/components/LoadingButton.tsx +1 -1
- package/src/components/Menu.tsx +2 -0
- package/src/components/Popover.tsx +9 -3
- package/src/components/RadioGroup.tsx +1 -1
- package/src/components/Select.tsx +8 -6
- package/src/components/Separator.tsx +2 -2
- package/src/components/Skeleton.tsx +25 -8
- package/src/components/TextField.tsx +27 -13
- package/src/components/ToggleButtonGroup.tsx +4 -2
- package/src/components/index.tsx +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDebounceCallback.tsx +47 -0
- package/src/index.css +43 -32
- package/src/styles.ts +1 -1
|
@@ -19,26 +19,26 @@
|
|
|
19
19
|
--color-field-disabled: rgb(224 224 226);
|
|
20
20
|
--color-field-disabled-dark: rgb(35 35 37);
|
|
21
21
|
|
|
22
|
-
/* Text Colors */
|
|
23
|
-
--color-text-primary:
|
|
24
|
-
--color-text-secondary:
|
|
25
|
-
--color-text-disabled:
|
|
22
|
+
/* Text Colors — using opaque values so icon strokes render solidly */
|
|
23
|
+
--color-text-primary: #212121;
|
|
24
|
+
--color-text-secondary: #757575;
|
|
25
|
+
--color-text-disabled: #9e9e9e;
|
|
26
26
|
--color-text-primary-dark: #ffffff;
|
|
27
|
-
--color-text-secondary-dark:
|
|
28
|
-
--color-text-disabled-dark:
|
|
27
|
+
--color-text-secondary-dark: #a0a0a9;
|
|
28
|
+
--color-text-disabled-dark: #757580;
|
|
29
29
|
|
|
30
30
|
/* Surface Colors */
|
|
31
|
-
--color-surface-50: #
|
|
32
|
-
--color-surface-100: #
|
|
33
|
-
--color-surface-200: #
|
|
34
|
-
--color-surface-300: #
|
|
35
|
-
--color-surface-400: #
|
|
36
|
-
--color-surface-500: #
|
|
37
|
-
--color-surface-600: #
|
|
38
|
-
--color-surface-700: #
|
|
39
|
-
--color-surface-800: #
|
|
40
|
-
--color-surface-900: #
|
|
41
|
-
--color-surface-950: #
|
|
31
|
+
--color-surface-50: #fafafa;
|
|
32
|
+
--color-surface-100: #f5f5f5;
|
|
33
|
+
--color-surface-200: #e5e5e5;
|
|
34
|
+
--color-surface-300: #d4d4d4;
|
|
35
|
+
--color-surface-400: #a3a3a3;
|
|
36
|
+
--color-surface-500: #737373;
|
|
37
|
+
--color-surface-600: #404040;
|
|
38
|
+
--color-surface-700: #2e2e33;
|
|
39
|
+
--color-surface-800: #1f1f23;
|
|
40
|
+
--color-surface-900: #131316;
|
|
41
|
+
--color-surface-950: #0d0d0f;
|
|
42
42
|
|
|
43
43
|
/* Surface Accent Colors */
|
|
44
44
|
--color-surface-accent-50: #f8fafc;
|
|
@@ -50,8 +50,18 @@
|
|
|
50
50
|
--color-surface-accent-600: #475569;
|
|
51
51
|
--color-surface-accent-700: #334155;
|
|
52
52
|
--color-surface-accent-800: #1e293b;
|
|
53
|
-
--color-surface-accent-900: #
|
|
54
|
-
--color-surface-accent-950: #
|
|
53
|
+
--color-surface-accent-900: #172033;
|
|
54
|
+
--color-surface-accent-950: #0f172a;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Native UI (scrollbars, form controls) must follow the active theme,
|
|
58
|
+
otherwise Chrome renders light scrollbars in dark mode */
|
|
59
|
+
html {
|
|
60
|
+
color-scheme: light;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
html.dark {
|
|
64
|
+
color-scheme: dark;
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
/* Chrome, Safari and Opera */
|
|
@@ -65,50 +75,51 @@
|
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
.typography-h1 {
|
|
68
|
-
@apply text-
|
|
78
|
+
@apply text-4xl font-headers font-semibold tracking-tight;
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
.typography-h2 {
|
|
72
|
-
@apply text-
|
|
82
|
+
@apply text-3xl font-headers font-semibold tracking-tight;
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
.typography-h3 {
|
|
76
|
-
@apply text-
|
|
86
|
+
@apply text-2xl font-headers font-semibold tracking-tight;
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
.typography-h4 {
|
|
80
|
-
@apply text-
|
|
90
|
+
@apply text-xl font-headers font-semibold tracking-[-0.01em];
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
.typography-h5 {
|
|
84
|
-
@apply text-
|
|
94
|
+
@apply text-lg font-headers font-semibold tracking-[-0.01em];
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
.typography-h6 {
|
|
88
|
-
@apply text-
|
|
98
|
+
@apply text-base font-headers font-semibold tracking-[-0.01em];
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
.typography-subtitle1 {
|
|
92
|
-
@apply text-
|
|
102
|
+
@apply text-sm font-headers font-semibold tracking-[-0.01em];
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
.typography-subtitle2 {
|
|
96
|
-
@apply text-
|
|
106
|
+
@apply text-sm font-headers font-medium;
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
.typography-body1 {
|
|
110
|
+
@apply text-sm;
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
.typography-body2 {
|
|
103
|
-
@apply text-
|
|
114
|
+
@apply text-xs;
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
.typography-caption {
|
|
107
|
-
@apply text-
|
|
118
|
+
@apply text-[11px] leading-[1.4];
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
.typography-label {
|
|
111
|
-
@apply text-
|
|
122
|
+
@apply text-xs font-medium tracking-wide;
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
.typography-inherit {
|
|
@@ -116,10 +127,10 @@
|
|
|
116
127
|
}
|
|
117
128
|
|
|
118
129
|
.typography-button {
|
|
119
|
-
@apply text-sm font-semibold
|
|
130
|
+
@apply text-sm font-semibold tracking-wide;
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
:focus-visible {
|
|
123
|
-
@apply outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-
|
|
134
|
+
@apply outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-0 focus-visible:ring-offset-transparent
|
|
124
135
|
}
|
|
125
136
|
|
package/dist/styles.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const focusedDisabled = "focus-visible:ring-0 focus-visible:ring-offset-0";
|
|
2
2
|
export declare const focusedInvisibleMixin = "focus:bg-opacity-70 focus:bg-surface-accent-100 focus:dark:bg-surface-800 focus:dark:bg-opacity-60 focus:bg-surface-accent-100/70 dark:focus:bg-surface-800/60";
|
|
3
3
|
export declare const focusedClasses = "z-30 outline-hidden outline-none ring-2 ring-primary ring-opacity-75 ring-primary/75 ring-offset-2 ring-offset-transparent ";
|
|
4
|
-
export declare const fieldBackgroundMixin = "bg-opacity-50 bg-surface-accent-200 bg-surface-accent-200/50 dark:bg-surface-800 dark:bg-opacity-
|
|
4
|
+
export declare const fieldBackgroundMixin = "bg-opacity-50 bg-surface-accent-200 bg-surface-accent-200/50 dark:bg-surface-800 dark:bg-opacity-90 dark:bg-surface-800/90";
|
|
5
5
|
export declare const fieldBackgroundInvisibleMixin = "bg-opacity-0 bg-surface-accent-100 dark:bg-surface-800 dark:bg-opacity-0 bg-surface-accent-200/0 dark:bg-surface-800/0";
|
|
6
6
|
export declare const fieldBackgroundDisabledMixin = "dark:bg-surface-800 bg-opacity-50 dark:bg-opacity-90 bg-surface-accent-200/50 dark:bg-surface-800/90";
|
|
7
7
|
export declare const fieldBackgroundHoverMixin = "hover:bg-opacity-70 dark:hover:bg-surface-700 dark:hover:bg-opacity-40 hover:bg-surface-accent-200/70 hover:dark:bg-surface-700/40";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.3.0-canary.
|
|
4
|
+
"version": "3.3.0-canary.289082f",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"clsx": "^2.1.1",
|
|
75
75
|
"cmdk": "^1.1.1",
|
|
76
76
|
"date-fns": "^3.6.0",
|
|
77
|
-
"markdown-it": "^14.
|
|
77
|
+
"markdown-it": "^14.2.0",
|
|
78
78
|
"react-dropzone": "^14.3.8",
|
|
79
79
|
"react-fast-compare": "^3.2.2",
|
|
80
80
|
"tailwind-merge": "^2.6.0"
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"@testing-library/react": "^16.3.0",
|
|
90
90
|
"@testing-library/user-event": "^14.6.1",
|
|
91
91
|
"@types/jest": "^29.5.14",
|
|
92
|
-
"@types/node": "^
|
|
92
|
+
"@types/node": "^26.1.1",
|
|
93
93
|
"@types/object-hash": "^3.0.6",
|
|
94
94
|
"@types/react": "^19.2.3",
|
|
95
95
|
"@types/react-dom": "^19.2.3",
|
|
@@ -99,14 +99,14 @@
|
|
|
99
99
|
"cross-env": "^7.0.3",
|
|
100
100
|
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
|
101
101
|
"jest": "^29.7.0",
|
|
102
|
-
"npm-run-
|
|
102
|
+
"npm-run-all2": "^6.2.6",
|
|
103
103
|
"rollup-preserve-directives": "^1.1.3",
|
|
104
104
|
"ts-jest": "^29.4.5",
|
|
105
105
|
"ts-node": "^10.9.2",
|
|
106
|
-
"tsd": "^0.
|
|
106
|
+
"tsd": "^0.33.0",
|
|
107
107
|
"typescript": "^5.9.3",
|
|
108
108
|
"vite": "^7.2.4",
|
|
109
|
-
"vite-plugin-static-copy": "^
|
|
109
|
+
"vite-plugin-static-copy": "^4.1.1"
|
|
110
110
|
},
|
|
111
111
|
"files": [
|
|
112
112
|
"dist",
|
package/src/components/Alert.tsx
CHANGED
|
@@ -26,16 +26,16 @@ const getSizeClasses = (size: "small" | "medium" | "large") => {
|
|
|
26
26
|
const getColorClasses = (severity: string) => {
|
|
27
27
|
switch (severity) {
|
|
28
28
|
case "error":
|
|
29
|
-
return "bg-red-50 dark:bg-red-800 dark:text-red-100 text-red-900";
|
|
29
|
+
return "bg-red-50 dark:bg-red-800 dark:text-red-100 text-red-900 border-l-[3px] border-l-red-500";
|
|
30
30
|
case "warning":
|
|
31
|
-
return "bg-amber-50 dark:bg-amber-800 dark:text-amber-100 text-amber-900";
|
|
31
|
+
return "bg-amber-50 dark:bg-amber-800 dark:text-amber-100 text-amber-900 border-l-[3px] border-l-amber-500";
|
|
32
32
|
case "info":
|
|
33
|
-
return "bg-blue-100 dark:bg-blue-800 dark:text-blue-100 text-blue-900";
|
|
33
|
+
return "bg-blue-100 dark:bg-blue-800 dark:text-blue-100 text-blue-900 border-l-[3px] border-l-blue-500";
|
|
34
34
|
case "success":
|
|
35
|
-
return "bg-emerald-50 dark:bg-emerald-800 dark:text-emerald-100 text-emerald-900";
|
|
35
|
+
return "bg-emerald-50 dark:bg-emerald-800 dark:text-emerald-100 text-emerald-900 border-l-[3px] border-l-emerald-500";
|
|
36
36
|
case "base":
|
|
37
37
|
default:
|
|
38
|
-
return "bg-surface-accent-50 dark:bg-surface-accent-800 dark:text-white text-surface-accent-900";
|
|
38
|
+
return "bg-surface-accent-50 dark:bg-surface-accent-800 dark:text-white text-surface-accent-900 border-l-[3px] border-l-surface-accent-400";
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -58,10 +58,10 @@ export const Alert: React.FC<AlertProps> = ({
|
|
|
58
58
|
getSizeClasses(size),
|
|
59
59
|
"w-full",
|
|
60
60
|
"font-medium",
|
|
61
|
-
"rounded-
|
|
61
|
+
"rounded-lg flex items-center gap-2",
|
|
62
62
|
classes,
|
|
63
63
|
outerClassName)}>
|
|
64
|
-
<div className={cls("
|
|
64
|
+
<div className={cls("grow", className)}>{children}</div>
|
|
65
65
|
{onDismiss && (
|
|
66
66
|
<button
|
|
67
67
|
className="text-surface-accent-400 hover:text-surface-accent-600 dark:text-surface-accent-500 dark:hover:text-surface-accent-400"
|
|
@@ -39,7 +39,7 @@ const AvatarInner: React.ForwardRefRenderFunction<HTMLButtonElement, AvatarProps
|
|
|
39
39
|
className={cls(
|
|
40
40
|
"rounded-full flex items-center justify-center overflow-hidden",
|
|
41
41
|
"p-1 w-12 h-12 min-w-12 min-h-12",
|
|
42
|
-
hover && "hover:bg-surface-accent-200 hover:
|
|
42
|
+
hover && "hover:bg-surface-accent-200 dark:hover:bg-surface-accent-700",
|
|
43
43
|
outerClassName
|
|
44
44
|
)}
|
|
45
45
|
>
|
|
@@ -27,6 +27,9 @@ export const BooleanSwitch = React.forwardRef(function BooleanSwitch({
|
|
|
27
27
|
return <button
|
|
28
28
|
type="button"
|
|
29
29
|
ref={ref}
|
|
30
|
+
role="switch"
|
|
31
|
+
aria-checked={allowIndeterminate && (value === null || value === undefined) ? "mixed" : !!value}
|
|
32
|
+
aria-disabled={disabled || undefined}
|
|
30
33
|
tabIndex={disabled ? -1 : undefined}
|
|
31
34
|
onClick={disabled
|
|
32
35
|
? (e) => e.preventDefault()
|
|
@@ -53,7 +56,7 @@ export const BooleanSwitch = React.forwardRef(function BooleanSwitch({
|
|
|
53
56
|
{allowIndeterminate && (value === null || value === undefined) && <div
|
|
54
57
|
key={"knob"}
|
|
55
58
|
className={cls(
|
|
56
|
-
"block rounded-full transition-transform duration-100 transform will-change-auto",
|
|
59
|
+
"block rounded-full transition-transform duration-100 ease-out transform will-change-auto shadow-sm",
|
|
57
60
|
disabled ? "bg-surface-accent-400 dark:bg-surface-accent-600" : "bg-surface-accent-400 dark:bg-surface-accent-600",
|
|
58
61
|
{
|
|
59
62
|
"w-[21px] h-[10px]": size === "medium" || size === "large",
|
|
@@ -69,8 +72,8 @@ export const BooleanSwitch = React.forwardRef(function BooleanSwitch({
|
|
|
69
72
|
{!(allowIndeterminate && (value === null || value === undefined)) && <div
|
|
70
73
|
key={"knob"}
|
|
71
74
|
className={cls(
|
|
72
|
-
"block rounded-full transition-transform duration-100 transform will-change-auto",
|
|
73
|
-
disabled ? "bg-surface-accent-300 dark:bg-surface-
|
|
75
|
+
"block rounded-full transition-transform duration-100 ease-out transform will-change-auto shadow-sm",
|
|
76
|
+
disabled ? "bg-surface-accent-300 dark:bg-surface-700" : (value ? "bg-white shadow" : "bg-surface-accent-600 dark:bg-surface-accent-400"),
|
|
74
77
|
{
|
|
75
78
|
"w-[21px] h-[21px]": size === "medium" || size === "large",
|
|
76
79
|
"w-[19px] h-[19px]": size === "small",
|
|
@@ -33,40 +33,44 @@ const ButtonInner = React.memo(React.forwardRef<
|
|
|
33
33
|
}: ButtonProps<any>, ref) => {
|
|
34
34
|
|
|
35
35
|
const baseClasses =
|
|
36
|
-
"typography-button h-fit rounded-
|
|
36
|
+
"typography-button h-fit rounded-lg whitespace-nowrap inline-flex items-center justify-center p-2 px-4 focus:outline-none transition-colors ease-in-out duration-150 gap-2";
|
|
37
37
|
|
|
38
38
|
const buttonClasses = cls({
|
|
39
39
|
"w-full": fullWidth,
|
|
40
40
|
"w-fit": !fullWidth,
|
|
41
41
|
|
|
42
42
|
// Filled Variants
|
|
43
|
-
"border border-primary bg-primary focus:ring-primary
|
|
44
|
-
"border border-secondary bg-secondary focus:ring-secondary
|
|
45
|
-
"border border-red-500 bg-red-500 hover:bg-red-
|
|
46
|
-
"border border-surface-accent-200 bg-surface-accent-200 hover:bg-surface-accent-300 focus:ring-surface-accent-400
|
|
47
|
-
"border border-transparent bg-surface-100 hover:bg-surface-accent-200 text-text-primary dark:bg-surface-
|
|
43
|
+
"border border-primary bg-primary focus:ring-primary text-white hover:text-white hover:brightness-105": variant === "filled" && color === "primary" && !disabled,
|
|
44
|
+
"border border-secondary bg-secondary focus:ring-secondary text-white hover:text-white hover:brightness-105": variant === "filled" && color === "secondary" && !disabled,
|
|
45
|
+
"border border-red-500 bg-red-500 hover:bg-red-600 focus:ring-red-500 text-white hover:text-white": variant === "filled" && color === "error" && !disabled,
|
|
46
|
+
"border border-surface-accent-200 bg-surface-accent-200 hover:bg-surface-accent-300 focus:ring-surface-accent-400 text-text-primary hover:text-text-primary dark:border-surface-accent-700 dark:bg-surface-accent-700 dark:hover:bg-surface-accent-600 dark:text-text-primary-dark hover:dark:text-text-primary-dark": variant === "filled" && color === "text" && !disabled,
|
|
47
|
+
"border border-transparent bg-surface-100 hover:bg-surface-accent-200 text-text-primary dark:bg-surface-700 dark:hover:bg-surface-accent-700 dark:text-text-primary-dark hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark": variant === "filled" && color === "neutral" && !disabled,
|
|
48
48
|
|
|
49
49
|
// Text Variants
|
|
50
50
|
"border border-transparent text-primary hover:text-primary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "text" && color === "primary" && !disabled,
|
|
51
51
|
"border border-transparent text-secondary hover:text-secondary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "text" && color === "secondary" && !disabled,
|
|
52
52
|
"border border-transparent text-red-500 hover:text-red-500 hover:bg-red-500 hover:bg-opacity-10 hover:bg-red-500/10": variant === "text" && color === "error" && !disabled,
|
|
53
|
-
"border border-transparent text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark hover:bg-surface-accent-200 hover:dark:bg-surface-
|
|
54
|
-
"border border-transparent text-text-primary hover:text-text-primary hover:bg-surface-accent-200 dark:text-text-primary-dark dark:hover:text-text-primary-dark dark:hover:bg-surface-accent-
|
|
53
|
+
"border border-transparent text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "text" && color === "text" && !disabled,
|
|
54
|
+
"border border-transparent text-text-primary hover:text-text-primary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:text-text-primary-dark dark:hover:text-text-primary-dark dark:hover:bg-surface-accent-800": variant === "text" && color === "neutral" && !disabled,
|
|
55
55
|
|
|
56
56
|
// Outlined Variants
|
|
57
57
|
"border border-primary text-primary hover:text-primary hover:bg-primary-bg hover:bg-primary/10": variant === "outlined" && color === "primary" && !disabled,
|
|
58
58
|
"border border-secondary text-secondary hover:text-secondary hover:bg-secondary-bg": variant === "outlined" && color === "secondary" && !disabled,
|
|
59
59
|
"border border-red-500 text-red-500 hover:text-red-500 hover:bg-red-500 hover:text-white": variant === "outlined" && color === "error" && !disabled,
|
|
60
|
-
"border border-surface-accent-400 text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:bg-surface-accent-200": variant === "outlined" && color === "text" && !disabled,
|
|
61
|
-
"border border-surface-300 text-text-primary hover:bg-surface-accent-200 dark:border-surface-600 dark:text-text-primary-dark dark:hover:bg-surface-accent-
|
|
60
|
+
"border border-surface-accent-400 text-text-primary hover:text-text-primary dark:text-text-primary-dark dark:border-surface-accent-600 hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "outlined" && color === "text" && !disabled,
|
|
61
|
+
"border border-surface-300 text-text-primary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:border-surface-600 dark:text-text-primary-dark dark:hover:bg-surface-accent-800": variant === "outlined" && color === "neutral" && !disabled,
|
|
62
62
|
|
|
63
63
|
// Disabled states for all variants
|
|
64
64
|
"text-text-disabled dark:text-text-disabled-dark": disabled,
|
|
65
65
|
"border border-transparent opacity-50": variant === "text" && disabled,
|
|
66
66
|
"border border-surface-500 opacity-50": variant === "outlined" && disabled,
|
|
67
|
-
"border border-transparent bg-surface-300 dark:bg-surface-500 opacity-
|
|
67
|
+
"border border-transparent bg-surface-300 dark:bg-surface-500 opacity-40 bg-surface-300/40 dark:bg-surface-500/40": variant === "filled" && disabled,
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
const iconColorClass = (color === "neutral" || color === "text") && !disabled
|
|
71
|
+
? "[&>svg]:text-surface-accent-500 dark:[&>svg]:text-surface-accent-300"
|
|
72
|
+
: "";
|
|
73
|
+
|
|
70
74
|
const sizeClasses = cls(
|
|
71
75
|
{
|
|
72
76
|
"py-1 px-2": size === "small",
|
|
@@ -82,7 +86,7 @@ const ButtonInner = React.memo(React.forwardRef<
|
|
|
82
86
|
<Component
|
|
83
87
|
ref={ref}
|
|
84
88
|
onClick={props.onClick}
|
|
85
|
-
className={cls(startIcon ? "pl-3" : "", baseClasses, buttonClasses, sizeClasses, className)}
|
|
89
|
+
className={cls(startIcon ? "pl-3" : "", baseClasses, buttonClasses, sizeClasses, iconColorClass, className)}
|
|
86
90
|
{...props}>
|
|
87
91
|
{startIcon}
|
|
88
92
|
{children}
|
|
@@ -94,7 +98,7 @@ const ButtonInner = React.memo(React.forwardRef<
|
|
|
94
98
|
<button ref={ref as any}
|
|
95
99
|
type={props.type ?? "button"}
|
|
96
100
|
onClick={props.onClick}
|
|
97
|
-
className={cls(startIcon ? "pl-3" : "", baseClasses, buttonClasses, sizeClasses, className)}
|
|
101
|
+
className={cls(startIcon ? "pl-3" : "", baseClasses, buttonClasses, sizeClasses, iconColorClass, className)}
|
|
98
102
|
disabled={disabled}
|
|
99
103
|
data-variant={variant}
|
|
100
104
|
data-size={size}
|
package/src/components/Card.tsx
CHANGED
|
@@ -8,7 +8,7 @@ type CardProps = {
|
|
|
8
8
|
style?: React.CSSProperties;
|
|
9
9
|
onClick?: (e?: React.MouseEvent) => void;
|
|
10
10
|
className?: string;
|
|
11
|
-
}
|
|
11
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
12
12
|
|
|
13
13
|
const Card = React.forwardRef<HTMLDivElement, CardProps>(({
|
|
14
14
|
children,
|
|
@@ -38,4 +38,6 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>(({
|
|
|
38
38
|
);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
Card.displayName = "Card";
|
|
42
|
+
|
|
41
43
|
export { Card };
|
|
@@ -22,7 +22,7 @@ export const CenteredView = React.forwardRef<HTMLDivElement, CenteredViewProps>(
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<div ref={ref}
|
|
25
|
-
className={cls("flex flex-col
|
|
25
|
+
className={cls("flex flex-col grow", fullScreen ? "h-screen" : "h-full", outerClassName)}
|
|
26
26
|
{...rest}>
|
|
27
27
|
<Container className={cls("m-auto", className)} maxWidth={maxWidth}>
|
|
28
28
|
{children}
|
|
@@ -13,6 +13,7 @@ export interface CheckboxProps {
|
|
|
13
13
|
padding?: boolean;
|
|
14
14
|
size?: "smallest" | "small" | "medium" | "large";
|
|
15
15
|
color?: "primary" | "secondary";
|
|
16
|
+
"aria-label"?: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const sizeClasses = {
|
|
@@ -26,13 +27,13 @@ const outerSizeClasses = {
|
|
|
26
27
|
medium: "w-10 h-10",
|
|
27
28
|
small: "w-8 h-8",
|
|
28
29
|
large: "w-12 h-12 ",
|
|
29
|
-
smallest: "w-
|
|
30
|
+
smallest: "w-8 h-8"
|
|
30
31
|
}
|
|
31
32
|
const paddingClasses = {
|
|
32
33
|
medium: "p-2",
|
|
33
34
|
small: "p-2",
|
|
34
35
|
large: "p-2",
|
|
35
|
-
smallest: ""
|
|
36
|
+
smallest: "p-2"
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const colorClasses = {
|
|
@@ -48,7 +49,8 @@ export const Checkbox = React.memo(({
|
|
|
48
49
|
disabled,
|
|
49
50
|
size = "medium",
|
|
50
51
|
onCheckedChange,
|
|
51
|
-
color = "primary"
|
|
52
|
+
color = "primary",
|
|
53
|
+
"aria-label": ariaLabel
|
|
52
54
|
}: CheckboxProps) => {
|
|
53
55
|
|
|
54
56
|
const isChecked = indeterminate ? false : checked;
|
|
@@ -65,6 +67,8 @@ export const Checkbox = React.memo(({
|
|
|
65
67
|
id={id}
|
|
66
68
|
checked={indeterminate || isChecked}
|
|
67
69
|
disabled={disabled}
|
|
70
|
+
aria-label={ariaLabel}
|
|
71
|
+
aria-checked={indeterminate ? "mixed" : isChecked}
|
|
68
72
|
onCheckedChange={disabled ? undefined : onCheckedChange}>
|
|
69
73
|
|
|
70
74
|
<div className={cls(
|
|
@@ -84,7 +88,7 @@ export const Checkbox = React.memo(({
|
|
|
84
88
|
(indeterminate || isChecked) ? "text-surface-accent-100 dark:text-surface-accent-900" : "",
|
|
85
89
|
disabled
|
|
86
90
|
? "border-transparent"
|
|
87
|
-
: (indeterminate || isChecked ? "border-transparent" : "border-surface-accent-800 dark:border-surface-accent-
|
|
91
|
+
: (indeterminate || isChecked ? "border-transparent" : "border-surface-accent-800 dark:border-surface-accent-500")
|
|
88
92
|
)}>
|
|
89
93
|
<CheckboxPrimitive.Indicator asChild>
|
|
90
94
|
{indeterminate
|
|
@@ -100,3 +104,5 @@ export const Checkbox = React.memo(({
|
|
|
100
104
|
</CheckboxPrimitive.Root>
|
|
101
105
|
);
|
|
102
106
|
});
|
|
107
|
+
|
|
108
|
+
Checkbox.displayName = "Checkbox";
|
package/src/components/Chip.tsx
CHANGED
|
@@ -4,6 +4,10 @@ import { CHIP_COLORS, cls, getColorSchemeForKey } from "../util";
|
|
|
4
4
|
export type ChipColorScheme = {
|
|
5
5
|
color: string;
|
|
6
6
|
text: string;
|
|
7
|
+
/** Background color override for dark mode. Falls back to `color`. */
|
|
8
|
+
darkColor?: string;
|
|
9
|
+
/** Text color override for dark mode. Falls back to `text`. */
|
|
10
|
+
darkText?: string;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
export type ChipColorKey = keyof typeof CHIP_COLORS;
|
|
@@ -11,7 +15,7 @@ export type ChipColorKey = keyof typeof CHIP_COLORS;
|
|
|
11
15
|
export interface ChipProps {
|
|
12
16
|
className?: string;
|
|
13
17
|
children: React.ReactNode;
|
|
14
|
-
size?: "small" | "medium" | "large";
|
|
18
|
+
size?: "smallest" | "small" | "medium" | "large";
|
|
15
19
|
colorScheme?: ChipColorScheme | ChipColorKey;
|
|
16
20
|
error?: boolean;
|
|
17
21
|
outlined?: boolean;
|
|
@@ -21,11 +25,37 @@ export interface ChipProps {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
const sizeClassNames = {
|
|
28
|
+
smallest: "px-1.5 py-px text-[10px]",
|
|
24
29
|
small: "px-2 py-0.5 text-sm",
|
|
25
30
|
medium: "px-3 py-1 text-sm",
|
|
26
31
|
large: "px-4 py-1.5 text-sm"
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Detect if the app is currently in dark mode by checking the
|
|
36
|
+
* Tailwind `dark` class on the document root.
|
|
37
|
+
*/
|
|
38
|
+
function isDarkMode(): boolean {
|
|
39
|
+
return typeof document !== "undefined" &&
|
|
40
|
+
document.documentElement.classList.contains("dark");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Helper to generate rgba from a hex color. Returns the input unchanged for
|
|
45
|
+
* non-hex values so it degrades gracefully.
|
|
46
|
+
*/
|
|
47
|
+
function getRgba(hex: string, alpha: number): string {
|
|
48
|
+
if (!hex || !hex.startsWith("#")) return hex;
|
|
49
|
+
let color = hex.slice(1);
|
|
50
|
+
if (color.length === 3) {
|
|
51
|
+
color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2];
|
|
52
|
+
}
|
|
53
|
+
const r = parseInt(color.slice(0, 2), 16);
|
|
54
|
+
const g = parseInt(color.slice(2, 4), 16);
|
|
55
|
+
const b = parseInt(color.slice(4, 6), 16);
|
|
56
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
57
|
+
}
|
|
58
|
+
|
|
29
59
|
/**
|
|
30
60
|
* @group Preview components
|
|
31
61
|
*/
|
|
@@ -42,30 +72,59 @@ export const Chip = React.forwardRef<HTMLDivElement, ChipProps>(function Chip({
|
|
|
42
72
|
}: ChipProps, ref) {
|
|
43
73
|
|
|
44
74
|
const usedColorScheme = typeof colorScheme === "string" ? getColorSchemeForKey(colorScheme) : colorScheme;
|
|
75
|
+
const dark = isDarkMode();
|
|
76
|
+
|
|
77
|
+
const hasScheme = Boolean(error || usedColorScheme);
|
|
78
|
+
|
|
79
|
+
let textColor = "";
|
|
80
|
+
let bgColor = "";
|
|
81
|
+
let border = "";
|
|
82
|
+
|
|
83
|
+
if (error) {
|
|
84
|
+
textColor = dark ? "#f87171" : "#dc2626";
|
|
85
|
+
} else if (usedColorScheme) {
|
|
86
|
+
// Prefer a dark-mode override when present, otherwise fall back to the
|
|
87
|
+
// existing scheme color so palettes without dark variants are unchanged.
|
|
88
|
+
textColor = dark && usedColorScheme.darkText ? usedColorScheme.darkText : usedColorScheme.text;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (hasScheme) {
|
|
92
|
+
if (outlined) {
|
|
93
|
+
bgColor = getRgba(textColor, dark ? 0.1 : 0.06);
|
|
94
|
+
border = `1px solid ${getRgba(textColor, dark ? 0.2 : 0.14)}`;
|
|
95
|
+
} else if (error) {
|
|
96
|
+
bgColor = dark ? "rgba(220, 38, 38, 0.15)" : "rgba(239, 68, 68, 0.1)";
|
|
97
|
+
border = `1px solid ${dark ? "rgba(220, 38, 38, 0.3)" : "rgba(239, 68, 68, 0.2)"}`;
|
|
98
|
+
} else if (usedColorScheme) {
|
|
99
|
+
bgColor = dark && usedColorScheme.darkColor ? usedColorScheme.darkColor : usedColorScheme.color;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
45
103
|
return (
|
|
46
104
|
<div
|
|
47
105
|
ref={ref}
|
|
48
|
-
className={cls("rounded-lg max-w-full w-max h-fit font-
|
|
106
|
+
className={cls("rounded-lg max-w-full w-max h-fit font-medium inline-flex gap-1",
|
|
49
107
|
"text-ellipsis",
|
|
50
108
|
"items-center",
|
|
51
|
-
|
|
109
|
+
"transition-colors duration-150",
|
|
110
|
+
!hasScheme && "bg-surface-accent-200 dark:bg-surface-accent-800 text-surface-accent-800 dark:text-white",
|
|
111
|
+
!hasScheme && outlined && "bg-transparent dark:bg-transparent border border-surface-accent-300 dark:border-surface-accent-700",
|
|
112
|
+
onClick ? "cursor-pointer hover:bg-primary/5 dark:hover:bg-primary/5" : "",
|
|
52
113
|
sizeClassNames[size],
|
|
53
|
-
error || !usedColorScheme ? "bg-surface-accent-200 dark:bg-surface-accent-800 text-surface-accent-800 dark:text-white" : "",
|
|
54
|
-
error ? "text-red-500 dark:text-red-400" : "",
|
|
55
114
|
className)}
|
|
56
115
|
onClick={onClick}
|
|
57
116
|
style={{
|
|
58
|
-
|
|
59
|
-
|
|
117
|
+
...(hasScheme ? {
|
|
118
|
+
backgroundColor: bgColor,
|
|
119
|
+
color: textColor,
|
|
120
|
+
border: border || undefined
|
|
121
|
+
} : {}),
|
|
60
122
|
overflow: "hidden",
|
|
61
123
|
...style
|
|
62
|
-
// display: "-webkit-box",
|
|
63
|
-
// WebkitLineClamp: 1,
|
|
64
|
-
// WebkitBoxOrient: "vertical",
|
|
65
124
|
}}
|
|
66
125
|
>
|
|
67
|
-
{children}
|
|
68
126
|
{icon}
|
|
127
|
+
{children}
|
|
69
128
|
</div>
|
|
70
129
|
);
|
|
71
130
|
});
|
|
@@ -26,6 +26,7 @@ export type DialogProps = {
|
|
|
26
26
|
*/
|
|
27
27
|
disableInitialFocus?: boolean;
|
|
28
28
|
portalContainer?: HTMLElement | null;
|
|
29
|
+
"aria-describedby"?: string;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const widthClasses = {
|
|
@@ -60,7 +61,8 @@ export const Dialog = ({
|
|
|
60
61
|
onPointerDownOutside,
|
|
61
62
|
onInteractOutside,
|
|
62
63
|
disableInitialFocus = true,
|
|
63
|
-
portalContainer
|
|
64
|
+
portalContainer,
|
|
65
|
+
"aria-describedby": ariaDescribedby
|
|
64
66
|
}: DialogProps) => {
|
|
65
67
|
const [displayed, setDisplayed] = useState(false);
|
|
66
68
|
|
|
@@ -92,7 +94,7 @@ export const Dialog = ({
|
|
|
92
94
|
<div className={cls("fixed inset-0 z-30", containerClassName)}>
|
|
93
95
|
|
|
94
96
|
<DialogPrimitive.Overlay
|
|
95
|
-
className={cls("fixed inset-0 transition-opacity z-20 ease-in-out duration-200 bg-black
|
|
97
|
+
className={cls("fixed inset-0 transition-opacity z-20 ease-in-out duration-200 bg-black/50 dark:bg-black/60 backdrop-blur-sm",
|
|
96
98
|
displayed && open ? "opacity-100" : "opacity-0",
|
|
97
99
|
"z-20 fixed top-0 left-0 w-full h-full flex justify-center items-center"
|
|
98
100
|
)}
|
|
@@ -111,7 +113,8 @@ export const Dialog = ({
|
|
|
111
113
|
}}
|
|
112
114
|
onPointerDownOutside={onPointerDownOutside}
|
|
113
115
|
onInteractOutside={onInteractOutside}
|
|
114
|
-
|
|
116
|
+
aria-describedby={ariaDescribedby}
|
|
117
|
+
className={cls("relative h-full outline-none flex justify-center items-center z-40 opacity-100 transition-all duration-200 ease-in-out")}
|
|
115
118
|
>
|
|
116
119
|
<div
|
|
117
120
|
className={cls(paperMixin,
|
|
@@ -124,10 +127,10 @@ export const Dialog = ({
|
|
|
124
127
|
fullHeight && !fullScreen ? "h-full" : undefined,
|
|
125
128
|
"text-surface-accent-900 dark:text-white",
|
|
126
129
|
"justify-center items-center",
|
|
127
|
-
fullScreen ? "h-screen w-screen" : "max-h-[90vh] shadow-
|
|
130
|
+
fullScreen ? "h-screen w-screen" : "max-h-[90vh] shadow-lg",
|
|
128
131
|
"ease-in-out duration-200",
|
|
129
132
|
scrollable && "overflow-y-auto",
|
|
130
|
-
displayed && open ? "opacity-100" : "opacity-0",
|
|
133
|
+
displayed && open ? "opacity-100 scale-100" : "opacity-0 scale-[0.97]",
|
|
131
134
|
maxWidth && !fullScreen ? widthClasses[maxWidth] : undefined,
|
|
132
135
|
className
|
|
133
136
|
)}>
|
|
@@ -81,7 +81,7 @@ export function ExpandablePanel({
|
|
|
81
81
|
<Collapsible.Root
|
|
82
82
|
className={cls(
|
|
83
83
|
!invisible && defaultBorderMixin + " border",
|
|
84
|
-
"rounded-
|
|
84
|
+
"rounded-lg",
|
|
85
85
|
"w-full",
|
|
86
86
|
className
|
|
87
87
|
)}
|
|
@@ -95,7 +95,7 @@ export function ExpandablePanel({
|
|
|
95
95
|
<div
|
|
96
96
|
className={cls(
|
|
97
97
|
"rounded-t flex items-center justify-between w-full min-h-[52px]",
|
|
98
|
-
"hover:bg-surface-accent-200 hover:bg-opacity-40 hover:bg-surface-accent-200/40 dark:hover:bg-surface-800 dark:hover:bg-opacity-40 dark:hover:bg-surface-800/40",
|
|
98
|
+
"hover:bg-surface-accent-200 hover:bg-opacity-40 hover:bg-surface-accent-200/40 dark:hover:bg-surface-800 dark:hover:bg-opacity-40 dark:hover:bg-surface-800/40 active:bg-surface-accent-300/50 dark:active:bg-surface-700/50",
|
|
99
99
|
invisible ? "border-b px-2" : "p-4",
|
|
100
100
|
open ? "py-6" : "py-4",
|
|
101
101
|
"transition-all duration-200",
|
|
@@ -106,6 +106,7 @@ export function ExpandablePanel({
|
|
|
106
106
|
)}
|
|
107
107
|
role="button"
|
|
108
108
|
tabIndex={0}
|
|
109
|
+
aria-expanded={open}
|
|
109
110
|
>
|
|
110
111
|
{title}
|
|
111
112
|
<KeyboardArrowDownIcon className={cls("transition", open ? "rotate-180" : "")}/>
|