@arun-dev/headless 2.1.0 → 3.0.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/README.md CHANGED
@@ -28,24 +28,32 @@ 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
+ A `render` component cannot be inspected, so a disabled Button gives it `aria-disabled` and
39
+ `data-disabled` rather than `disabled` — actually disabling itself is up to the component.
38
40
 
39
41
  ```tsx
40
42
  import { Button } from '@arun-dev/headless/button';
41
43
 
42
- <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>;
44
+ <Button href="/docs" target="_blank" rel="noreferrer">
45
+ Docs
46
+ </Button>;
43
47
  ```
44
48
 
45
49
  `Switch.Root` renders a native `<button>`, so focus, `Space`, `Enter` and disabled semantics come
46
50
  from the platform. It carries `role="switch"` and `aria-checked`, but **no accessible name** —
47
51
  wrap it in a `<label>` or pass `aria-label`. A headless component should not guess at your copy.
48
52
 
53
+ In a form it behaves like a native checkbox: with a `name` it submits its `value` only when checked
54
+ and enabled, and `form.reset()` returns it to the state it mounted with, reported through
55
+ `onCheckedChange`.
56
+
49
57
  ## State reaches CSS through `data-*`
50
58
 
51
59
  A headless component owns no class names, so state is projected onto the DOM instead. That
@@ -87,6 +95,15 @@ Every part takes a `render` prop to change the element, and spreads unrecognised
87
95
  `className` is concatenated, `style` is merged, and refs are merged — so a `ref` on the `render`
88
96
  element and a `ref` on the component both receive the node.
89
97
 
98
+ Everything else, `children` included, follows the plain rule: the `render` element's own props
99
+ come last and win. An element that declares no children inherits yours, one that declares some
100
+ keeps them.
101
+
102
+ ```tsx
103
+ <Button render={<a href="/docs" />}>Docs</Button> // renders "Docs"
104
+ <Button render={<a href="/docs">Read the docs</a>}>Docs</Button> // renders "Read the docs"
105
+ ```
106
+
90
107
  Event handlers are chained rather than replaced, and **your handler runs before the component's**,
91
108
  so you can stop it:
92
109
 
@@ -101,24 +118,23 @@ so you can stop it:
101
118
  The primitives the components are built from are exported from the root, for building your own:
102
119
 
103
120
  ```ts
104
- import {
105
- useRender,
106
- useControlled,
107
- mergeProps,
108
- getStateAttributes,
109
- booleanAttribute,
110
- } from '@arun-dev/headless';
121
+ import { useRender, useControlled, mergeProps } from '@arun-dev/headless';
111
122
  ```
