@arun-dev/headless 2.1.0 → 3.0.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.
package/README.md CHANGED
@@ -28,18 +28,20 @@ import { Switch } from '@arun-dev/headless/switch';
28
28
 
29
29
  | Component | Parts | Props |
30
30
  | --------- | ----------------------- | --------------------------------------------------------------------------- |
31
- | `Button` | — | `disabled`, `nativeButton` |
31
+ | `Button` | — | `disabled`, `href`, `type` |
32
32
  | `Switch` | `Switch.Root`, `.Thumb` | `checked`, `defaultChecked`, `onCheckedChange`, `disabled`, `name`, `value` |
33
33
 
34
- `Button` exists for the moment `render` points at something that is not a `<button>`. It then
35
- supplies what the platform stops giving you — focus, `Enter` and `Space` activation, and a
36
- `disabled` state that actually disables. It takes no `href`: a control that navigates should be an
37
- anchor, so pass one in and keep middle-click, cmd-click and "link" in assistive technology.
34
+ `Button` renders a `<button>`, or a real `<a href>` when you give it an `href` — a control that
35
+ navigates should be an anchor, so middle-click, cmd-click and "link" in assistive technology all
36
+ keep working. It defaults `type="button"` so a button never submits a form by accident, and a
37
+ disabled `href` renders a `<button disabled>`, because a link that navigates nowhere is not a link.
38
38
 
39
39
  ```tsx
40
40
  import { Button } from '@arun-dev/headless/button';
41
41
 
42
- <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>;
42
+ <Button href="/docs" target="_blank" rel="noreferrer">
43
+ Docs
44
+ </Button>;
43
45
  ```
44
46
 
45
47
  `Switch.Root` renders a native `<button>`, so focus, `Space`, `Enter` and disabled semantics come
@@ -87,6 +89,15 @@ Every part takes a `render` prop to change the element, and spreads unrecognised
87
89
  `className` is concatenated, `style` is merged, and refs are merged — so a `ref` on the `render`
88
90
  element and a `ref` on the component both receive the node.
89
91
 
92
+ Everything else, `children` included, follows the plain rule: the `render` element's own props
93
+ come last and win. An element that declares no children inherits yours, one that declares some
94
+ keeps them.
95
+
96
+ ```tsx
97
+ <Button render={<a href="/docs" />}>Docs</Button> // renders "Docs"
98
+ <Button render={<a href="/docs">Read the docs</a>}>Docs</Button> // renders "Read the docs"
99
+ ```
100
+
90
101
  Event handlers are chained rather than replaced, and **your handler runs before the component's**,
91
102
  so you can stop it:
92
103
 
@@ -101,24 +112,23 @@ so you can stop it:
101
112
  The primitives the components are built from are exported from the root, for building your own:
102
113
 
103
114
  ```ts
104
- import {
105
- useRender,
106
- useControlled,
107
- mergeProps,
108
- getStateAttributes,
109
- booleanAttribute,
110
- } from '@arun-dev/headless';
115
+ import { useRender, useControlled, mergeProps } from '@arun-dev/headless';
111
116
  ```
112
117
 
113
- | Export | Purpose |
114
- | -------------------- | ----------------------------------------------------------------------------- |
115
- | `useRender` | Resolves what a part renders — merges props, projects state, applies `render` |
116
- | `useControlled` | One value, controlled or uncontrolled, decided at mount |
117
- | `mergeProps` | Merges prop objects: handlers chain, `className` concatenates, refs merge |
118
- | `getStateAttributes` | Projects a state object onto `data-*` attributes via a declared mapping |
119
- | `booleanAttribute` | The common mapping — one attribute when true, another when false |
120
- | `disabledAttribute` | The shared spelling of `data-disabled`, so every component agrees on it |
121
- | `ComponentEvent` | Type for a handler that can call `preventComponentHandler()` |
118
+ | Export | Purpose |
119
+ | ---------------- | ------------------------------------------------------------------------- |
120
+ | `useRender` | Resolves what a part renders — merges props and applies `render` |
121
+ | `useControlled` | One value, controlled or uncontrolled, decided at mount |
122
+ | `mergeProps` | Merges prop objects: handlers chain, `className` concatenates, refs merge |
123
+ | `ComponentEvent` | Type for a handler that can call `preventComponentHandler()` |
124
+
125
+ State attributes are plain objects a component spreads onto its element — React drops the
126
+ `undefined` ones — so there is no mapping layer to learn:
127
+
128
+ ```ts
129
+ 'data-checked': checked ? '' : undefined,
130
+ 'data-unchecked': checked ? undefined : '',
131
+ ```
122
132
 
