@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 +38 -22
- package/dist/button/index.cjs +25 -136
- package/dist/button/index.d.cts +34 -23
- package/dist/button/index.d.ts +34 -23
- package/dist/button/index.js +23 -16
- package/dist/{chunk-PYLPZVWQ.js → chunk-OQTWWZ4B.js} +3 -38
- package/dist/index.cjs +3 -43
- package/dist/index.d.cts +18 -61
- package/dist/index.d.ts +18 -61
- package/dist/index.js +1 -7
- package/dist/switch/index.cjs +117 -199
- package/dist/switch/index.d.cts +41 -42
- package/dist/switch/index.d.ts +41 -42
- package/dist/switch/index.js +74 -40
- package/package.json +2 -2
- package/dist/chunk-TNMGZWHA.js +0 -96
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
|
-
|
|
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
|
|
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
|
package/dist/index.d.cts
CHANGED
|
@@ -24,6 +24,11 @@ type ComponentEvent<E = unknown> = E & {
|
|
|
24
24
|
* `undefined` values are skipped, so an absent key on a later object never
|
|
25
25
|
* clobbers a value set by an earlier one.
|
|
26
26
|
*
|
|
27
|
+
* `children` is deliberately not special-cased: it is a plain value, so the last
|
|
28
|
+
* object to declare it wins. That is what lets a `render` element either inherit the
|
|
29
|
+
* component's children (it declares none, so the key is absent and skipped) or supply
|
|
30
|
+
* its own (it declares them, and they win like any other value).
|
|
31
|
+
*
|
|
27
32
|
* **Event handlers run right to left** — the last object's handler first, the first
|
|
28
33
|
* object's last. Since a component passes its own props first and the consumer's last,
|
|
29
34
|
* the consumer's handler runs before the component's and can stop it:
|
|
@@ -37,73 +42,29 @@ type ComponentEvent<E = unknown> = E & {
|
|
|
37
42
|
*/
|
|
38
43
|
declare function mergeProps(...objects: (UnknownProps | undefined)[]): UnknownProps;
|
|
39
44
|
|
|
40
|
-
/**
|
|
41
|
-
* Projects a component's state onto the DOM as `data-*` attributes.
|
|
42
|
-
*
|
|
43
|
-
* This is the contract between behaviour and styling. A headless component owns no
|
|
44
|
-
* class names, so the only way CSS can react to `checked` or `disabled` is for the
|
|
45
|
-
* state to be visible in the DOM:
|
|
46
|
-
*
|
|
47
|
-
* .switch[data-checked] { background: var(--switch-track-bg-checked); }
|
|
48
|
-
*
|
|
49
|
-
* Doing it through a declared mapping rather than by hand keeps the attributes
|
|
50
|
-
* consistent across components — Base UI's Checkbox emits eleven of them, which is
|
|
51
|
-
* not something anyone maintains by hand — and makes the state a component exposes
|
|
52
|
-
* a single readable object rather than scattered JSX.
|
|
53
|
-
*/
|
|
54
|
-
/**
|
|
55
|
-
* Maps one state value to the attributes it should produce. Return `null` for
|
|
56
|
-
* "no attribute". A single value may produce several, and mutually exclusive
|
|
57
|
-
* attributes are how a third state stays addressable: with only `data-checked`,
|
|
58
|
-
* `:not([data-checked])` would match both unchecked *and* indeterminate.
|
|
59
|
-
*/
|
|
60
|
-
type StateAttributeMapping<State> = {
|
|
61
|
-
[Key in keyof State]?: (value: State[Key]) => Record<string, string> | null;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Turns a state object into the `data-*` attributes a mapping declares for it.
|
|
65
|
-
*
|
|
66
|
-
* Walks the state's own keys, so a field the mapping does not cover contributes
|
|
67
|
-
* nothing, and a mapping entry that returns `null` is skipped. Entries may each
|
|
68
|
-
* emit several attributes; later keys win if two entries name the same attribute.
|
|
69
|
-
*
|
|
70
|
-
* @param state - The component's current state.
|
|
71
|
-
* @param mapping - Which fields become attributes. `undefined` yields `{}`.
|
|
72
|
-
* @returns The attributes to spread onto the element.
|
|
73
|
-
*/
|
|
74
|
-
declare function getStateAttributes<State extends Record<string, unknown>>(state: State, mapping: StateAttributeMapping<State> | undefined): UnknownProps;
|
|
75
|
-
/**
|
|
76
|
-
* The common case: a boolean that emits one attribute when true and another when
|
|
77
|
-
* false, so both sides are addressable at equal specificity.
|
|
78
|
-
*
|
|
79
|
-
* checked: booleanAttribute('data-checked', 'data-unchecked')
|
|
80
|
-
*/
|
|
81
|
-
declare function booleanAttribute(whenTrue: string, whenFalse?: string): (value: unknown) => Record<string, string> | null;
|
|
82
|
-
/**
|
|
83
|
-
* The shared spelling of the disabled state. Every component uses this rather than
|
|
84
|
-
* writing the string again, so `[data-disabled]` means the same thing system-wide and
|
|
85
|
-
* a typo cannot silently split the CSS contract.
|
|
86
|
-
*/
|
|
87
|
-
declare const disabledAttribute: (value: unknown) => Record<string, string> | null;
|
|
88
|
-
|
|
89
45
|
/**
|
|
90
46
|
* Resolves what a component part actually renders.
|
|
91
47
|
*
|
|
92
48
|
* Every part goes through here, which is what makes the whole library consistent:
|
|
93
|
-
* one place decides how props merge
|
|
94
|
-
*
|
|
95
|
-
*
|
|
49
|
+
* one place decides how props merge and what element comes out. A part supplies its
|
|
50
|
+
* default element and the props it wants; the consumer can replace the element
|
|
51
|
+
* entirely via `render` without losing any of it.
|
|
96
52
|
*
|
|
97
53
|
* Currently uses no hooks. The `use` prefix matches the API it will grow into
|
|
98
54
|
* (memoised merging, so parts stop re-rendering their children needlessly) and keeps
|
|
99
55
|
* call sites stable when that lands.
|
|
100
56
|
*/
|
|
101
|
-
interface UseRenderParams
|
|
102
|
-
/**
|
|
57
|
+
interface UseRenderParams {
|
|
58
|
+
/**
|
|
59
|
+
* Element to render instead of the default. Props, className and ref are merged onto it.
|
|
60
|
+
*
|
|
61
|
+
* Its own props are the last word, `children` included: an element with no children of
|
|
62
|
+
* its own takes the component's, and one with children keeps them.
|
|
63
|
+
*/
|
|
103
64
|
render?: ReactElement | undefined;
|
|
104
65
|
/** Tag rendered when `render` is not supplied. */
|
|
105
66
|
defaultTagName: string;
|
|
106
|
-
/** The component's own props. */
|
|
67
|
+
/** The component's own props, including any `data-*` state attributes it emits. */
|
|
107
68
|
props?: UnknownProps;
|
|
108
69
|
/**
|
|
109
70
|
* The consumer's props, spread from `...rest`.
|
|
@@ -113,12 +74,8 @@ interface UseRenderParams<State extends Record<string, unknown>> {
|
|
|
113
74
|
* cannot put a consumer's props before its own, because there is nowhere to put them.
|
|
114
75
|
*/
|
|
115
76
|
consumerProps?: UnknownProps;
|
|
116
|
-
/** The part's state, projected onto the DOM through `stateAttributes`. */
|
|
117
|
-
state?: State;
|
|
118
|
-
/** How each state field becomes `data-*` attributes. */
|
|
119
|
-
stateAttributes?: StateAttributeMapping<State>;
|
|
120
77
|
}
|
|
121
|
-
declare function useRender
|
|
78
|
+
declare function useRender({ render, defaultTagName, props, consumerProps, }: UseRenderParams): ReactElement;
|
|
122
79
|
|
|
123
80
|
/**
|
|
124
81
|
* Supports both controlled and uncontrolled use of a single value.
|
|
@@ -138,4 +95,4 @@ declare function useControlled<T>({ controlled, default: defaultValue, name, sta
|
|
|
138
95
|
state?: string;
|
|
139
96
|
}): [T, (next: T) => void];
|
|
140
97
|
|
|
141
|
-
export { type ComponentEvent, type
|
|
98
|
+
export { type ComponentEvent, type UnknownProps, type UseRenderParams, mergeProps, useControlled, useRender };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,11 @@ type ComponentEvent<E = unknown> = E & {
|
|
|
24
24
|
* `undefined` values are skipped, so an absent key on a later object never
|
|
25
25
|
* clobbers a value set by an earlier one.
|
|
26
26
|
*
|
|
27
|
+
* `children` is deliberately not special-cased: it is a plain value, so the last
|
|
28
|
+
* object to declare it wins. That is what lets a `render` element either inherit the
|
|
29
|
+
* component's children (it declares none, so the key is absent and skipped) or supply
|
|
30
|
+
* its own (it declares them, and they win like any other value).
|
|
31
|
+
*
|
|
27
32
|
* **Event handlers run right to left** — the last object's handler first, the first
|
|
28
33
|
* object's last. Since a component passes its own props first and the consumer's last,
|
|
29
34
|
* the consumer's handler runs before the component's and can stop it:
|
|
@@ -37,73 +42,29 @@ type ComponentEvent<E = unknown> = E & {
|
|
|
37
42
|
*/
|
|
38
43
|
declare function mergeProps(...objects: (UnknownProps | undefined)[]): UnknownProps;
|
|
39
44
|
|
|
40
|
-
/**
|
|
41
|
-
* Projects a component's state onto the DOM as `data-*` attributes.
|
|
42
|
-
*
|
|
43
|
-
* This is the contract between behaviour and styling. A headless component owns no
|
|
44
|
-
* class names, so the only way CSS can react to `checked` or `disabled` is for the
|
|
45
|
-
* state to be visible in the DOM:
|
|
46
|
-
*
|
|
47
|
-
* .switch[data-checked] { background: var(--switch-track-bg-checked); }
|
|
48
|
-
*
|
|
49
|
-
* Doing it through a declared mapping rather than by hand keeps the attributes
|
|
50
|
-
* consistent across components — Base UI's Checkbox emits eleven of them, which is
|
|
51
|
-
* not something anyone maintains by hand — and makes the state a component exposes
|
|
52
|
-
* a single readable object rather than scattered JSX.
|
|
53
|
-
*/
|
|
54
|
-
/**
|
|
55
|
-
* Maps one state value to the attributes it should produce. Return `null` for
|
|
56
|
-
* "no attribute". A single value may produce several, and mutually exclusive
|
|
57
|
-
* attributes are how a third state stays addressable: with only `data-checked`,
|
|
58
|
-
* `:not([data-checked])` would match both unchecked *and* indeterminate.
|
|
59
|
-
*/
|
|
60
|
-
type StateAttributeMapping<State> = {
|
|
61
|
-
[Key in keyof State]?: (value: State[Key]) => Record<string, string> | null;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Turns a state object into the `data-*` attributes a mapping declares for it.
|
|
65
|
-
*
|
|
66
|
-
* Walks the state's own keys, so a field the mapping does not cover contributes
|
|
67
|
-
* nothing, and a mapping entry that returns `null` is skipped. Entries may each
|
|
68
|
-
* emit several attributes; later keys win if two entries name the same attribute.
|
|
69
|
-
*
|
|
70
|
-
* @param state - The component's current state.
|
|
71
|
-
* @param mapping - Which fields become attributes. `undefined` yields `{}`.
|
|
72
|
-
* @returns The attributes to spread onto the element.
|
|
73
|
-
*/
|
|
74
|
-
declare function getStateAttributes<State extends Record<string, unknown>>(state: State, mapping: StateAttributeMapping<State> | undefined): UnknownProps;
|
|
75
|
-
/**
|
|
76
|
-
* The common case: a boolean that emits one attribute when true and another when
|
|
77
|
-
* false, so both sides are addressable at equal specificity.
|
|
78
|
-
*
|
|
79
|
-
* checked: booleanAttribute('data-checked', 'data-unchecked')
|
|
80
|
-
*/
|
|
81
|
-
declare function booleanAttribute(whenTrue: string, whenFalse?: string): (value: unknown) => Record<string, string> | null;
|
|
82
|
-
/**
|
|
83
|
-
* The shared spelling of the disabled state. Every component uses this rather than
|
|
84
|
-
* writing the string again, so `[data-disabled]` means the same thing system-wide and
|
|
85
|
-
* a typo cannot silently split the CSS contract.
|
|
86
|
-
*/
|
|
87
|
-
declare const disabledAttribute: (value: unknown) => Record<string, string> | null;
|
|
88
|
-
|
|
89
45
|
/**
|
|
90
46
|
* Resolves what a component part actually renders.
|
|
91
47
|
*
|
|
92
48
|
* Every part goes through here, which is what makes the whole library consistent:
|
|
93
|
-
* one place decides how props merge
|
|
94
|
-
*
|
|
95
|
-
*
|
|
49
|
+
* one place decides how props merge and what element comes out. A part supplies its
|
|
50
|
+
* default element and the props it wants; the consumer can replace the element
|
|
51
|
+
* entirely via `render` without losing any of it.
|
|
96
52
|
*
|
|
97
53
|
* Currently uses no hooks. The `use` prefix matches the API it will grow into
|
|
98
54
|
* (memoised merging, so parts stop re-rendering their children needlessly) and keeps
|
|
99
55
|
* call sites stable when that lands.
|
|
100
56
|
*/
|
|
101
|
-
interface UseRenderParams
|
|
102
|
-
/**
|
|
57
|
+
interface UseRenderParams {
|
|
58
|
+
/**
|
|
59
|
+
* Element to render instead of the default. Props, className and ref are merged onto it.
|
|
60
|
+
*
|
|
61
|
+
* Its own props are the last word, `children` included: an element with no children of
|
|
62
|
+
* its own takes the component's, and one with children keeps them.
|
|
63
|
+
*/
|
|
103
64
|
render?: ReactElement | undefined;
|
|
104
65
|
/** Tag rendered when `render` is not supplied. */
|
|
105
66
|
defaultTagName: string;
|
|
106
|
-
/** The component's own props. */
|
|
67
|
+
/** The component's own props, including any `data-*` state attributes it emits. */
|
|
107
68
|
props?: UnknownProps;
|
|
108
69
|
/**
|
|
109
70
|
* The consumer's props, spread from `...rest`.
|
|
@@ -113,12 +74,8 @@ interface UseRenderParams<State extends Record<string, unknown>> {
|
|
|
113
74
|
* cannot put a consumer's props before its own, because there is nowhere to put them.
|
|
114
75
|
*/
|
|
115
76
|
consumerProps?: UnknownProps;
|
|
116
|
-
/** The part's state, projected onto the DOM through `stateAttributes`. */
|
|
117
|
-
state?: State;
|
|
118
|
-
/** How each state field becomes `data-*` attributes. */
|
|
119
|
-
stateAttributes?: StateAttributeMapping<State>;
|
|
120
77
|
}
|
|
121
|
-
declare function useRender
|
|
78
|
+
declare function useRender({ render, defaultTagName, props, consumerProps, }: UseRenderParams): ReactElement;
|
|
122
79
|
|
|
123
80
|
/**
|
|
124
81
|
* Supports both controlled and uncontrolled use of a single value.
|
|
@@ -138,4 +95,4 @@ declare function useControlled<T>({ controlled, default: defaultValue, name, sta
|
|
|
138
95
|
state?: string;
|
|
139
96
|
}): [T, (next: T) => void];
|
|
140
97
|
|
|
141
|
-
export { type ComponentEvent, type
|
|
98
|
+
export { type ComponentEvent, type UnknownProps, type UseRenderParams, mergeProps, useControlled, useRender };
|
package/dist/index.js
CHANGED
|
@@ -2,16 +2,10 @@ import {
|
|
|
2
2
|
useControlled
|
|
3
3
|
} from "./chunk-UEIB3I3T.js";
|
|
4
4
|
import {
|
|
5
|
-
booleanAttribute,
|
|
6
|
-
disabledAttribute,
|
|
7
|
-
getStateAttributes,
|
|
8
5
|
mergeProps,
|
|
9
6
|
useRender
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OQTWWZ4B.js";
|
|
11
8
|
export {
|
|
12
|
-
booleanAttribute,
|
|
13
|
-
disabledAttribute,
|
|
14
|
-
getStateAttributes,
|
|
15
9
|
mergeProps,
|
|
16
10
|
useControlled,
|
|
17
11
|
useRender
|