@arun-dev/headless 4.10.0 → 4.12.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/dist/combobox/index.cjs +15 -2
- package/dist/combobox/index.d.cts +24 -4
- package/dist/combobox/index.d.ts +24 -4
- package/dist/combobox/index.js +15 -2
- package/dist/field/index.cjs +287 -0
- package/dist/field/index.d.cts +92 -0
- package/dist/field/index.d.ts +92 -0
- package/dist/field/index.js +176 -0
- package/package.json +11 -1
package/dist/combobox/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_parts_exports, {
|
|
|
40
40
|
List: () => ComboboxList,
|
|
41
41
|
Popup: () => ComboboxPopup,
|
|
42
42
|
Root: () => ComboboxRoot,
|
|
43
|
+
Separator: () => ComboboxSeparator,
|
|
43
44
|
Status: () => ComboboxStatus,
|
|
44
45
|
Trigger: () => ComboboxTrigger,
|
|
45
46
|
Value: () => ComboboxValue
|
|
@@ -341,7 +342,7 @@ function ComboboxRoot({
|
|
|
341
342
|
(0, import_react3.useEffect)(() => {
|
|
342
343
|
if (lastSelectedKeyRef.current === selectedKey) return;
|
|
343
344
|
lastSelectedKeyRef.current = selectedKey;
|
|
344
|
-
|
|
345
|
+
setInputValue(selectedLabel, "value-change");
|
|
345
346
|
}, [selectedKey]);
|
|
346
347
|
const [chips, setChips] = (0, import_react3.useState)([]);
|
|
347
348
|
const registerChip = (0, import_react3.useCallback)((entry) => {
|
|
@@ -831,7 +832,8 @@ function ComboboxClear({ className, children, render, ...rest }) {
|
|
|
831
832
|
type: "button",
|
|
832
833
|
tabIndex: -1,
|
|
833
834
|
disabled: disabled || void 0,
|
|
834
|
-
|
|
835
|
+
// Nothing to clear while disabled: a disabled field hides it, as it has no effect.
|
|
836
|
+
...comboboxClearDataAttributes(!disabled && selectedItems.length > 0),
|
|
835
837
|
className,
|
|
836
838
|
children,
|
|
837
839
|
ref: elementRef,
|
|
@@ -1085,6 +1087,17 @@ function ComboboxGroupLabel({
|
|
|
1085
1087
|
});
|
|
1086
1088
|
}
|
|
1087
1089
|
|
|
1090
|
+
// src/combobox/ComboboxSeparator.tsx
|
|
1091
|
+
function ComboboxSeparator({ className, render, ...rest }) {
|
|
1092
|
+
useComboboxRootContext("Separator");
|
|
1093
|
+
return useRender({
|
|
1094
|
+
render,
|
|
1095
|
+
defaultTagName: "div",
|
|
1096
|
+
props: { "aria-hidden": true, className },
|
|
1097
|
+
consumerProps: rest
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1088
1101
|
// src/combobox/ComboboxEmpty.tsx
|
|
1089
1102
|
function ComboboxEmpty({ className, children, render, ...rest }) {
|
|
1090
1103
|
const { filteredItems, loading } = useComboboxRootContext("Empty");
|
|
@@ -3,7 +3,9 @@ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
|
3
3
|
import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.cjs';
|
|
4
4
|
|
|
5
5
|
/** Why a value, the input's text or the open state changed — the second callback argument. */
|
|
6
|
-
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
6
|
+
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
7
|
+
/** The input's text followed a change of `value` — the parent's, not the user's. */
|
|
8
|
+
| 'value-change';
|
|
7
9
|
type ComboboxChangeDetails = {
|
|
8
10
|
reason: ComboboxChangeReason;
|
|
9
11
|
};
|
|
@@ -182,7 +184,8 @@ type ComboboxClearProps = ComboboxClearOwnProps & Omit<ComponentPropsWithRef<'bu
|
|
|
182
184
|
* Empties the input and the selection — every selected item, with `multiple`. Give it an
|
|
183
185
|
* `aria-label`.
|
|
184
186
|
*
|
|
185
|
-
* `data-visible` is present while there is a selection to clear
|
|
187
|
+
* `data-visible` is present while there is a selection to clear and the Root is not disabled;
|
|
188
|
+
* style it hidden otherwise.
|
|
186
189
|
* Out of the tab order, and a press keeps focus in the input.
|
|
187
190
|
*/
|
|
188
191
|
declare function ComboboxClear({ className, children, render, ...rest }: ComboboxClearProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
@@ -285,6 +288,23 @@ type ComboboxGroupLabelProps = ComboboxGroupLabelOwnProps & Omit<ComponentPropsW
|
|
|
285
288
|
*/
|
|
286
289
|
declare function ComboboxGroupLabel({ className, children, render, ...rest }: ComboboxGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
287
290
|
|
|
291
|
+
type ComboboxSeparatorOwnProps = {
|
|
292
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
293
|
+
render?: ReactElement;
|
|
294
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
295
|
+
ref?: Ref<HTMLElement>;
|
|
296
|
+
};
|
|
297
|
+
type ComboboxSeparatorProps = ComboboxSeparatorOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxSeparatorOwnProps>;
|
|
298
|
+
/**
|
|
299
|
+
* A line between items or groups in the List, as an `<hr>` in a `<select>`. The arrow keys pass
|
|
300
|
+
* it.
|
|
301
|
+
*
|
|
302
|
+
* Visual only: `aria-hidden`, with no `role="separator"`. A listbox may own only options and
|
|
303
|
+
* groups, so a separator role inside one fails `aria-required-children`; a Group, named by its
|
|
304
|
+
* label, is what tells a screen reader where one set ends.
|
|
305
|
+
*/
|
|
306
|
+
declare function ComboboxSeparator({ className, render, ...rest }: ComboboxSeparatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
307
|
+
|
|
288
308
|
type ComboboxEmptyOwnProps = {
|
|
289
309
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
290
310
|
render?: ReactElement;
|
|
@@ -362,7 +382,7 @@ type ComboboxValueProps<T = unknown> = {
|
|
|
362
382
|
declare function ComboboxValue<T = unknown>({ children }: ComboboxValueProps<T>): react.JSX.Element;
|
|
363
383
|
|
|
364
384
|
declare namespace index_parts {
|
|
365
|
-
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
385
|
+
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxSeparator as Separator, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
366
386
|
}
|
|
367
387
|
|
|
368
388
|
/**
|
|
@@ -373,4 +393,4 @@ declare namespace index_parts {
|
|
|
373
393
|
*/
|
|
374
394
|
declare function defaultFilter<T>(items: readonly T[], query: string, itemToString: (item: T) => string): T[];
|
|
375
395
|
|
|
376
|
-
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
|
396
|
+
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSeparatorProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
package/dist/combobox/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
|
3
3
|
import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.js';
|
|
4
4
|
|
|
5
5
|
/** Why a value, the input's text or the open state changed — the second callback argument. */
|
|
6
|
-
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
6
|
+
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
7
|
+
/** The input's text followed a change of `value` — the parent's, not the user's. */
|
|
8
|
+
| 'value-change';
|
|
7
9
|
type ComboboxChangeDetails = {
|
|
8
10
|
reason: ComboboxChangeReason;
|
|
9
11
|
};
|
|
@@ -182,7 +184,8 @@ type ComboboxClearProps = ComboboxClearOwnProps & Omit<ComponentPropsWithRef<'bu
|
|
|
182
184
|
* Empties the input and the selection — every selected item, with `multiple`. Give it an
|
|
183
185
|
* `aria-label`.
|
|
184
186
|
*
|
|
185
|
-
* `data-visible` is present while there is a selection to clear
|
|
187
|
+
* `data-visible` is present while there is a selection to clear and the Root is not disabled;
|
|
188
|
+
* style it hidden otherwise.
|
|
186
189
|
* Out of the tab order, and a press keeps focus in the input.
|
|
187
190
|
*/
|
|
188
191
|
declare function ComboboxClear({ className, children, render, ...rest }: ComboboxClearProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
@@ -285,6 +288,23 @@ type ComboboxGroupLabelProps = ComboboxGroupLabelOwnProps & Omit<ComponentPropsW
|
|
|
285
288
|
*/
|
|
286
289
|
declare function ComboboxGroupLabel({ className, children, render, ...rest }: ComboboxGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
287
290
|
|
|
291
|
+
type ComboboxSeparatorOwnProps = {
|
|
292
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
293
|
+
render?: ReactElement;
|
|
294
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
295
|
+
ref?: Ref<HTMLElement>;
|
|
296
|
+
};
|
|
297
|
+
type ComboboxSeparatorProps = ComboboxSeparatorOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxSeparatorOwnProps>;
|
|
298
|
+
/**
|
|
299
|
+
* A line between items or groups in the List, as an `<hr>` in a `<select>`. The arrow keys pass
|
|
300
|
+
* it.
|
|
301
|
+
*
|
|
302
|
+
* Visual only: `aria-hidden`, with no `role="separator"`. A listbox may own only options and
|
|
303
|
+
* groups, so a separator role inside one fails `aria-required-children`; a Group, named by its
|
|
304
|
+
* label, is what tells a screen reader where one set ends.
|
|
305
|
+
*/
|
|
306
|
+
declare function ComboboxSeparator({ className, render, ...rest }: ComboboxSeparatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
307
|
+
|
|
288
308
|
type ComboboxEmptyOwnProps = {
|
|
289
309
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
290
310
|
render?: ReactElement;
|
|
@@ -362,7 +382,7 @@ type ComboboxValueProps<T = unknown> = {
|
|
|
362
382
|
declare function ComboboxValue<T = unknown>({ children }: ComboboxValueProps<T>): react.JSX.Element;
|
|
363
383
|
|
|
364
384
|
declare namespace index_parts {
|
|
365
|
-
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
385
|
+
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxSeparator as Separator, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
366
386
|
}
|
|
367
387
|
|
|
368
388
|
/**
|
|
@@ -373,4 +393,4 @@ declare namespace index_parts {
|
|
|
373
393
|
*/
|
|
374
394
|
declare function defaultFilter<T>(items: readonly T[], query: string, itemToString: (item: T) => string): T[];
|
|
375
395
|
|
|
376
|
-
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
|
396
|
+
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSeparatorProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
package/dist/combobox/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_parts_exports, {
|
|
|
30
30
|
List: () => ComboboxList,
|
|
31
31
|
Popup: () => ComboboxPopup,
|
|
32
32
|
Root: () => ComboboxRoot,
|
|
33
|
+
Separator: () => ComboboxSeparator,
|
|
33
34
|
Status: () => ComboboxStatus,
|
|
34
35
|
Trigger: () => ComboboxTrigger,
|
|
35
36
|
Value: () => ComboboxValue
|
|
@@ -247,7 +248,7 @@ function ComboboxRoot({
|
|
|
247
248
|
useEffect(() => {
|
|
248
249
|
if (lastSelectedKeyRef.current === selectedKey) return;
|
|
249
250
|
lastSelectedKeyRef.current = selectedKey;
|
|
250
|
-
|
|
251
|
+
setInputValue(selectedLabel, "value-change");
|
|
251
252
|
}, [selectedKey]);
|
|
252
253
|
const [chips, setChips] = useState([]);
|
|
253
254
|
const registerChip = useCallback((entry) => {
|
|
@@ -648,7 +649,8 @@ function ComboboxClear({ className, children, render, ...rest }) {
|
|
|
648
649
|
type: "button",
|
|
649
650
|
tabIndex: -1,
|
|
650
651
|
disabled: disabled || void 0,
|
|
651
|
-
|
|
652
|
+
// Nothing to clear while disabled: a disabled field hides it, as it has no effect.
|
|
653
|
+
...comboboxClearDataAttributes(!disabled && selectedItems.length > 0),
|
|
652
654
|
className,
|
|
653
655
|
children,
|
|
654
656
|
ref: elementRef,
|
|
@@ -902,6 +904,17 @@ function ComboboxGroupLabel({
|
|
|
902
904
|
});
|
|
903
905
|
}
|
|
904
906
|
|
|
907
|
+
// src/combobox/ComboboxSeparator.tsx
|
|
908
|
+
function ComboboxSeparator({ className, render, ...rest }) {
|
|
909
|
+
useComboboxRootContext("Separator");
|
|
910
|
+
return useRender({
|
|
911
|
+
render,
|
|
912
|
+
defaultTagName: "div",
|
|
913
|
+
props: { "aria-hidden": true, className },
|
|
914
|
+
consumerProps: rest
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
|
|
905
918
|
// src/combobox/ComboboxEmpty.tsx
|
|
906
919
|
function ComboboxEmpty({ className, children, render, ...rest }) {
|
|
907
920
|
const { filteredItems, loading } = useComboboxRootContext("Empty");
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/field/index.ts
|
|
21
|
+
var field_exports = {};
|
|
22
|
+
__export(field_exports, {
|
|
23
|
+
Field: () => index_parts_exports
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(field_exports);
|
|
26
|
+
|
|
27
|
+
// src/field/index.parts.ts
|
|
28
|
+
var index_parts_exports = {};
|
|
29
|
+
__export(index_parts_exports, {
|
|
30
|
+
Control: () => FieldControl,
|
|
31
|
+
Description: () => FieldDescription,
|
|
32
|
+
Error: () => FieldError,
|
|
33
|
+
Label: () => FieldLabel,
|
|
34
|
+
Root: () => FieldRoot
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// src/field/FieldRoot.tsx
|
|
38
|
+
var import_react3 = require("react");
|
|
39
|
+
|
|
40
|
+
// src/core/useRender.ts
|
|
41
|
+
var import_react = require("react");
|
|
42
|
+
|
|
43
|
+
// src/core/mergeProps.ts
|
|
44
|
+
function isEventHandler(key) {
|
|
45
|
+
return key.length > 2 && key.startsWith("on") && key[2] === key[2]?.toUpperCase();
|
|
46
|
+
}
|
|
47
|
+
function mergeRefs(...refs) {
|
|
48
|
+
return (node) => {
|
|
49
|
+
const cleanups = refs.map((ref) => {
|
|
50
|
+
if (typeof ref === "function") {
|
|
51
|
+
const result = ref(node);
|
|
52
|
+
return typeof result === "function" ? result : () => ref(null);
|
|
53
|
+
}
|
|
54
|
+
if (ref && typeof ref === "object") {
|
|
55
|
+
ref.current = node;
|
|
56
|
+
return () => {
|
|
57
|
+
ref.current = null;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return void 0;
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
cleanups.forEach((cleanup) => {
|
|
64
|
+
if (typeof cleanup === "function") cleanup();
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function isSyntheticEvent(event) {
|
|
70
|
+
return typeof event === "object" && event !== null && "nativeEvent" in event;
|
|
71
|
+
}
|
|
72
|
+
function makeEventPreventable(event) {
|
|
73
|
+
if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
|
|
74
|
+
const target = event;
|
|
75
|
+
target.preventComponentHandler = () => {
|
|
76
|
+
target.componentHandlerPrevented = true;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function isComponentHandlerPrevented(event) {
|
|
80
|
+
return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
|
|
81
|
+
}
|
|
82
|
+
function chainHandlers(earlier, value) {
|
|
83
|
+
return (...args) => {
|
|
84
|
+
const event = args[0];
|
|
85
|
+
if (isSyntheticEvent(event)) makeEventPreventable(event);
|
|
86
|
+
value(...args);
|
|
87
|
+
if (isComponentHandlerPrevented(event)) return;
|
|
88
|
+
earlier(...args);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function mergeProps(...objects) {
|
|
92
|
+
const merged = {};
|
|
93
|
+
for (const props of objects) {
|
|
94
|
+
if (!props) continue;
|
|
95
|
+
for (const key of Object.keys(props)) {
|
|
96
|
+
const value = props[key];
|
|
97
|
+
if (value === void 0) continue;
|
|
98
|
+
if (isEventHandler(key) && typeof value === "function") {
|
|
99
|
+
const earlier = merged[key];
|
|
100
|
+
merged[key] = typeof earlier === "function" ? chainHandlers(earlier, value) : value;
|
|
101
|
+
} else if (key === "className") {
|
|
102
|
+
merged.className = merged.className ? `${String(merged.className)} ${String(value)}` : value;
|
|
103
|
+
} else if (key === "style") {
|
|
104
|
+
merged.style = { ...merged.style, ...value };
|
|
105
|
+
} else if (key === "ref") {
|
|
106
|
+
merged.ref = merged.ref ? mergeRefs(merged.ref, value) : value;
|
|
107
|
+
} else {
|
|
108
|
+
merged[key] = value;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return merged;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/core/useRender.ts
|
|
116
|
+
function useRender({
|
|
117
|
+
render,
|
|
118
|
+
defaultTagName,
|
|
119
|
+
props,
|
|
120
|
+
consumerProps
|
|
121
|
+
}) {
|
|
122
|
+
const merged = mergeProps(props, consumerProps);
|
|
123
|
+
if ((0, import_react.isValidElement)(render)) {
|
|
124
|
+
return (0, import_react.cloneElement)(render, mergeProps(merged, render.props));
|
|
125
|
+
}
|
|
126
|
+
return (0, import_react.createElement)(defaultTagName, merged);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/field/FieldRootContext.ts
|
|
130
|
+
var import_react2 = require("react");
|
|
131
|
+
var FieldRootContext = (0, import_react2.createContext)(null);
|
|
132
|
+
function useFieldRootContext(part) {
|
|
133
|
+
const context = (0, import_react2.useContext)(FieldRootContext);
|
|
134
|
+
if (context === null) {
|
|
135
|
+
throw new Error(`<Field.${part}> must be rendered inside <Field.Root>.`);
|
|
136
|
+
}
|
|
137
|
+
return context;
|
|
138
|
+
}
|
|
139
|
+
function fieldDataAttributes({ invalid, disabled, required }) {
|
|
140
|
+
return {
|
|
141
|
+
"data-invalid": invalid ? "" : void 0,
|
|
142
|
+
"data-disabled": disabled ? "" : void 0,
|
|
143
|
+
"data-required": required ? "" : void 0
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/field/FieldRoot.tsx
|
|
148
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
149
|
+
function usePresence() {
|
|
150
|
+
const [count, setCount] = (0, import_react3.useState)(0);
|
|
151
|
+
const register = (0, import_react3.useCallback)(() => {
|
|
152
|
+
setCount((n) => n + 1);
|
|
153
|
+
return () => setCount((n) => n - 1);
|
|
154
|
+
}, []);
|
|
155
|
+
return [count > 0, register];
|
|
156
|
+
}
|
|
157
|
+
function FieldRoot({
|
|
158
|
+
invalid = false,
|
|
159
|
+
disabled = false,
|
|
160
|
+
required = false,
|
|
161
|
+
className,
|
|
162
|
+
children,
|
|
163
|
+
render,
|
|
164
|
+
...rest
|
|
165
|
+
}) {
|
|
166
|
+
const id = (0, import_react3.useId)();
|
|
167
|
+
const [hasDescription, registerDescription] = usePresence();
|
|
168
|
+
const [hasError, registerError] = usePresence();
|
|
169
|
+
const context = (0, import_react3.useMemo)(
|
|
170
|
+
() => ({
|
|
171
|
+
invalid,
|
|
172
|
+
disabled,
|
|
173
|
+
required,
|
|
174
|
+
controlId: `${id}-control`,
|
|
175
|
+
descriptionId: `${id}-description`,
|
|
176
|
+
errorId: `${id}-error`,
|
|
177
|
+
hasDescription,
|
|
178
|
+
hasError,
|
|
179
|
+
registerDescription,
|
|
180
|
+
registerError
|
|
181
|
+
}),
|
|
182
|
+
[invalid, disabled, required, id, hasDescription, hasError, registerDescription, registerError]
|
|
183
|
+
);
|
|
184
|
+
const element = useRender({
|
|
185
|
+
render,
|
|
186
|
+
defaultTagName: "div",
|
|
187
|
+
props: { ...fieldDataAttributes({ invalid, disabled, required }), className, children },
|
|
188
|
+
consumerProps: rest
|
|
189
|
+
});
|
|
190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldRootContext.Provider, { value: context, children: element });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/field/FieldLabel.tsx
|
|
194
|
+
function FieldLabel({ className, children, render, ...rest }) {
|
|
195
|
+
const { controlId, ...state } = useFieldRootContext("Label");
|
|
196
|
+
return useRender({
|
|
197
|
+
render,
|
|
198
|
+
defaultTagName: "label",
|
|
199
|
+
props: { htmlFor: controlId, ...fieldDataAttributes(state), className, children },
|
|
200
|
+
consumerProps: rest
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/field/FieldControl.tsx
|
|
205
|
+
function FieldControl({
|
|
206
|
+
render,
|
|
207
|
+
"aria-describedby": describedBy,
|
|
208
|
+
...rest
|
|
209
|
+
}) {
|
|
210
|
+
const { controlId, descriptionId, errorId, hasDescription, hasError, ...state } = useFieldRootContext("Control");
|
|
211
|
+
const describedByIds = [
|
|
212
|
+
hasDescription ? descriptionId : void 0,
|
|
213
|
+
hasError ? errorId : void 0,
|
|
214
|
+
describedBy
|
|
215
|
+
].filter(Boolean).join(" ");
|
|
216
|
+
return useRender({
|
|
217
|
+
render,
|
|
218
|
+
defaultTagName: "input",
|
|
219
|
+
props: {
|
|
220
|
+
id: controlId,
|
|
221
|
+
"aria-describedby": describedByIds || void 0,
|
|
222
|
+
"aria-invalid": state.invalid || void 0,
|
|
223
|
+
disabled: state.disabled || void 0,
|
|
224
|
+
required: state.required || void 0,
|
|
225
|
+
...fieldDataAttributes(state)
|
|
226
|
+
},
|
|
227
|
+
consumerProps: rest
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/field/FieldDescription.tsx
|
|
232
|
+
var import_react4 = require("react");
|
|
233
|
+
function FieldDescription({ className, children, render, ...rest }) {
|
|
234
|
+
const context = useFieldRootContext("Description");
|
|
235
|
+
const { descriptionId, registerDescription, invalid, disabled, required } = context;
|
|
236
|
+
(0, import_react4.useLayoutEffect)(registerDescription, [registerDescription]);
|
|
237
|
+
return useRender({
|
|
238
|
+
render,
|
|
239
|
+
defaultTagName: "p",
|
|
240
|
+
props: {
|
|
241
|
+
id: descriptionId,
|
|
242
|
+
...fieldDataAttributes({ invalid, disabled, required }),
|
|
243
|
+
className,
|
|
244
|
+
children
|
|
245
|
+
},
|
|
246
|
+
consumerProps: rest
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/field/FieldError.tsx
|
|
251
|
+
var import_react5 = require("react");
|
|
252
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
253
|
+
function FieldError({ className, children, render, ...rest }) {
|
|
254
|
+
const context = useFieldRootContext("Error");
|
|
255
|
+
const { invalid, disabled, required } = context;
|
|
256
|
+
if (!invalid) return null;
|
|
257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
258
|
+
ShownError,
|
|
259
|
+
{
|
|
260
|
+
className,
|
|
261
|
+
render,
|
|
262
|
+
state: { invalid, disabled, required },
|
|
263
|
+
...rest,
|
|
264
|
+
children
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function ShownError({
|
|
269
|
+
className,
|
|
270
|
+
children,
|
|
271
|
+
render,
|
|
272
|
+
state,
|
|
273
|
+
...rest
|
|
274
|
+
}) {
|
|
275
|
+
const { errorId, registerError } = useFieldRootContext("Error");
|
|
276
|
+
(0, import_react5.useLayoutEffect)(registerError, [registerError]);
|
|
277
|
+
return useRender({
|
|
278
|
+
render,
|
|
279
|
+
defaultTagName: "p",
|
|
280
|
+
props: { id: errorId, ...fieldDataAttributes(state), className, children },
|
|
281
|
+
consumerProps: rest
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
285
|
+
0 && (module.exports = {
|
|
286
|
+
Field
|
|
287
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
3
|
+
|
|
4
|
+
type FieldRootOwnProps = {
|
|
5
|
+
/** Shows the Error and marks the control `aria-invalid`. Yours to set — Field validates nothing. */
|
|
6
|
+
invalid?: boolean;
|
|
7
|
+
/** Disables the control and marks every part `data-disabled`. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Marks the control `required`, so the browser's own validation reports it. */
|
|
10
|
+
required?: boolean;
|
|
11
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
12
|
+
render?: ReactElement;
|
|
13
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
14
|
+
ref?: Ref<HTMLElement>;
|
|
15
|
+
};
|
|
16
|
+
type FieldRootProps = FieldRootOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof FieldRootOwnProps>;
|
|
17
|
+
/**
|
|
18
|
+
* One control with its label, description and error (decision 15). Generates their ids and
|
|
19
|
+
* holds `invalid`, `disabled` and `required`; `Control` puts them on the control.
|
|
20
|
+
*
|
|
21
|
+
* Validity is yours: set `invalid` from react-hook-form's `fieldState`, or from what the
|
|
22
|
+
* browser reported. A group of controls under one label is a native `<fieldset>`.
|
|
23
|
+
*/
|
|
24
|
+
declare function FieldRoot({ invalid, disabled, required, className, children, render, ...rest }: FieldRootProps): react.JSX.Element;
|
|
25
|
+
|
|
26
|
+
type FieldLabelOwnProps = {
|
|
27
|
+
/** Element to render instead of the default `<label>`. Props and ref are merged onto it. */
|
|
28
|
+
render?: ReactElement;
|
|
29
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
30
|
+
ref?: Ref<HTMLElement>;
|
|
31
|
+
};
|
|
32
|
+
type FieldLabelProps = FieldLabelOwnProps & Omit<ComponentPropsWithRef<'label'>, keyof FieldLabelOwnProps>;
|
|
33
|
+
/** Names the control: a `<label>` whose `htmlFor` is the control's id, so a press focuses it. */
|
|
34
|
+
declare function FieldLabel({ className, children, render, ...rest }: FieldLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
35
|
+
|
|
36
|
+
type FieldControlOwnProps = {
|
|
37
|
+
/**
|
|
38
|
+
* The control: `<Input />`, `<Select />`, `<Checkbox.Root />`, `<Combobox.Input />` or your
|
|
39
|
+
* own. Defaults to an `<input>`. The Field's `id`, `aria-describedby`, `aria-invalid`,
|
|
40
|
+
* `disabled` and `required` are merged onto it.
|
|
41
|
+
*/
|
|
42
|
+
render?: ReactElement;
|
|
43
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
44
|
+
ref?: Ref<HTMLElement>;
|
|
45
|
+
};
|
|
46
|
+
type FieldControlProps = FieldControlOwnProps & Omit<ComponentPropsWithRef<'input'>, keyof FieldControlOwnProps>;
|
|
47
|
+
/**
|
|
48
|
+
* Puts the Field on its control. `render` is the seam: Field does not reach into each control,
|
|
49
|
+
* it hands the control the attributes that tie it to the label, description and error.
|
|
50
|
+
*
|
|
51
|
+
* `aria-describedby` names the Description, then the Error — only those rendered — followed by
|
|
52
|
+
* any of your own. The id is the Field's: an `id` of your own breaks the Label's `htmlFor`.
|
|
53
|
+
*/
|
|
54
|
+
declare function FieldControl({ render, 'aria-describedby': describedBy, ...rest }: FieldControlProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
55
|
+
|
|
56
|
+
type FieldDescriptionOwnProps = {
|
|
57
|
+
/** Element to render instead of the default `<p>`. Props and ref are merged onto it. */
|
|
58
|
+
render?: ReactElement;
|
|
59
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
60
|
+
ref?: Ref<HTMLElement>;
|
|
61
|
+
};
|
|
62
|
+
type FieldDescriptionProps = FieldDescriptionOwnProps & Omit<ComponentPropsWithRef<'p'>, keyof FieldDescriptionOwnProps>;
|
|
63
|
+
/**
|
|
64
|
+
* Help text under the control, read out with it through `aria-describedby`.
|
|
65
|
+
*/
|
|
66
|
+
declare function FieldDescription({ className, children, render, ...rest }: FieldDescriptionProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
67
|
+
|
|
68
|
+
type FieldErrorOwnProps = {
|
|
69
|
+
/** Element to render instead of the default `<p>`. Props and ref are merged onto it. */
|
|
70
|
+
render?: ReactElement;
|
|
71
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
72
|
+
ref?: Ref<HTMLElement>;
|
|
73
|
+
};
|
|
74
|
+
type FieldErrorProps = FieldErrorOwnProps & Omit<ComponentPropsWithRef<'p'>, keyof FieldErrorOwnProps>;
|
|
75
|
+
/**
|
|
76
|
+
* What is wrong, read out with the control through `aria-describedby`. Rendered only while the
|
|
77
|
+
* Root is `invalid`, so it is named only while it is shown.
|
|
78
|
+
*/
|
|
79
|
+
declare function FieldError({ className, children, render, ...rest }: FieldErrorProps): react.JSX.Element | null;
|
|
80
|
+
|
|
81
|
+
declare namespace index_parts {
|
|
82
|
+
export { FieldControl as Control, FieldDescription as Description, FieldError as Error, FieldLabel as Label, FieldRoot as Root };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The state Field.Root shares with its parts, and projects as `data-*` attributes. */
|
|
86
|
+
type FieldState = {
|
|
87
|
+
invalid: boolean;
|
|
88
|
+
disabled: boolean;
|
|
89
|
+
required: boolean;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export { index_parts as Field, type FieldControlProps, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldRootProps, type FieldState };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
3
|
+
|
|
4
|
+
type FieldRootOwnProps = {
|
|
5
|
+
/** Shows the Error and marks the control `aria-invalid`. Yours to set — Field validates nothing. */
|
|
6
|
+
invalid?: boolean;
|
|
7
|
+
/** Disables the control and marks every part `data-disabled`. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Marks the control `required`, so the browser's own validation reports it. */
|
|
10
|
+
required?: boolean;
|
|
11
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
12
|
+
render?: ReactElement;
|
|
13
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
14
|
+
ref?: Ref<HTMLElement>;
|
|
15
|
+
};
|
|
16
|
+
type FieldRootProps = FieldRootOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof FieldRootOwnProps>;
|
|
17
|
+
/**
|
|
18
|
+
* One control with its label, description and error (decision 15). Generates their ids and
|
|
19
|
+
* holds `invalid`, `disabled` and `required`; `Control` puts them on the control.
|
|
20
|
+
*
|
|
21
|
+
* Validity is yours: set `invalid` from react-hook-form's `fieldState`, or from what the
|
|
22
|
+
* browser reported. A group of controls under one label is a native `<fieldset>`.
|
|
23
|
+
*/
|
|
24
|
+
declare function FieldRoot({ invalid, disabled, required, className, children, render, ...rest }: FieldRootProps): react.JSX.Element;
|
|
25
|
+
|
|
26
|
+
type FieldLabelOwnProps = {
|
|
27
|
+
/** Element to render instead of the default `<label>`. Props and ref are merged onto it. */
|
|
28
|
+
render?: ReactElement;
|
|
29
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
30
|
+
ref?: Ref<HTMLElement>;
|
|
31
|
+
};
|
|
32
|
+
type FieldLabelProps = FieldLabelOwnProps & Omit<ComponentPropsWithRef<'label'>, keyof FieldLabelOwnProps>;
|
|
33
|
+
/** Names the control: a `<label>` whose `htmlFor` is the control's id, so a press focuses it. */
|
|
34
|
+
declare function FieldLabel({ className, children, render, ...rest }: FieldLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
35
|
+
|
|
36
|
+
type FieldControlOwnProps = {
|
|
37
|
+
/**
|
|
38
|
+
* The control: `<Input />`, `<Select />`, `<Checkbox.Root />`, `<Combobox.Input />` or your
|
|
39
|
+
* own. Defaults to an `<input>`. The Field's `id`, `aria-describedby`, `aria-invalid`,
|
|
40
|
+
* `disabled` and `required` are merged onto it.
|
|
41
|
+
*/
|
|
42
|
+
render?: ReactElement;
|
|
43
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
44
|
+
ref?: Ref<HTMLElement>;
|
|
45
|
+
};
|
|
46
|
+
type FieldControlProps = FieldControlOwnProps & Omit<ComponentPropsWithRef<'input'>, keyof FieldControlOwnProps>;
|
|
47
|
+
/**
|
|
48
|
+
* Puts the Field on its control. `render` is the seam: Field does not reach into each control,
|
|
49
|
+
* it hands the control the attributes that tie it to the label, description and error.
|
|
50
|
+
*
|
|
51
|
+
* `aria-describedby` names the Description, then the Error — only those rendered — followed by
|
|
52
|
+
* any of your own. The id is the Field's: an `id` of your own breaks the Label's `htmlFor`.
|
|
53
|
+
*/
|
|
54
|
+
declare function FieldControl({ render, 'aria-describedby': describedBy, ...rest }: FieldControlProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
55
|
+
|
|
56
|
+
type FieldDescriptionOwnProps = {
|
|
57
|
+
/** Element to render instead of the default `<p>`. Props and ref are merged onto it. */
|
|
58
|
+
render?: ReactElement;
|
|
59
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
60
|
+
ref?: Ref<HTMLElement>;
|
|
61
|
+
};
|
|
62
|
+
type FieldDescriptionProps = FieldDescriptionOwnProps & Omit<ComponentPropsWithRef<'p'>, keyof FieldDescriptionOwnProps>;
|
|
63
|
+
/**
|
|
64
|
+
* Help text under the control, read out with it through `aria-describedby`.
|
|
65
|
+
*/
|
|
66
|
+
declare function FieldDescription({ className, children, render, ...rest }: FieldDescriptionProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
67
|
+
|
|
68
|
+
type FieldErrorOwnProps = {
|
|
69
|
+
/** Element to render instead of the default `<p>`. Props and ref are merged onto it. */
|
|
70
|
+
render?: ReactElement;
|
|
71
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
72
|
+
ref?: Ref<HTMLElement>;
|
|
73
|
+
};
|
|
74
|
+
type FieldErrorProps = FieldErrorOwnProps & Omit<ComponentPropsWithRef<'p'>, keyof FieldErrorOwnProps>;
|
|
75
|
+
/**
|
|
76
|
+
* What is wrong, read out with the control through `aria-describedby`. Rendered only while the
|
|
77
|
+
* Root is `invalid`, so it is named only while it is shown.
|
|
78
|
+
*/
|
|
79
|
+
declare function FieldError({ className, children, render, ...rest }: FieldErrorProps): react.JSX.Element | null;
|
|
80
|
+
|
|
81
|
+
declare namespace index_parts {
|
|
82
|
+
export { FieldControl as Control, FieldDescription as Description, FieldError as Error, FieldLabel as Label, FieldRoot as Root };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The state Field.Root shares with its parts, and projects as `data-*` attributes. */
|
|
86
|
+
type FieldState = {
|
|
87
|
+
invalid: boolean;
|
|
88
|
+
disabled: boolean;
|
|
89
|
+
required: boolean;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export { index_parts as Field, type FieldControlProps, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldRootProps, type FieldState };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export,
|
|
3
|
+
useRender
|
|
4
|
+
} from "../chunk-OQTWWZ4B.js";
|
|
5
|
+
|
|
6
|
+
// src/field/index.parts.ts
|
|
7
|
+
var index_parts_exports = {};
|
|
8
|
+
__export(index_parts_exports, {
|
|
9
|
+
Control: () => FieldControl,
|
|
10
|
+
Description: () => FieldDescription,
|
|
11
|
+
Error: () => FieldError,
|
|
12
|
+
Label: () => FieldLabel,
|
|
13
|
+
Root: () => FieldRoot
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// src/field/FieldRoot.tsx
|
|
17
|
+
import { useCallback, useId, useMemo, useState } from "react";
|
|
18
|
+
|
|
19
|
+
// src/field/FieldRootContext.ts
|
|
20
|
+
import { createContext, useContext } from "react";
|
|
21
|
+
var FieldRootContext = createContext(null);
|
|
22
|
+
function useFieldRootContext(part) {
|
|
23
|
+
const context = useContext(FieldRootContext);
|
|
24
|
+
if (context === null) {
|
|
25
|
+
throw new Error(`<Field.${part}> must be rendered inside <Field.Root>.`);
|
|
26
|
+
}
|
|
27
|
+
return context;
|
|
28
|
+
}
|
|
29
|
+
function fieldDataAttributes({ invalid, disabled, required }) {
|
|
30
|
+
return {
|
|
31
|
+
"data-invalid": invalid ? "" : void 0,
|
|
32
|
+
"data-disabled": disabled ? "" : void 0,
|
|
33
|
+
"data-required": required ? "" : void 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/field/FieldRoot.tsx
|
|
38
|
+
import { jsx } from "react/jsx-runtime";
|
|
39
|
+
function usePresence() {
|
|
40
|
+
const [count, setCount] = useState(0);
|
|
41
|
+
const register = useCallback(() => {
|
|
42
|
+
setCount((n) => n + 1);
|
|
43
|
+
return () => setCount((n) => n - 1);
|
|
44
|
+
}, []);
|
|
45
|
+
return [count > 0, register];
|
|
46
|
+
}
|
|
47
|
+
function FieldRoot({
|
|
48
|
+
invalid = false,
|
|
49
|
+
disabled = false,
|
|
50
|
+
required = false,
|
|
51
|
+
className,
|
|
52
|
+
children,
|
|
53
|
+
render,
|
|
54
|
+
...rest
|
|
55
|
+
}) {
|
|
56
|
+
const id = useId();
|
|
57
|
+
const [hasDescription, registerDescription] = usePresence();
|
|
58
|
+
const [hasError, registerError] = usePresence();
|
|
59
|
+
const context = useMemo(
|
|
60
|
+
() => ({
|
|
61
|
+
invalid,
|
|
62
|
+
disabled,
|
|
63
|
+
required,
|
|
64
|
+
controlId: `${id}-control`,
|
|
65
|
+
descriptionId: `${id}-description`,
|
|
66
|
+
errorId: `${id}-error`,
|
|
67
|
+
hasDescription,
|
|
68
|
+
hasError,
|
|
69
|
+
registerDescription,
|
|
70
|
+
registerError
|
|
71
|
+
}),
|
|
72
|
+
[invalid, disabled, required, id, hasDescription, hasError, registerDescription, registerError]
|
|
73
|
+
);
|
|
74
|
+
const element = useRender({
|
|
75
|
+
render,
|
|
76
|
+
defaultTagName: "div",
|
|
77
|
+
props: { ...fieldDataAttributes({ invalid, disabled, required }), className, children },
|
|
78
|
+
consumerProps: rest
|
|
79
|
+
});
|
|
80
|
+
return /* @__PURE__ */ jsx(FieldRootContext.Provider, { value: context, children: element });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/field/FieldLabel.tsx
|
|
84
|
+
function FieldLabel({ className, children, render, ...rest }) {
|
|
85
|
+
const { controlId, ...state } = useFieldRootContext("Label");
|
|
86
|
+
return useRender({
|
|
87
|
+
render,
|
|
88
|
+
defaultTagName: "label",
|
|
89
|
+
props: { htmlFor: controlId, ...fieldDataAttributes(state), className, children },
|
|
90
|
+
consumerProps: rest
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/field/FieldControl.tsx
|
|
95
|
+
function FieldControl({
|
|
96
|
+
render,
|
|
97
|
+
"aria-describedby": describedBy,
|
|
98
|
+
...rest
|
|
99
|
+
}) {
|
|
100
|
+
const { controlId, descriptionId, errorId, hasDescription, hasError, ...state } = useFieldRootContext("Control");
|
|
101
|
+
const describedByIds = [
|
|
102
|
+
hasDescription ? descriptionId : void 0,
|
|
103
|
+
hasError ? errorId : void 0,
|
|
104
|
+
describedBy
|
|
105
|
+
].filter(Boolean).join(" ");
|
|
106
|
+
return useRender({
|
|
107
|
+
render,
|
|
108
|
+
defaultTagName: "input",
|
|
109
|
+
props: {
|
|
110
|
+
id: controlId,
|
|
111
|
+
"aria-describedby": describedByIds || void 0,
|
|
112
|
+
"aria-invalid": state.invalid || void 0,
|
|
113
|
+
disabled: state.disabled || void 0,
|
|
114
|
+
required: state.required || void 0,
|
|
115
|
+
...fieldDataAttributes(state)
|
|
116
|
+
},
|
|
117
|
+
consumerProps: rest
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/field/FieldDescription.tsx
|
|
122
|
+
import { useLayoutEffect } from "react";
|
|
123
|
+
function FieldDescription({ className, children, render, ...rest }) {
|
|
124
|
+
const context = useFieldRootContext("Description");
|
|
125
|
+
const { descriptionId, registerDescription, invalid, disabled, required } = context;
|
|
126
|
+
useLayoutEffect(registerDescription, [registerDescription]);
|
|
127
|
+
return useRender({
|
|
128
|
+
render,
|
|
129
|
+
defaultTagName: "p",
|
|
130
|
+
props: {
|
|
131
|
+
id: descriptionId,
|
|
132
|
+
...fieldDataAttributes({ invalid, disabled, required }),
|
|
133
|
+
className,
|
|
134
|
+
children
|
|
135
|
+
},
|
|
136
|
+
consumerProps: rest
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/field/FieldError.tsx
|
|
141
|
+
import { useLayoutEffect as useLayoutEffect2 } from "react";
|
|
142
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
143
|
+
function FieldError({ className, children, render, ...rest }) {
|
|
144
|
+
const context = useFieldRootContext("Error");
|
|
145
|
+
const { invalid, disabled, required } = context;
|
|
146
|
+
if (!invalid) return null;
|
|
147
|
+
return /* @__PURE__ */ jsx2(
|
|
148
|
+
ShownError,
|
|
149
|
+
{
|
|
150
|
+
className,
|
|
151
|
+
render,
|
|
152
|
+
state: { invalid, disabled, required },
|
|
153
|
+
...rest,
|
|
154
|
+
children
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
function ShownError({
|
|
159
|
+
className,
|
|
160
|
+
children,
|
|
161
|
+
render,
|
|
162
|
+
state,
|
|
163
|
+
...rest
|
|
164
|
+
}) {
|
|
165
|
+
const { errorId, registerError } = useFieldRootContext("Error");
|
|
166
|
+
useLayoutEffect2(registerError, [registerError]);
|
|
167
|
+
return useRender({
|
|
168
|
+
render,
|
|
169
|
+
defaultTagName: "p",
|
|
170
|
+
props: { id: errorId, ...fieldDataAttributes(state), className, children },
|
|
171
|
+
consumerProps: rest
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
export {
|
|
175
|
+
index_parts_exports as Field
|
|
176
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arun-dev/headless",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.0",
|
|
4
4
|
"description": "Unstyled React behaviour primitives — render engine, controlled/uncontrolled state, and data-* state projection. Ships no CSS and no class names.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -104,6 +104,16 @@
|
|
|
104
104
|
"default": "./dist/radio-group/index.cjs"
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
+
"./field": {
|
|
108
|
+
"import": {
|
|
109
|
+
"types": "./dist/field/index.d.ts",
|
|
110
|
+
"default": "./dist/field/index.js"
|
|
111
|
+
},
|
|
112
|
+
"require": {
|
|
113
|
+
"types": "./dist/field/index.d.cts",
|
|
114
|
+
"default": "./dist/field/index.cjs"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
107
117
|
"./switch": {
|
|
108
118
|
"import": {
|
|
109
119
|
"types": "./dist/switch/index.d.ts",
|