123
133
  Everything this library uses to implement its own components stays private, so it can
124
134
  change without breaking anyone. The public surface is the table above plus the
@@ -24,9 +24,6 @@ __export(button_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(button_exports);
26
26
 
27
- // src/button/Button.tsx
28
- var import_react3 = require("react");
29
-
30
27
  // src/core/useRender.ts
31
28
  var import_react = require("react");
32
29
 
@@ -62,18 +59,9 @@ function isSyntheticEvent(event) {
62
59
  function makeEventPreventable(event) {
63
60
  if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
64
61
  const target = event;
65
- const prevent = () => {
62
+ target.preventComponentHandler = () => {
66
63
  target.componentHandlerPrevented = true;
67
64
  };
68
- target.preventComponentHandler = prevent;
69
- const native = event.nativeEvent;
70
- const stopImmediate = native?.stopImmediatePropagation?.bind(native);
71
- if (native && stopImmediate) {
72
- native.stopImmediatePropagation = () => {
73
- stopImmediate();
74
- prevent();
75
- };
76
- }
77
65
  }
78
66
  function isComponentHandlerPrevented(event) {
79
67
  return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
@@ -111,150 +99,51 @@ function mergeProps(...objects) {
111
99
  return merged;
112
100
  }
113
101
 
114
- // src/core/stateAttributes.ts
115
- function getStateAttributes(state, mapping) {
116
- if (!mapping) return {};
117
- const attributes = {};
118
- for (const key of Object.keys(state)) {
119
- const toAttributes = mapping[key];
120
- if (!toAttributes) continue;
121
- const result = toAttributes(state[key]);
122
- if (result) Object.assign(attributes, result);
123
- }
124
- return attributes;
125
- }
126
- function booleanAttribute(whenTrue, whenFalse) {
127
- return (value) => {
128
- if (value) return { [whenTrue]: "" };
129
- return whenFalse ? { [whenFalse]: "" } : null;
130
- };
131
- }
132
- var disabledAttribute = booleanAttribute("data-disabled");
133
-
134
102
  // src/core/useRender.ts
135
103
  function useRender({
136
104
  render,
137
105
  defaultTagName,
138
106
  props,
139
- consumerProps,
140
- state,
141
- stateAttributes
107
+ consumerProps
142
108
  }) {
143
- const attributes = state ? getStateAttributes(state, stateAttributes) : {};
144
- const merged = mergeProps(attributes, props, consumerProps);
109
+ const merged = mergeProps(props, consumerProps);
145
110
  if ((0, import_react.isValidElement)(render)) {
146
111
  return (0, import_react.cloneElement)(render, mergeProps(merged, render.props));
147
112
  }
148
113
  return (0, import_react.createElement)(defaultTagName, merged);
149
114
  }
150
115
 
151
- // src/useButton.ts
152
- var import_react2 = require("react");
153
- var ACTIVATION_HANDLERS = [
154
- "onClick",
155
- "onDoubleClick",
156
- "onMouseDown",
157
- "onMouseUp",
158
- "onPointerDown",
159
- "onPointerUp",
160
- "onTouchStart",
161
- "onTouchEnd",
162
- "onKeyDown",
163
- "onKeyUp",
164
- "onKeyPress"
165
- ];
166
- function activationHandlers() {
167
- return {
168
- onKeyDown(event) {
169
- if (event.target !== event.currentTarget || event.defaultPrevented) return;
170
- if (event.key === " ") {
171
- event.preventDefault();
172
- return;
173
- }
174
- if (event.key === "Enter") {
175
- event.preventDefault();
176
- click(event.currentTarget);
177
- }
178
- },
179
- onKeyUp(event) {
180
- if (event.target !== event.currentTarget || event.defaultPrevented) return;
181
- if (event.key === " ") click(event.currentTarget);
182
- }
183
- };
184
- }
185
- function click(element) {
186
- if (element && typeof element.click === "function") {
187
- element.click();
188
- }
189
- }
190
- function useButton({
191
- disabled = false,
192
- native,
193
- props = {}
194
- }) {
195
- const elementRef = (0, import_react2.useRef)(null);
196
- (0, import_react2.useEffect)(() => {
197
- if (process.env.NODE_ENV === "production") return;
198
- const element = elementRef.current;
199
- if (!element) return;
200
- const isButtonTag = element.tagName === "BUTTON";
201
- if (native && !isButtonTag) {
202
- console.error(
203
- `A component expected a native <button> but rendered <${element.tagName.toLowerCase()}>. Focus, keyboard activation and \`disabled\` will not behave natively.`
204
- );
205
- } else if (!native && isButtonTag) {
206
- console.error(
207
- "A component rendered a native <button> while treating it as a non-native element, so it carries synthesised attributes it does not need."
208
- );
209
- }
210
- }, [native]);
211
- return { props: buttonProps({ disabled, native, props }), ref: elementRef };
212
- }
213
- function buttonProps({ disabled, native, props }) {
214
- if (!disabled) {
215
- return native ? mergeProps({ type: "button" }, props) : mergeProps({ tabIndex: 0 }, activationHandlers(), props);
216
- }
217
- if (native) return mergeProps({ type: "button" }, props, { disabled: true, "data-disabled": "" });
218
- const sanitised = {};
219
- for (const key of Object.keys(props)) {
220
- if (key === "href" || ACTIVATION_HANDLERS.includes(key)) continue;
221
- sanitised[key] = props[key];
222
- }
223
- return {
224
- ...sanitised,
225
- "aria-disabled": true,
226
- "data-disabled": "",
227
- // Mirrors a native disabled button, which is not focusable.
228
- tabIndex: -1
229
- };
230
- }
231
- function retractActivationProps(props) {
232
- const overrides = {};
233
- for (const key of Object.keys(props)) {
234
- if (key === "href" || ACTIVATION_HANDLERS.includes(key)) overrides[key] = void 0;
235
- }
236
- return overrides;
237
- }
238
-
239
116
  // src/button/Button.tsx
240
117
  function Button({
241
118
  disabled = false,
242
- nativeButton,
119
+ href,
120
+ type = "button",
243
121
  className,
244
122
  children,
245
123
  render,
246
124
  ...rest
247
125
  }) {
248
- const native = nativeButton ?? (render === void 0 || render.type === "button");
249
- const isAnchor = render !== void 0 && render.type === "a";
250
- const role = native || isAnchor ? void 0 : "button";
251
- const { props: elementProps, ref: buttonRef } = useButton({ disabled, native, props: rest });
252
- const safeRender = disabled && !native && render !== void 0 ? (0, import_react3.cloneElement)(render, retractActivationProps(render.props)) : render;
126
+ const linksOut = href !== void 0 && !disabled;
127
+ const rendersButton = render === void 0 ? !linksOut : render.type === "button";
128
+ if (process.env.NODE_ENV !== "production" && disabled && render !== void 0) {
129
+ const renderProps = render.props;
130
+ if (renderProps?.href !== void 0) {
131
+ console.error(
132
+ "Button: `disabled` cannot remove the `href` on a `render` element \u2014 its own props outrank the component. Pass the URL as `href` on Button instead."
133
+ );
134
+ }
135
+ }
136
+ const elementProps = rendersButton ? { type, disabled: disabled || void 0 } : { href: linksOut ? href : void 0, "aria-disabled": disabled || void 0 };
253
137
  return useRender({
254
- render: safeRender,
255
- defaultTagName: "button",
256
- props: { role, className, children, ref: buttonRef },
257
- consumerProps: elementProps
138
+ render,
139
+ defaultTagName: linksOut ? "a" : "button",
140
+ props: {
141
+ ...elementProps,
142
+ "data-disabled": disabled ? "" : void 0,
143
+ className,
144
+ children
145
+ },
146
+ consumerProps: rest
258
147
  });
259
148
  }
260
149
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,44 +1,52 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ReactElement, Ref } from 'react';
2
+ import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
3
3
 
4
- interface ButtonProps {
4
+ /**
5
+ * Button's own props. Everything else — `id`, `className`, `children`, `aria-*`,
6
+ * `data-*`, event handlers — comes from React's own `<button>` props, so it is typed
7
+ * and checked without being declared here.
8
+ */
9
+ type ButtonOwnProps = {
5
10
  /**
6
- * Prevents activation. On a native `<button>` the platform handles it; on any other
7
- * element the state is synthesised — `aria-disabled`, removal from the tab order,
8
- * no activation, and a navigation target dropped.
11
+ * Prevents activation. On a `<button>` the platform does it; on the `<a>` that
12
+ * `href` renders, dropping the `href` does it — the DOM leaves an anchor without one
13
+ * unfocusable, unactivatable and no longer a link.
9
14
  */
10
15
  disabled?: boolean;
11
16
  /**
12
- * Whether the rendered element is a native `<button>`.
17
+ * Renders an `<a href>` instead of a `<button>`.
13
18
  *
14
- * Inferred from `render`, which is right for an element literal. Set it explicitly
15
- * when rendering a *component* — `render={<MyButton />}` cannot be inspected, and
16
- * gets treated as non-native. A mismatch logs a development warning.
19
+ * A control that navigates should be an anchor, so middle-click, cmd-click, the
20
+ * status bar and "link" in assistive technology all work. It is a prop rather than
21
+ * something to write on a `render` element because `disabled` has to be able to take
22
+ * it away, and a `render` element's own props outrank everything.
17
23
  */
18
- nativeButton?: boolean;
19
- className?: string;
20
- children?: ReactNode;
24
+ href?: string;
21
25
  /**
22
- * Element to render instead of the default `<button>`. Props, className, event
26
+ * Element or component to render instead of the default. Props, className, event
23
27
  * handlers and ref are merged onto it.
28
+ *
29
+ * @example <Button render={<NextLink href="/docs" />}>Docs</Button>
24
30
  */
25
31
  render?: ReactElement;
32
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
26
33
  ref?: Ref<HTMLElement>;
27
- }
34
+ };
35
+ type ButtonProps = ButtonOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof ButtonOwnProps> & Pick<ComponentPropsWithRef<'a'>, 'target' | 'rel' | 'download'>;
28
36
  /**
29
37
  * A button — behaviour only, no styling.
30
38
  *
31
- * A native `<button>` needs almost none of this; the platform supplies focus, `Enter`
32
- * and `Space` activation, and `disabled`. The component earns its place the moment
33
- * `render` points somewhere else, which is exactly when all of that stops holding.
34
- *
35
- * It has no `href`. A control that navigates should be an `<a>`, so that middle-click,
36
- * cmd-click, the status bar and "link" in assistive technology all work — pass one in:
39
+ * Renders a `<button>`, or an `<a href>` when `href` is set. Both are natively
40
+ * focusable and keyboard-activatable, so nothing here is synthesised: the component
41
+ * picks the right element, defaults `type` so a button does not submit by accident,
42
+ * and expresses `disabled` the way that element already understands.
37
43
  *
38
- * <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>
44
+ * A disabled `href` renders a `<button disabled>` rather than a dead link — the
45
+ * platform then removes it from the tab order and suppresses activation, with no
46
+ * handler stripping or `tabindex` bookkeeping of our own.
39
47
  *
40
- * Emits `data-disabled` so one selector styles a disabled control whatever the element.
48
+ * Emits `data-disabled` so one selector styles a disabled control either way.
41
49
  */
42
- declare function Button({ disabled, nativeButton, className, children, render, ...rest }: ButtonProps & Record<string, unknown>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
50
+ declare function Button({ disabled, href, type, className, children, render, ...rest }: ButtonProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
43
51
 
44
52
  export { Button, type ButtonProps };
@@ -1,44 +1,52 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ReactElement, Ref } from 'react';
2
+ import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
3
3
 
4
- interface ButtonProps {
4
+ /**
5
+ * Button's own props. Everything else — `id`, `className`, `children`, `aria-*`,
6
+ * `data-*`, event handlers — comes from React's own `<button>` props, so it is typed
7
+ * and checked without being declared here.
8
+ */
9
+ type ButtonOwnProps = {
5
10
  /**
6
- * Prevents activation. On a native `<button>` the platform handles it; on any other
7
- * element the state is synthesised — `aria-disabled`, removal from the tab order,
8
- * no activation, and a navigation target dropped.
11
+ * Prevents activation. On a `<button>` the platform does it; on the `<a>` that
12
+ * `href` renders, dropping the `href` does it — the DOM leaves an anchor without one
13
+ * unfocusable, unactivatable and no longer a link.
9
14
  */
10
15
  disabled?: boolean;
11
16
  /**
12
- * Whether the rendered element is a native `<button>`.
17
+ * Renders an `<a href>` instead of a `<button>`.
13
18
  *
14
- * Inferred from `render`, which is right for an element literal. Set it explicitly
15
- * when rendering a *component* — `render={<MyButton />}` cannot be inspected, and
16
- * gets treated as non-native. A mismatch logs a development warning.
19
+ * A control that navigates should be an anchor, so middle-click, cmd-click, the
20
+ * status bar and "link" in assistive technology all work. It is a prop rather than
21
+ * something to write on a `render` element because `disabled` has to be able to take
22
+ * it away, and a `render` element's own props outrank everything.
17
23
  */
18
- nativeButton?: boolean;
19
- className?: string;
20
- children?: ReactNode;
24
+ href?: string;
21
25
  /**
22
- * Element to render instead of the default `<button>`. Props, className, event
26
+ * Element or component to render instead of the default. Props, className, event
23
27
  * handlers and ref are merged onto it.
28
+ *
29
+ * @example <Button render={<NextLink href="/docs" />}>Docs</Button>
24
30
  */
25
31
  render?: ReactElement;
32
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
26
33
  ref?: Ref<HTMLElement>;
27
- }
34
+ };
35
+ type ButtonProps = ButtonOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof ButtonOwnProps> & Pick<ComponentPropsWithRef<'a'>, 'target' | 'rel' | 'download'>;
28
36
  /**
29
37
  * A button — behaviour only, no styling.
30
38
  *
31
- * A native `<button>` needs almost none of this; the platform supplies focus, `Enter`
32
- * and `Space` activation, and `disabled`. The component earns its place the moment
33
- * `render` points somewhere else, which is exactly when all of that stops holding.
34
- *
35
- * It has no `href`. A control that navigates should be an `<a>`, so that middle-click,
36
- * cmd-click, the status bar and "link" in assistive technology all work — pass one in:
39
+ * Renders a `<button>`, or an `<a href>` when `href` is set. Both are natively
40
+ * focusable and keyboard-activatable, so nothing here is synthesised: the component
41
+ * picks the right element, defaults `type` so a button does not submit by accident,
42
+ * and expresses `disabled` the way that element already understands.
37
43
  *
38
- * <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>
44
+ * A disabled `href` renders a `<button disabled>` rather than a dead link — the
45
+ * platform then removes it from the tab order and suppresses activation, with no
46
+ * handler stripping or `tabindex` bookkeeping of our own.
39
47
  *
40
- * Emits `data-disabled` so one selector styles a disabled control whatever the element.
48
+ * Emits `data-disabled` so one selector styles a disabled control either way.
41
49
  */
42
- declare function Button({ disabled, nativeButton, className, children, render, ...rest }: ButtonProps & Record<string, unknown>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
50
+ declare function Button({ disabled, href, type, className, children, render, ...rest }: ButtonProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
43
51
 
44
52
  export { Button, type ButtonProps };
@@ -1,31 +1,38 @@
1
- import {
2
- retractActivationProps,
3
- useButton
4
- } from "../chunk-TNMGZWHA.js";
5
1
  import {
6
2
  useRender
7
- } from "../chunk-PYLPZVWQ.js";
3
+ } from "../chunk-OQTWWZ4B.js";
8
4
 
9
5
  // src/button/Button.tsx
10
- import { cloneElement } from "react";
11
6
  function Button({
12
7
  disabled = false,
13
- nativeButton,
8
+ href,
9
+ type = "button",
14
10
  className,
15
11
  children,
16
12
  render,
17
13
  ...rest
18
14
  }) {
19
- const native = nativeButton ?? (render === void 0 || render.type === "button");
20
- const isAnchor = render !== void 0 && render.type === "a";
21
- const role = native || isAnchor ? void 0 : "button";
22
- const { props: elementProps, ref: buttonRef } = useButton({ disabled, native, props: rest });
23
- const safeRender = disabled && !native && render !== void 0 ? cloneElement(render, retractActivationProps(render.props)) : render;
15
+ const linksOut = href !== void 0 && !disabled;
16
+ const rendersButton = render === void 0 ? !linksOut : render.type === "button";
17
+ if (process.env.NODE_ENV !== "production" && disabled && render !== void 0) {
18
+ const renderProps = render.props;
19
+ if (renderProps?.href !== void 0) {
20
+ console.error(
21
+ "Button: `disabled` cannot remove the `href` on a `render` element \u2014 its own props outrank the component. Pass the URL as `href` on Button instead."
22
+ );
23
+ }
24
+ }
25
+ const elementProps = rendersButton ? { type, disabled: disabled || void 0 } : { href: linksOut ? href : void 0, "aria-disabled": disabled || void 0 };
24
26
  return useRender({
25
- render: safeRender,
26
- defaultTagName: "button",
27
- props: { role, className, children, ref: buttonRef },
28
- consumerProps: elementProps
27
+ render,
28
+ defaultTagName: linksOut ? "a" : "button",
29
+ props: {
30
+ ...elementProps,
31
+ "data-disabled": disabled ? "" : void 0,
32
+ className,
33
+ children
34
+ },
35
+ consumerProps: rest
29
36
  });
30
37
  }
31
38
  export {
@@ -36,18 +36,9 @@ function isSyntheticEvent(event) {
36
36
  function makeEventPreventable(event) {
37
37
  if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
38
38
  const target = event;
39
- const prevent = () => {
39
+ target.preventComponentHandler = () => {
40
40
  target.componentHandlerPrevented = true;
41
41
  };
42
- target.preventComponentHandler = prevent;
43
- const native = event.nativeEvent;
44
- const stopImmediate = native?.stopImmediatePropagation?.bind(native);
45
- if (native && stopImmediate) {
46
- native.stopImmediatePropagation = () => {
47
- stopImmediate();
48
- prevent();
49
- };
50
- }
51
42
  }
52
43
  function isComponentHandlerPrevented(event) {
53
44
  return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
@@ -85,38 +76,15 @@ function mergeProps(...objects) {
85
76
  return merged;
86
77
  }
87
78
 
88
- // src/core/stateAttributes.ts
89
- function getStateAttributes(state, mapping) {
90
- if (!mapping) return {};
91
- const attributes = {};
92
- for (const key of Object.keys(state)) {
93
- const toAttributes = mapping[key];
94
- if (!toAttributes) continue;
95
- const result = toAttributes(state[key]);
96
- if (result) Object.assign(attributes, result);
97
- }
98
- return attributes;
99
- }
100
- function booleanAttribute(whenTrue, whenFalse) {
101
- return (value) => {
102
- if (value) return { [whenTrue]: "" };
103
- return whenFalse ? { [whenFalse]: "" } : null;
104
- };
105
- }
106
- var disabledAttribute = booleanAttribute("data-disabled");
107
-
108
79
  // src/core/useRender.ts
109
80
  import { cloneElement, createElement, isValidElement } from "react";
110
81
  function useRender({
111
82
  render,
112
83
  defaultTagName,
113
84
  props,
114
- consumerProps,
115
- state,
116
- stateAttributes
85
+ consumerProps
117
86
  }) {
118
- const attributes = state ? getStateAttributes(state, stateAttributes) : {};
119
- const merged = mergeProps(attributes, props, consumerProps);
87
+ const merged = mergeProps(props, consumerProps);
120
88
  if (isValidElement(render)) {
121
89
  return cloneElement(render, mergeProps(merged, render.props));
122
90
  }
@@ -126,8 +94,5 @@ function useRender({
126
94
  export {
127
95
  __export,
128
96
  mergeProps,
129
- getStateAttributes,
130
- booleanAttribute,
131
- disabledAttribute,
132
97
  useRender
133
98
  };
package/dist/index.cjs CHANGED
@@ -20,9 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- booleanAttribute: () => booleanAttribute,
24
- disabledAttribute: () => disabledAttribute,
25
- getStateAttributes: () => getStateAttributes,
26
23
  mergeProps: () => mergeProps,
27
24
  useControlled: () => useControlled,
28
25
  useRender: () => useRender
@@ -61,18 +58,9 @@ function isSyntheticEvent(event) {
61
58
  function makeEventPreventable(event) {
62
59
  if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
63
60
  const target = event;
64
- const prevent = () => {
61
+ target.preventComponentHandler = () => {
65
62
  target.componentHandlerPrevented = true;
66
63
  };
67
- target.preventComponentHandler = prevent;
68
- const native = event.nativeEvent;
69
- const stopImmediate = native?.stopImmediatePropagation?.bind(native);
70
- if (native && stopImmediate) {
71
- native.stopImmediatePropagation = () => {
72
- stopImmediate();
73
- prevent();
74
- };
75
- }
76
64
  }
77
65
  function isComponentHandlerPrevented(event) {
78
66
  return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
@@ -112,38 +100,13 @@ function mergeProps(...objects) {
112
100
 
113
101
  // src/core/useRender.ts
114
102
  var import_react = require("react");
115
-
116
- // src/core/stateAttributes.ts
117
- function getStateAttributes(state, mapping) {
118
- if (!mapping) return {};
119
- const attributes = {};
120
- for (const key of Object.keys(state)) {
121
- const toAttributes = mapping[key];
122
- if (!toAttributes) continue;
123
- const result = toAttributes(state[key]);
124
- if (result) Object.assign(attributes, result);
125
- }
126
- return attributes;
127
- }
128
- function booleanAttribute(whenTrue, whenFalse) {
129
- return (value) => {
130
- if (value) return { [whenTrue]: "" };
131
- return whenFalse ? { [whenFalse]: "" } : null;
132
- };
133
- }
134
- var disabledAttribute = booleanAttribute("data-disabled");
135
-
136
- // src/core/useRender.ts
137
103
  function useRender({
138
104
  render,
139
105
  defaultTagName,
140
106
  props,
141
- consumerProps,
142
- state,
143
- stateAttributes
107
+ consumerProps
144
108
  }) {
145
- const attributes = state ? getStateAttributes(state, stateAttributes) : {};
146
- const merged = mergeProps(attributes, props, consumerProps);
109
+ const merged = mergeProps(props, consumerProps);
147
110
  if ((0, import_react.isValidElement)(render)) {
148
111
  return (0, import_react.cloneElement)(render, mergeProps(merged, render.props));
149
112
  }
@@ -184,9 +147,6 @@ function useControlled({
184
147
  }
185
148
  // Annotate the CommonJS export names for ESM import in node:
186
149
  0 && (module.exports = {
187
- booleanAttribute,
188
- disabledAttribute,
189
- getStateAttributes,
190
150
  mergeProps,
191
151
  useControlled,
192
152
  useRender