112
123
 
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()` |
124
+ | Export | Purpose |
125
+ | ---------------- | ------------------------------------------------------------------------- |
126
+ | `useRender` | Resolves what a part renders — merges props and applies `render` |
127
+ | `useControlled` | One value, controlled or uncontrolled, decided at mount |
128
+ | `mergeProps` | Merges prop objects: handlers chain, `className` concatenates, refs merge |
129
+ | `ComponentEvent` | Type for a handler that can call `preventComponentHandler()` |
130
+
131
+ State attributes are plain objects a component spreads onto its element — React drops the
132
+ `undefined` ones — so there is no mapping layer to learn:
133
+
134
+ ```ts
135
+ 'data-checked': checked ? '' : undefined,
136
+ 'data-unchecked': checked ? undefined : '',
137
+ ```
122
138
 
123
139
  Everything this library uses to implement its own components stays private, so it can
124
140
  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,55 @@
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.
14
+ *
15
+ * A `render` component cannot be inspected, so it gets `aria-disabled` and
16
+ * `data-disabled` rather than `disabled`: actually disabling itself is up to it.
9
17
  */
10
18
  disabled?: boolean;
11
19
  /**
12
- * Whether the rendered element is a native `<button>`.
20
+ * Renders an `<a href>` instead of a `<button>`.
13
21
  *
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.
22
+ * A control that navigates should be an anchor, so middle-click, cmd-click, the
23
+ * status bar and "link" in assistive technology all work. It is a prop rather than
24
+ * something to write on a `render` element because `disabled` has to be able to take
25
+ * it away, and a `render` element's own props outrank everything.
17
26
  */
18
- nativeButton?: boolean;
19
- className?: string;
20
- children?: ReactNode;
27
+ href?: string;
21
28
  /**
22
- * Element to render instead of the default `<button>`. Props, className, event
29
+ * Element or component to render instead of the default. Props, className, event
23
30
  * handlers and ref are merged onto it.
31
+ *
32
+ * @example <Button render={<NextLink href="/docs" />}>Docs</Button>
24
33
  */
25
34
  render?: ReactElement;
35
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
26
36
  ref?: Ref<HTMLElement>;
27
- }
37
+ };
38
+ type ButtonProps = ButtonOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof ButtonOwnProps> & Pick<ComponentPropsWithRef<'a'>, 'target' | 'rel' | 'download'>;
28
39
  /**
29
40
  * A button — behaviour only, no styling.
30
41
  *
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:
42
+ * Renders a `<button>`, or an `<a href>` when `href` is set. Both are natively
43
+ * focusable and keyboard-activatable, so nothing here is synthesised: the component
44
+ * picks the right element, defaults `type` so a button does not submit by accident,
45
+ * and expresses `disabled` the way that element already understands.
37
46
  *
38
- * <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>
47
+ * A disabled `href` renders a `<button disabled>` rather than a dead link — the
48
+ * platform then removes it from the tab order and suppresses activation, with no
49
+ * handler stripping or `tabindex` bookkeeping of our own.
39
50
  *
40
- * Emits `data-disabled` so one selector styles a disabled control whatever the element.
51
+ * Emits `data-disabled` so one selector styles a disabled control either way.
41
52
  */
42
- declare function Button({ disabled, nativeButton, className, children, render, ...rest }: ButtonProps & Record<string, unknown>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
53
+ declare function Button({ disabled, href, type, className, children, render, ...rest }: ButtonProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
43
54
 
44
55
  export { Button, type ButtonProps };
@@ -1,44 +1,55 @@
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.
14
+ *
15
+ * A `render` component cannot be inspected, so it gets `aria-disabled` and
16
+ * `data-disabled` rather than `disabled`: actually disabling itself is up to it.
9
17
  */
10
18
  disabled?: boolean;
11
19
  /**
12
- * Whether the rendered element is a native `<button>`.
20
+ * Renders an `<a href>` instead of a `<button>`.
13
21
  *
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.
22
+ * A control that navigates should be an anchor, so middle-click, cmd-click, the
23
+ * status bar and "link" in assistive technology all work. It is a prop rather than
24
+ * something to write on a `render` element because `disabled` has to be able to take
25
+ * it away, and a `render` element's own props outrank everything.
17
26
  */
18
- nativeButton?: boolean;
19
- className?: string;
20
- children?: ReactNode;
27
+ href?: string;
21
28
  /**
22
- * Element to render instead of the default `<button>`. Props, className, event
29
+ * Element or component to render instead of the default. Props, className, event
23
30
  * handlers and ref are merged onto it.
31
+ *
32
+ * @example <Button render={<NextLink href="/docs" />}>Docs</Button>
24
33
  */
25
34
  render?: ReactElement;
35
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
26
36
  ref?: Ref<HTMLElement>;
27
- }
37
+ };
38
+ type ButtonProps = ButtonOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof ButtonOwnProps> & Pick<ComponentPropsWithRef<'a'>, 'target' | 'rel' | 'download'>;
28
39
  /**
29
40
  * A button — behaviour only, no styling.
30
41
  *
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:
42
+ * Renders a `<button>`, or an `<a href>` when `href` is set. Both are natively
43
+ * focusable and keyboard-activatable, so nothing here is synthesised: the component
44
+ * picks the right element, defaults `type` so a button does not submit by accident,
45
+ * and expresses `disabled` the way that element already understands.
37
46
  *
38
- * <Button render={<a href="/docs" target="_blank" rel="noreferrer" />}>Docs</Button>
47
+ * A disabled `href` renders a `<button disabled>` rather than a dead link — the
48
+ * platform then removes it from the tab order and suppresses activation, with no
49
+ * handler stripping or `tabindex` bookkeeping of our own.
39
50
  *
40
- * Emits `data-disabled` so one selector styles a disabled control whatever the element.
51
+ * Emits `data-disabled` so one selector styles a disabled control either way.
41
52
  */
42
- declare function Button({ disabled, nativeButton, className, children, render, ...rest }: ButtonProps & Record<string, unknown>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
53
+ declare function Button({ disabled, href, type, className, children, render, ...rest }: ButtonProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
43
54
 
44
55
  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
  };