@arun-dev/headless 2.0.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 +32 -22
- package/dist/button/index.cjs +25 -126
- package/dist/button/index.d.cts +31 -23
- package/dist/button/index.d.ts +31 -23
- package/dist/button/index.js +23 -16
- package/dist/{chunk-IGKX2XWC.js → chunk-OQTWWZ4B.js} +3 -28
- package/dist/index.cjs +3 -33
- package/dist/index.d.cts +19 -57
- package/dist/index.d.ts +19 -57
- package/dist/index.js +1 -7
- package/dist/switch/index.cjs +80 -189
- package/dist/switch/index.d.cts +35 -27
- package/dist/switch/index.d.ts +35 -27
- package/dist/switch/index.js +37 -40
- package/package.json +1 -1
- package/dist/chunk-ER7IAVR5.js +0 -96
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`, `
|
|
31
|
+
| `Button` | — | `disabled`, `href`, `type` |
|
|
32
32
|
| `Switch` | `Switch.Root`, `.Thumb` | `checked`, `defaultChecked`, `onCheckedChange`, `disabled`, `name`, `value` |
|
|
33
33
|
|
|
34
|
-
`Button`
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
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
|
|
114
|
-
|
|
|
115
|
-
| `useRender`
|
|
116
|
-
| `useControlled`
|
|
117
|
-
| `mergeProps`
|
|
118
|
-
| `
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
package/dist/button/index.cjs
CHANGED
|
@@ -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
|
|
|
@@ -60,6 +57,7 @@ function isSyntheticEvent(event) {
|
|
|
60
57
|
return typeof event === "object" && event !== null && "nativeEvent" in event;
|
|
61
58
|
}
|
|
62
59
|
function makeEventPreventable(event) {
|
|
60
|
+
if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
|
|
63
61
|
const target = event;
|
|
64
62
|
target.preventComponentHandler = () => {
|
|
65
63
|
target.componentHandlerPrevented = true;
|
|
@@ -101,150 +99,51 @@ function mergeProps(...objects) {
|
|
|
101
99
|
return merged;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
// src/core/stateAttributes.ts
|
|
105
|
-
function getStateAttributes(state, mapping) {
|
|
106
|
-
if (!mapping) return {};
|
|
107
|
-
const attributes = {};
|
|
108
|
-
for (const key of Object.keys(state)) {
|
|
109
|
-
const toAttributes = mapping[key];
|
|
110
|
-
if (!toAttributes) continue;
|
|
111
|
-
const result = toAttributes(state[key]);
|
|
112
|
-
if (result) Object.assign(attributes, result);
|
|
113
|
-
}
|
|
114
|
-
return attributes;
|
|
115
|
-
}
|
|
116
|
-
function booleanAttribute(whenTrue, whenFalse) {
|
|
117
|
-
return (value) => {
|
|
118
|
-
if (value) return { [whenTrue]: "" };
|
|
119
|
-
return whenFalse ? { [whenFalse]: "" } : null;
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
var disabledAttribute = booleanAttribute("data-disabled");
|
|
123
|
-
|
|
124
102
|
// src/core/useRender.ts
|
|
125
103
|
function useRender({
|
|
126
104
|
render,
|
|
127
105
|
defaultTagName,
|
|
128
106
|
props,
|
|
129
|
-
consumerProps
|
|
130
|
-
state,
|
|
131
|
-
stateAttributes
|
|
107
|
+
consumerProps
|
|
132
108
|
}) {
|
|
133
|
-
const
|
|
134
|
-
const merged = mergeProps(attributes, props, consumerProps);
|
|
109
|
+
const merged = mergeProps(props, consumerProps);
|
|
135
110
|
if ((0, import_react.isValidElement)(render)) {
|
|
136
111
|
return (0, import_react.cloneElement)(render, mergeProps(merged, render.props));
|
|
137
112
|
}
|
|
138
113
|
return (0, import_react.createElement)(defaultTagName, merged);
|
|
139
114
|
}
|
|
140
115
|
|
|
141
|
-
// src/useButton.ts
|
|
142
|
-
var import_react2 = require("react");
|
|
143
|
-
var ACTIVATION_HANDLERS = [
|
|
144
|
-
"onClick",
|
|
145
|
-
"onDoubleClick",
|
|
146
|
-
"onMouseDown",
|
|
147
|
-
"onMouseUp",
|
|
148
|
-
"onPointerDown",
|
|
149
|
-
"onPointerUp",
|
|
150
|
-
"onTouchStart",
|
|
151
|
-
"onTouchEnd",
|
|
152
|
-
"onKeyDown",
|
|
153
|
-
"onKeyUp",
|
|
154
|
-
"onKeyPress"
|
|
155
|
-
];
|
|
156
|
-
function activationHandlers() {
|
|
157
|
-
return {
|
|
158
|
-
onKeyDown(event) {
|
|
159
|
-
if (event.target !== event.currentTarget || event.defaultPrevented) return;
|
|
160
|
-
if (event.key === " ") {
|
|
161
|
-
event.preventDefault();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (event.key === "Enter") {
|
|
165
|
-
event.preventDefault();
|
|
166
|
-
click(event.currentTarget);
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
onKeyUp(event) {
|
|
170
|
-
if (event.target !== event.currentTarget || event.defaultPrevented) return;
|
|
171
|
-
if (event.key === " ") click(event.currentTarget);
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
function click(element) {
|
|
176
|
-
if (element && typeof element.click === "function") {
|
|
177
|
-
element.click();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function useButton({
|
|
181
|
-
disabled = false,
|
|
182
|
-
native,
|
|
183
|
-
props = {}
|
|
184
|
-
}) {
|
|
185
|
-
const elementRef = (0, import_react2.useRef)(null);
|
|
186
|
-
(0, import_react2.useEffect)(() => {
|
|
187
|
-
if (process.env.NODE_ENV === "production") return;
|
|
188
|
-
const element = elementRef.current;
|
|
189
|
-
if (!element) return;
|
|
190
|
-
const isButtonTag = element.tagName === "BUTTON";
|
|
191
|
-
if (native && !isButtonTag) {
|
|
192
|
-
console.error(
|
|
193
|
-
`A component expected a native <button> but rendered <${element.tagName.toLowerCase()}>. Focus, keyboard activation and \`disabled\` will not behave natively.`
|
|
194
|
-
);
|
|
195
|
-
} else if (!native && isButtonTag) {
|
|
196
|
-
console.error(
|
|
197
|
-
"A component rendered a native <button> while treating it as a non-native element, so it carries synthesised attributes it does not need."
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
}, [native]);
|
|
201
|
-
return { props: buttonProps({ disabled, native, props }), ref: elementRef };
|
|
202
|
-
}
|
|
203
|
-
function buttonProps({ disabled, native, props }) {
|
|
204
|
-
if (!disabled) {
|
|
205
|
-
return native ? mergeProps({ type: "button" }, props) : mergeProps({ tabIndex: 0 }, activationHandlers(), props);
|
|
206
|
-
}
|
|
207
|
-
if (native) return mergeProps({ type: "button" }, props, { disabled: true, "data-disabled": "" });
|
|
208
|
-
const sanitised = {};
|
|
209
|
-
for (const key of Object.keys(props)) {
|
|
210
|
-
if (key === "href" || ACTIVATION_HANDLERS.includes(key)) continue;
|
|
211
|
-
sanitised[key] = props[key];
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
...sanitised,
|
|
215
|
-
"aria-disabled": true,
|
|
216
|
-
"data-disabled": "",
|
|
217
|
-
// Mirrors a native disabled button, which is not focusable.
|
|
218
|
-
tabIndex: -1
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
function retractActivationProps(props) {
|
|
222
|
-
const overrides = {};
|
|
223
|
-
for (const key of Object.keys(props)) {
|
|
224
|
-
if (key === "href" || ACTIVATION_HANDLERS.includes(key)) overrides[key] = void 0;
|
|
225
|
-
}
|
|
226
|
-
return overrides;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
116
|
// src/button/Button.tsx
|
|
230
117
|
function Button({
|
|
231
118
|
disabled = false,
|
|
232
|
-
|
|
119
|
+
href,
|
|
120
|
+
type = "button",
|
|
233
121
|
className,
|
|
234
122
|
children,
|
|
235
123
|
render,
|
|
236
124
|
...rest
|
|
237
125
|
}) {
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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 };
|
|
243
137
|
return useRender({
|
|
244
|
-
render
|
|
245
|
-
defaultTagName: "button",
|
|
246
|
-
props: {
|
|
247
|
-
|
|
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
|
|
248
147
|
});
|
|
249
148
|
}
|
|
250
149
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/button/index.d.cts
CHANGED
|
@@ -1,44 +1,52 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
17
|
+
* Renders an `<a href>` instead of a `<button>`.
|
|
13
18
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
|
|
19
|
-
className?: string;
|
|
20
|
-
children?: ReactNode;
|
|
24
|
+
href?: string;
|
|
21
25
|
/**
|
|
22
|
-
* Element to render instead of the default
|
|
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
|
-
*
|
|
32
|
-
* and
|
|
33
|
-
*
|
|
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
|
-
*
|
|
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
|
|
48
|
+
* Emits `data-disabled` so one selector styles a disabled control either way.
|
|
41
49
|
*/
|
|
42
|
-
declare function Button({ disabled,
|
|
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 };
|
package/dist/button/index.d.ts
CHANGED
|
@@ -1,44 +1,52 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
17
|
+
* Renders an `<a href>` instead of a `<button>`.
|
|
13
18
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
|
|
19
|
-
className?: string;
|
|
20
|
-
children?: ReactNode;
|
|
24
|
+
href?: string;
|
|
21
25
|
/**
|
|
22
|
-
* Element to render instead of the default
|
|
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
|
-
*
|
|
32
|
-
* and
|
|
33
|
-
*
|
|
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
|
-
*
|
|
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
|
|
48
|
+
* Emits `data-disabled` so one selector styles a disabled control either way.
|
|
41
49
|
*/
|
|
42
|
-
declare function Button({ disabled,
|
|
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 };
|
package/dist/button/index.js
CHANGED
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
retractActivationProps,
|
|
3
|
-
useButton
|
|
4
|
-
} from "../chunk-ER7IAVR5.js";
|
|
5
1
|
import {
|
|
6
2
|
useRender
|
|
7
|
-
} from "../chunk-
|
|
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
|
-
|
|
8
|
+
href,
|
|
9
|
+
type = "button",
|
|
14
10
|
className,
|
|
15
11
|
children,
|
|
16
12
|
render,
|
|
17
13
|
...rest
|
|
18
14
|
}) {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
26
|
-
defaultTagName: "button",
|
|
27
|
-
props: {
|
|
28
|
-
|
|
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 {
|
|
@@ -34,6 +34,7 @@ function isSyntheticEvent(event) {
|
|
|
34
34
|
return typeof event === "object" && event !== null && "nativeEvent" in event;
|
|
35
35
|
}
|
|
36
36
|
function makeEventPreventable(event) {
|
|
37
|
+
if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
|
|
37
38
|
const target = event;
|
|
38
39
|
target.preventComponentHandler = () => {
|
|
39
40
|
target.componentHandlerPrevented = true;
|
|
@@ -75,38 +76,15 @@ function mergeProps(...objects) {
|
|
|
75
76
|
return merged;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
// src/core/stateAttributes.ts
|
|
79
|
-
function getStateAttributes(state, mapping) {
|
|
80
|
-
if (!mapping) return {};
|
|
81
|
-
const attributes = {};
|
|
82
|
-
for (const key of Object.keys(state)) {
|
|
83
|
-
const toAttributes = mapping[key];
|
|
84
|
-
if (!toAttributes) continue;
|
|
85
|
-
const result = toAttributes(state[key]);
|
|
86
|
-
if (result) Object.assign(attributes, result);
|
|
87
|
-
}
|
|
88
|
-
return attributes;
|
|
89
|
-
}
|
|
90
|
-
function booleanAttribute(whenTrue, whenFalse) {
|
|
91
|
-
return (value) => {
|
|
92
|
-
if (value) return { [whenTrue]: "" };
|
|
93
|
-
return whenFalse ? { [whenFalse]: "" } : null;
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
var disabledAttribute = booleanAttribute("data-disabled");
|
|
97
|
-
|
|
98
79
|
// src/core/useRender.ts
|
|
99
80
|
import { cloneElement, createElement, isValidElement } from "react";
|
|
100
81
|
function useRender({
|
|
101
82
|
render,
|
|
102
83
|
defaultTagName,
|
|
103
84
|
props,
|
|
104
|
-
consumerProps
|
|
105
|
-
state,
|
|
106
|
-
stateAttributes
|
|
85
|
+
consumerProps
|
|
107
86
|
}) {
|
|
108
|
-
const
|
|
109
|
-
const merged = mergeProps(attributes, props, consumerProps);
|
|
87
|
+
const merged = mergeProps(props, consumerProps);
|
|
110
88
|
if (isValidElement(render)) {
|
|
111
89
|
return cloneElement(render, mergeProps(merged, render.props));
|
|
112
90
|
}
|
|
@@ -116,8 +94,5 @@ function useRender({
|
|
|
116
94
|
export {
|
|
117
95
|
__export,
|
|
118
96
|
mergeProps,
|
|
119
|
-
getStateAttributes,
|
|
120
|
-
booleanAttribute,
|
|
121
|
-
disabledAttribute,
|
|
122
97
|
useRender
|
|
123
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
|
|
@@ -59,6 +56,7 @@ function isSyntheticEvent(event) {
|
|
|
59
56
|
return typeof event === "object" && event !== null && "nativeEvent" in event;
|
|
60
57
|
}
|
|
61
58
|
function makeEventPreventable(event) {
|
|
59
|
+
if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
|
|
62
60
|
const target = event;
|
|
63
61
|
target.preventComponentHandler = () => {
|
|
64
62
|
target.componentHandlerPrevented = true;
|
|
@@ -102,38 +100,13 @@ function mergeProps(...objects) {
|
|
|
102
100
|
|
|
103
101
|
// src/core/useRender.ts
|
|
104
102
|
var import_react = require("react");
|
|
105
|
-
|
|
106
|
-
// src/core/stateAttributes.ts
|
|
107
|
-
function getStateAttributes(state, mapping) {
|
|
108
|
-
if (!mapping) return {};
|
|
109
|
-
const attributes = {};
|
|
110
|
-
for (const key of Object.keys(state)) {
|
|
111
|
-
const toAttributes = mapping[key];
|
|
112
|
-
if (!toAttributes) continue;
|
|
113
|
-
const result = toAttributes(state[key]);
|
|
114
|
-
if (result) Object.assign(attributes, result);
|
|
115
|
-
}
|
|
116
|
-
return attributes;
|
|
117
|
-
}
|
|
118
|
-
function booleanAttribute(whenTrue, whenFalse) {
|
|
119
|
-
return (value) => {
|
|
120
|
-
if (value) return { [whenTrue]: "" };
|
|
121
|
-
return whenFalse ? { [whenFalse]: "" } : null;
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
var disabledAttribute = booleanAttribute("data-disabled");
|
|
125
|
-
|
|
126
|
-
// src/core/useRender.ts
|
|
127
103
|
function useRender({
|
|
128
104
|
render,
|
|
129
105
|
defaultTagName,
|
|
130
106
|
props,
|
|
131
|
-
consumerProps
|
|
132
|
-
state,
|
|
133
|
-
stateAttributes
|
|
107
|
+
consumerProps
|
|
134
108
|
}) {
|
|
135
|
-
const
|
|
136
|
-
const merged = mergeProps(attributes, props, consumerProps);
|
|
109
|
+
const merged = mergeProps(props, consumerProps);
|
|
137
110
|
if ((0, import_react.isValidElement)(render)) {
|
|
138
111
|
return (0, import_react.cloneElement)(render, mergeProps(merged, render.props));
|
|
139
112
|
}
|
|
@@ -174,9 +147,6 @@ function useControlled({
|
|
|
174
147
|
}
|
|
175
148
|
// Annotate the CommonJS export names for ESM import in node:
|
|
176
149
|
0 && (module.exports = {
|
|
177
|
-
booleanAttribute,
|
|
178
|
-
disabledAttribute,
|
|
179
|
-
getStateAttributes,
|
|
180
150
|
mergeProps,
|
|
181
151
|
useControlled,
|
|
182
152
|
useRender
|