@jobber/components 9.5.3 → 9.6.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/Combobox.d.ts +1 -0
- package/Combobox.js +17 -0
- package/dist/Autocomplete/index.cjs +0 -2
- package/dist/Autocomplete/index.mjs +0 -2
- package/dist/Autocomplete-cjs.js +4 -5
- package/dist/Autocomplete-es.js +1 -2
- package/dist/Card/index.cjs +2 -2
- package/dist/Card/index.mjs +2 -2
- package/dist/Chip/index.cjs +0 -2
- package/dist/Chip/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.mjs +0 -2
- package/dist/Chips/index.cjs +0 -2
- package/dist/Chips/index.mjs +0 -2
- package/dist/Combobox/Combobox.contentSlots.d.ts +5 -0
- package/dist/Combobox/Combobox.context.d.ts +34 -0
- package/dist/Combobox/Combobox.d.ts +69 -0
- package/dist/Combobox/Combobox.footer.d.ts +7 -0
- package/dist/Combobox/Combobox.items.d.ts +25 -0
- package/dist/Combobox/Combobox.responsive.d.ts +54 -0
- package/dist/Combobox/Combobox.selectAll.d.ts +4 -0
- package/dist/Combobox/Combobox.slotFactory.d.ts +7 -0
- package/dist/Combobox/Combobox.testUtils.d.ts +12 -0
- package/dist/Combobox/Combobox.types.d.ts +166 -0
- package/dist/Combobox/index.cjs +35 -0
- package/dist/Combobox/index.d.ts +2 -0
- package/dist/Combobox/index.mjs +29 -0
- package/dist/Combobox-cjs.js +675 -0
- package/dist/Combobox-es.js +673 -0
- package/dist/ComboboxPrimitive-cjs.js +88 -47
- package/dist/ComboboxPrimitive-es.js +39 -23
- package/dist/{ComboboxChipRemove-cjs.js → ComboboxSeparator-cjs.js} +501 -455
- package/dist/{ComboboxChipRemove-es.js → ComboboxSeparator-es.js} +500 -456
- package/dist/ConfirmationModal/index.cjs +0 -2
- package/dist/ConfirmationModal/index.mjs +0 -2
- package/dist/ContentBlock/index.cjs +1 -0
- package/dist/ContentBlock/index.mjs +1 -0
- package/dist/ContentBlock-cjs.js +2 -18
- package/dist/ContentBlock-es.js +1 -17
- package/dist/DataDump/index.cjs +2 -2
- package/dist/DataDump/index.mjs +2 -2
- package/dist/DataList/components/DataListActions/index.cjs +0 -2
- package/dist/DataList/components/DataListActions/index.mjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.cjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/index.mjs +0 -2
- package/dist/DataList/components/DataListHeader/index.cjs +0 -2
- package/dist/DataList/components/DataListHeader/index.mjs +0 -2
- package/dist/DataList/components/DataListItem/index.cjs +0 -2
- package/dist/DataList/components/DataListItem/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -2
- package/dist/DataList/components/DataListItems/index.cjs +0 -2
- package/dist/DataList/components/DataListItems/index.mjs +0 -2
- package/dist/DataList/components/DataListLayout/index.cjs +0 -2
- package/dist/DataList/components/DataListLayout/index.mjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -2
- package/dist/DataList/index.cjs +0 -2
- package/dist/DataList/index.mjs +0 -2
- package/dist/DatePicker/index.cjs +0 -2
- package/dist/DatePicker/index.mjs +0 -2
- package/dist/DatePicker-cjs.js +4 -5
- package/dist/DatePicker-es.js +1 -2
- package/dist/Dialog/index.cjs +2 -2
- package/dist/Dialog/index.mjs +2 -2
- package/dist/DrawerDescription-cjs.js +268 -99
- package/dist/DrawerDescription-es.js +270 -103
- package/dist/DrawerTitle-cjs.js +2 -6
- package/dist/DrawerTitle-es.js +3 -7
- package/dist/FieldDescription-cjs.js +184 -181
- package/dist/FieldDescription-es.js +187 -184
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -2
- package/dist/FilterPicker/index.cjs +0 -2
- package/dist/FilterPicker/index.mjs +0 -2
- package/dist/FilterPickerContent-cjs.js +4 -5
- package/dist/FilterPickerContent-es.js +1 -2
- package/dist/FormatFile/index.cjs +0 -2
- package/dist/FormatFile/index.mjs +0 -2
- package/dist/Gallery/index.cjs +0 -2
- package/dist/Gallery/index.mjs +0 -2
- package/dist/InputDate/index.cjs +0 -2
- package/dist/InputDate/index.mjs +0 -2
- package/dist/InputNumber/index.cjs +2 -2
- package/dist/InputNumber/index.mjs +2 -2
- package/dist/InputNumber/types.d.ts +5 -0
- package/dist/InputNumber-cjs.js +2 -2
- package/dist/InputNumber-es.js +2 -2
- package/dist/LightBox/index.cjs +0 -2
- package/dist/LightBox/index.mjs +0 -2
- package/dist/Menu/index.cjs +2 -2
- package/dist/Menu/index.mjs +2 -2
- package/dist/Menu-cjs.js +4 -5
- package/dist/Menu-es.js +1 -2
- package/dist/MenuSubmenuTrigger-cjs.js +206 -164
- package/dist/MenuSubmenuTrigger-es.js +194 -152
- package/dist/Modal/index.cjs +0 -2
- package/dist/Modal/index.mjs +1 -3
- package/dist/NumberFieldInput-cjs.js +187 -308
- package/dist/NumberFieldInput-es.js +187 -308
- package/dist/Page/index.cjs +2 -2
- package/dist/Page/index.mjs +2 -2
- package/dist/Popover/index.cjs +0 -2
- package/dist/Popover/index.mjs +0 -2
- package/dist/Popover-cjs.js +7 -8
- package/dist/Popover-es.js +1 -2
- package/dist/ScrollAreaViewport-cjs.js +747 -1093
- package/dist/ScrollAreaViewport-es.js +734 -1081
- package/dist/Select/index.cjs +2 -2
- package/dist/Select/index.mjs +2 -2
- package/dist/SelectGroupLabel-cjs.js +207 -306
- package/dist/SelectGroupLabel-es.js +203 -302
- package/dist/SelectPrimitive-cjs.js +11 -17
- package/dist/SelectPrimitive-es.js +1 -7
- package/dist/Tooltip/index.cjs +0 -2
- package/dist/Tooltip/index.mjs +0 -2
- package/dist/Tooltip-cjs.js +6 -7
- package/dist/Tooltip-es.js +1 -2
- package/dist/buttonRenderAdapter-cjs.js +2 -1
- package/dist/buttonRenderAdapter-es.js +2 -1
- package/dist/dialogReturnFocus-cjs.js +1 -1
- package/dist/dialogReturnFocus-es.js +2 -2
- package/dist/docs/InputNumber/InputNumber.md +2 -2
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +1 -1
- package/dist/floating-ui.react-cjs.js +2557 -185
- package/dist/floating-ui.react-es.js +2512 -149
- package/dist/getMappedBreakpointWidth-cjs.js +21 -0
- package/dist/getMappedBreakpointWidth-es.js +18 -0
- package/dist/index.cjs +15 -10
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +14 -10
- package/dist/mergeClassName-cjs.js +12 -0
- package/dist/mergeClassName-es.js +10 -0
- package/dist/primitives/BottomSheet/index.cjs +1 -1
- package/dist/primitives/BottomSheet/index.mjs +1 -1
- package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +2 -2
- package/dist/primitives/ComboboxPrimitive/index.cjs +4 -5
- package/dist/primitives/ComboboxPrimitive/index.mjs +4 -5
- package/dist/primitives/SelectPrimitive/index.cjs +1 -2
- package/dist/primitives/SelectPrimitive/index.mjs +1 -2
- package/dist/primitives/index.cjs +3 -3
- package/dist/primitives/index.mjs +3 -3
- package/dist/scrollEdges-cjs.js +1 -11
- package/dist/scrollEdges-es.js +1 -11
- package/dist/scrollable-cjs.js +58 -0
- package/dist/scrollable-es.js +54 -0
- package/dist/styles.css +759 -42
- package/dist/unstyledPrimitives/index.cjs +720 -478
- package/dist/unstyledPrimitives/index.mjs +663 -421
- package/dist/useCompositeListItem-cjs.js +2108 -361
- package/dist/useCompositeListItem-es.js +2076 -331
- package/dist/useLabel-cjs.js +2 -3
- package/dist/useLabel-es.js +2 -3
- package/dist/useRenderElement-cjs.js +9 -7
- package/dist/useRenderElement-es.js +9 -7
- package/dist/useScrollLock-cjs.js +819 -344
- package/dist/useScrollLock-es.js +732 -296
- package/dist/useScrollToActive-cjs.js +4 -5
- package/dist/useScrollToActive-es.js +1 -2
- package/dist/utils/meta/meta.json +43 -1
- package/package.json +8 -3
- package/dist/floating-ui.react-dom-cjs.js +0 -2103
- package/dist/floating-ui.react-dom-es.js +0 -2072
- package/dist/floating-ui.utils-cjs.js +0 -342
- package/dist/floating-ui.utils-es.js +0 -300
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { q as useTimeout, d as useStableCallback, u as useBaseUiId, c as useIsoLayoutEffect, S as SafeReact, r as error, t as transitionStatusMapping, s as useTransitionStatus, l as useOpenChangeComplete } from './useScrollLock-es.js';
|
|
3
|
+
import { a as useFormContext, u as useLabelableContext, D as DEFAULT_VALIDITY_STATE, L as LabelableContext, f as fieldValidityMapping, F as FieldRootContext, b as useFieldRootContext } from './useCompositeListItem-es.js';
|
|
4
|
+
import { a as useRefWithInit, m as mergeProps, E as EMPTY_OBJECT, f as formatErrorMessage, u as useRenderElement } from './useRenderElement-es.js';
|
|
5
5
|
import { jsx } from 'react/jsx-runtime';
|
|
6
6
|
import { u as useLabel } from './useLabel-es.js';
|
|
7
7
|
|
|
@@ -14,77 +14,6 @@ function useFieldItemContext() {
|
|
|
14
14
|
return context;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const FieldsetRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
18
|
-
if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
|
|
19
|
-
function useFieldsetRootContext(optional = false) {
|
|
20
|
-
const context = React.useContext(FieldsetRootContext);
|
|
21
|
-
if (!context && !optional) {
|
|
22
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : formatErrorMessage(86));
|
|
23
|
-
}
|
|
24
|
-
return context;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const LabelableProvider = function LabelableProvider(props) {
|
|
28
|
-
const defaultId = useBaseUiId();
|
|
29
|
-
const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
|
|
30
|
-
const [controlId, setControlIdState] = React.useState(initialControlId);
|
|
31
|
-
const [labelId, setLabelId] = React.useState(props.labelId);
|
|
32
|
-
const [messageIds, setMessageIds] = React.useState([]);
|
|
33
|
-
const registrationsRef = useRefWithInit(() => new Map());
|
|
34
|
-
const {
|
|
35
|
-
messageIds: parentMessageIds
|
|
36
|
-
} = useLabelableContext();
|
|
37
|
-
const registerControlId = useStableCallback((source, nextId) => {
|
|
38
|
-
const registrations = registrationsRef.current;
|
|
39
|
-
if (nextId === undefined) {
|
|
40
|
-
registrations.delete(source);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
registrations.set(source, nextId);
|
|
44
|
-
|
|
45
|
-
// Only flush when registering, not when unregistering.
|
|
46
|
-
// This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
|
|
47
|
-
// The next registration will pick up the correct state.
|
|
48
|
-
setControlIdState(prev => {
|
|
49
|
-
if (registrations.size === 0) {
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
let nextControlId;
|
|
53
|
-
for (const id of registrations.values()) {
|
|
54
|
-
if (prev !== undefined && id === prev) {
|
|
55
|
-
return prev;
|
|
56
|
-
}
|
|
57
|
-
if (nextControlId === undefined) {
|
|
58
|
-
nextControlId = id;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return nextControlId;
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
const getDescriptionProps = React.useCallback(externalProps => {
|
|
65
|
-
const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
|
|
66
|
-
ids.push(...parentMessageIds, ...messageIds);
|
|
67
|
-
return {
|
|
68
|
-
...externalProps,
|
|
69
|
-
'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
|
|
70
|
-
};
|
|
71
|
-
}, [parentMessageIds, messageIds]);
|
|
72
|
-
const contextValue = React.useMemo(() => ({
|
|
73
|
-
controlId,
|
|
74
|
-
registerControlId,
|
|
75
|
-
labelId,
|
|
76
|
-
setLabelId,
|
|
77
|
-
messageIds,
|
|
78
|
-
setMessageIds,
|
|
79
|
-
getDescriptionProps
|
|
80
|
-
}), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
|
|
81
|
-
return /*#__PURE__*/jsx(LabelableContext.Provider, {
|
|
82
|
-
value: contextValue,
|
|
83
|
-
children: props.children
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
|
|
87
|
-
|
|
88
17
|
/**
|
|
89
18
|
* Combines the field's client-side, stateful validity data with the external invalid state to
|
|
90
19
|
* determine the field's true validity.
|
|
@@ -100,34 +29,35 @@ function getCombinedFieldValidityData(validityData, invalid) {
|
|
|
100
29
|
}
|
|
101
30
|
|
|
102
31
|
const validityKeys = Object.keys(DEFAULT_VALIDITY_STATE);
|
|
103
|
-
|
|
104
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Whether an input participates in the surrounding Base UI Form. Inputs that are effectively
|
|
34
|
+
* disabled, or whose `form` attribute explicitly associates them with another form, are excluded.
|
|
35
|
+
* DOM position only matters when it associates the input with a different form. Otherwise, field
|
|
36
|
+
* registration is context-driven, so portaled inputs (for example inside a dialog) still belong to
|
|
37
|
+
* the form for both validation and values projected into `onFormSubmit`.
|
|
38
|
+
*/
|
|
39
|
+
function isEligibleInput(input, formElement) {
|
|
40
|
+
if (input.matches(':disabled')) {
|
|
105
41
|
return false;
|
|
106
42
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (key === 'valid') {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
if (key === 'valueMissing') {
|
|
113
|
-
onlyValueMissing = state[key];
|
|
114
|
-
} else if (state[key]) {
|
|
115
|
-
onlyValueMissing = false;
|
|
116
|
-
}
|
|
43
|
+
if (!formElement || input.form === formElement) {
|
|
44
|
+
return true;
|
|
117
45
|
}
|
|
118
|
-
|
|
46
|
+
|
|
47
|
+
// React context crosses portal boundaries. An unassociated portaled input still participates in
|
|
48
|
+
// contextual validation, unless an explicit `form` attribute opts it out of the surrounding Form.
|
|
49
|
+
return input.form === null && !input.hasAttribute('form');
|
|
119
50
|
}
|
|
120
51
|
|
|
121
52
|
/**
|
|
122
53
|
* Picks the input whose native validity should represent a field that owns several inputs (such as a
|
|
123
|
-
* checkbox group). Prefers the first
|
|
124
|
-
*
|
|
125
|
-
* skipped because they don't participate in native constraint validation.
|
|
54
|
+
* checkbox or radio group). Prefers the first eligible currently-invalid input, where "first" follows
|
|
55
|
+
* registration order (mount order), and otherwise returns the first eligible input.
|
|
126
56
|
*/
|
|
127
|
-
function findRepresentativeInput(inputs) {
|
|
57
|
+
function findRepresentativeInput(inputs, formElement) {
|
|
128
58
|
let fallback = null;
|
|
129
|
-
for (const input of inputs) {
|
|
130
|
-
if (input
|
|
59
|
+
for (const input of inputs.keys()) {
|
|
60
|
+
if (!isEligibleInput(input, formElement)) {
|
|
131
61
|
continue;
|
|
132
62
|
}
|
|
133
63
|
if (!input.validity.valid) {
|
|
@@ -138,17 +68,14 @@ function findRepresentativeInput(inputs) {
|
|
|
138
68
|
return fallback;
|
|
139
69
|
}
|
|
140
70
|
function clearCustomValidity(element, inputs) {
|
|
141
|
-
|
|
142
|
-
for (const input of inputs) {
|
|
71
|
+
for (const input of inputs.keys()) {
|
|
143
72
|
input.setCustomValidity('');
|
|
144
|
-
didClearElement ||= input === element;
|
|
145
|
-
}
|
|
146
|
-
if (!didClearElement) {
|
|
147
|
-
element.setCustomValidity('');
|
|
148
73
|
}
|
|
74
|
+
element?.setCustomValidity('');
|
|
149
75
|
}
|
|
150
76
|
function useFieldValidation(params) {
|
|
151
77
|
const {
|
|
78
|
+
elementRef,
|
|
152
79
|
formRef
|
|
153
80
|
} = useFormContext();
|
|
154
81
|
const {
|
|
@@ -160,7 +87,7 @@ function useFieldValidation(params) {
|
|
|
160
87
|
markedDirtyRef,
|
|
161
88
|
state,
|
|
162
89
|
shouldValidateOnChange,
|
|
163
|
-
|
|
90
|
+
registeredFieldIdRef
|
|
164
91
|
} = params;
|
|
165
92
|
const {
|
|
166
93
|
controlId,
|
|
@@ -168,32 +95,27 @@ function useFieldValidation(params) {
|
|
|
168
95
|
} = useLabelableContext();
|
|
169
96
|
const timeout = useTimeout();
|
|
170
97
|
const inputRef = React.useRef(null);
|
|
171
|
-
const registeredInputs = useRefWithInit(() => new
|
|
98
|
+
const registeredInputs = useRefWithInit(() => new Map()).current;
|
|
172
99
|
const validationCommitIdRef = React.useRef(0);
|
|
173
100
|
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
registeredInputs.add(element);
|
|
101
|
+
// Groups register several inputs against a single field so focus, validation, and form-value
|
|
102
|
+
// projection can use the same live controls. This also ensures a `required` checkbox can't be
|
|
103
|
+
// satisfied by another input in the group, matching native per-checkbox behavior.
|
|
104
|
+
const registerInput = React.useCallback((element, registration) => {
|
|
105
|
+
registeredInputs.set(element, registration);
|
|
181
106
|
return () => {
|
|
182
107
|
registeredInputs.delete(element);
|
|
183
108
|
};
|
|
184
109
|
}, [registeredInputs]);
|
|
110
|
+
const getInputControl = useStableCallback(() => {
|
|
111
|
+
const element = findRepresentativeInput(registeredInputs, elementRef.current);
|
|
112
|
+
return element && registeredInputs.get(element)?.controlRef.current || null;
|
|
113
|
+
});
|
|
185
114
|
const commit = useStableCallback(async (value, revalidate = false) => {
|
|
186
|
-
// A field can own several inputs (a checkbox group), but only the last-mounted one wins the shared
|
|
187
|
-
// `inputRef`. Validate against the registry instead so every input counts; `inputRef` is the
|
|
188
|
-
// fallback only when no registered input applies (none registered, or all of them disabled).
|
|
189
|
-
const element = findRepresentativeInput(registeredInputs) ?? inputRef.current;
|
|
190
|
-
if (!element) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
115
|
validationCommitIdRef.current += 1;
|
|
194
116
|
const validationCommitId = validationCommitIdRef.current;
|
|
195
117
|
function updateRegisteredFieldValidity(nextValidityData, externalInvalid = invalid) {
|
|
196
|
-
const fieldId =
|
|
118
|
+
const fieldId = registeredFieldIdRef.current ?? controlId;
|
|
197
119
|
if (fieldId == null) {
|
|
198
120
|
return;
|
|
199
121
|
}
|
|
@@ -207,8 +129,31 @@ function useFieldValidation(params) {
|
|
|
207
129
|
validityData: validityDataWithFormErrors
|
|
208
130
|
});
|
|
209
131
|
}
|
|
132
|
+
function publishAllValid(input, externalInvalid) {
|
|
133
|
+
const nextValidityData = {
|
|
134
|
+
value,
|
|
135
|
+
state: {
|
|
136
|
+
...DEFAULT_VALIDITY_STATE,
|
|
137
|
+
valid: true
|
|
138
|
+
},
|
|
139
|
+
error: '',
|
|
140
|
+
errors: [],
|
|
141
|
+
initialValue: validityData.initialValue
|
|
142
|
+
};
|
|
143
|
+
clearCustomValidity(input, registeredInputs);
|
|
144
|
+
updateRegisteredFieldValidity(nextValidityData, externalInvalid);
|
|
145
|
+
setValidityData(nextValidityData);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// A field can own several inputs (such as a checkbox or radio group), but only the last-mounted
|
|
149
|
+
// one wins the shared `inputRef`. Validate against the registry instead so every input counts;
|
|
150
|
+
// `inputRef` is the fallback only when no inputs are registered.
|
|
151
|
+
const element = registeredInputs.size > 0 ? findRepresentativeInput(registeredInputs, elementRef.current) : inputRef.current;
|
|
152
|
+
// A field with no eligible input has no native constraint, but its custom validator still
|
|
153
|
+
// applies to the logical value at the configured validation boundary.
|
|
154
|
+
|
|
210
155
|
if (revalidate) {
|
|
211
|
-
if (state.valid !== false) {
|
|
156
|
+
if (state.valid !== false || !element) {
|
|
212
157
|
return;
|
|
213
158
|
}
|
|
214
159
|
const currentNativeValidity = element.validity;
|
|
@@ -216,39 +161,20 @@ function useFieldValidation(params) {
|
|
|
216
161
|
// The 'valueMissing' (required) condition has been resolved by the user typing.
|
|
217
162
|
// Temporarily mark the field as valid for this onChange event.
|
|
218
163
|
// Other native errors (e.g., typeMismatch) will be caught by full validation on blur or submit.
|
|
219
|
-
const nextValidityData = {
|
|
220
|
-
value,
|
|
221
|
-
state: {
|
|
222
|
-
...DEFAULT_VALIDITY_STATE,
|
|
223
|
-
valid: true
|
|
224
|
-
},
|
|
225
|
-
error: '',
|
|
226
|
-
errors: [],
|
|
227
|
-
initialValue: validityData.initialValue
|
|
228
|
-
};
|
|
229
|
-
clearCustomValidity(element, registeredInputs);
|
|
230
|
-
|
|
231
164
|
// The required value is now present; ignore stale external invalid state for this pass.
|
|
232
|
-
|
|
233
|
-
setValidityData(nextValidityData);
|
|
165
|
+
publishAllValid(element, false);
|
|
234
166
|
return;
|
|
235
167
|
}
|
|
236
168
|
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}, {});
|
|
243
|
-
|
|
244
|
-
// If it's (still) natively invalid due to something other than just valueMissing,
|
|
245
|
-
// then bail from this revalidation on change to avoid "scolding" for other errors.
|
|
246
|
-
if (!currentNativeValidityObject.valid && !isOnlyValueMissing(currentNativeValidityObject)) {
|
|
247
|
-
return;
|
|
169
|
+
// A stale custom error can coexist with valueMissing, but defer any other native errors.
|
|
170
|
+
for (const key of validityKeys) {
|
|
171
|
+
if (key !== 'valid' && key !== 'valueMissing' && key !== 'customError' && currentNativeValidity[key]) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
248
174
|
}
|
|
249
175
|
|
|
250
|
-
//
|
|
251
|
-
//
|
|
176
|
+
// Value is still missing: publish the current native state so valueMissing and the changed
|
|
177
|
+
// value are observable immediately. Full custom validation still waits for its boundary.
|
|
252
178
|
}
|
|
253
179
|
function getState(el) {
|
|
254
180
|
const computedState = validityKeys.reduce((acc, key) => {
|
|
@@ -278,10 +204,16 @@ function useFieldValidation(params) {
|
|
|
278
204
|
timeout.clear();
|
|
279
205
|
let result = null;
|
|
280
206
|
let validationErrors = [];
|
|
281
|
-
|
|
207
|
+
|
|
208
|
+
// With no representative input the field carries no native constraint, so start from an
|
|
209
|
+
// all-valid native state and let the custom `validate` result below decide the outcome.
|
|
210
|
+
const nextState = element ? getState(element) : {
|
|
211
|
+
...DEFAULT_VALIDITY_STATE,
|
|
212
|
+
valid: true
|
|
213
|
+
};
|
|
282
214
|
let defaultValidationMessage;
|
|
283
215
|
const isValidatingOnChange = shouldValidateOnChange();
|
|
284
|
-
if (element.validationMessage && !isValidatingOnChange) {
|
|
216
|
+
if (element && element.validationMessage && !isValidatingOnChange) {
|
|
285
217
|
// not validating on change, if there is a `validationMessage` from
|
|
286
218
|
// native validity, set errors and skip calling the custom validate fn
|
|
287
219
|
defaultValidationMessage = element.validationMessage;
|
|
@@ -310,20 +242,20 @@ function useFieldValidation(params) {
|
|
|
310
242
|
nextState.customError = true;
|
|
311
243
|
if (Array.isArray(result)) {
|
|
312
244
|
validationErrors = result;
|
|
313
|
-
element
|
|
245
|
+
element?.setCustomValidity(result.join('\n'));
|
|
314
246
|
} else if (result) {
|
|
315
247
|
validationErrors = [result];
|
|
316
|
-
element
|
|
248
|
+
element?.setCustomValidity(result);
|
|
317
249
|
}
|
|
318
250
|
} else if (isValidatingOnChange) {
|
|
319
251
|
// validate function returned no errors, if validating on change
|
|
320
252
|
// we need to clear the custom validity state
|
|
321
253
|
clearCustomValidity(element, registeredInputs);
|
|
322
254
|
nextState.customError = false;
|
|
323
|
-
if (element.validationMessage) {
|
|
255
|
+
if (element && element.validationMessage) {
|
|
324
256
|
defaultValidationMessage = element.validationMessage;
|
|
325
257
|
validationErrors = [element.validationMessage];
|
|
326
|
-
} else if (element.validity.valid && !nextState.valid) {
|
|
258
|
+
} else if ((!element || element.validity.valid) && !nextState.valid) {
|
|
327
259
|
nextState.valid = true;
|
|
328
260
|
}
|
|
329
261
|
}
|
|
@@ -358,12 +290,85 @@ function useFieldValidation(params) {
|
|
|
358
290
|
return React.useMemo(() => ({
|
|
359
291
|
getValidationProps,
|
|
360
292
|
inputRef,
|
|
293
|
+
registeredInputs,
|
|
361
294
|
registerInput,
|
|
295
|
+
getInputControl,
|
|
362
296
|
commit,
|
|
363
297
|
change
|
|
364
|
-
}), [getValidationProps, registerInput, commit, change]);
|
|
298
|
+
}), [getValidationProps, registeredInputs, registerInput, getInputControl, commit, change]);
|
|
365
299
|
}
|
|
366
300
|
|
|
301
|
+
const FieldsetRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
302
|
+
if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
|
|
303
|
+
function useFieldsetRootContext(optional = false) {
|
|
304
|
+
const context = React.useContext(FieldsetRootContext);
|
|
305
|
+
if (!context && !optional) {
|
|
306
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : formatErrorMessage(86));
|
|
307
|
+
}
|
|
308
|
+
return context;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const LabelableProvider = function LabelableProvider(props) {
|
|
312
|
+
const defaultId = useBaseUiId();
|
|
313
|
+
const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
|
|
314
|
+
const [controlId, setControlIdState] = React.useState(initialControlId);
|
|
315
|
+
const [labelId, setLabelId] = React.useState(props.labelId);
|
|
316
|
+
const [messageIds, setMessageIds] = React.useState([]);
|
|
317
|
+
const registrationsRef = useRefWithInit(() => new Map());
|
|
318
|
+
const {
|
|
319
|
+
messageIds: parentMessageIds
|
|
320
|
+
} = useLabelableContext();
|
|
321
|
+
const registerControlId = useStableCallback((source, nextId) => {
|
|
322
|
+
const registrations = registrationsRef.current;
|
|
323
|
+
if (nextId === undefined) {
|
|
324
|
+
registrations.delete(source);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
registrations.set(source, nextId);
|
|
328
|
+
|
|
329
|
+
// Only flush when registering, not when unregistering.
|
|
330
|
+
// This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
|
|
331
|
+
// The next registration will pick up the correct state.
|
|
332
|
+
setControlIdState(prev => {
|
|
333
|
+
if (registrations.size === 0) {
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
336
|
+
let nextControlId;
|
|
337
|
+
for (const id of registrations.values()) {
|
|
338
|
+
if (prev !== undefined && id === prev) {
|
|
339
|
+
return prev;
|
|
340
|
+
}
|
|
341
|
+
if (nextControlId === undefined) {
|
|
342
|
+
nextControlId = id;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return nextControlId;
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
const getDescriptionProps = React.useCallback(externalProps => {
|
|
349
|
+
const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
|
|
350
|
+
ids.push(...parentMessageIds, ...messageIds);
|
|
351
|
+
return {
|
|
352
|
+
...externalProps,
|
|
353
|
+
'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
|
|
354
|
+
};
|
|
355
|
+
}, [parentMessageIds, messageIds]);
|
|
356
|
+
const contextValue = React.useMemo(() => ({
|
|
357
|
+
controlId,
|
|
358
|
+
registerControlId,
|
|
359
|
+
labelId,
|
|
360
|
+
setLabelId,
|
|
361
|
+
messageIds,
|
|
362
|
+
setMessageIds,
|
|
363
|
+
getDescriptionProps
|
|
364
|
+
}), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
|
|
365
|
+
return /*#__PURE__*/jsx(LabelableContext.Provider, {
|
|
366
|
+
value: contextValue,
|
|
367
|
+
children: props.children
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
|
|
371
|
+
|
|
367
372
|
function useFieldControlRegistration(params) {
|
|
368
373
|
const {
|
|
369
374
|
commit,
|
|
@@ -371,7 +376,7 @@ function useFieldControlRegistration(params) {
|
|
|
371
376
|
markedDirtyRef,
|
|
372
377
|
name,
|
|
373
378
|
setRegisteredFieldName,
|
|
374
|
-
|
|
379
|
+
registeredFieldIdRef,
|
|
375
380
|
setValidityData,
|
|
376
381
|
validityData
|
|
377
382
|
} = params;
|
|
@@ -380,7 +385,7 @@ function useFieldControlRegistration(params) {
|
|
|
380
385
|
} = useFormContext();
|
|
381
386
|
const activeFieldControlSourceRef = React.useRef(null);
|
|
382
387
|
const registrationRef = React.useRef(null);
|
|
383
|
-
const
|
|
388
|
+
const initialValueCapturedRef = React.useRef(false);
|
|
384
389
|
const getValueForForm = useStableCallback(() => {
|
|
385
390
|
const registration = registrationRef.current;
|
|
386
391
|
if (!registration) {
|
|
@@ -411,7 +416,7 @@ function useFieldControlRegistration(params) {
|
|
|
411
416
|
formRef.current.fields.set(registration.id, {
|
|
412
417
|
getValue: getValueForForm,
|
|
413
418
|
name: name ?? registration.name,
|
|
414
|
-
controlRef: registration.controlRef
|
|
419
|
+
controlRef: registration.controlRef,
|
|
415
420
|
validityData: getCombinedFieldValidityData(validityData, invalid),
|
|
416
421
|
validate
|
|
417
422
|
});
|
|
@@ -421,18 +426,23 @@ function useFieldControlRegistration(params) {
|
|
|
421
426
|
formRef.current.fields.delete(id);
|
|
422
427
|
}
|
|
423
428
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
429
|
+
|
|
430
|
+
// The baseline belongs to the field, not to a control instance: registration re-runs on every
|
|
431
|
+
// value change, and a control that unmounts and remounts (or is swapped for another one) comes
|
|
432
|
+
// back as a brand new registration. Capturing more than once would turn whichever value the
|
|
433
|
+
// control happens to hold at that point into the initial value, so a modified field would read
|
|
434
|
+
// pristine and its real initial value would read dirty. Consumers that want a fresh baseline
|
|
435
|
+
// remount or key `<Field.Root>` itself.
|
|
436
|
+
function captureInitialValue(registration) {
|
|
437
|
+
if (initialValueCapturedRef.current) {
|
|
427
438
|
return;
|
|
428
439
|
}
|
|
440
|
+
initialValueCapturedRef.current = true;
|
|
429
441
|
const initialValue = getRegistrationValue(registration);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}));
|
|
435
|
-
}
|
|
442
|
+
setValidityData(prev => prev.initialValue === initialValue ? prev : {
|
|
443
|
+
...prev,
|
|
444
|
+
initialValue
|
|
445
|
+
});
|
|
436
446
|
}
|
|
437
447
|
useIsoLayoutEffect(() => {
|
|
438
448
|
const registration = registrationRef.current;
|
|
@@ -443,7 +453,7 @@ function useFieldControlRegistration(params) {
|
|
|
443
453
|
formRef.current.fields.set(registration.id, {
|
|
444
454
|
getValue: getValueForForm,
|
|
445
455
|
name: name ?? registration.name,
|
|
446
|
-
controlRef: registration.controlRef
|
|
456
|
+
controlRef: registration.controlRef,
|
|
447
457
|
validityData: getCombinedFieldValidityData(validityData, invalid),
|
|
448
458
|
validate
|
|
449
459
|
});
|
|
@@ -464,7 +474,7 @@ function useFieldControlRegistration(params) {
|
|
|
464
474
|
deleteRegistration();
|
|
465
475
|
registrationRef.current = null;
|
|
466
476
|
setRegisteredFieldName(undefined);
|
|
467
|
-
|
|
477
|
+
registeredFieldIdRef.current = undefined;
|
|
468
478
|
}
|
|
469
479
|
return;
|
|
470
480
|
}
|
|
@@ -474,11 +484,11 @@ function useFieldControlRegistration(params) {
|
|
|
474
484
|
if (!name) {
|
|
475
485
|
setRegisteredFieldName(registration.name);
|
|
476
486
|
}
|
|
477
|
-
|
|
487
|
+
registeredFieldIdRef.current = registration.id;
|
|
478
488
|
if (previousId && previousId !== registration.id) {
|
|
479
489
|
deleteRegistration(previousId);
|
|
480
490
|
}
|
|
481
|
-
|
|
491
|
+
captureInitialValue(registration);
|
|
482
492
|
refreshRegistration();
|
|
483
493
|
});
|
|
484
494
|
return [validate, register];
|
|
@@ -523,10 +533,6 @@ const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(com
|
|
|
523
533
|
markedDirtyRef.current = dirtyProp;
|
|
524
534
|
}
|
|
525
535
|
}, [dirtyProp]);
|
|
526
|
-
const getRegisteredFieldId = React.useCallback(() => registeredFieldIdRef.current, []);
|
|
527
|
-
const setRegisteredFieldId = React.useCallback(id => {
|
|
528
|
-
registeredFieldIdRef.current = id;
|
|
529
|
-
}, []);
|
|
530
536
|
const setDirty = useStableCallback(value => {
|
|
531
537
|
if (dirtyProp !== undefined) {
|
|
532
538
|
return;
|
|
@@ -553,7 +559,11 @@ const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(com
|
|
|
553
559
|
value: null,
|
|
554
560
|
initialValue: null
|
|
555
561
|
});
|
|
556
|
-
|
|
562
|
+
|
|
563
|
+
// App-controlled invalidity (the `invalid` prop and `<Form>` errors) keeps the field marked
|
|
564
|
+
// invalid even while disabled. Only computed validity (native constraints and `validate`)
|
|
565
|
+
// is suppressed when disabled, matching `:disabled` not participating in constraint validation.
|
|
566
|
+
const valid = !invalid && (disabled ? null : validityData.state.valid);
|
|
557
567
|
const state = React.useMemo(() => ({
|
|
558
568
|
disabled,
|
|
559
569
|
touched,
|
|
@@ -571,7 +581,7 @@ const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(com
|
|
|
571
581
|
markedDirtyRef,
|
|
572
582
|
state,
|
|
573
583
|
shouldValidateOnChange,
|
|
574
|
-
|
|
584
|
+
registeredFieldIdRef
|
|
575
585
|
});
|
|
576
586
|
const [validateFieldControl, registerFieldControl] = useFieldControlRegistration({
|
|
577
587
|
commit: validation.commit,
|
|
@@ -579,7 +589,7 @@ const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(com
|
|
|
579
589
|
markedDirtyRef,
|
|
580
590
|
name,
|
|
581
591
|
setRegisteredFieldName,
|
|
582
|
-
|
|
592
|
+
registeredFieldIdRef,
|
|
583
593
|
setValidityData,
|
|
584
594
|
validityData
|
|
585
595
|
});
|
|
@@ -592,23 +602,16 @@ const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(com
|
|
|
592
602
|
validityData,
|
|
593
603
|
setValidityData,
|
|
594
604
|
disabled,
|
|
595
|
-
touched,
|
|
596
605
|
setTouched,
|
|
597
|
-
dirty,
|
|
598
606
|
setDirty,
|
|
599
|
-
filled,
|
|
600
607
|
setFilled,
|
|
601
|
-
focused,
|
|
602
608
|
setFocused,
|
|
603
|
-
validate,
|
|
604
609
|
validationMode,
|
|
605
|
-
validationDebounceTime,
|
|
606
610
|
shouldValidateOnChange,
|
|
607
611
|
state,
|
|
608
|
-
markedDirtyRef,
|
|
609
612
|
registerFieldControl,
|
|
610
613
|
validation
|
|
611
|
-
}), [invalid, effectiveName, validityData, disabled,
|
|
614
|
+
}), [invalid, effectiveName, validityData, disabled, setTouched, setDirty, setFilled, setFocused, validationMode, shouldValidateOnChange, state, registerFieldControl, validation]);
|
|
612
615
|
const element = useRenderElement('div', componentProps, {
|
|
613
616
|
ref: forwardedRef,
|
|
614
617
|
state,
|
|
@@ -765,13 +768,13 @@ const FieldError = /*#__PURE__*/React.forwardRef(function FieldError(componentPr
|
|
|
765
768
|
} else if (validityData.errors.length > 1) {
|
|
766
769
|
error = validityData.errors;
|
|
767
770
|
}
|
|
768
|
-
let errorMessage = error
|
|
771
|
+
let errorMessage = error;
|
|
769
772
|
if (Array.isArray(error)) {
|
|
770
773
|
errorMessage = error.length > 1 ? /*#__PURE__*/jsx("ul", {
|
|
771
774
|
children: error.map(message => /*#__PURE__*/jsx("li", {
|
|
772
775
|
children: message
|
|
773
776
|
}, message))
|
|
774
|
-
}) : error[0]
|
|
777
|
+
}) : error[0];
|
|
775
778
|
}
|
|
776
779
|
const errorKey = Array.isArray(error) ? JSON.stringify(error) : error;
|
|
777
780
|
if (rendered && errorKey !== lastRenderedMessageKey) {
|
|
@@ -18,10 +18,8 @@ require('../../../useAtlantisI18n-cjs.js');
|
|
|
18
18
|
require('../../../AtlantisContext-cjs.js');
|
|
19
19
|
require('../../../Tooltip-cjs.js');
|
|
20
20
|
require('../../../floating-ui.react-cjs.js');
|
|
21
|
-
require('../../../floating-ui.utils-cjs.js');
|
|
22
21
|
require('react/jsx-runtime');
|
|
23
22
|
require('react-dom');
|
|
24
|
-
require('../../../floating-ui.react-dom-cjs.js');
|
|
25
23
|
require('framer-motion');
|
|
26
24
|
require('../../../FilterPickerProvider-cjs.js');
|
|
27
25
|
require('../../../constants-cjs.js');
|
|
@@ -16,10 +16,8 @@ import '../../../useAtlantisI18n-es.js';
|
|
|
16
16
|
import '../../../AtlantisContext-es.js';
|
|
17
17
|
import '../../../Tooltip-es.js';
|
|
18
18
|
import '../../../floating-ui.react-es.js';
|
|
19
|
-
import '../../../floating-ui.utils-es.js';
|
|
20
19
|
import 'react/jsx-runtime';
|
|
21
20
|
import 'react-dom';
|
|
22
|
-
import '../../../floating-ui.react-dom-es.js';
|
|
23
21
|
import 'framer-motion';
|
|
24
22
|
import '../../../FilterPickerProvider-es.js';
|
|
25
23
|
import '../../../constants-es.js';
|
|
@@ -4,10 +4,8 @@ var FilterPickerContent = require('../../../FilterPickerContent-cjs.js');
|
|
|
4
4
|
require('react');
|
|
5
5
|
require('classnames');
|
|
6
6
|
require('../../../floating-ui.react-cjs.js');
|
|
7
|
-
require('../../../floating-ui.utils-cjs.js');
|
|
8
7
|
require('react/jsx-runtime');
|
|
9
8
|
require('react-dom');
|
|
10
|
-
require('../../../floating-ui.react-dom-cjs.js');
|
|
11
9
|
require('../../../FilterPickerContentSearch-cjs.js');
|
|
12
10
|
require('../../../Icon-cjs.js');
|
|
13
11
|
require('@jobber/design');
|
|
@@ -2,10 +2,8 @@ export { F as FilterPickerContent } from '../../../FilterPickerContent-es.js';
|
|
|
2
2
|
import 'react';
|
|
3
3
|
import 'classnames';
|
|
4
4
|
import '../../../floating-ui.react-es.js';
|
|
5
|
-
import '../../../floating-ui.utils-es.js';
|
|
6
5
|
import 'react/jsx-runtime';
|
|
7
6
|
import 'react-dom';
|
|
8
|
-
import '../../../floating-ui.react-dom-es.js';
|
|
9
7
|
import '../../../FilterPickerContentSearch-es.js';
|
|
10
8
|
import '../../../Icon-es.js';
|
|
11
9
|
import '@jobber/design';
|
|
@@ -16,10 +16,8 @@ require('../../../AtlantisContext-cjs.js');
|
|
|
16
16
|
require('../../../Typography-cjs.js');
|
|
17
17
|
require('../../../Tooltip-cjs.js');
|
|
18
18
|
require('../../../floating-ui.react-cjs.js');
|
|
19
|
-
require('../../../floating-ui.utils-cjs.js');
|
|
20
19
|
require('react/jsx-runtime');
|
|
21
20
|
require('react-dom');
|
|
22
|
-
require('../../../floating-ui.react-dom-cjs.js');
|
|
23
21
|
require('framer-motion');
|
|
24
22
|
require('../../../FilterPickerProvider-cjs.js');
|
|
25
23
|
|
|
@@ -14,9 +14,7 @@ import '../../../AtlantisContext-es.js';
|
|
|
14
14
|
import '../../../Typography-es.js';
|
|
15
15
|
import '../../../Tooltip-es.js';
|
|
16
16
|
import '../../../floating-ui.react-es.js';
|
|
17
|
-
import '../../../floating-ui.utils-es.js';
|
|
18
17
|
import 'react/jsx-runtime';
|
|
19
18
|
import 'react-dom';
|
|
20
|
-
import '../../../floating-ui.react-dom-es.js';
|
|
21
19
|
import 'framer-motion';
|
|
22
20
|
import '../../../FilterPickerProvider-es.js';
|