@arun-dev/headless 4.0.0 → 4.2.0

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.
@@ -0,0 +1,157 @@
1
+ import {
2
+ useControlled
3
+ } from "../chunk-UEIB3I3T.js";
4
+ import {
5
+ __export,
6
+ useRender
7
+ } from "../chunk-OQTWWZ4B.js";
8
+
9
+ // src/radio-group/index.parts.ts
10
+ var index_parts_exports = {};
11
+ __export(index_parts_exports, {
12
+ Item: () => RadioGroupItem,
13
+ Root: () => RadioGroupRoot
14
+ });
15
+
16
+ // src/radio-group/RadioGroupRoot.tsx
17
+ import { useCallback, useEffect, useId, useMemo, useRef } from "react";
18
+
19
+ // src/radio-group/RadioGroupRootContext.ts
20
+ import { createContext, useContext } from "react";
21
+ var RadioGroupRootContext = createContext(null);
22
+ function useRadioGroupRootContext() {
23
+ const context = useContext(RadioGroupRootContext);
24
+ if (context === null) {
25
+ throw new Error("<RadioGroup.Item> must be rendered inside <RadioGroup.Root>.");
26
+ }
27
+ return context;
28
+ }
29
+
30
+ // src/radio-group/radioGroupDataAttributes.ts
31
+ function radioGroupItemDataAttributes({ checked, disabled }) {
32
+ return {
33
+ "data-checked": checked ? "" : void 0,
34
+ "data-unchecked": checked ? void 0 : "",
35
+ "data-disabled": disabled ? "" : void 0
36
+ };
37
+ }
38
+ function radioGroupDataAttributes({ disabled }) {
39
+ return {
40
+ "data-disabled": disabled ? "" : void 0
41
+ };
42
+ }
43
+
44
+ // src/radio-group/RadioGroupRoot.tsx
45
+ import { jsx } from "react/jsx-runtime";
46
+ function radiosIn(root, name) {
47
+ if (!root) return [];
48
+ return [...root.querySelectorAll('input[type="radio"]')].filter(
49
+ (input) => input.name === name
50
+ );
51
+ }
52
+ function RadioGroupRoot({
53
+ value: valueProp,
54
+ defaultValue,
55
+ onValueChange,
56
+ name: nameProp,
57
+ disabled = false,
58
+ required = false,
59
+ form,
60
+ className,
61
+ children,
62
+ render,
63
+ ...rest
64
+ }) {
65
+ const [value, setValue] = useControlled({
66
+ controlled: valueProp,
67
+ default: defaultValue ?? null,
68
+ name: "RadioGroup.Root",
69
+ state: "value"
70
+ });
71
+ const generatedName = useId();
72
+ const name = nameProp ?? generatedName;
73
+ const commitValue = useCallback(
74
+ (next) => {
75
+ setValue(next);
76
+ onValueChange?.(next);
77
+ },
78
+ [setValue, onValueChange]
79
+ );
80
+ const elementRef = useRef(null);
81
+ const { current: initialValue } = useRef(value);
82
+ useEffect(() => {
83
+ const owner = radiosIn(elementRef.current, name)[0]?.form;
84
+ if (!owner) return;
85
+ function onReset(event) {
86
+ queueMicrotask(() => {
87
+ if (event.defaultPrevented) return;
88
+ for (const input of radiosIn(elementRef.current, name)) {
89
+ input.checked = input.value === value;
90
+ }
91
+ if (value === initialValue) return;
92
+ commitValue(initialValue);
93
+ });
94
+ }
95
+ owner.addEventListener("reset", onReset);
96
+ return () => owner.removeEventListener("reset", onReset);
97
+ }, [name, value, commitValue, initialValue]);
98
+ const state = useMemo(
99
+ () => ({ value, disabled, required, name, form, select: commitValue }),
100
+ [value, disabled, required, name, form, commitValue]
101
+ );
102
+ const element = useRender({
103
+ render,
104
+ defaultTagName: "div",
105
+ props: {
106
+ role: "radiogroup",
107
+ "aria-disabled": disabled || void 0,
108
+ "aria-required": required || void 0,
109
+ ...radioGroupDataAttributes(state),
110
+ className,
111
+ children,
112
+ ref: elementRef
113
+ },
114
+ consumerProps: rest
115
+ });
116
+ return /* @__PURE__ */ jsx(RadioGroupRootContext.Provider, { value: state, children: element });
117
+ }
118
+
119
+ // src/radio-group/RadioGroupItem.tsx
120
+ import { useMemo as useMemo2 } from "react";
121
+ function RadioGroupItem({
122
+ value,
123
+ disabled: disabledProp = false,
124
+ className,
125
+ render,
126
+ ...rest
127
+ }) {
128
+ const group = useRadioGroupRootContext();
129
+ const disabled = group.disabled || disabledProp;
130
+ const checked = group.value === value;
131
+ const state = useMemo2(() => ({ checked, disabled }), [checked, disabled]);
132
+ return useRender({
133
+ render,
134
+ defaultTagName: "input",
135
+ props: {
136
+ type: "radio",
137
+ name: group.name,
138
+ value,
139
+ // Controlled from the group's value, so React restores it after any change the
140
+ // group declines — the platform never gets the last word on what is checked.
141
+ checked,
142
+ form: group.form,
143
+ required: group.required || void 0,
144
+ disabled: disabled || void 0,
145
+ ...radioGroupItemDataAttributes(state),
146
+ className,
147
+ onChange() {
148
+ if (disabled) return;
149
+ group.select(value);
150
+ }
151
+ },
152
+ consumerProps: rest
153
+ });
154
+ }
155
+ export {
156
+ index_parts_exports as RadioGroup
157
+ };
@@ -32,7 +32,7 @@ __export(index_parts_exports, {
32
32
  });
