@choice-ui/checkbox 0.0.4
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/README.md +272 -0
- package/dist/index.cjs +255 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +252 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
- package/src/checkbox-label.tsx +33 -0
- package/src/checkbox.tsx +120 -0
- package/src/context.ts +21 -0
- package/src/index.ts +5 -0
- package/src/tv.ts +128 -0
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Checkbox
|
|
2
|
+
|
|
3
|
+
A flexible checkbox component with support for labels, mixed state, and multiple visual variants. It uses a compound component pattern for maximum composability.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Checkbox } from "@choice-ui/react"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Three visual variants (default, accent, outline) for different UI contexts
|
|
14
|
+
- Support for indeterminate/mixed state
|
|
15
|
+
- Compound component pattern with `Checkbox.Label`
|
|
16
|
+
- Full keyboard navigation (Space/Enter to toggle)
|
|
17
|
+
- Proper ARIA attributes for accessibility
|
|
18
|
+
- Focus state management
|
|
19
|
+
- Disabled state styling
|
|
20
|
+
- Auto-wrapping of string children as labels
|
|
21
|
+
- Context-based communication between sub-components
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<Checkbox
|
|
29
|
+
value={checked}
|
|
30
|
+
onChange={setChecked}
|
|
31
|
+
>
|
|
32
|
+
Accept terms and conditions
|
|
33
|
+
</Checkbox>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### With separate label
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Checkbox
|
|
40
|
+
value={checked}
|
|
41
|
+
onChange={setChecked}
|
|
42
|
+
>
|
|
43
|
+
<Checkbox.Label>Enable notifications</Checkbox.Label>
|
|
44
|
+
</Checkbox>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Variants
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<Checkbox variant="default" value={checked} onChange={setChecked}>
|
|
51
|
+
Default style
|
|
52
|
+
</Checkbox>
|
|
53
|
+
|
|
54
|
+
<Checkbox variant="accent" value={checked} onChange={setChecked}>
|
|
55
|
+
Accent style
|
|
56
|
+
</Checkbox>
|
|
57
|
+
|
|
58
|
+
<Checkbox variant="outline" value={checked} onChange={setChecked}>
|
|
59
|
+
Outline style
|
|
60
|
+
</Checkbox>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Mixed/Indeterminate state
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<Checkbox
|
|
67
|
+
value={isPartiallySelected}
|
|
68
|
+
mixed={true}
|
|
69
|
+
onChange={handleSelectAll}
|
|
70
|
+
>
|
|
71
|
+
Select all
|
|
72
|
+
</Checkbox>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Disabled state
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<Checkbox
|
|
79
|
+
disabled
|
|
80
|
+
value={checked}
|
|
81
|
+
onChange={setChecked}
|
|
82
|
+
>
|
|
83
|
+
This option is disabled
|
|
84
|
+
</Checkbox>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### With custom label styling
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<Checkbox
|
|
91
|
+
value={checked}
|
|
92
|
+
onChange={setChecked}
|
|
93
|
+
>
|
|
94
|
+
<Checkbox.Label className="text-body-small-strong">Custom styled label</Checkbox.Label>
|
|
95
|
+
</Checkbox>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Controlled with focus
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
<Checkbox
|
|
102
|
+
value={checked}
|
|
103
|
+
onChange={setChecked}
|
|
104
|
+
focused={isFocused}
|
|
105
|
+
>
|
|
106
|
+
Controlled focus state
|
|
107
|
+
</Checkbox>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Props
|
|
111
|
+
|
|
112
|
+
### Checkbox
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
|
|
116
|
+
/** Child elements (strings auto-wrapped in Checkbox.Label) */
|
|
117
|
+
children?: ReactNode
|
|
118
|
+
|
|
119
|
+
/** Additional CSS class names */
|
|
120
|
+
className?: string
|
|
121
|
+
|
|
122
|
+
/** Whether the checkbox appears focused */
|
|
123
|
+
focused?: boolean
|
|
124
|
+
|
|
125
|
+
/** Whether to show mixed/indeterminate state */
|
|
126
|
+
mixed?: boolean
|
|
127
|
+
|
|
128
|
+
/** Callback when checked state changes */
|
|
129
|
+
onChange?: (value: boolean) => void
|
|
130
|
+
|
|
131
|
+
/** Whether the checkbox is checked */
|
|
132
|
+
value?: boolean
|
|
133
|
+
|
|
134
|
+
/** Visual style variant */
|
|
135
|
+
variant?: "default" | "accent" | "outline"
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Checkbox.Label
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
interface CheckboxLabelProps extends Omit<
|
|
143
|
+
HTMLProps<HTMLLabelElement>,
|
|
144
|
+
"htmlFor" | "id" | "disabled"
|
|
145
|
+
> {
|
|
146
|
+
/** Label content */
|
|
147
|
+
children: ReactNode
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- Defaults:
|
|
152
|
+
- `variant`: "default"
|
|
153
|
+
- `value`: `false`
|
|
154
|
+
- `mixed`: `false`
|
|
155
|
+
- `focused`: `false`
|
|
156
|
+
|
|
157
|
+
- Accessibility:
|
|
158
|
+
- Proper `aria-checked` attribute (including "mixed" state)
|
|
159
|
+
- Automatic label association via context
|
|
160
|
+
- Keyboard support for Space and Enter keys
|
|
161
|
+
- Screen reader announcements
|
|
162
|
+
|
|
163
|
+
## Styling
|
|
164
|
+
|
|
165
|
+
- Uses Tailwind CSS via `tailwind-variants` with slot-based styling
|
|
166
|
+
- Slots available: `root`, `box`, `input`, `label`
|
|
167
|
+
- Each variant has distinct visual treatments
|
|
168
|
+
- Focus states include border color changes and shadow effects
|
|
169
|
+
- Disabled state applies to both checkbox and label
|
|
170
|
+
|
|
171
|
+
## Best practices
|
|
172
|
+
|
|
173
|
+
- Always provide a label for accessibility (either as children or via aria-label)
|
|
174
|
+
- Use the accent variant for primary actions
|
|
175
|
+
- Use mixed state for "select all" scenarios with partial selection
|
|
176
|
+
- Keep labels concise and action-oriented
|
|
177
|
+
- Group related checkboxes together visually
|
|
178
|
+
- Consider using Checkbox with forms and validation
|
|
179
|
+
|
|
180
|
+
## Examples
|
|
181
|
+
|
|
182
|
+
### Select all with mixed state
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
function SelectAllExample() {
|
|
186
|
+
const [items, setItems] = useState([
|
|
187
|
+
{ id: 1, checked: false },
|
|
188
|
+
{ id: 2, checked: true },
|
|
189
|
+
{ id: 3, checked: false },
|
|
190
|
+
])
|
|
191
|
+
|
|
192
|
+
const checkedCount = items.filter((item) => item.checked).length
|
|
193
|
+
const allChecked = checkedCount === items.length
|
|
194
|
+
const someChecked = checkedCount > 0 && checkedCount < items.length
|
|
195
|
+
|
|
196
|
+
const handleSelectAll = (checked: boolean) => {
|
|
197
|
+
setItems(items.map((item) => ({ ...item, checked })))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<Checkbox
|
|
202
|
+
value={allChecked}
|
|
203
|
+
mixed={someChecked}
|
|
204
|
+
onChange={handleSelectAll}
|
|
205
|
+
>
|
|
206
|
+
Select all ({checkedCount}/{items.length})
|
|
207
|
+
</Checkbox>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Form with validation
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<form onSubmit={handleSubmit}>
|
|
216
|
+
<Checkbox
|
|
217
|
+
value={agreedToTerms}
|
|
218
|
+
onChange={setAgreedToTerms}
|
|
219
|
+
variant="accent"
|
|
220
|
+
required
|
|
221
|
+
>
|
|
222
|
+
I agree to the{" "}
|
|
223
|
+
<a
|
|
224
|
+
href="/terms"
|
|
225
|
+
className="underline"
|
|
226
|
+
>
|
|
227
|
+
terms and conditions
|
|
228
|
+
</a>
|
|
229
|
+
</Checkbox>
|
|
230
|
+
|
|
231
|
+
<Button
|
|
232
|
+
type="submit"
|
|
233
|
+
disabled={!agreedToTerms}
|
|
234
|
+
>
|
|
235
|
+
Continue
|
|
236
|
+
</Button>
|
|
237
|
+
</form>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Settings panel
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<div className="space-y-2">
|
|
244
|
+
<Checkbox
|
|
245
|
+
value={emailNotifications}
|
|
246
|
+
onChange={setEmailNotifications}
|
|
247
|
+
>
|
|
248
|
+
<Checkbox.Label>
|
|
249
|
+
<div>Email notifications</div>
|
|
250
|
+
<div className="text-secondary-foreground text-body-small">
|
|
251
|
+
Receive updates about your account
|
|
252
|
+
</div>
|
|
253
|
+
</Checkbox.Label>
|
|
254
|
+
</Checkbox>
|
|
255
|
+
|
|
256
|
+
<Checkbox
|
|
257
|
+
value={marketingEmails}
|
|
258
|
+
onChange={setMarketingEmails}
|
|
259
|
+
disabled={!emailNotifications}
|
|
260
|
+
>
|
|
261
|
+
Marketing emails
|
|
262
|
+
</Checkbox>
|
|
263
|
+
</div>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Notes
|
|
267
|
+
|
|
268
|
+
- The component uses a context provider for communication between Checkbox and Label
|
|
269
|
+
- String children are automatically wrapped in `Checkbox.Label` for convenience
|
|
270
|
+
- The mixed state displays an indeterminate icon instead of a checkmark
|
|
271
|
+
- Focus management can be controlled externally via the `focused` prop
|
|
272
|
+
- The component is fully controlled - you must manage the `value` state
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var shared = require('@choice-ui/shared');
|
|
4
|
+
var iconsReact = require('@choiceform/icons-react');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var usehooksTs = require('usehooks-ts');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
// src/checkbox.tsx
|
|
10
|
+
var CheckboxContext = react.createContext(null);
|
|
11
|
+
function useCheckboxContext() {
|
|
12
|
+
const context = react.useContext(CheckboxContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
throw new Error("Checkbox components must be used within a Checkbox component");
|
|
15
|
+
}
|
|
16
|
+
return context;
|
|
17
|
+
}
|
|
18
|
+
var checkboxTv = shared.tcv({
|
|
19
|
+
slots: {
|
|
20
|
+
root: "flex items-center select-none",
|
|
21
|
+
box: ["relative flex size-4 items-center justify-center", "border border-solid"],
|
|
22
|
+
input: "peer pointer-events-auto absolute inset-0 appearance-none opacity-0",
|
|
23
|
+
label: "pl-2"
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
type: {
|
|
27
|
+
checkbox: {
|
|
28
|
+
box: "rounded-md"
|
|
29
|
+
},
|
|
30
|
+
radio: {
|
|
31
|
+
box: "rounded-full"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
variant: {
|
|
35
|
+
default: {},
|
|
36
|
+
accent: {},
|
|
37
|
+
outline: {}
|
|
38
|
+
},
|
|
39
|
+
checked: {
|
|
40
|
+
true: {},
|
|
41
|
+
false: {}
|
|
42
|
+
},
|
|
43
|
+
disabled: {
|
|
44
|
+
true: {},
|
|
45
|
+
false: {}
|
|
46
|
+
},
|
|
47
|
+
focused: {
|
|
48
|
+
true: {},
|
|
49
|
+
false: {}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
compoundVariants: [
|
|
53
|
+
// 未选中状态
|
|
54
|
+
{
|
|
55
|
+
variant: ["default", "accent"],
|
|
56
|
+
checked: false,
|
|
57
|
+
disabled: false,
|
|
58
|
+
focused: false,
|
|
59
|
+
class: {
|
|
60
|
+
box: "bg-secondary-background border-default-boundary"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
variant: "outline",
|
|
65
|
+
checked: false,
|
|
66
|
+
disabled: false,
|
|
67
|
+
focused: false,
|
|
68
|
+
class: {
|
|
69
|
+
box: ["border-default-foreground", "peer-focus-visible:border-selected-boundary"]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
// 选中状态 - default
|
|
73
|
+
{
|
|
74
|
+
variant: "default",
|
|
75
|
+
checked: true,
|
|
76
|
+
disabled: false,
|
|
77
|
+
focused: false,
|
|
78
|
+
class: {
|
|
79
|
+
box: [
|
|
80
|
+
"bg-secondary-background border-default-boundary",
|
|
81
|
+
"peer-focus-visible:border-selected-strong-boundary"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
// 选中状态 - accent & outline
|
|
86
|
+
{
|
|
87
|
+
variant: ["accent", "outline"],
|
|
88
|
+
checked: true,
|
|
89
|
+
disabled: false,
|
|
90
|
+
focused: false,
|
|
91
|
+
class: {
|
|
92
|
+
box: [
|
|
93
|
+
"bg-accent-background border-selected-strong-boundary text-on-accent-foreground",
|
|
94
|
+
"peer-focus-visible:border-selected-strong-boundary",
|
|
95
|
+
"peer-focus-visible:text-on-accent-foreground",
|
|
96
|
+
"peer-focus-visible:shadow-checked-focused"
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
variant: ["default", "accent", "outline"],
|
|
102
|
+
checked: false,
|
|
103
|
+
disabled: false,
|
|
104
|
+
focused: true,
|
|
105
|
+
class: {
|
|
106
|
+
box: "border-selected-boundary"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
variant: "default",
|
|
111
|
+
checked: true,
|
|
112
|
+
disabled: false,
|
|
113
|
+
focused: true,
|
|
114
|
+
class: {
|
|
115
|
+
box: "border-selected-strong-boundary"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
variant: ["accent", "outline"],
|
|
120
|
+
checked: true,
|
|
121
|
+
disabled: false,
|
|
122
|
+
focused: true,
|
|
123
|
+
class: {
|
|
124
|
+
box: "text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
variant: ["accent", "outline", "default"],
|
|
129
|
+
disabled: true,
|
|
130
|
+
class: {
|
|
131
|
+
root: "text-default-background",
|
|
132
|
+
box: "border-disabled-background bg-disabled-background",
|
|
133
|
+
label: "text-disabled-foreground"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
defaultVariants: {
|
|
138
|
+
variant: "default",
|
|
139
|
+
checked: false,
|
|
140
|
+
disabled: false,
|
|
141
|
+
focused: false
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
var CheckboxLabel = react.memo(
|
|
145
|
+
react.forwardRef(function CheckboxLabel2(props, ref) {
|
|
146
|
+
const { children, className, ...rest } = props;
|
|
147
|
+
const { id, descriptionId, disabled } = useCheckboxContext();
|
|
148
|
+
const styles = checkboxTv({ disabled });
|
|
149
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
150
|
+
"label",
|
|
151
|
+
{
|
|
152
|
+
ref,
|
|
153
|
+
id: descriptionId,
|
|
154
|
+
htmlFor: id,
|
|
155
|
+
className: shared.tcx(styles.label(), className),
|
|
156
|
+
...rest,
|
|
157
|
+
children
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
CheckboxLabel.displayName = "Checkbox.Label";
|
|
163
|
+
var CheckboxBase = react.forwardRef(function Checkbox(props, ref) {
|
|
164
|
+
const {
|
|
165
|
+
value,
|
|
166
|
+
onChange,
|
|
167
|
+
disabled,
|
|
168
|
+
readOnly = false,
|
|
169
|
+
variant = "default",
|
|
170
|
+
className,
|
|
171
|
+
focused,
|
|
172
|
+
mixed,
|
|
173
|
+
children,
|
|
174
|
+
id,
|
|
175
|
+
"aria-label": ariaLabel,
|
|
176
|
+
"aria-describedby": ariaDescribedby,
|
|
177
|
+
onKeyDown,
|
|
178
|
+
...rest
|
|
179
|
+
} = props;
|
|
180
|
+
const internalId = react.useId();
|
|
181
|
+
const descriptionId = react.useId();
|
|
182
|
+
const styles = checkboxTv({
|
|
183
|
+
type: "checkbox",
|
|
184
|
+
variant,
|
|
185
|
+
disabled,
|
|
186
|
+
checked: value,
|
|
187
|
+
focused
|
|
188
|
+
});
|
|
189
|
+
const handleChange = usehooksTs.useEventCallback((e) => {
|
|
190
|
+
if (readOnly) return;
|
|
191
|
+
onChange?.(e.target.checked);
|
|
192
|
+
});
|
|
193
|
+
const handleKeyDown = usehooksTs.useEventCallback((e) => {
|
|
194
|
+
if (readOnly) return;
|
|
195
|
+
if (e.key === " " || e.key === "Enter") {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
onChange?.(!value);
|
|
198
|
+
}
|
|
199
|
+
onKeyDown?.(e);
|
|
200
|
+
});
|
|
201
|
+
const renderChildren = () => {
|
|
202
|
+
if (typeof children === "string" || typeof children === "number") {
|
|
203
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CheckboxLabel, { children });
|
|
204
|
+
}
|
|
205
|
+
return children;
|
|
206
|
+
};
|
|
207
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
208
|
+
CheckboxContext.Provider,
|
|
209
|
+
{
|
|
210
|
+
value: {
|
|
211
|
+
value,
|
|
212
|
+
onChange: (val) => onChange?.(val),
|
|
213
|
+
disabled,
|
|
214
|
+
id: id || internalId,
|
|
215
|
+
descriptionId,
|
|
216
|
+
variant,
|
|
217
|
+
mixed
|
|
218
|
+
},
|
|
219
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: shared.tcx(styles.root(), className), children: [
|
|
220
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none relative", children: [
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
222
|
+
"input",
|
|
223
|
+
{
|
|
224
|
+
ref,
|
|
225
|
+
className: styles.input(),
|
|
226
|
+
type: "checkbox",
|
|
227
|
+
id: id || internalId,
|
|
228
|
+
checked: value,
|
|
229
|
+
disabled: disabled || readOnly,
|
|
230
|
+
onChange: handleChange,
|
|
231
|
+
"aria-label": ariaLabel,
|
|
232
|
+
"aria-describedby": ariaDescribedby || descriptionId,
|
|
233
|
+
"aria-checked": mixed ? "mixed" : value,
|
|
234
|
+
"aria-disabled": disabled || readOnly,
|
|
235
|
+
role: "checkbox",
|
|
236
|
+
onKeyDown: handleKeyDown,
|
|
237
|
+
...rest
|
|
238
|
+
}
|
|
239
|
+
),
|
|
240
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.box(), children: value && (mixed ? /* @__PURE__ */ jsxRuntime.jsx(iconsReact.Indeterminate, {}) : /* @__PURE__ */ jsxRuntime.jsx(iconsReact.Check, {})) })
|
|
241
|
+
] }),
|
|
242
|
+
renderChildren()
|
|
243
|
+
] })
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
var MemoizedCheckbox = react.memo(CheckboxBase);
|
|
248
|
+
var Checkbox2 = MemoizedCheckbox;
|
|
249
|
+
Checkbox2.Label = CheckboxLabel;
|
|
250
|
+
Checkbox2.displayName = "Checkbox";
|
|
251
|
+
|
|
252
|
+
exports.Checkbox = Checkbox2;
|
|
253
|
+
exports.useCheckboxContext = useCheckboxContext;
|
|
254
|
+
//# sourceMappingURL=index.cjs.map
|
|
255
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/tv.ts","../src/checkbox-label.tsx","../src/checkbox.tsx"],"names":["createContext","useContext","tcv","memo","forwardRef","CheckboxLabel","jsx","tcx","useId","useEventCallback","jsxs","Indeterminate","Check","Checkbox"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, useContext } from \"react\"\n\nexport interface CheckboxContextValue {\n descriptionId?: string\n disabled?: boolean\n id: string\n mixed?: boolean\n onChange: (value: boolean) => void\n value?: boolean\n variant?: \"default\" | \"accent\" | \"outline\"\n}\n\nexport const CheckboxContext = createContext<CheckboxContextValue | null>(null)\n\nexport function useCheckboxContext() {\n const context = useContext(CheckboxContext)\n if (!context) {\n throw new Error(\"Checkbox components must be used within a Checkbox component\")\n }\n return context\n}\n","import { tcv } from \"@choice-ui/shared\"\n\nexport const checkboxTv = tcv({\n slots: {\n root: \"flex items-center select-none\",\n box: [\"relative flex size-4 items-center justify-center\", \"border border-solid\"],\n input: \"peer pointer-events-auto absolute inset-0 appearance-none opacity-0\",\n label: \"pl-2\",\n },\n variants: {\n type: {\n checkbox: {\n box: \"rounded-md\",\n },\n radio: {\n box: \"rounded-full\",\n },\n },\n variant: {\n default: {},\n accent: {},\n outline: {},\n },\n checked: {\n true: {},\n false: {},\n },\n disabled: {\n true: {},\n false: {},\n },\n focused: {\n true: {},\n false: {},\n },\n },\n compoundVariants: [\n // 未选中状态\n {\n variant: [\"default\", \"accent\"],\n checked: false,\n disabled: false,\n focused: false,\n class: {\n box: \"bg-secondary-background border-default-boundary\",\n },\n },\n {\n variant: \"outline\",\n checked: false,\n disabled: false,\n focused: false,\n class: {\n box: [\"border-default-foreground\", \"peer-focus-visible:border-selected-boundary\"],\n },\n },\n // 选中状态 - default\n {\n variant: \"default\",\n checked: true,\n disabled: false,\n focused: false,\n class: {\n box: [\n \"bg-secondary-background border-default-boundary\",\n \"peer-focus-visible:border-selected-strong-boundary\",\n ],\n },\n },\n // 选中状态 - accent & outline\n {\n variant: [\"accent\", \"outline\"],\n checked: true,\n disabled: false,\n focused: false,\n class: {\n box: [\n \"bg-accent-background border-selected-strong-boundary text-on-accent-foreground\",\n \"peer-focus-visible:border-selected-strong-boundary\",\n \"peer-focus-visible:text-on-accent-foreground\",\n \"peer-focus-visible:shadow-checked-focused\",\n ],\n },\n },\n {\n variant: [\"default\", \"accent\", \"outline\"],\n checked: false,\n disabled: false,\n focused: true,\n class: {\n box: \"border-selected-boundary\",\n },\n },\n {\n variant: \"default\",\n checked: true,\n disabled: false,\n focused: true,\n class: {\n box: \"border-selected-strong-boundary\",\n },\n },\n {\n variant: [\"accent\", \"outline\"],\n checked: true,\n disabled: false,\n focused: true,\n class: {\n box: \"text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused\",\n },\n },\n {\n variant: [\"accent\", \"outline\", \"default\"],\n disabled: true,\n class: {\n root: \"text-default-background\",\n box: \"border-disabled-background bg-disabled-background\",\n label: \"text-disabled-foreground\",\n },\n },\n ],\n defaultVariants: {\n variant: \"default\",\n checked: false,\n disabled: false,\n focused: false,\n },\n})\n","import { tcx } from \"@choice-ui/shared\"\nimport { forwardRef, HTMLProps, memo, ReactNode } from \"react\"\nimport { useCheckboxContext } from \"./context\"\nimport { checkboxTv } from \"./tv\"\n\nexport interface CheckboxLabelProps extends Omit<\n HTMLProps<HTMLLabelElement>,\n \"htmlFor\" | \"id\" | \"disabled\"\n> {\n children: ReactNode\n}\n\nexport const CheckboxLabel = memo(\n forwardRef<HTMLLabelElement, CheckboxLabelProps>(function CheckboxLabel(props, ref) {\n const { children, className, ...rest } = props\n const { id, descriptionId, disabled } = useCheckboxContext()\n const styles = checkboxTv({ disabled })\n\n return (\n <label\n ref={ref}\n id={descriptionId}\n htmlFor={id}\n className={tcx(styles.label(), className)}\n {...rest}\n >\n {children}\n </label>\n )\n }),\n)\n\nCheckboxLabel.displayName = \"Checkbox.Label\"\n","import { tcx } from \"@choice-ui/shared\"\nimport { Check, Indeterminate } from \"@choiceform/icons-react\"\nimport { forwardRef, HTMLProps, memo, ReactNode, useId } from \"react\"\nimport { useEventCallback } from \"usehooks-ts\"\nimport { CheckboxLabel } from \"./checkbox-label\"\nimport { CheckboxContext } from \"./context\"\nimport { checkboxTv } from \"./tv\"\n\nexport interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, \"value\" | \"onChange\"> {\n children?: ReactNode\n className?: string\n focused?: boolean\n mixed?: boolean\n onChange?: (value: boolean) => void\n readOnly?: boolean\n value?: boolean\n variant?: \"default\" | \"accent\" | \"outline\"\n}\n\nconst CheckboxBase = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox(props, ref) {\n const {\n value,\n onChange,\n disabled,\n readOnly = false,\n variant = \"default\",\n className,\n focused,\n mixed,\n children,\n id,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedby,\n onKeyDown,\n ...rest\n } = props\n const internalId = useId()\n const descriptionId = useId()\n\n const styles = checkboxTv({\n type: \"checkbox\",\n variant,\n disabled,\n checked: value,\n focused: focused,\n })\n\n const handleChange = useEventCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n if (readOnly) return\n onChange?.(e.target.checked)\n })\n\n const handleKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (readOnly) return\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault()\n onChange?.(!value)\n }\n onKeyDown?.(e)\n })\n\n // 自动将字符串类型的 children 包装成 CheckboxLabel\n const renderChildren = () => {\n if (typeof children === \"string\" || typeof children === \"number\") {\n return <CheckboxLabel>{children}</CheckboxLabel>\n }\n return children\n }\n\n return (\n <CheckboxContext.Provider\n value={{\n value,\n onChange: (val) => onChange?.(val),\n disabled,\n id: id || internalId,\n descriptionId,\n variant,\n mixed,\n }}\n >\n <div className={tcx(styles.root(), className)}>\n <div className=\"pointer-events-none relative\">\n <input\n ref={ref}\n className={styles.input()}\n type=\"checkbox\"\n id={id || internalId}\n checked={value}\n disabled={disabled || readOnly}\n onChange={handleChange}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby || descriptionId}\n aria-checked={mixed ? \"mixed\" : value}\n aria-disabled={disabled || readOnly}\n role=\"checkbox\"\n onKeyDown={handleKeyDown}\n {...rest}\n />\n\n <div className={styles.box()}>{value && (mixed ? <Indeterminate /> : <Check />)}</div>\n </div>\n\n {renderChildren()}\n </div>\n </CheckboxContext.Provider>\n )\n})\n\nconst MemoizedCheckbox = memo(CheckboxBase) as unknown as CheckboxType\n\ninterface CheckboxType {\n (props: CheckboxProps & { ref?: React.Ref<HTMLInputElement> }): JSX.Element\n Label: typeof CheckboxLabel\n displayName?: string\n}\n\nexport const Checkbox = MemoizedCheckbox as CheckboxType\nCheckbox.Label = CheckboxLabel\nCheckbox.displayName = \"Checkbox\"\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLProps, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CheckboxLabelProps extends Omit<HTMLProps<HTMLLabelElement>, "htmlFor" | "id" | "disabled"> {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
declare const CheckboxLabel: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<CheckboxLabelProps, "ref"> & react.RefAttributes<HTMLLabelElement>>>;
|
|
8
|
+
|
|
9
|
+
interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
focused?: boolean;
|
|
13
|
+
mixed?: boolean;
|
|
14
|
+
onChange?: (value: boolean) => void;
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
value?: boolean;
|
|
17
|
+
variant?: "default" | "accent" | "outline";
|
|
18
|
+
}
|
|
19
|
+
interface CheckboxType {
|
|
20
|
+
(props: CheckboxProps & {
|
|
21
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
22
|
+
}): JSX.Element;
|
|
23
|
+
Label: typeof CheckboxLabel;
|
|
24
|
+
displayName?: string;
|
|
25
|
+
}
|
|
26
|
+
declare const Checkbox: CheckboxType;
|
|
27
|
+
|
|
28
|
+
interface CheckboxContextValue {
|
|
29
|
+
descriptionId?: string;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
id: string;
|
|
32
|
+
mixed?: boolean;
|
|
33
|
+
onChange: (value: boolean) => void;
|
|
34
|
+
value?: boolean;
|
|
35
|
+
variant?: "default" | "accent" | "outline";
|
|
36
|
+
}
|
|
37
|
+
declare function useCheckboxContext(): CheckboxContextValue;
|
|
38
|
+
|
|
39
|
+
export { Checkbox, type CheckboxContextValue, type CheckboxLabelProps, type CheckboxProps, useCheckboxContext };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLProps, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CheckboxLabelProps extends Omit<HTMLProps<HTMLLabelElement>, "htmlFor" | "id" | "disabled"> {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
declare const CheckboxLabel: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<CheckboxLabelProps, "ref"> & react.RefAttributes<HTMLLabelElement>>>;
|
|
8
|
+
|
|
9
|
+
interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
focused?: boolean;
|
|
13
|
+
mixed?: boolean;
|
|
14
|
+
onChange?: (value: boolean) => void;
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
value?: boolean;
|
|
17
|
+
variant?: "default" | "accent" | "outline";
|
|
18
|
+
}
|
|
19
|
+
interface CheckboxType {
|
|
20
|
+
(props: CheckboxProps & {
|
|
21
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
22
|
+
}): JSX.Element;
|
|
23
|
+
Label: typeof CheckboxLabel;
|
|
24
|
+
displayName?: string;
|
|
25
|
+
}
|
|
26
|
+
declare const Checkbox: CheckboxType;
|
|
27
|
+
|
|
28
|
+
interface CheckboxContextValue {
|
|
29
|
+
descriptionId?: string;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
id: string;
|
|
32
|
+
mixed?: boolean;
|
|
33
|
+
onChange: (value: boolean) => void;
|
|
34
|
+
value?: boolean;
|
|
35
|
+
variant?: "default" | "accent" | "outline";
|
|
36
|
+
}
|
|
37
|
+
declare function useCheckboxContext(): CheckboxContextValue;
|
|
38
|
+
|
|
39
|
+
export { Checkbox, type CheckboxContextValue, type CheckboxLabelProps, type CheckboxProps, useCheckboxContext };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { tcv, tcx } from '@choice-ui/shared';
|
|
2
|
+
import { Indeterminate, Check } from '@choiceform/icons-react';
|
|
3
|
+
import { createContext, memo, forwardRef, useId, useContext } from 'react';
|
|
4
|
+
import { useEventCallback } from 'usehooks-ts';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/checkbox.tsx
|
|
8
|
+
var CheckboxContext = createContext(null);
|
|
9
|
+
function useCheckboxContext() {
|
|
10
|
+
const context = useContext(CheckboxContext);
|
|
11
|
+
if (!context) {
|
|
12
|
+
throw new Error("Checkbox components must be used within a Checkbox component");
|
|
13
|
+
}
|
|
14
|
+
return context;
|
|
15
|
+
}
|
|
16
|
+
var checkboxTv = tcv({
|
|
17
|
+
slots: {
|
|
18
|
+
root: "flex items-center select-none",
|
|
19
|
+
box: ["relative flex size-4 items-center justify-center", "border border-solid"],
|
|
20
|
+
input: "peer pointer-events-auto absolute inset-0 appearance-none opacity-0",
|
|
21
|
+
label: "pl-2"
|
|
22
|
+
},
|
|
23
|
+
variants: {
|
|
24
|
+
type: {
|
|
25
|
+
checkbox: {
|
|
26
|
+
box: "rounded-md"
|
|
27
|
+
},
|
|
28
|
+
radio: {
|
|
29
|
+
box: "rounded-full"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
variant: {
|
|
33
|
+
default: {},
|
|
34
|
+
accent: {},
|
|
35
|
+
outline: {}
|
|
36
|
+
},
|
|
37
|
+
checked: {
|
|
38
|
+
true: {},
|
|
39
|
+
false: {}
|
|
40
|
+
},
|
|
41
|
+
disabled: {
|
|
42
|
+
true: {},
|
|
43
|
+
false: {}
|
|
44
|
+
},
|
|
45
|
+
focused: {
|
|
46
|
+
true: {},
|
|
47
|
+
false: {}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
compoundVariants: [
|
|
51
|
+
// 未选中状态
|
|
52
|
+
{
|
|
53
|
+
variant: ["default", "accent"],
|
|
54
|
+
checked: false,
|
|
55
|
+
disabled: false,
|
|
56
|
+
focused: false,
|
|
57
|
+
class: {
|
|
58
|
+
box: "bg-secondary-background border-default-boundary"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
variant: "outline",
|
|
63
|
+
checked: false,
|
|
64
|
+
disabled: false,
|
|
65
|
+
focused: false,
|
|
66
|
+
class: {
|
|
67
|
+
box: ["border-default-foreground", "peer-focus-visible:border-selected-boundary"]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
// 选中状态 - default
|
|
71
|
+
{
|
|
72
|
+
variant: "default",
|
|
73
|
+
checked: true,
|
|
74
|
+
disabled: false,
|
|
75
|
+
focused: false,
|
|
76
|
+
class: {
|
|
77
|
+
box: [
|
|
78
|
+
"bg-secondary-background border-default-boundary",
|
|
79
|
+
"peer-focus-visible:border-selected-strong-boundary"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
// 选中状态 - accent & outline
|
|
84
|
+
{
|
|
85
|
+
variant: ["accent", "outline"],
|
|
86
|
+
checked: true,
|
|
87
|
+
disabled: false,
|
|
88
|
+
focused: false,
|
|
89
|
+
class: {
|
|
90
|
+
box: [
|
|
91
|
+
"bg-accent-background border-selected-strong-boundary text-on-accent-foreground",
|
|
92
|
+
"peer-focus-visible:border-selected-strong-boundary",
|
|
93
|
+
"peer-focus-visible:text-on-accent-foreground",
|
|
94
|
+
"peer-focus-visible:shadow-checked-focused"
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
variant: ["default", "accent", "outline"],
|
|
100
|
+
checked: false,
|
|
101
|
+
disabled: false,
|
|
102
|
+
focused: true,
|
|
103
|
+
class: {
|
|
104
|
+
box: "border-selected-boundary"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
variant: "default",
|
|
109
|
+
checked: true,
|
|
110
|
+
disabled: false,
|
|
111
|
+
focused: true,
|
|
112
|
+
class: {
|
|
113
|
+
box: "border-selected-strong-boundary"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
variant: ["accent", "outline"],
|
|
118
|
+
checked: true,
|
|
119
|
+
disabled: false,
|
|
120
|
+
focused: true,
|
|
121
|
+
class: {
|
|
122
|
+
box: "text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
variant: ["accent", "outline", "default"],
|
|
127
|
+
disabled: true,
|
|
128
|
+
class: {
|
|
129
|
+
root: "text-default-background",
|
|
130
|
+
box: "border-disabled-background bg-disabled-background",
|
|
131
|
+
label: "text-disabled-foreground"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
defaultVariants: {
|
|
136
|
+
variant: "default",
|
|
137
|
+
checked: false,
|
|
138
|
+
disabled: false,
|
|
139
|
+
focused: false
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
var CheckboxLabel = memo(
|
|
143
|
+
forwardRef(function CheckboxLabel2(props, ref) {
|
|
144
|
+
const { children, className, ...rest } = props;
|
|
145
|
+
const { id, descriptionId, disabled } = useCheckboxContext();
|
|
146
|
+
const styles = checkboxTv({ disabled });
|
|
147
|
+
return /* @__PURE__ */ jsx(
|
|
148
|
+
"label",
|
|
149
|
+
{
|
|
150
|
+
ref,
|
|
151
|
+
id: descriptionId,
|
|
152
|
+
htmlFor: id,
|
|
153
|
+
className: tcx(styles.label(), className),
|
|
154
|
+
...rest,
|
|
155
|
+
children
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
CheckboxLabel.displayName = "Checkbox.Label";
|
|
161
|
+
var CheckboxBase = forwardRef(function Checkbox(props, ref) {
|
|
162
|
+
const {
|
|
163
|
+
value,
|
|
164
|
+
onChange,
|
|
165
|
+
disabled,
|
|
166
|
+
readOnly = false,
|
|
167
|
+
variant = "default",
|
|
168
|
+
className,
|
|
169
|
+
focused,
|
|
170
|
+
mixed,
|
|
171
|
+
children,
|
|
172
|
+
id,
|
|
173
|
+
"aria-label": ariaLabel,
|
|
174
|
+
"aria-describedby": ariaDescribedby,
|
|
175
|
+
onKeyDown,
|
|
176
|
+
...rest
|
|
177
|
+
} = props;
|
|
178
|
+
const internalId = useId();
|
|
179
|
+
const descriptionId = useId();
|
|
180
|
+
const styles = checkboxTv({
|
|
181
|
+
type: "checkbox",
|
|
182
|
+
variant,
|
|
183
|
+
disabled,
|
|
184
|
+
checked: value,
|
|
185
|
+
focused
|
|
186
|
+
});
|
|
187
|
+
const handleChange = useEventCallback((e) => {
|
|
188
|
+
if (readOnly) return;
|
|
189
|
+
onChange?.(e.target.checked);
|
|
190
|
+
});
|
|
191
|
+
const handleKeyDown = useEventCallback((e) => {
|
|
192
|
+
if (readOnly) return;
|
|
193
|
+
if (e.key === " " || e.key === "Enter") {
|
|
194
|
+
e.preventDefault();
|
|
195
|
+
onChange?.(!value);
|
|
196
|
+
}
|
|
197
|
+
onKeyDown?.(e);
|
|
198
|
+
});
|
|
199
|
+
const renderChildren = () => {
|
|
200
|
+
if (typeof children === "string" || typeof children === "number") {
|
|
201
|
+
return /* @__PURE__ */ jsx(CheckboxLabel, { children });
|
|
202
|
+
}
|
|
203
|
+
return children;
|
|
204
|
+
};
|
|
205
|
+
return /* @__PURE__ */ jsx(
|
|
206
|
+
CheckboxContext.Provider,
|
|
207
|
+
{
|
|
208
|
+
value: {
|
|
209
|
+
value,
|
|
210
|
+
onChange: (val) => onChange?.(val),
|
|
211
|
+
disabled,
|
|
212
|
+
id: id || internalId,
|
|
213
|
+
descriptionId,
|
|
214
|
+
variant,
|
|
215
|
+
mixed
|
|
216
|
+
},
|
|
217
|
+
children: /* @__PURE__ */ jsxs("div", { className: tcx(styles.root(), className), children: [
|
|
218
|
+
/* @__PURE__ */ jsxs("div", { className: "pointer-events-none relative", children: [
|
|
219
|
+
/* @__PURE__ */ jsx(
|
|
220
|
+
"input",
|
|
221
|
+
{
|
|
222
|
+
ref,
|
|
223
|
+
className: styles.input(),
|
|
224
|
+
type: "checkbox",
|
|
225
|
+
id: id || internalId,
|
|
226
|
+
checked: value,
|
|
227
|
+
disabled: disabled || readOnly,
|
|
228
|
+
onChange: handleChange,
|
|
229
|
+
"aria-label": ariaLabel,
|
|
230
|
+
"aria-describedby": ariaDescribedby || descriptionId,
|
|
231
|
+
"aria-checked": mixed ? "mixed" : value,
|
|
232
|
+
"aria-disabled": disabled || readOnly,
|
|
233
|
+
role: "checkbox",
|
|
234
|
+
onKeyDown: handleKeyDown,
|
|
235
|
+
...rest
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
/* @__PURE__ */ jsx("div", { className: styles.box(), children: value && (mixed ? /* @__PURE__ */ jsx(Indeterminate, {}) : /* @__PURE__ */ jsx(Check, {})) })
|
|
239
|
+
] }),
|
|
240
|
+
renderChildren()
|
|
241
|
+
] })
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
var MemoizedCheckbox = memo(CheckboxBase);
|
|
246
|
+
var Checkbox2 = MemoizedCheckbox;
|
|
247
|
+
Checkbox2.Label = CheckboxLabel;
|
|
248
|
+
Checkbox2.displayName = "Checkbox";
|
|
249
|
+
|
|
250
|
+
export { Checkbox2 as Checkbox, useCheckboxContext };
|
|
251
|
+
//# sourceMappingURL=index.js.map
|
|
252
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/tv.ts","../src/checkbox-label.tsx","../src/checkbox.tsx"],"names":["CheckboxLabel","forwardRef","jsx","tcx","memo","Checkbox"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext } from \"react\"\n\nexport interface CheckboxContextValue {\n descriptionId?: string\n disabled?: boolean\n id: string\n mixed?: boolean\n onChange: (value: boolean) => void\n value?: boolean\n variant?: \"default\" | \"accent\" | \"outline\"\n}\n\nexport const CheckboxContext = createContext<CheckboxContextValue | null>(null)\n\nexport function useCheckboxContext() {\n const context = useContext(CheckboxContext)\n if (!context) {\n throw new Error(\"Checkbox components must be used within a Checkbox component\")\n }\n return context\n}\n","import { tcv } from \"@choice-ui/shared\"\n\nexport const checkboxTv = tcv({\n slots: {\n root: \"flex items-center select-none\",\n box: [\"relative flex size-4 items-center justify-center\", \"border border-solid\"],\n input: \"peer pointer-events-auto absolute inset-0 appearance-none opacity-0\",\n label: \"pl-2\",\n },\n variants: {\n type: {\n checkbox: {\n box: \"rounded-md\",\n },\n radio: {\n box: \"rounded-full\",\n },\n },\n variant: {\n default: {},\n accent: {},\n outline: {},\n },\n checked: {\n true: {},\n false: {},\n },\n disabled: {\n true: {},\n false: {},\n },\n focused: {\n true: {},\n false: {},\n },\n },\n compoundVariants: [\n // 未选中状态\n {\n variant: [\"default\", \"accent\"],\n checked: false,\n disabled: false,\n focused: false,\n class: {\n box: \"bg-secondary-background border-default-boundary\",\n },\n },\n {\n variant: \"outline\",\n checked: false,\n disabled: false,\n focused: false,\n class: {\n box: [\"border-default-foreground\", \"peer-focus-visible:border-selected-boundary\"],\n },\n },\n // 选中状态 - default\n {\n variant: \"default\",\n checked: true,\n disabled: false,\n focused: false,\n class: {\n box: [\n \"bg-secondary-background border-default-boundary\",\n \"peer-focus-visible:border-selected-strong-boundary\",\n ],\n },\n },\n // 选中状态 - accent & outline\n {\n variant: [\"accent\", \"outline\"],\n checked: true,\n disabled: false,\n focused: false,\n class: {\n box: [\n \"bg-accent-background border-selected-strong-boundary text-on-accent-foreground\",\n \"peer-focus-visible:border-selected-strong-boundary\",\n \"peer-focus-visible:text-on-accent-foreground\",\n \"peer-focus-visible:shadow-checked-focused\",\n ],\n },\n },\n {\n variant: [\"default\", \"accent\", \"outline\"],\n checked: false,\n disabled: false,\n focused: true,\n class: {\n box: \"border-selected-boundary\",\n },\n },\n {\n variant: \"default\",\n checked: true,\n disabled: false,\n focused: true,\n class: {\n box: \"border-selected-strong-boundary\",\n },\n },\n {\n variant: [\"accent\", \"outline\"],\n checked: true,\n disabled: false,\n focused: true,\n class: {\n box: \"text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused\",\n },\n },\n {\n variant: [\"accent\", \"outline\", \"default\"],\n disabled: true,\n class: {\n root: \"text-default-background\",\n box: \"border-disabled-background bg-disabled-background\",\n label: \"text-disabled-foreground\",\n },\n },\n ],\n defaultVariants: {\n variant: \"default\",\n checked: false,\n disabled: false,\n focused: false,\n },\n})\n","import { tcx } from \"@choice-ui/shared\"\nimport { forwardRef, HTMLProps, memo, ReactNode } from \"react\"\nimport { useCheckboxContext } from \"./context\"\nimport { checkboxTv } from \"./tv\"\n\nexport interface CheckboxLabelProps extends Omit<\n HTMLProps<HTMLLabelElement>,\n \"htmlFor\" | \"id\" | \"disabled\"\n> {\n children: ReactNode\n}\n\nexport const CheckboxLabel = memo(\n forwardRef<HTMLLabelElement, CheckboxLabelProps>(function CheckboxLabel(props, ref) {\n const { children, className, ...rest } = props\n const { id, descriptionId, disabled } = useCheckboxContext()\n const styles = checkboxTv({ disabled })\n\n return (\n <label\n ref={ref}\n id={descriptionId}\n htmlFor={id}\n className={tcx(styles.label(), className)}\n {...rest}\n >\n {children}\n </label>\n )\n }),\n)\n\nCheckboxLabel.displayName = \"Checkbox.Label\"\n","import { tcx } from \"@choice-ui/shared\"\nimport { Check, Indeterminate } from \"@choiceform/icons-react\"\nimport { forwardRef, HTMLProps, memo, ReactNode, useId } from \"react\"\nimport { useEventCallback } from \"usehooks-ts\"\nimport { CheckboxLabel } from \"./checkbox-label\"\nimport { CheckboxContext } from \"./context\"\nimport { checkboxTv } from \"./tv\"\n\nexport interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, \"value\" | \"onChange\"> {\n children?: ReactNode\n className?: string\n focused?: boolean\n mixed?: boolean\n onChange?: (value: boolean) => void\n readOnly?: boolean\n value?: boolean\n variant?: \"default\" | \"accent\" | \"outline\"\n}\n\nconst CheckboxBase = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox(props, ref) {\n const {\n value,\n onChange,\n disabled,\n readOnly = false,\n variant = \"default\",\n className,\n focused,\n mixed,\n children,\n id,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedby,\n onKeyDown,\n ...rest\n } = props\n const internalId = useId()\n const descriptionId = useId()\n\n const styles = checkboxTv({\n type: \"checkbox\",\n variant,\n disabled,\n checked: value,\n focused: focused,\n })\n\n const handleChange = useEventCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n if (readOnly) return\n onChange?.(e.target.checked)\n })\n\n const handleKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (readOnly) return\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault()\n onChange?.(!value)\n }\n onKeyDown?.(e)\n })\n\n // 自动将字符串类型的 children 包装成 CheckboxLabel\n const renderChildren = () => {\n if (typeof children === \"string\" || typeof children === \"number\") {\n return <CheckboxLabel>{children}</CheckboxLabel>\n }\n return children\n }\n\n return (\n <CheckboxContext.Provider\n value={{\n value,\n onChange: (val) => onChange?.(val),\n disabled,\n id: id || internalId,\n descriptionId,\n variant,\n mixed,\n }}\n >\n <div className={tcx(styles.root(), className)}>\n <div className=\"pointer-events-none relative\">\n <input\n ref={ref}\n className={styles.input()}\n type=\"checkbox\"\n id={id || internalId}\n checked={value}\n disabled={disabled || readOnly}\n onChange={handleChange}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby || descriptionId}\n aria-checked={mixed ? \"mixed\" : value}\n aria-disabled={disabled || readOnly}\n role=\"checkbox\"\n onKeyDown={handleKeyDown}\n {...rest}\n />\n\n <div className={styles.box()}>{value && (mixed ? <Indeterminate /> : <Check />)}</div>\n </div>\n\n {renderChildren()}\n </div>\n </CheckboxContext.Provider>\n )\n})\n\nconst MemoizedCheckbox = memo(CheckboxBase) as unknown as CheckboxType\n\ninterface CheckboxType {\n (props: CheckboxProps & { ref?: React.Ref<HTMLInputElement> }): JSX.Element\n Label: typeof CheckboxLabel\n displayName?: string\n}\n\nexport const Checkbox = MemoizedCheckbox as CheckboxType\nCheckbox.Label = CheckboxLabel\nCheckbox.displayName = \"Checkbox\"\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@choice-ui/checkbox",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "Checkbox component for Choiceform Design System",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./src/index.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"src"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./src/index.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@choiceform/icons-react": "^1.3.8",
|
|
26
|
+
"usehooks-ts": "^3.1.0",
|
|
27
|
+
"@choice-ui/shared": "0.0.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/react": "^18.3.12",
|
|
31
|
+
"@types/react-dom": "^18.3.1",
|
|
32
|
+
"react": "^18.3.1",
|
|
33
|
+
"react-dom": "^18.3.1",
|
|
34
|
+
"rimraf": "^6.0.1",
|
|
35
|
+
"tsup": "^8.5.0",
|
|
36
|
+
"typescript": "^5.5.3"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": ">=18.0.0",
|
|
40
|
+
"react-dom": ">=18.0.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"build:watch": "tsup --watch",
|
|
45
|
+
"clean": "rimraf dist"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { tcx } from "@choice-ui/shared"
|
|
2
|
+
import { forwardRef, HTMLProps, memo, ReactNode } from "react"
|
|
3
|
+
import { useCheckboxContext } from "./context"
|
|
4
|
+
import { checkboxTv } from "./tv"
|
|
5
|
+
|
|
6
|
+
export interface CheckboxLabelProps extends Omit<
|
|
7
|
+
HTMLProps<HTMLLabelElement>,
|
|
8
|
+
"htmlFor" | "id" | "disabled"
|
|
9
|
+
> {
|
|
10
|
+
children: ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const CheckboxLabel = memo(
|
|
14
|
+
forwardRef<HTMLLabelElement, CheckboxLabelProps>(function CheckboxLabel(props, ref) {
|
|
15
|
+
const { children, className, ...rest } = props
|
|
16
|
+
const { id, descriptionId, disabled } = useCheckboxContext()
|
|
17
|
+
const styles = checkboxTv({ disabled })
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<label
|
|
21
|
+
ref={ref}
|
|
22
|
+
id={descriptionId}
|
|
23
|
+
htmlFor={id}
|
|
24
|
+
className={tcx(styles.label(), className)}
|
|
25
|
+
{...rest}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</label>
|
|
29
|
+
)
|
|
30
|
+
}),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
CheckboxLabel.displayName = "Checkbox.Label"
|
package/src/checkbox.tsx
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { tcx } from "@choice-ui/shared"
|
|
2
|
+
import { Check, Indeterminate } from "@choiceform/icons-react"
|
|
3
|
+
import { forwardRef, HTMLProps, memo, ReactNode, useId } from "react"
|
|
4
|
+
import { useEventCallback } from "usehooks-ts"
|
|
5
|
+
import { CheckboxLabel } from "./checkbox-label"
|
|
6
|
+
import { CheckboxContext } from "./context"
|
|
7
|
+
import { checkboxTv } from "./tv"
|
|
8
|
+
|
|
9
|
+
export interface CheckboxProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
|
|
10
|
+
children?: ReactNode
|
|
11
|
+
className?: string
|
|
12
|
+
focused?: boolean
|
|
13
|
+
mixed?: boolean
|
|
14
|
+
onChange?: (value: boolean) => void
|
|
15
|
+
readOnly?: boolean
|
|
16
|
+
value?: boolean
|
|
17
|
+
variant?: "default" | "accent" | "outline"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const CheckboxBase = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox(props, ref) {
|
|
21
|
+
const {
|
|
22
|
+
value,
|
|
23
|
+
onChange,
|
|
24
|
+
disabled,
|
|
25
|
+
readOnly = false,
|
|
26
|
+
variant = "default",
|
|
27
|
+
className,
|
|
28
|
+
focused,
|
|
29
|
+
mixed,
|
|
30
|
+
children,
|
|
31
|
+
id,
|
|
32
|
+
"aria-label": ariaLabel,
|
|
33
|
+
"aria-describedby": ariaDescribedby,
|
|
34
|
+
onKeyDown,
|
|
35
|
+
...rest
|
|
36
|
+
} = props
|
|
37
|
+
const internalId = useId()
|
|
38
|
+
const descriptionId = useId()
|
|
39
|
+
|
|
40
|
+
const styles = checkboxTv({
|
|
41
|
+
type: "checkbox",
|
|
42
|
+
variant,
|
|
43
|
+
disabled,
|
|
44
|
+
checked: value,
|
|
45
|
+
focused: focused,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const handleChange = useEventCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
49
|
+
if (readOnly) return
|
|
50
|
+
onChange?.(e.target.checked)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const handleKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
54
|
+
if (readOnly) return
|
|
55
|
+
if (e.key === " " || e.key === "Enter") {
|
|
56
|
+
e.preventDefault()
|
|
57
|
+
onChange?.(!value)
|
|
58
|
+
}
|
|
59
|
+
onKeyDown?.(e)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// 自动将字符串类型的 children 包装成 CheckboxLabel
|
|
63
|
+
const renderChildren = () => {
|
|
64
|
+
if (typeof children === "string" || typeof children === "number") {
|
|
65
|
+
return <CheckboxLabel>{children}</CheckboxLabel>
|
|
66
|
+
}
|
|
67
|
+
return children
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<CheckboxContext.Provider
|
|
72
|
+
value={{
|
|
73
|
+
value,
|
|
74
|
+
onChange: (val) => onChange?.(val),
|
|
75
|
+
disabled,
|
|
76
|
+
id: id || internalId,
|
|
77
|
+
descriptionId,
|
|
78
|
+
variant,
|
|
79
|
+
mixed,
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<div className={tcx(styles.root(), className)}>
|
|
83
|
+
<div className="pointer-events-none relative">
|
|
84
|
+
<input
|
|
85
|
+
ref={ref}
|
|
86
|
+
className={styles.input()}
|
|
87
|
+
type="checkbox"
|
|
88
|
+
id={id || internalId}
|
|
89
|
+
checked={value}
|
|
90
|
+
disabled={disabled || readOnly}
|
|
91
|
+
onChange={handleChange}
|
|
92
|
+
aria-label={ariaLabel}
|
|
93
|
+
aria-describedby={ariaDescribedby || descriptionId}
|
|
94
|
+
aria-checked={mixed ? "mixed" : value}
|
|
95
|
+
aria-disabled={disabled || readOnly}
|
|
96
|
+
role="checkbox"
|
|
97
|
+
onKeyDown={handleKeyDown}
|
|
98
|
+
{...rest}
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<div className={styles.box()}>{value && (mixed ? <Indeterminate /> : <Check />)}</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
{renderChildren()}
|
|
105
|
+
</div>
|
|
106
|
+
</CheckboxContext.Provider>
|
|
107
|
+
)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const MemoizedCheckbox = memo(CheckboxBase) as unknown as CheckboxType
|
|
111
|
+
|
|
112
|
+
interface CheckboxType {
|
|
113
|
+
(props: CheckboxProps & { ref?: React.Ref<HTMLInputElement> }): JSX.Element
|
|
114
|
+
Label: typeof CheckboxLabel
|
|
115
|
+
displayName?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const Checkbox = MemoizedCheckbox as CheckboxType
|
|
119
|
+
Checkbox.Label = CheckboxLabel
|
|
120
|
+
Checkbox.displayName = "Checkbox"
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, useContext } from "react"
|
|
2
|
+
|
|
3
|
+
export interface CheckboxContextValue {
|
|
4
|
+
descriptionId?: string
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
id: string
|
|
7
|
+
mixed?: boolean
|
|
8
|
+
onChange: (value: boolean) => void
|
|
9
|
+
value?: boolean
|
|
10
|
+
variant?: "default" | "accent" | "outline"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const CheckboxContext = createContext<CheckboxContextValue | null>(null)
|
|
14
|
+
|
|
15
|
+
export function useCheckboxContext() {
|
|
16
|
+
const context = useContext(CheckboxContext)
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw new Error("Checkbox components must be used within a Checkbox component")
|
|
19
|
+
}
|
|
20
|
+
return context
|
|
21
|
+
}
|
package/src/index.ts
ADDED
package/src/tv.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { tcv } from "@choice-ui/shared"
|
|
2
|
+
|
|
3
|
+
export const checkboxTv = tcv({
|
|
4
|
+
slots: {
|
|
5
|
+
root: "flex items-center select-none",
|
|
6
|
+
box: ["relative flex size-4 items-center justify-center", "border border-solid"],
|
|
7
|
+
input: "peer pointer-events-auto absolute inset-0 appearance-none opacity-0",
|
|
8
|
+
label: "pl-2",
|
|
9
|
+
},
|
|
10
|
+
variants: {
|
|
11
|
+
type: {
|
|
12
|
+
checkbox: {
|
|
13
|
+
box: "rounded-md",
|
|
14
|
+
},
|
|
15
|
+
radio: {
|
|
16
|
+
box: "rounded-full",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
variant: {
|
|
20
|
+
default: {},
|
|
21
|
+
accent: {},
|
|
22
|
+
outline: {},
|
|
23
|
+
},
|
|
24
|
+
checked: {
|
|
25
|
+
true: {},
|
|
26
|
+
false: {},
|
|
27
|
+
},
|
|
28
|
+
disabled: {
|
|
29
|
+
true: {},
|
|
30
|
+
false: {},
|
|
31
|
+
},
|
|
32
|
+
focused: {
|
|
33
|
+
true: {},
|
|
34
|
+
false: {},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
compoundVariants: [
|
|
38
|
+
// 未选中状态
|
|
39
|
+
{
|
|
40
|
+
variant: ["default", "accent"],
|
|
41
|
+
checked: false,
|
|
42
|
+
disabled: false,
|
|
43
|
+
focused: false,
|
|
44
|
+
class: {
|
|
45
|
+
box: "bg-secondary-background border-default-boundary",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
variant: "outline",
|
|
50
|
+
checked: false,
|
|
51
|
+
disabled: false,
|
|
52
|
+
focused: false,
|
|
53
|
+
class: {
|
|
54
|
+
box: ["border-default-foreground", "peer-focus-visible:border-selected-boundary"],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// 选中状态 - default
|
|
58
|
+
{
|
|
59
|
+
variant: "default",
|
|
60
|
+
checked: true,
|
|
61
|
+
disabled: false,
|
|
62
|
+
focused: false,
|
|
63
|
+
class: {
|
|
64
|
+
box: [
|
|
65
|
+
"bg-secondary-background border-default-boundary",
|
|
66
|
+
"peer-focus-visible:border-selected-strong-boundary",
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
// 选中状态 - accent & outline
|
|
71
|
+
{
|
|
72
|
+
variant: ["accent", "outline"],
|
|
73
|
+
checked: true,
|
|
74
|
+
disabled: false,
|
|
75
|
+
focused: false,
|
|
76
|
+
class: {
|
|
77
|
+
box: [
|
|
78
|
+
"bg-accent-background border-selected-strong-boundary text-on-accent-foreground",
|
|
79
|
+
"peer-focus-visible:border-selected-strong-boundary",
|
|
80
|
+
"peer-focus-visible:text-on-accent-foreground",
|
|
81
|
+
"peer-focus-visible:shadow-checked-focused",
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
variant: ["default", "accent", "outline"],
|
|
87
|
+
checked: false,
|
|
88
|
+
disabled: false,
|
|
89
|
+
focused: true,
|
|
90
|
+
class: {
|
|
91
|
+
box: "border-selected-boundary",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
variant: "default",
|
|
96
|
+
checked: true,
|
|
97
|
+
disabled: false,
|
|
98
|
+
focused: true,
|
|
99
|
+
class: {
|
|
100
|
+
box: "border-selected-strong-boundary",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
variant: ["accent", "outline"],
|
|
105
|
+
checked: true,
|
|
106
|
+
disabled: false,
|
|
107
|
+
focused: true,
|
|
108
|
+
class: {
|
|
109
|
+
box: "text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
variant: ["accent", "outline", "default"],
|
|
114
|
+
disabled: true,
|
|
115
|
+
class: {
|
|
116
|
+
root: "text-default-background",
|
|
117
|
+
box: "border-disabled-background bg-disabled-background",
|
|
118
|
+
label: "text-disabled-foreground",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
defaultVariants: {
|
|
123
|
+
variant: "default",
|
|
124
|
+
checked: false,
|
|
125
|
+
disabled: false,
|
|
126
|
+
focused: false,
|
|
127
|
+
},
|
|
128
|
+
})
|