@seed-design/react-checkbox 0.0.0-alpha-20241004093556

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/lib/index.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ /// <reference types="react" />
2
+ export interface UseCheckboxStateProps {
3
+ checked?: boolean;
4
+ defaultChecked?: boolean;
5
+ onCheckedChange?: (checked: boolean) => void;
6
+ }
7
+ export declare function useCheckboxState(props: UseCheckboxStateProps): {
8
+ isChecked: boolean;
9
+ setIsChecked: import("react").Dispatch<import("react").SetStateAction<boolean>>;
10
+ isHovered: boolean;
11
+ setIsHovered: import("react").Dispatch<import("react").SetStateAction<boolean>>;
12
+ isPressed: boolean;
13
+ setIsPressed: import("react").Dispatch<import("react").SetStateAction<boolean>>;
14
+ isFocused: boolean;
15
+ setIsFocused: import("react").Dispatch<import("react").SetStateAction<boolean>>;
16
+ isFocusVisible: boolean;
17
+ setIsFocusVisible: import("react").Dispatch<import("react").SetStateAction<boolean>>;
18
+ };
19
+ export interface UseCheckboxProps extends UseCheckboxStateProps {
20
+ disabled?: boolean;
21
+ required?: boolean;
22
+ invalid?: boolean;
23
+ name?: string;
24
+ form?: string;
25
+ value?: string;
26
+ }
27
+ export declare function useCheckbox(props: UseCheckboxProps): {
28
+ isChecked: boolean;
29
+ setIsChecked: import("react").Dispatch<import("react").SetStateAction<boolean>>;
30
+ isFocused: boolean;
31
+ setIsFocused: import("react").Dispatch<import("react").SetStateAction<boolean>>;
32
+ setIsFocusVisible: import("react").Dispatch<import("react").SetStateAction<boolean>>;
33
+ restProps: {};
34
+ stateProps: {
35
+ "data-checked": string;
36
+ "data-hover": string;
37
+ "data-active": string;
38
+ "data-focus": string;
39
+ "data-focus-visible": string;
40
+ "data-disabled": string;
41
+ };
42
+ rootProps: import("react").LabelHTMLAttributes<HTMLLabelElement> & {
43
+ [x: `data-${string}`]: string;
44
+ };
45
+ controlProps: import("react").HTMLAttributes<HTMLElement> & {
46
+ [x: `data-${string}`]: string;
47
+ };
48
+ hiddenInputProps: import("react").InputHTMLAttributes<HTMLInputElement> & {
49
+ [x: `data-${string}`]: string;
50
+ };
51
+ };
package/lib/index.js ADDED
@@ -0,0 +1,154 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ useCheckbox: () => useCheckbox,
24
+ useCheckboxState: () => useCheckboxState
25
+ });
26
+ module.exports = __toCommonJS(src_exports);
27
+ var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state");
28
+ var import_react = require("react");
29
+ var import_dom_utils = require("@seed-design/dom-utils");
30
+ function useCheckboxState(props) {
31
+ const [isChecked, setIsChecked] = (0, import_react_use_controllable_state.useControllableState)({
32
+ prop: props.checked,
33
+ defaultProp: props.defaultChecked,
34
+ onChange: props.onCheckedChange
35
+ });
36
+ const [isHovered, setIsHovered] = (0, import_react.useState)(false);
37
+ const [isPressed, setIsPressed] = (0, import_react.useState)(false);
38
+ const [isFocused, setIsFocused] = (0, import_react.useState)(false);
39
+ const [isFocusVisible, setIsFocusVisible] = (0, import_react.useState)(false);
40
+ return {
41
+ isChecked,
42
+ setIsChecked,
43
+ isHovered,
44
+ setIsHovered,
45
+ isPressed,
46
+ setIsPressed,
47
+ isFocused,
48
+ setIsFocused,
49
+ isFocusVisible,
50
+ setIsFocusVisible
51
+ };
52
+ }
53
+ __name(useCheckboxState, "useCheckboxState");
54
+ function useCheckbox(props) {
55
+ const {
56
+ checked,
57
+ defaultChecked,
58
+ disabled,
59
+ form,
60
+ invalid,
61
+ name,
62
+ onCheckedChange,
63
+ required,
64
+ value,
65
+ ...restProps
66
+ } = props;
67
+ const {
68
+ setIsChecked,
69
+ isChecked,
70
+ setIsHovered,
71
+ isHovered,
72
+ setIsPressed,
73
+ isPressed,
74
+ setIsFocused,
75
+ isFocused,
76
+ setIsFocusVisible,
77
+ isFocusVisible
78
+ } = useCheckboxState(props);
79
+ const stateProps = {
80
+ "data-checked": (0, import_dom_utils.dataAttr)(isChecked),
81
+ "data-hover": (0, import_dom_utils.dataAttr)(isHovered),
82
+ "data-active": (0, import_dom_utils.dataAttr)(isPressed),
83
+ "data-focus": (0, import_dom_utils.dataAttr)(isFocused),
84
+ "data-focus-visible": (0, import_dom_utils.dataAttr)(isFocusVisible),
85
+ "data-disabled": (0, import_dom_utils.dataAttr)(props.disabled)
86
+ };
87
+ const isControlled = checked != null;
88
+ return {
89
+ isChecked,
90
+ setIsChecked,
91
+ isFocused,
92
+ setIsFocused,
93
+ setIsFocusVisible,
94
+ restProps,
95
+ stateProps,
96
+ rootProps: (0, import_dom_utils.labelProps)({
97
+ ...stateProps,
98
+ onPointerMove() {
99
+ setIsHovered(true);
100
+ },
101
+ onPointerDown() {
102
+ setIsPressed(true);
103
+ },
104
+ onPointerUp() {
105
+ setIsPressed(false);
106
+ },
107
+ onPointerLeave() {
108
+ setIsHovered(false);
109
+ setIsPressed(false);
110
+ }
111
+ }),
112
+ controlProps: (0, import_dom_utils.elementProps)({
113
+ ...stateProps,
114
+ "aria-hidden": true
115
+ }),
116
+ hiddenInputProps: (0, import_dom_utils.inputProps)({
117
+ type: "checkbox",
118
+ defaultChecked,
119
+ checked: isControlled ? isChecked : void 0,
120
+ disabled: props.disabled,
121
+ required: props.required,
122
+ "aria-invalid": props.invalid,
123
+ name: props.name,
124
+ form: props.form,
125
+ value: props.value,
126
+ ...stateProps,
127
+ onChange(event) {
128
+ setIsChecked(event.currentTarget.checked);
129
+ setIsFocusVisible(event.target.matches(":focus-visible"));
130
+ },
131
+ onFocus(event) {
132
+ setIsFocused(true);
133
+ setIsFocusVisible(event.target.matches(":focus-visible"));
134
+ },
135
+ onBlur() {
136
+ setIsFocused(false);
137
+ setIsFocusVisible(false);
138
+ },
139
+ onKeyDown(event) {
140
+ if (event.key === " ") {
141
+ setIsPressed(true);
142
+ }
143
+ },
144
+ onKeyUp(event) {
145
+ if (event.key === " ") {
146
+ setIsPressed(false);
147
+ }
148
+ }
149
+ })
150
+ };
151
+ }
152
+ __name(useCheckbox, "useCheckbox");
153
+ /*! For license information please see index.js.LEGAL.txt */
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useState } from \"react\";\n\nimport { dataAttr, elementProps, inputProps, labelProps } from \"@seed-design/dom-utils\";\n\nexport interface UseCheckboxStateProps {\n checked?: boolean;\n\n defaultChecked?: boolean;\n\n onCheckedChange?: (checked: boolean) => void;\n}\n\nexport function useCheckboxState(props: UseCheckboxStateProps) {\n const [isChecked, setIsChecked] = useControllableState({\n prop: props.checked,\n defaultProp: props.defaultChecked,\n onChange: props.onCheckedChange,\n });\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n\n return {\n isChecked,\n setIsChecked,\n isHovered,\n setIsHovered,\n isPressed,\n setIsPressed,\n isFocused,\n setIsFocused,\n isFocusVisible,\n setIsFocusVisible,\n };\n}\n\nexport interface UseCheckboxProps extends UseCheckboxStateProps {\n disabled?: boolean;\n\n required?: boolean;\n\n invalid?: boolean;\n\n name?: string;\n\n form?: string;\n\n value?: string;\n}\n\nexport function useCheckbox(props: UseCheckboxProps) {\n const {\n checked,\n defaultChecked,\n disabled,\n form,\n invalid,\n name,\n onCheckedChange,\n required,\n value,\n ...restProps\n } = props;\n\n const {\n setIsChecked,\n isChecked,\n setIsHovered,\n isHovered,\n setIsPressed,\n isPressed,\n setIsFocused,\n isFocused,\n setIsFocusVisible,\n isFocusVisible,\n } = useCheckboxState(props);\n\n const stateProps = {\n \"data-checked\": dataAttr(isChecked),\n \"data-hover\": dataAttr(isHovered),\n \"data-active\": dataAttr(isPressed),\n \"data-focus\": dataAttr(isFocused),\n \"data-focus-visible\": dataAttr(isFocusVisible),\n \"data-disabled\": dataAttr(props.disabled),\n };\n\n const isControlled = checked != null;\n\n return {\n isChecked,\n setIsChecked,\n isFocused,\n setIsFocused,\n setIsFocusVisible,\n\n restProps,\n stateProps,\n rootProps: labelProps({\n ...stateProps,\n onPointerMove() {\n setIsHovered(true);\n },\n onPointerDown() {\n setIsPressed(true);\n },\n onPointerUp() {\n setIsPressed(false);\n },\n onPointerLeave() {\n setIsHovered(false);\n setIsPressed(false);\n },\n }),\n\n controlProps: elementProps({\n ...stateProps,\n \"aria-hidden\": true,\n }),\n\n hiddenInputProps: inputProps({\n type: \"checkbox\",\n defaultChecked,\n checked: isControlled ? isChecked : undefined,\n disabled: props.disabled,\n required: props.required,\n \"aria-invalid\": props.invalid,\n name: props.name,\n form: props.form,\n value: props.value,\n ...stateProps,\n onChange(event) {\n setIsChecked(event.currentTarget.checked);\n setIsFocusVisible(event.target.matches(\":focus-visible\"));\n },\n onFocus(event) {\n setIsFocused(true);\n setIsFocusVisible(event.target.matches(\":focus-visible\"));\n },\n onBlur() {\n setIsFocused(false);\n setIsFocusVisible(false);\n },\n onKeyDown(event) {\n if (event.key === \" \") {\n setIsPressed(true);\n }\n },\n onKeyUp(event) {\n if (event.key === \" \") {\n setIsPressed(false);\n }\n },\n }),\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/lib/index.mjs ADDED
@@ -0,0 +1,136 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/index.ts
5
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
6
+ import { useState } from "react";
7
+ import { dataAttr, elementProps, inputProps, labelProps } from "@seed-design/dom-utils";
8
+ function useCheckboxState(props) {
9
+ const [isChecked, setIsChecked] = useControllableState({
10
+ prop: props.checked,
11
+ defaultProp: props.defaultChecked,
12
+ onChange: props.onCheckedChange
13
+ });
14
+ const [isHovered, setIsHovered] = useState(false);
15
+ const [isPressed, setIsPressed] = useState(false);
16
+ const [isFocused, setIsFocused] = useState(false);
17
+ const [isFocusVisible, setIsFocusVisible] = useState(false);
18
+ return {
19
+ isChecked,
20
+ setIsChecked,
21
+ isHovered,
22
+ setIsHovered,
23
+ isPressed,
24
+ setIsPressed,
25
+ isFocused,
26
+ setIsFocused,
27
+ isFocusVisible,
28
+ setIsFocusVisible
29
+ };
30
+ }
31
+ __name(useCheckboxState, "useCheckboxState");
32
+ function useCheckbox(props) {
33
+ const {
34
+ checked,
35
+ defaultChecked,
36
+ disabled,
37
+ form,
38
+ invalid,
39
+ name,
40
+ onCheckedChange,
41
+ required,
42
+ value,
43
+ ...restProps
44
+ } = props;
45
+ const {
46
+ setIsChecked,
47
+ isChecked,
48
+ setIsHovered,
49
+ isHovered,
50
+ setIsPressed,
51
+ isPressed,
52
+ setIsFocused,
53
+ isFocused,
54
+ setIsFocusVisible,
55
+ isFocusVisible
56
+ } = useCheckboxState(props);
57
+ const stateProps = {
58
+ "data-checked": dataAttr(isChecked),
59
+ "data-hover": dataAttr(isHovered),
60
+ "data-active": dataAttr(isPressed),
61
+ "data-focus": dataAttr(isFocused),
62
+ "data-focus-visible": dataAttr(isFocusVisible),
63
+ "data-disabled": dataAttr(props.disabled)
64
+ };
65
+ const isControlled = checked != null;
66
+ return {
67
+ isChecked,
68
+ setIsChecked,
69
+ isFocused,
70
+ setIsFocused,
71
+ setIsFocusVisible,
72
+ restProps,
73
+ stateProps,
74
+ rootProps: labelProps({
75
+ ...stateProps,
76
+ onPointerMove() {
77
+ setIsHovered(true);
78
+ },
79
+ onPointerDown() {
80
+ setIsPressed(true);
81
+ },
82
+ onPointerUp() {
83
+ setIsPressed(false);
84
+ },
85
+ onPointerLeave() {
86
+ setIsHovered(false);
87
+ setIsPressed(false);
88
+ }
89
+ }),
90
+ controlProps: elementProps({
91
+ ...stateProps,
92
+ "aria-hidden": true
93
+ }),
94
+ hiddenInputProps: inputProps({
95
+ type: "checkbox",
96
+ defaultChecked,
97
+ checked: isControlled ? isChecked : void 0,
98
+ disabled: props.disabled,
99
+ required: props.required,
100
+ "aria-invalid": props.invalid,
101
+ name: props.name,
102
+ form: props.form,
103
+ value: props.value,
104
+ ...stateProps,
105
+ onChange(event) {
106
+ setIsChecked(event.currentTarget.checked);
107
+ setIsFocusVisible(event.target.matches(":focus-visible"));
108
+ },
109
+ onFocus(event) {
110
+ setIsFocused(true);
111
+ setIsFocusVisible(event.target.matches(":focus-visible"));
112
+ },
113
+ onBlur() {
114
+ setIsFocused(false);
115
+ setIsFocusVisible(false);
116
+ },
117
+ onKeyDown(event) {
118
+ if (event.key === " ") {
119
+ setIsPressed(true);
120
+ }
121
+ },
122
+ onKeyUp(event) {
123
+ if (event.key === " ") {
124
+ setIsPressed(false);
125
+ }
126
+ }
127
+ })
128
+ };
129
+ }
130
+ __name(useCheckbox, "useCheckbox");
131
+ export {
132
+ useCheckbox,
133
+ useCheckboxState
134
+ };
135
+ /*! For license information please see index.mjs.LEGAL.txt */
136
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useState } from \"react\";\n\nimport { dataAttr, elementProps, inputProps, labelProps } from \"@seed-design/dom-utils\";\n\nexport interface UseCheckboxStateProps {\n checked?: boolean;\n\n defaultChecked?: boolean;\n\n onCheckedChange?: (checked: boolean) => void;\n}\n\nexport function useCheckboxState(props: UseCheckboxStateProps) {\n const [isChecked, setIsChecked] = useControllableState({\n prop: props.checked,\n defaultProp: props.defaultChecked,\n onChange: props.onCheckedChange,\n });\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n\n return {\n isChecked,\n setIsChecked,\n isHovered,\n setIsHovered,\n isPressed,\n setIsPressed,\n isFocused,\n setIsFocused,\n isFocusVisible,\n setIsFocusVisible,\n };\n}\n\nexport interface UseCheckboxProps extends UseCheckboxStateProps {\n disabled?: boolean;\n\n required?: boolean;\n\n invalid?: boolean;\n\n name?: string;\n\n form?: string;\n\n value?: string;\n}\n\nexport function useCheckbox(props: UseCheckboxProps) {\n const {\n checked,\n defaultChecked,\n disabled,\n form,\n invalid,\n name,\n onCheckedChange,\n required,\n value,\n ...restProps\n } = props;\n\n const {\n setIsChecked,\n isChecked,\n setIsHovered,\n isHovered,\n setIsPressed,\n isPressed,\n setIsFocused,\n isFocused,\n setIsFocusVisible,\n isFocusVisible,\n } = useCheckboxState(props);\n\n const stateProps = {\n \"data-checked\": dataAttr(isChecked),\n \"data-hover\": dataAttr(isHovered),\n \"data-active\": dataAttr(isPressed),\n \"data-focus\": dataAttr(isFocused),\n \"data-focus-visible\": dataAttr(isFocusVisible),\n \"data-disabled\": dataAttr(props.disabled),\n };\n\n const isControlled = checked != null;\n\n return {\n isChecked,\n setIsChecked,\n isFocused,\n setIsFocused,\n setIsFocusVisible,\n\n restProps,\n stateProps,\n rootProps: labelProps({\n ...stateProps,\n onPointerMove() {\n setIsHovered(true);\n },\n onPointerDown() {\n setIsPressed(true);\n },\n onPointerUp() {\n setIsPressed(false);\n },\n onPointerLeave() {\n setIsHovered(false);\n setIsPressed(false);\n },\n }),\n\n controlProps: elementProps({\n ...stateProps,\n \"aria-hidden\": true,\n }),\n\n hiddenInputProps: inputProps({\n type: \"checkbox\",\n defaultChecked,\n checked: isControlled ? isChecked : undefined,\n disabled: props.disabled,\n required: props.required,\n \"aria-invalid\": props.invalid,\n name: props.name,\n form: props.form,\n value: props.value,\n ...stateProps,\n onChange(event) {\n setIsChecked(event.currentTarget.checked);\n setIsFocusVisible(event.target.matches(\":focus-visible\"));\n },\n onFocus(event) {\n setIsFocused(true);\n setIsFocusVisible(event.target.matches(\":focus-visible\"));\n },\n onBlur() {\n setIsFocused(false);\n setIsFocusVisible(false);\n },\n onKeyDown(event) {\n if (event.key === \" \") {\n setIsPressed(true);\n }\n },\n onKeyUp(event) {\n if (event.key === \" \") {\n setIsPressed(false);\n }\n },\n }),\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@seed-design/react-checkbox",
3
+ "version": "0.0.0-alpha-20241004093556",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/daangn/seed-design.git",
7
+ "directory": "packages/react-headless/checkbox"
8
+ },
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./lib/index.d.ts",
13
+ "require": "./lib/index.js",
14
+ "import": "./lib/index.mjs"
15
+ }
16
+ },
17
+ "main": "./lib/index.js",
18
+ "files": [
19
+ "lib",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "prepack": "rm -rf lib && yarn build",
24
+ "build": "nanobundle build"
25
+ },
26
+ "dependencies": {
27
+ "@radix-ui/react-use-controllable-state": "1.0.1",
28
+ "@seed-design/dom-utils": "0.0.0-alpha-20241004093556"
29
+ },
30
+ "devDependencies": {
31
+ "nanobundle": "^1.6.0"
32
+ },
33
+ "peerDependencies": {
34
+ "react": ">=18.0.0",
35
+ "react-dom": ">=18.0.0"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "ultra": {
41
+ "concurrent": [
42
+ "dev",
43
+ "build"
44
+ ]
45
+ }
46
+ }
package/src/index.ts ADDED
@@ -0,0 +1,157 @@
1
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
2
+ import { useState } from "react";
3
+
4
+ import { dataAttr, elementProps, inputProps, labelProps } from "@seed-design/dom-utils";
5
+
6
+ export interface UseCheckboxStateProps {
7
+ checked?: boolean;
8
+
9
+ defaultChecked?: boolean;
10
+
11
+ onCheckedChange?: (checked: boolean) => void;
12
+ }
13
+
14
+ export function useCheckboxState(props: UseCheckboxStateProps) {
15
+ const [isChecked, setIsChecked] = useControllableState({
16
+ prop: props.checked,
17
+ defaultProp: props.defaultChecked,
18
+ onChange: props.onCheckedChange,
19
+ });
20
+ const [isHovered, setIsHovered] = useState(false);
21
+ const [isPressed, setIsPressed] = useState(false);
22
+ const [isFocused, setIsFocused] = useState(false);
23
+ const [isFocusVisible, setIsFocusVisible] = useState(false);
24
+
25
+ return {
26
+ isChecked,
27
+ setIsChecked,
28
+ isHovered,
29
+ setIsHovered,
30
+ isPressed,
31
+ setIsPressed,
32
+ isFocused,
33
+ setIsFocused,
34
+ isFocusVisible,
35
+ setIsFocusVisible,
36
+ };
37
+ }
38
+
39
+ export interface UseCheckboxProps extends UseCheckboxStateProps {
40
+ disabled?: boolean;
41
+
42
+ required?: boolean;
43
+
44
+ invalid?: boolean;
45
+
46
+ name?: string;
47
+
48
+ form?: string;
49
+
50
+ value?: string;
51
+ }
52
+
53
+ export function useCheckbox(props: UseCheckboxProps) {
54
+ const {
55
+ checked,
56
+ defaultChecked,
57
+ disabled,
58
+ form,
59
+ invalid,
60
+ name,
61
+ onCheckedChange,
62
+ required,
63
+ value,
64
+ ...restProps
65
+ } = props;
66
+
67
+ const {
68
+ setIsChecked,
69
+ isChecked,
70
+ setIsHovered,
71
+ isHovered,
72
+ setIsPressed,
73
+ isPressed,
74
+ setIsFocused,
75
+ isFocused,
76
+ setIsFocusVisible,
77
+ isFocusVisible,
78
+ } = useCheckboxState(props);
79
+
80
+ const stateProps = {
81
+ "data-checked": dataAttr(isChecked),
82
+ "data-hover": dataAttr(isHovered),
83
+ "data-active": dataAttr(isPressed),
84
+ "data-focus": dataAttr(isFocused),
85
+ "data-focus-visible": dataAttr(isFocusVisible),
86
+ "data-disabled": dataAttr(props.disabled),
87
+ };
88
+
89
+ const isControlled = checked != null;
90
+
91
+ return {
92
+ isChecked,
93
+ setIsChecked,
94
+ isFocused,
95
+ setIsFocused,
96
+ setIsFocusVisible,
97
+
98
+ restProps,
99
+ stateProps,
100
+ rootProps: labelProps({
101
+ ...stateProps,
102
+ onPointerMove() {
103
+ setIsHovered(true);
104
+ },
105
+ onPointerDown() {
106
+ setIsPressed(true);
107
+ },
108
+ onPointerUp() {
109
+ setIsPressed(false);
110
+ },
111
+ onPointerLeave() {
112
+ setIsHovered(false);
113
+ setIsPressed(false);
114
+ },
115
+ }),
116
+
117
+ controlProps: elementProps({
118
+ ...stateProps,
119
+ "aria-hidden": true,
120
+ }),
121
+
122
+ hiddenInputProps: inputProps({
123
+ type: "checkbox",
124
+ defaultChecked,
125
+ checked: isControlled ? isChecked : undefined,
126
+ disabled: props.disabled,
127
+ required: props.required,
128
+ "aria-invalid": props.invalid,
129
+ name: props.name,
130
+ form: props.form,
131
+ value: props.value,
132
+ ...stateProps,
133
+ onChange(event) {
134
+ setIsChecked(event.currentTarget.checked);
135
+ setIsFocusVisible(event.target.matches(":focus-visible"));
136
+ },
137
+ onFocus(event) {
138
+ setIsFocused(true);
139
+ setIsFocusVisible(event.target.matches(":focus-visible"));
140
+ },
141
+ onBlur() {
142
+ setIsFocused(false);
143
+ setIsFocusVisible(false);
144
+ },
145
+ onKeyDown(event) {
146
+ if (event.key === " ") {
147
+ setIsPressed(true);
148
+ }
149
+ },
150
+ onKeyUp(event) {
151
+ if (event.key === " ") {
152
+ setIsPressed(false);
153
+ }
154
+ },
155
+ }),
156
+ };
157
+ }
@@ -0,0 +1,174 @@
1
+ import "@testing-library/jest-dom/vitest";
2
+ import { cleanup, render } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ import type { ReactElement } from "react";
7
+ import * as React from "react";
8
+
9
+ import { useCheckbox, type UseCheckboxProps } from "./index";
10
+
11
+ afterEach(cleanup);
12
+
13
+ function setUp(jsx: ReactElement) {
14
+ return {
15
+ user: userEvent.setup(),
16
+ ...render(jsx),
17
+ };
18
+ }
19
+
20
+ function Checkbox(props: UseCheckboxProps) {
21
+ const { controlProps, hiddenInputProps, restProps, rootProps, stateProps } = useCheckbox(props);
22
+ return (
23
+ <label {...rootProps}>
24
+ <div {...controlProps}>
25
+ <svg {...stateProps} />
26
+ </div>
27
+ <input {...hiddenInputProps} {...restProps} />
28
+ <span {...stateProps} />
29
+ </label>
30
+ );
31
+ }
32
+
33
+ describe("useCheckbox", () => {
34
+ it("should render the checkbox correctly", () => {
35
+ const { getByRole } = setUp(<Checkbox />);
36
+ const checkbox = getByRole("checkbox");
37
+
38
+ expect(checkbox).not.toBeChecked();
39
+ });
40
+
41
+ it("should render the checkbox with defaultChecked=true", () => {
42
+ const { getByRole } = setUp(<Checkbox defaultChecked={true} />);
43
+ const checkbox = getByRole("checkbox");
44
+
45
+ expect(checkbox).toBeChecked();
46
+ });
47
+
48
+ it("should render the checkbox with defaultChecked=false", () => {
49
+ const { getByRole } = setUp(<Checkbox defaultChecked={false} />);
50
+ const checkbox = getByRole("checkbox");
51
+
52
+ expect(checkbox).not.toBeChecked();
53
+ });
54
+
55
+ it("should checked when clicked", async () => {
56
+ const { getByRole, user } = setUp(<Checkbox />);
57
+ const checkbox = getByRole("checkbox");
58
+
59
+ await user.click(checkbox);
60
+ expect(checkbox).toBeChecked();
61
+ });
62
+
63
+ it("should onCheckedChange is called when clicked", async () => {
64
+ const handleCheckedChange = vi.fn();
65
+
66
+ const { getByRole, user } = setUp(<Checkbox onCheckedChange={handleCheckedChange} />);
67
+ const checkbox = getByRole("checkbox");
68
+
69
+ await user.click(checkbox);
70
+ expect(handleCheckedChange).toHaveBeenCalledWith(true);
71
+ });
72
+
73
+ it("should hover state updates correctly", async () => {
74
+ const { getByRole, user } = setUp(<Checkbox />);
75
+ const checkbox = getByRole("checkbox");
76
+
77
+ await user.hover(checkbox);
78
+ expect(checkbox).toHaveAttribute("data-hover");
79
+
80
+ await user.unhover(checkbox);
81
+ expect(checkbox).not.toHaveAttribute("data-hover");
82
+ });
83
+
84
+ it("should focus state updates correctly", async () => {
85
+ const { getByRole, user } = setUp(<Checkbox />);
86
+ const checkbox = getByRole("checkbox");
87
+
88
+ await user.click(checkbox);
89
+ expect(checkbox).toHaveFocus();
90
+
91
+ await user.click(document.body);
92
+ expect(checkbox).not.toHaveFocus();
93
+ });
94
+
95
+ it("should required state when required prop is true", () => {
96
+ const { getByRole } = setUp(<Checkbox required={true} />);
97
+ const checkbox = getByRole("checkbox");
98
+
99
+ expect(checkbox).toBeRequired();
100
+ });
101
+
102
+ describe("disabled prop test", () => {
103
+ it("should disabled when disabled prop is true", async () => {
104
+ const { getByRole } = setUp(<Checkbox disabled={true} />);
105
+ const checkbox = getByRole("checkbox");
106
+
107
+ expect(checkbox).toBeDisabled();
108
+ });
109
+
110
+ it("should not change checked state when clicked", async () => {
111
+ const { getByRole, user } = setUp(<Checkbox disabled={true} />);
112
+ const checkbox = getByRole("checkbox");
113
+
114
+ await user.click(checkbox);
115
+ expect(checkbox).not.toBeChecked();
116
+ });
117
+
118
+ it("should not onCheckedChange be called when clicked", async () => {
119
+ const handleCheckedChange = vi.fn();
120
+
121
+ const { getByRole, user } = setUp(
122
+ <Checkbox disabled={true} onCheckedChange={handleCheckedChange} />,
123
+ );
124
+ const checkbox = getByRole("checkbox");
125
+
126
+ await user.click(checkbox);
127
+ expect(handleCheckedChange).not.toHaveBeenCalled();
128
+ });
129
+ });
130
+
131
+ describe("form integration", () => {
132
+ it("should reset the checkbox state on form reset", async () => {
133
+ const { getByRole, user } = setUp(
134
+ <form>
135
+ <Checkbox defaultChecked={true} />
136
+ <button type="reset">Reset</button>
137
+ </form>,
138
+ );
139
+
140
+ const checkbox = getByRole("checkbox");
141
+ const resetButton = getByRole("button", { name: /reset/i });
142
+
143
+ await user.click(checkbox);
144
+
145
+ expect(checkbox).not.toBeChecked();
146
+
147
+ await user.click(resetButton);
148
+
149
+ expect(checkbox).toBeChecked();
150
+ });
151
+
152
+ it("should mark the checkbox as invalid if it's required and not checked", async () => {
153
+ const { getByRole, user } = setUp(
154
+ <form>
155
+ <Checkbox required={true} />
156
+ <button type="submit">Submit</button>
157
+ </form>,
158
+ );
159
+
160
+ const checkbox = getByRole("checkbox");
161
+ const submitButton = getByRole("button", { name: /submit/i });
162
+
163
+ await user.click(submitButton);
164
+
165
+ // Required field should be invalid if not checked
166
+ expect(checkbox).toBeInvalid();
167
+
168
+ await user.click(checkbox);
169
+
170
+ // Required field should be valid if checked
171
+ expect(checkbox).toBeValid();
172
+ });
173
+ });
174
+ });