33
33
 
34
34
  // src/switch/SwitchRoot.tsx
35
- var import_react4 = require("react");
35
+ var import_react5 = require("react");
36
36
 
37
37
  // src/core/useControlled.ts
38
38
  var import_react = require("react");
@@ -67,8 +67,34 @@ function useControlled({
67
67
  return [value, setValue];
68
68
  }
69
69
 
70
- // src/core/useRender.ts
70
+ // src/core/useFormReset.ts
71
71
  var import_react2 = require("react");
72
+ function useFormReset({
73
+ elementRef,
74
+ inputRef,
75
+ value,
76
+ inputChecked,
77
+ commit
78
+ }) {
79
+ const { current: initialValue } = (0, import_react2.useRef)(value);
80
+ (0, import_react2.useEffect)(() => {
81
+ const form = elementRef.current?.form;
82
+ if (!form) return;
83
+ function onReset(event) {
84
+ queueMicrotask(() => {
85
+ if (event.defaultPrevented) return;
86
+ if (inputRef.current) inputRef.current.checked = inputChecked;
87
+ if (value === initialValue) return;
88
+ commit(initialValue);
89
+ });
90
+ }
91
+ form.addEventListener("reset", onReset);
92
+ return () => form.removeEventListener("reset", onReset);
93
+ }, [elementRef, inputRef, value, inputChecked, commit, initialValue]);
94
+ }
95
+
96
+ // src/core/useRender.ts
97
+ var import_react3 = require("react");
72
98
 
73
99
  // src/core/mergeProps.ts
74
100
  function isEventHandler(key) {
@@ -150,17 +176,17 @@ function useRender({
150
176
  consumerProps
151
177
  }) {
152
178
  const merged = mergeProps(props, consumerProps);
153
- if ((0, import_react2.isValidElement)(render)) {
154
- return (0, import_react2.cloneElement)(render, mergeProps(merged, render.props));
179
+ if ((0, import_react3.isValidElement)(render)) {
180
+ return (0, import_react3.cloneElement)(render, mergeProps(merged, render.props));
155
181
  }
156
- return (0, import_react2.createElement)(defaultTagName, merged);
182
+ return (0, import_react3.createElement)(defaultTagName, merged);
157
183
  }
158
184
 
159
185
  // src/switch/SwitchRootContext.ts
160
- var import_react3 = require("react");
161
- var SwitchRootContext = (0, import_react3.createContext)(null);
186
+ var import_react4 = require("react");
187
+ var SwitchRootContext = (0, import_react4.createContext)(null);
162
188
  function useSwitchRootContext() {
163
- const context = (0, import_react3.useContext)(SwitchRootContext);
189
+ const context = (0, import_react4.useContext)(SwitchRootContext);
164
190
  if (context === null) {
165
191
  throw new Error("<Switch.Thumb> must be rendered inside <Switch.Root>.");
166
192
  }
@@ -196,17 +222,23 @@ function SwitchRoot({
196
222
  name: "Switch.Root",
197
223
  state: "checked"
198
224
  });
199
- const commitChecked = (0, import_react4.useCallback)(
225
+ const commitChecked = (0, import_react5.useCallback)(
200
226
  (next) => {
201
227
  setChecked(next);
202
228
  onCheckedChange?.(next);
203
229
  },
204
230
  [setChecked, onCheckedChange]
205
231
  );
206
- const state = (0, import_react4.useMemo)(() => ({ checked, disabled }), [checked, disabled]);
207
- const elementRef = (0, import_react4.useRef)(null);
208
- const inputRef = (0, import_react4.useRef)(null);
209
- useFormReset({ elementRef, inputRef, checked, commitChecked });
232
+ const state = (0, import_react5.useMemo)(() => ({ checked, disabled }), [checked, disabled]);
233
+ const elementRef = (0, import_react5.useRef)(null);
234
+ const inputRef = (0, import_react5.useRef)(null);
235
+ useFormReset({
236
+ elementRef,
237
+ inputRef,
238
+ value: checked,
239
+ inputChecked: checked,
240
+ commit: commitChecked
241
+ });
210
242
  const element = useRender({
211
243
  render,
212
244
  defaultTagName: "button",
@@ -245,28 +277,6 @@ function SwitchRoot({
245
277
  ) : null
246
278
  ] });
247
279
  }
248
- function useFormReset({
249
- elementRef,
250
- inputRef,
251
- checked,
252
- commitChecked
253
- }) {
254
- const { current: initialChecked } = (0, import_react4.useRef)(checked);
255
- (0, import_react4.useEffect)(() => {
256
- const form = elementRef.current?.form;
257
- if (!form) return;
258
- function onReset(event) {
259
- queueMicrotask(() => {
260
- if (event.defaultPrevented) return;
261
- if (inputRef.current) inputRef.current.checked = checked;
262
- if (checked === initialChecked) return;
263
- commitChecked(initialChecked);
264
- });
265
- }
266
- form.addEventListener("reset", onReset);
267
- return () => form.removeEventListener("reset", onReset);
268
- }, [elementRef, inputRef, checked, commitChecked, initialChecked]);
269
- }
270
280
 
271
281
  // src/switch/SwitchThumb.tsx
272
282
  function SwitchThumb({ className, children, render, ...rest }) {
@@ -1,3 +1,6 @@
1
+ import {
2
+ useFormReset
3
+ } from "../chunk-IWUVUY76.js";
1
4
  import {
2
5
  useControlled
3
6
  } from "../chunk-UEIB3I3T.js";
@@ -14,7 +17,7 @@ __export(index_parts_exports, {
14
17
  });
15
18
 
16
19
  // src/switch/SwitchRoot.tsx
17
- import { useCallback, useEffect, useMemo, useRef } from "react";
20
+ import { useCallback, useMemo, useRef } from "react";
18
21
 
19
22
  // src/switch/SwitchRootContext.ts
20
23
  import { createContext, useContext } from "react";
@@ -66,7 +69,13 @@ function SwitchRoot({
66
69
  const state = useMemo(() => ({ checked, disabled }), [checked, disabled]);
67
70
  const elementRef = useRef(null);
68
71
  const inputRef = useRef(null);
69
- useFormReset({ elementRef, inputRef, checked, commitChecked });
72
+ useFormReset({
73
+ elementRef,
74
+ inputRef,
75
+ value: checked,
76
+ inputChecked: checked,
77
+ commit: commitChecked
78
+ });
70
79
  const element = useRender({
71
80
  render,
72
81
  defaultTagName: "button",
@@ -105,28 +114,6 @@ function SwitchRoot({
105
114
  ) : null
106
115
  ] });
107
116
  }
108
- function useFormReset({
109
- elementRef,
110
- inputRef,
111
- checked,
112
- commitChecked
113
- }) {
114
- const { current: initialChecked } = useRef(checked);
115
- useEffect(() => {
116
- const form = elementRef.current?.form;
117
- if (!form) return;
118
- function onReset(event) {
119
- queueMicrotask(() => {
120
- if (event.defaultPrevented) return;
121
- if (inputRef.current) inputRef.current.checked = checked;
122
- if (checked === initialChecked) return;
123
- commitChecked(initialChecked);
124
- });
125
- }
126
- form.addEventListener("reset", onReset);
127
- return () => form.removeEventListener("reset", onReset);
128
- }, [elementRef, inputRef, checked, commitChecked, initialChecked]);
129
- }
130
117
 
131
118
  // src/switch/SwitchThumb.tsx
132
119
  function SwitchThumb({ className, children, render, ...rest }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arun-dev/headless",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "Unstyled React behaviour primitives — render engine, controlled/uncontrolled state, and data-* state projection. Ships no CSS and no class names.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,6 +44,26 @@
44
44
  "default": "./dist/button/index.cjs"
45
45
  }
46
46
  },
47
+ "./checkbox": {
48
+ "import": {
49
+ "types": "./dist/checkbox/index.d.ts",
50
+ "default": "./dist/checkbox/index.js"
51
+ },
52
+ "require": {
53
+ "types": "./dist/checkbox/index.d.cts",
54
+ "default": "./dist/checkbox/index.cjs"
55
+ }
56
+ },
57
+ "./radio-group": {
58
+ "import": {
59
+ "types": "./dist/radio-group/index.d.ts",
60
+ "default": "./dist/radio-group/index.js"
61
+ },
62
+ "require": {
63
+ "types": "./dist/radio-group/index.d.cts",
64
+ "default": "./dist/radio-group/index.cjs"
65
+ }
66
+ },
47
67
  "./switch": {
48
68
  "import": {
49
69
  "types": "./dist/switch/index.d.ts",