@cosxai/ui 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -13,6 +13,13 @@ export interface CheckboxProps {
|
|
|
13
13
|
suffix?: React.ReactNode;
|
|
14
14
|
disabled?: boolean;
|
|
15
15
|
className?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Test hook forwarded to the visual button. Consumers with
|
|
18
|
+
* getByTestId('…') queries can keep them working across the swap
|
|
19
|
+
* from native <input type="checkbox"> to this primitive without
|
|
20
|
+
* touching each test file.
|
|
21
|
+
*/
|
|
22
|
+
"data-testid"?: string;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export function Checkbox({
|
|
@@ -22,6 +29,7 @@ export function Checkbox({
|
|
|
22
29
|
suffix,
|
|
23
30
|
disabled,
|
|
24
31
|
className,
|
|
32
|
+
"data-testid": testId,
|
|
25
33
|
}: CheckboxProps) {
|
|
26
34
|
return (
|
|
27
35
|
<label
|
|
@@ -43,6 +51,7 @@ export function Checkbox({
|
|
|
43
51
|
aria-checked={checked}
|
|
44
52
|
disabled={disabled}
|
|
45
53
|
onClick={() => !disabled && onChange(!checked)}
|
|
54
|
+
data-testid={testId}
|
|
46
55
|
style={{
|
|
47
56
|
width: 16,
|
|
48
57
|
height: 16,
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { cn } from "../lib/cn";
|
|
2
|
+
|
|
3
|
+
// Custom-styled radio — accent-bordered circle that becomes filled
|
|
4
|
+
// accent + white dot when checked. Paired with Checkbox: same
|
|
5
|
+
// disabled/label/suffix contract, same 16px hit target size. Use
|
|
6
|
+
// this anywhere you'd reach for a `<input type="radio">` — the
|
|
7
|
+
// native control renders as the OS accent (blue on macOS by
|
|
8
|
+
// default) which doesn't respect --ck-accent per workspace, and the
|
|
9
|
+
// unstyled defaults look inconsistent alongside our Checkbox.
|
|
10
|
+
//
|
|
11
|
+
// Radio is a single option in a group; the caller owns the group's
|
|
12
|
+
// selection state and passes `checked` + `onChange` per option.
|
|
13
|
+
// Radios with the same `name` still get the browser's native "one
|
|
14
|
+
// selected at a time" behaviour if you need form-post semantics; we
|
|
15
|
+
// forward it to a hidden native input so aria-pressed on the visual
|
|
16
|
+
// button doesn't drift from the actual form value.
|
|
17
|
+
|
|
18
|
+
export interface RadioProps {
|
|
19
|
+
checked: boolean;
|
|
20
|
+
onChange: (next: boolean) => void;
|
|
21
|
+
label?: React.ReactNode;
|
|
22
|
+
suffix?: React.ReactNode;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Native radio-group name. Optional but recommended: browsers
|
|
26
|
+
* enforce "only one checked at a time" for same-name radios, so
|
|
27
|
+
* passing a shared name is a belt-and-braces guard against a
|
|
28
|
+
* stale onChange handler leaving two visually-checked radios.
|
|
29
|
+
*/
|
|
30
|
+
name?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Value that lands in the form-post payload when this radio is
|
|
33
|
+
* checked. Only meaningful when `name` is also set.
|
|
34
|
+
*/
|
|
35
|
+
value?: string;
|
|
36
|
+
className?: string;
|
|
37
|
+
/** Test hook forwarded to the visual button — see Checkbox. */
|
|
38
|
+
"data-testid"?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function Radio({
|
|
42
|
+
checked,
|
|
43
|
+
onChange,
|
|
44
|
+
label,
|
|
45
|
+
suffix,
|
|
46
|
+
disabled,
|
|
47
|
+
name,
|
|
48
|
+
value,
|
|
49
|
+
className,
|
|
50
|
+
"data-testid": testId,
|
|
51
|
+
}: RadioProps) {
|
|
52
|
+
return (
|
|
53
|
+
<label
|
|
54
|
+
className={cn("ck-radio", className)}
|
|
55
|
+
style={{
|
|
56
|
+
display: "inline-flex",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
gap: 8,
|
|
59
|
+
font: "400 13px/1 var(--ck-font-sans)",
|
|
60
|
+
color: "var(--ck-text-secondary)",
|
|
61
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
62
|
+
opacity: disabled ? 0.5 : 1,
|
|
63
|
+
userSelect: "none",
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
role="radio"
|
|
69
|
+
aria-checked={checked}
|
|
70
|
+
disabled={disabled}
|
|
71
|
+
onClick={() => !disabled && !checked && onChange(true)}
|
|
72
|
+
data-testid={testId}
|
|
73
|
+
style={{
|
|
74
|
+
width: 16,
|
|
75
|
+
height: 16,
|
|
76
|
+
borderRadius: "50%",
|
|
77
|
+
border: "1.5px solid var(--ck-accent)",
|
|
78
|
+
background: "transparent",
|
|
79
|
+
display: "inline-flex",
|
|
80
|
+
alignItems: "center",
|
|
81
|
+
justifyContent: "center",
|
|
82
|
+
padding: 0,
|
|
83
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
84
|
+
flexShrink: 0,
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{checked && (
|
|
88
|
+
<span
|
|
89
|
+
aria-hidden
|
|
90
|
+
style={{
|
|
91
|
+
width: 8,
|
|
92
|
+
height: 8,
|
|
93
|
+
borderRadius: "50%",
|
|
94
|
+
background: "var(--ck-accent)",
|
|
95
|
+
display: "inline-block",
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
)}
|
|
99
|
+
</button>
|
|
100
|
+
{/* Hidden native input keeps the browser's same-name enforcement
|
|
101
|
+
+ lets consumers use the surrounding <form> for post payload. */}
|
|
102
|
+
{name && (
|
|
103
|
+
<input
|
|
104
|
+
type="radio"
|
|
105
|
+
name={name}
|
|
106
|
+
value={value}
|
|
107
|
+
checked={checked}
|
|
108
|
+
onChange={(e) => !disabled && onChange(e.target.checked)}
|
|
109
|
+
disabled={disabled}
|
|
110
|
+
tabIndex={-1}
|
|
111
|
+
aria-hidden
|
|
112
|
+
style={{
|
|
113
|
+
position: "absolute",
|
|
114
|
+
width: 1,
|
|
115
|
+
height: 1,
|
|
116
|
+
padding: 0,
|
|
117
|
+
margin: -1,
|
|
118
|
+
overflow: "hidden",
|
|
119
|
+
clip: "rect(0,0,0,0)",
|
|
120
|
+
whiteSpace: "nowrap",
|
|
121
|
+
border: 0,
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
)}
|
|
125
|
+
{label}
|
|
126
|
+
{suffix && (
|
|
127
|
+
<span style={{ color: "var(--ck-text-tertiary)" }}>{suffix}</span>
|
|
128
|
+
)}
|
|
129
|
+
</label>
|
|
130
|
+
);
|
|
131
|
+
}
|
package/src/primitives/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ export { Textarea } from "./Textarea";
|
|
|
18
18
|
export type { TextareaProps } from "./Textarea";
|
|
19
19
|
export { Checkbox } from "./Checkbox";
|
|
20
20
|
export type { CheckboxProps } from "./Checkbox";
|
|
21
|
+
export { Radio } from "./Radio";
|
|
22
|
+
export type { RadioProps } from "./Radio";
|
|
21
23
|
export { ToggleSwitch } from "./ToggleSwitch";
|
|
22
24
|
export type { ToggleSwitchProps } from "./ToggleSwitch";
|
|
23
25
|
export { Tooltip } from "./Tooltip";
|