@choice-ui/radio 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/dist/index.cjs ADDED
@@ -0,0 +1,341 @@
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/radio.tsx
10
+ var RadioContext = react.createContext(null);
11
+ function useRadioContext() {
12
+ const context = react.useContext(RadioContext);
13
+ if (!context) {
14
+ throw new Error("Radio.Label must be used within a Radio component");
15
+ }
16
+ return context;
17
+ }
18
+ var RadioGroupContext = react.createContext(null);
19
+ function useRadioGroupContext() {
20
+ const context = react.useContext(RadioGroupContext);
21
+ if (!context) {
22
+ throw new Error("RadioGroupItem must be used within a RadioGroup");
23
+ }
24
+ return context;
25
+ }
26
+ var radioTv = shared.tcv({
27
+ slots: {
28
+ root: "flex items-center select-none",
29
+ box: ["relative flex size-4 items-center justify-center", "border border-solid"],
30
+ input: "peer pointer-events-auto absolute inset-0 appearance-none opacity-0",
31
+ label: "pl-2"
32
+ },
33
+ variants: {
34
+ type: {
35
+ checkbox: {
36
+ box: "rounded-md"
37
+ },
38
+ radio: {
39
+ box: "rounded-full"
40
+ }
41
+ },
42
+ variant: {
43
+ default: {},
44
+ accent: {},
45
+ outline: {}
46
+ },
47
+ checked: {
48
+ true: {},
49
+ false: {}
50
+ },
51
+ disabled: {
52
+ true: {},
53
+ false: {}
54
+ },
55
+ focused: {
56
+ true: {},
57
+ false: {}
58
+ }
59
+ },
60
+ compoundVariants: [
61
+ // 未选中状态
62
+ {
63
+ variant: ["default", "accent"],
64
+ checked: false,
65
+ disabled: false,
66
+ focused: false,
67
+ class: {
68
+ box: "bg-secondary-background border-default-boundary"
69
+ }
70
+ },
71
+ {
72
+ variant: "outline",
73
+ checked: false,
74
+ disabled: false,
75
+ focused: false,
76
+ class: {
77
+ box: ["border-default-foreground", "peer-focus-visible:border-selected-boundary"]
78
+ }
79
+ },
80
+ // 选中状态 - default
81
+ {
82
+ variant: "default",
83
+ checked: true,
84
+ disabled: false,
85
+ focused: false,
86
+ class: {
87
+ box: [
88
+ "bg-secondary-background border-default-boundary",
89
+ "peer-focus-visible:border-selected-strong-boundary"
90
+ ]
91
+ }
92
+ },
93
+ // 选中状态 - accent & outline
94
+ {
95
+ variant: ["accent", "outline"],
96
+ checked: true,
97
+ disabled: false,
98
+ focused: false,
99
+ class: {
100
+ box: [
101
+ "bg-accent-background border-selected-strong-boundary text-on-accent-foreground",
102
+ "peer-focus-visible:border-selected-strong-boundary",
103
+ "peer-focus-visible:text-on-accent-foreground",
104
+ "peer-focus-visible:shadow-checked-focused"
105
+ ]
106
+ }
107
+ },
108
+ {
109
+ variant: ["default", "accent", "outline"],
110
+ checked: false,
111
+ disabled: false,
112
+ focused: true,
113
+ class: {
114
+ box: "border-selected-boundary"
115
+ }
116
+ },
117
+ {
118
+ variant: "default",
119
+ checked: true,
120
+ disabled: false,
121
+ focused: true,
122
+ class: {
123
+ box: "border-selected-strong-boundary"
124
+ }
125
+ },
126
+ {
127
+ variant: ["accent", "outline"],
128
+ checked: true,
129
+ disabled: false,
130
+ focused: true,
131
+ class: {
132
+ box: "text-on-accent-foreground border-selected-strong-boundary shadow-checked-focused"
133
+ }
134
+ },
135
+ {
136
+ variant: ["accent", "outline", "default"],
137
+ disabled: true,
138
+ class: {
139
+ root: "text-default-background",
140
+ box: "border-disabled-background bg-disabled-background",
141
+ label: "text-disabled-foreground"
142
+ }
143
+ }
144
+ ],
145
+ defaultVariants: {
146
+ variant: "default",
147
+ checked: false,
148
+ disabled: false,
149
+ focused: false
150
+ }
151
+ });
152
+ var RadioLabel = react.memo(
153
+ react.forwardRef(function RadioLabel2(props, ref) {
154
+ const { children, className, ...rest } = props;
155
+ const { id, descriptionId, disabled } = useRadioContext();
156
+ const styles = radioTv({ disabled });
157
+ return /* @__PURE__ */ jsxRuntime.jsx(
158
+ "label",
159
+ {
160
+ ref,
161
+ id: descriptionId,
162
+ htmlFor: id,
163
+ className: shared.tcx(styles.label(), className),
164
+ ...rest,
165
+ children
166
+ }
167
+ );
168
+ })
169
+ );
170
+ RadioLabel.displayName = "Radio.Label";
171
+ var RadioBase = react.forwardRef(function Radio(props, ref) {
172
+ const {
173
+ value,
174
+ onChange,
175
+ disabled,
176
+ readOnly = false,
177
+ name,
178
+ variant = "default",
179
+ className,
180
+ focused,
181
+ children,
182
+ "aria-label": ariaLabel,
183
+ "aria-describedby": ariaDescribedby,
184
+ onKeyDown,
185
+ ...rest
186
+ } = props;
187
+ const id = react.useId();
188
+ const descriptionId = react.useId();
189
+ const styles = radioTv({
190
+ type: "radio",
191
+ variant,
192
+ disabled,
193
+ checked: value,
194
+ focused
195
+ });
196
+ const handleChange = usehooksTs.useEventCallback((e) => {
197
+ if (readOnly) return;
198
+ onChange(e.target.checked);
199
+ });
200
+ const handleKeyDown = usehooksTs.useEventCallback((e) => {
201
+ if (readOnly) return;
202
+ if (e.key === " " || e.key === "Enter") {
203
+ e.preventDefault();
204
+ onChange(!value);
205
+ }
206
+ onKeyDown?.(e);
207
+ });
208
+ const renderChildren = () => {
209
+ if (typeof children === "string" || typeof children === "number") {
210
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioLabel, { children });
211
+ }
212
+ return children;
213
+ };
214
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioContext.Provider, { value: { id, descriptionId, disabled }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: shared.tcx(styles.root(), className), children: [
215
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none relative", children: [
216
+ /* @__PURE__ */ jsxRuntime.jsx(
217
+ "input",
218
+ {
219
+ ref,
220
+ className: styles.input(),
221
+ type: "radio",
222
+ id,
223
+ name,
224
+ checked: value,
225
+ disabled: disabled || readOnly,
226
+ onChange: handleChange,
227
+ "aria-label": ariaLabel,
228
+ "aria-describedby": ariaDescribedby || descriptionId,
229
+ "aria-checked": value,
230
+ "aria-disabled": disabled || readOnly,
231
+ role: "radio",
232
+ onKeyDown: handleKeyDown,
233
+ ...rest
234
+ }
235
+ ),
236
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.box(), children: value && /* @__PURE__ */ jsxRuntime.jsx(iconsReact.Dot, {}) })
237
+ ] }),
238
+ renderChildren()
239
+ ] }) });
240
+ });
241
+ var MemoizedRadio = react.memo(RadioBase);
242
+ var Radio2 = MemoizedRadio;
243
+ Radio2.Label = RadioLabel;
244
+ Radio2.displayName = "Radio";
245
+ var RadioGroupItem = react.memo(
246
+ react.forwardRef(function RadioGroupItem2(props, ref) {
247
+ const { value, children, className, disabled, ...rest } = props;
248
+ const {
249
+ name,
250
+ value: selectedValue,
251
+ onChange,
252
+ variant,
253
+ readOnly: contextReadonly
254
+ } = useRadioGroupContext();
255
+ const isChecked = selectedValue === value;
256
+ const handleChange = usehooksTs.useEventCallback(() => {
257
+ if (contextReadonly) return;
258
+ onChange(value);
259
+ });
260
+ return /* @__PURE__ */ jsxRuntime.jsx(
261
+ Radio2,
262
+ {
263
+ name,
264
+ value: isChecked,
265
+ disabled,
266
+ readOnly: contextReadonly,
267
+ variant,
268
+ onChange: handleChange,
269
+ className,
270
+ ...rest,
271
+ ref,
272
+ children: /* @__PURE__ */ jsxRuntime.jsx(Radio2.Label, { children })
273
+ }
274
+ );
275
+ })
276
+ );
277
+ RadioGroupItem.displayName = "RadioGroup.Item";
278
+ var RadioGroupBase = react.forwardRef(function RadioGroup(props, ref) {
279
+ const {
280
+ className,
281
+ options,
282
+ value,
283
+ onChange,
284
+ disabled,
285
+ readOnly = false,
286
+ variant = "default",
287
+ children,
288
+ ...rest
289
+ } = props;
290
+ const id = react.useId();
291
+ const handleChange = usehooksTs.useEventCallback((newValue) => {
292
+ if (readOnly) return;
293
+ onChange(newValue);
294
+ });
295
+ const contextValue = react.useMemo(
296
+ () => ({
297
+ name: id,
298
+ value,
299
+ onChange: handleChange,
300
+ disabled,
301
+ readOnly,
302
+ variant
303
+ }),
304
+ [id, value, handleChange, disabled, readOnly, variant]
305
+ );
306
+ const renderOptionsRadios = react.useMemo(() => {
307
+ if (!options) return null;
308
+ return options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
309
+ RadioGroupItem,
310
+ {
311
+ value: option.value,
312
+ disabled: option.disabled || disabled,
313
+ variant,
314
+ children: option.label
315
+ },
316
+ option.value
317
+ ));
318
+ }, [disabled, options, variant]);
319
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
320
+ "div",
321
+ {
322
+ className: shared.tcx("flex flex-col gap-2", className),
323
+ ref,
324
+ role: "radiogroup",
325
+ "aria-labelledby": props["aria-labelledby"],
326
+ "aria-label": props["aria-label"],
327
+ ...rest,
328
+ children: options ? renderOptionsRadios : children
329
+ }
330
+ ) });
331
+ });
332
+ var MemoizedRadioGroup = react.memo(RadioGroupBase);
333
+ var RadioGroup2 = MemoizedRadioGroup;
334
+ RadioGroup2.Item = RadioGroupItem;
335
+ RadioGroup2.displayName = "RadioGroup";
336
+
337
+ exports.Radio = Radio2;
338
+ exports.RadioGroup = RadioGroup2;
339
+ exports.RadioLabel = RadioLabel;
340
+ exports.useRadioContext = useRadioContext;
341
+ exports.useRadioGroupContext = useRadioGroupContext;
@@ -0,0 +1,69 @@
1
+ import * as react from 'react';
2
+ import { HTMLProps, ReactNode } from 'react';
3
+
4
+ interface RadioLabelProps extends Omit<HTMLProps<HTMLLabelElement>, "htmlFor" | "id" | "disabled"> {
5
+ children: ReactNode;
6
+ }
7
+ declare const RadioLabel: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<RadioLabelProps, "ref"> & react.RefAttributes<HTMLLabelElement>>>;
8
+
9
+ interface RadioProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
10
+ children?: ReactNode;
11
+ className?: string;
12
+ focused?: boolean;
13
+ onChange: (value: boolean) => void;
14
+ readOnly?: boolean;
15
+ value: boolean;
16
+ variant?: "default" | "accent" | "outline";
17
+ }
18
+ interface RadioType {
19
+ (props: RadioProps & {
20
+ ref?: React.Ref<HTMLInputElement>;
21
+ }): JSX.Element;
22
+ Label: typeof RadioLabel;
23
+ displayName?: string;
24
+ }
25
+ declare const Radio: RadioType;
26
+
27
+ interface RadioGroupProps extends Omit<HTMLProps<HTMLDivElement>, "value" | "onChange"> {
28
+ children?: ReactNode;
29
+ onChange: (value: string) => void;
30
+ options?: {
31
+ disabled?: boolean;
32
+ label: string;
33
+ value: string;
34
+ }[];
35
+ readOnly?: boolean;
36
+ value: string;
37
+ variant?: "default" | "accent" | "outline";
38
+ }
39
+ type RadioGroupItemProps = Omit<RadioProps, "value" | "onChange"> & {
40
+ children: ReactNode;
41
+ value: string;
42
+ };
43
+ declare const RadioGroupItem: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<RadioGroupItemProps, "ref"> & react.RefAttributes<HTMLInputElement>>>;
44
+ interface RadioGroupType {
45
+ (props: RadioGroupProps & {
46
+ ref?: React.Ref<HTMLDivElement>;
47
+ }): JSX.Element;
48
+ Item: typeof RadioGroupItem;
49
+ displayName?: string;
50
+ }
51
+ declare const RadioGroup: RadioGroupType;
52
+
53
+ interface RadioContextType {
54
+ descriptionId: string;
55
+ disabled?: boolean;
56
+ id: string;
57
+ }
58
+ declare function useRadioContext(): RadioContextType;
59
+ interface RadioGroupContextType {
60
+ disabled?: boolean;
61
+ name: string;
62
+ onChange: (value: string) => void;
63
+ readOnly?: boolean;
64
+ value: string;
65
+ variant?: "default" | "accent" | "outline";
66
+ }
67
+ declare function useRadioGroupContext(): RadioGroupContextType;
68
+
69
+ export { Radio, type RadioContextType, RadioGroup, type RadioGroupContextType, type RadioGroupProps, RadioLabel, type RadioLabelProps, type RadioProps, useRadioContext, useRadioGroupContext };
@@ -0,0 +1,69 @@
1
+ import * as react from 'react';
2
+ import { HTMLProps, ReactNode } from 'react';
3
+
4
+ interface RadioLabelProps extends Omit<HTMLProps<HTMLLabelElement>, "htmlFor" | "id" | "disabled"> {
5
+ children: ReactNode;
6
+ }
7
+ declare const RadioLabel: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<RadioLabelProps, "ref"> & react.RefAttributes<HTMLLabelElement>>>;
8
+
9
+ interface RadioProps extends Omit<HTMLProps<HTMLInputElement>, "value" | "onChange"> {
10
+ children?: ReactNode;
11
+ className?: string;
12
+ focused?: boolean;
13
+ onChange: (value: boolean) => void;
14
+ readOnly?: boolean;
15
+ value: boolean;
16
+ variant?: "default" | "accent" | "outline";
17
+ }
18
+ interface RadioType {
19
+ (props: RadioProps & {
20
+ ref?: React.Ref<HTMLInputElement>;
21
+ }): JSX.Element;
22
+ Label: typeof RadioLabel;
23
+ displayName?: string;
24
+ }
25
+ declare const Radio: RadioType;
26
+
27
+ interface RadioGroupProps extends Omit<HTMLProps<HTMLDivElement>, "value" | "onChange"> {
28
+ children?: ReactNode;
29
+ onChange: (value: string) => void;
30
+ options?: {
31
+ disabled?: boolean;
32
+ label: string;
33
+ value: string;
34
+ }[];
35
+ readOnly?: boolean;
36
+ value: string;
37
+ variant?: "default" | "accent" | "outline";
38
+ }
39
+ type RadioGroupItemProps = Omit<RadioProps, "value" | "onChange"> & {
40
+ children: ReactNode;
41
+ value: string;
42
+ };
43
+ declare const RadioGroupItem: react.MemoExoticComponent<react.ForwardRefExoticComponent<Omit<RadioGroupItemProps, "ref"> & react.RefAttributes<HTMLInputElement>>>;
44
+ interface RadioGroupType {
45
+ (props: RadioGroupProps & {
46
+ ref?: React.Ref<HTMLDivElement>;
47
+ }): JSX.Element;
48
+ Item: typeof RadioGroupItem;
49
+ displayName?: string;
50
+ }
51
+ declare const RadioGroup: RadioGroupType;
52
+
53
+ interface RadioContextType {
54
+ descriptionId: string;
55
+ disabled?: boolean;
56
+ id: string;
57
+ }
58
+ declare function useRadioContext(): RadioContextType;
59
+ interface RadioGroupContextType {
60
+ disabled?: boolean;
61
+ name: string;
62
+ onChange: (value: string) => void;
63
+ readOnly?: boolean;
64
+ value: string;
65
+ variant?: "default" | "accent" | "outline";
66
+ }
67
+ declare function useRadioGroupContext(): RadioGroupContextType;
68
+
69
+ export { Radio, type RadioContextType, RadioGroup, type RadioGroupContextType, type RadioGroupProps, RadioLabel, type RadioLabelProps, type RadioProps, useRadioContext, useRadioGroupContext };