@jobber/components 9.6.0 → 9.6.2
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/ActivityIndicator-cjs.js +1 -0
- package/dist/ActivityIndicator-es.js +1 -0
- package/dist/Autocomplete/index.cjs +2 -0
- package/dist/Autocomplete/index.mjs +2 -0
- package/dist/Autocomplete-cjs.js +6 -4
- package/dist/Autocomplete-es.js +3 -1
- package/dist/Banner-cjs.js +1 -0
- package/dist/Banner-es.js +1 -0
- package/dist/Card/index.cjs +2 -1
- package/dist/Card/index.mjs +2 -1
- package/dist/Chip/index.cjs +2 -0
- package/dist/Chip/index.mjs +2 -0
- package/dist/Chip-cjs.js +1 -0
- package/dist/Chip-es.js +1 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +2 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +2 -0
- package/dist/Chips/InternalChipDismissible/index.cjs +2 -0
- package/dist/Chips/InternalChipDismissible/index.mjs +2 -0
- package/dist/Chips/index.cjs +2 -0
- package/dist/Chips/index.mjs +2 -0
- package/dist/Combobox/index.cjs +4 -2
- package/dist/Combobox/index.mjs +4 -2
- package/dist/{ComboboxSeparator-cjs.js → ComboboxChipRemove-cjs.js} +455 -501
- package/dist/{ComboboxSeparator-es.js → ComboboxChipRemove-es.js} +456 -500
- package/dist/ComboboxPrimitive-cjs.js +30 -29
- package/dist/ComboboxPrimitive-es.js +3 -2
- package/dist/ConfirmationModal/index.cjs +2 -0
- package/dist/ConfirmationModal/index.mjs +2 -0
- package/dist/ConfirmationModal-cjs.js +1 -0
- package/dist/ConfirmationModal-es.js +1 -0
- package/dist/DataDump/index.cjs +2 -1
- package/dist/DataDump/index.mjs +2 -1
- package/dist/DataDump-cjs.js +1 -0
- package/dist/DataDump-es.js +1 -0
- package/dist/DataList/components/DataListActions/index.cjs +2 -0
- package/dist/DataList/components/DataListActions/index.mjs +2 -0
- package/dist/DataList/components/DataListBulkActions/index.cjs +2 -0
- package/dist/DataList/components/DataListBulkActions/index.mjs +2 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +2 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +2 -0
- package/dist/DataList/components/DataListFilters/index.cjs +2 -0
- package/dist/DataList/components/DataListFilters/index.mjs +2 -0
- package/dist/DataList/components/DataListHeader/index.cjs +2 -0
- package/dist/DataList/components/DataListHeader/index.mjs +2 -0
- package/dist/DataList/components/DataListItem/index.cjs +2 -0
- package/dist/DataList/components/DataListItem/index.mjs +2 -0
- package/dist/DataList/components/DataListItemActions/index.cjs +2 -0
- package/dist/DataList/components/DataListItemActions/index.mjs +2 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +2 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +2 -0
- package/dist/DataList/components/DataListItems/index.cjs +2 -0
- package/dist/DataList/components/DataListItems/index.mjs +2 -0
- package/dist/DataList/components/DataListLayout/index.cjs +2 -0
- package/dist/DataList/components/DataListLayout/index.mjs +2 -0
- package/dist/DataList/components/DataListLayoutActions/index.cjs +2 -0
- package/dist/DataList/components/DataListLayoutActions/index.mjs +2 -0
- package/dist/DataList/index.cjs +2 -0
- package/dist/DataList/index.mjs +2 -0
- package/dist/DataTable-cjs.js +1 -0
- package/dist/DataTable-es.js +1 -0
- package/dist/DatePicker/index.cjs +2 -0
- package/dist/DatePicker/index.mjs +2 -0
- package/dist/DatePicker-cjs.js +8 -7
- package/dist/DatePicker-es.js +6 -5
- package/dist/Dialog/index.cjs +2 -1
- package/dist/Dialog/index.mjs +2 -1
- package/dist/DrawerDescription-cjs.js +99 -268
- package/dist/DrawerDescription-es.js +103 -270
- package/dist/DrawerGrid-cjs.js +1 -0
- package/dist/DrawerGrid-es.js +1 -0
- package/dist/DrawerTitle-cjs.js +6 -2
- package/dist/DrawerTitle-es.js +7 -3
- package/dist/FeatureSwitch-cjs.js +1 -0
- package/dist/FeatureSwitch-es.js +1 -0
- package/dist/FieldDescription-cjs.js +181 -184
- package/dist/FieldDescription-es.js +184 -187
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +2 -0
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +2 -0
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +2 -0
- package/dist/FilterPicker/index.cjs +2 -0
- package/dist/FilterPicker/index.mjs +2 -0
- package/dist/FilterPickerContent-cjs.js +5 -4
- package/dist/FilterPickerContent-es.js +2 -1
- package/dist/FormFieldWrapper-cjs.js +1 -0
- package/dist/FormFieldWrapper-es.js +1 -0
- package/dist/FormatFile/index.cjs +2 -0
- package/dist/FormatFile/index.mjs +2 -0
- package/dist/FormatFile-cjs.js +1 -0
- package/dist/FormatFile-es.js +1 -0
- package/dist/Gallery/index.cjs +2 -0
- package/dist/Gallery/index.mjs +2 -0
- package/dist/InputAvatar-cjs.js +1 -0
- package/dist/InputAvatar-es.js +1 -0
- package/dist/InputDate/index.cjs +2 -0
- package/dist/InputDate/index.mjs +2 -0
- package/dist/InputDate-cjs.js +1 -0
- package/dist/InputDate-es.js +1 -0
- package/dist/InputNumber/index.cjs +2 -1
- package/dist/InputNumber/index.mjs +2 -1
- package/dist/InternalChipDismissible-cjs.js +1 -0
- package/dist/InternalChipDismissible-es.js +1 -0
- package/dist/LightBox/index.cjs +2 -0
- package/dist/LightBox/index.mjs +2 -0
- package/dist/LightBox-cjs.js +1 -0
- package/dist/LightBox-es.js +1 -0
- package/dist/Menu/index.cjs +2 -1
- package/dist/Menu/index.mjs +2 -1
- package/dist/Menu-cjs.js +6 -4
- package/dist/Menu-es.js +3 -1
- package/dist/MenuSubmenuTrigger-cjs.js +164 -206
- package/dist/MenuSubmenuTrigger-es.js +152 -194
- package/dist/Modal/index.cjs +3 -1
- package/dist/Modal/index.mjs +4 -2
- package/dist/NumberFieldInput-cjs.js +308 -187
- package/dist/NumberFieldInput-es.js +308 -187
- package/dist/Page/index.cjs +2 -1
- package/dist/Page/index.mjs +2 -1
- package/dist/Page-cjs.js +1 -0
- package/dist/Page-es.js +1 -0
- package/dist/Popover/index.cjs +2 -0
- package/dist/Popover/index.mjs +2 -0
- package/dist/Popover-cjs.js +9 -7
- package/dist/Popover-es.js +3 -1
- package/dist/ProgressBar-cjs.js +1 -0
- package/dist/ProgressBar-es.js +1 -0
- package/dist/ScrollAreaViewport-cjs.js +1093 -747
- package/dist/ScrollAreaViewport-es.js +1081 -734
- package/dist/Select/index.cjs +2 -1
- package/dist/Select/index.mjs +2 -1
- package/dist/SelectGroupLabel-cjs.js +306 -207
- package/dist/SelectGroupLabel-es.js +302 -203
- package/dist/SideDrawer-cjs.js +1 -0
- package/dist/SideDrawer-es.js +1 -0
- package/dist/Spinner-cjs.js +1 -0
- package/dist/Spinner-es.js +1 -0
- package/dist/Tooltip/index.cjs +2 -0
- package/dist/Tooltip/index.mjs +2 -0
- package/dist/Tooltip-cjs.js +7 -6
- package/dist/Tooltip-es.js +2 -1
- package/dist/dialogReturnFocus-cjs.js +1 -1
- package/dist/dialogReturnFocus-es.js +2 -2
- package/dist/floating-ui.react-cjs.js +192 -2564
- package/dist/floating-ui.react-dom-cjs.js +2103 -0
- package/dist/floating-ui.react-dom-es.js +2072 -0
- package/dist/floating-ui.react-es.js +156 -2519
- package/dist/floating-ui.utils-cjs.js +342 -0
- package/dist/floating-ui.utils-es.js +300 -0
- package/dist/index.cjs +4 -3
- package/dist/index.mjs +4 -3
- package/dist/primitives/BottomSheet/index.cjs +1 -1
- package/dist/primitives/BottomSheet/index.mjs +1 -1
- package/dist/primitives/ComboboxPrimitive/index.cjs +4 -2
- package/dist/primitives/ComboboxPrimitive/index.mjs +4 -2
- package/dist/primitives/SelectPrimitive/index.cjs +2 -0
- package/dist/primitives/SelectPrimitive/index.mjs +2 -0
- package/dist/primitives/index.cjs +3 -2
- package/dist/primitives/index.mjs +3 -2
- package/dist/scrollEdges-cjs.js +11 -1
- package/dist/scrollEdges-es.js +11 -1
- package/dist/sharedHelpers/i18n/index.cjs +1 -0
- package/dist/sharedHelpers/i18n/index.d.ts +1 -0
- package/dist/sharedHelpers/i18n/index.mjs +1 -1
- package/dist/sharedHelpers/i18n/releasedLanguages.d.ts +12 -0
- package/dist/sharedHelpers/i18n/useReleasedLocale.d.ts +6 -0
- package/dist/showToast-cjs.js +1 -1
- package/dist/showToast-es.js +1 -1
- package/dist/testUtils/releasedLanguages.d.ts +16 -0
- package/dist/unstyledPrimitives/index.cjs +478 -720
- package/dist/unstyledPrimitives/index.mjs +421 -663
- package/dist/useAtlantisI18n-cjs.js +44 -11
- package/dist/useAtlantisI18n-es.js +44 -12
- package/dist/useCompositeListItem-cjs.js +361 -2108
- package/dist/useCompositeListItem-es.js +331 -2076
- package/dist/useLabel-cjs.js +3 -2
- package/dist/useLabel-es.js +3 -2
- package/dist/useRenderElement-cjs.js +7 -9
- package/dist/useRenderElement-es.js +7 -9
- package/dist/useScrollLock-cjs.js +344 -819
- package/dist/useScrollLock-es.js +296 -732
- package/dist/useScrollToActive-cjs.js +5 -4
- package/dist/useScrollToActive-es.js +2 -1
- package/package.json +3 -3
- package/dist/scrollable-cjs.js +0 -58
- package/dist/scrollable-es.js +0 -54
|
@@ -35,6 +35,77 @@ function useFieldItemContext() {
|
|
|
35
35
|
return context;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const FieldsetRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
39
|
+
if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
|
|
40
|
+
function useFieldsetRootContext(optional = false) {
|
|
41
|
+
const context = React__namespace.useContext(FieldsetRootContext);
|
|
42
|
+
if (!context && !optional) {
|
|
43
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : useRenderElement.formatErrorMessage(86));
|
|
44
|
+
}
|
|
45
|
+
return context;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const LabelableProvider = function LabelableProvider(props) {
|
|
49
|
+
const defaultId = useScrollLock.useBaseUiId();
|
|
50
|
+
const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
|
|
51
|
+
const [controlId, setControlIdState] = React__namespace.useState(initialControlId);
|
|
52
|
+
const [labelId, setLabelId] = React__namespace.useState(props.labelId);
|
|
53
|
+
const [messageIds, setMessageIds] = React__namespace.useState([]);
|
|
54
|
+
const registrationsRef = useRenderElement.useRefWithInit(() => new Map());
|
|
55
|
+
const {
|
|
56
|
+
messageIds: parentMessageIds
|
|
57
|
+
} = useCompositeListItem.useLabelableContext();
|
|
58
|
+
const registerControlId = useScrollLock.useStableCallback((source, nextId) => {
|
|
59
|
+
const registrations = registrationsRef.current;
|
|
60
|
+
if (nextId === undefined) {
|
|
61
|
+
registrations.delete(source);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
registrations.set(source, nextId);
|
|
65
|
+
|
|
66
|
+
// Only flush when registering, not when unregistering.
|
|
67
|
+
// This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
|
|
68
|
+
// The next registration will pick up the correct state.
|
|
69
|
+
setControlIdState(prev => {
|
|
70
|
+
if (registrations.size === 0) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
let nextControlId;
|
|
74
|
+
for (const id of registrations.values()) {
|
|
75
|
+
if (prev !== undefined && id === prev) {
|
|
76
|
+
return prev;
|
|
77
|
+
}
|
|
78
|
+
if (nextControlId === undefined) {
|
|
79
|
+
nextControlId = id;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return nextControlId;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
const getDescriptionProps = React__namespace.useCallback(externalProps => {
|
|
86
|
+
const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
|
|
87
|
+
ids.push(...parentMessageIds, ...messageIds);
|
|
88
|
+
return {
|
|
89
|
+
...externalProps,
|
|
90
|
+
'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
|
|
91
|
+
};
|
|
92
|
+
}, [parentMessageIds, messageIds]);
|
|
93
|
+
const contextValue = React__namespace.useMemo(() => ({
|
|
94
|
+
controlId,
|
|
95
|
+
registerControlId,
|
|
96
|
+
labelId,
|
|
97
|
+
setLabelId,
|
|
98
|
+
messageIds,
|
|
99
|
+
setMessageIds,
|
|
100
|
+
getDescriptionProps
|
|
101
|
+
}), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
|
|
102
|
+
return /*#__PURE__*/jsxRuntime.jsx(useCompositeListItem.LabelableContext.Provider, {
|
|
103
|
+
value: contextValue,
|
|
104
|
+
children: props.children
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
|
|
108
|
+
|
|
38
109
|
/**
|
|
39
110
|
* Combines the field's client-side, stateful validity data with the external invalid state to
|
|
40
111
|
* determine the field's true validity.
|
|
@@ -50,35 +121,34 @@ function getCombinedFieldValidityData(validityData, invalid) {
|
|
|
50
121
|
}
|
|
51
122
|
|
|
52
123
|
const validityKeys = Object.keys(useCompositeListItem.DEFAULT_VALIDITY_STATE);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* disabled, or whose `form` attribute explicitly associates them with another form, are excluded.
|
|
56
|
-
* DOM position only matters when it associates the input with a different form. Otherwise, field
|
|
57
|
-
* registration is context-driven, so portaled inputs (for example inside a dialog) still belong to
|
|
58
|
-
* the form for both validation and values projected into `onFormSubmit`.
|
|
59
|
-
*/
|
|
60
|
-
function isEligibleInput(input, formElement) {
|
|
61
|
-
if (input.matches(':disabled')) {
|
|
124
|
+
function isOnlyValueMissing(state) {
|
|
125
|
+
if (!state || state.valid || !state.valueMissing) {
|
|
62
126
|
return false;
|
|
63
127
|
}
|
|
64
|
-
|
|
65
|
-
|
|
128
|
+
let onlyValueMissing = false;
|
|
129
|
+
for (const key of validityKeys) {
|
|
130
|
+
if (key === 'valid') {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (key === 'valueMissing') {
|
|
134
|
+
onlyValueMissing = state[key];
|
|
135
|
+
} else if (state[key]) {
|
|
136
|
+
onlyValueMissing = false;
|
|
137
|
+
}
|
|
66
138
|
}
|
|
67
|
-
|
|
68
|
-
// React context crosses portal boundaries. An unassociated portaled input still participates in
|
|
69
|
-
// contextual validation, unless an explicit `form` attribute opts it out of the surrounding Form.
|
|
70
|
-
return input.form === null && !input.hasAttribute('form');
|
|
139
|
+
return onlyValueMissing;
|
|
71
140
|
}
|
|
72
141
|
|
|
73
142
|
/**
|
|
74
143
|
* Picks the input whose native validity should represent a field that owns several inputs (such as a
|
|
75
|
-
* checkbox
|
|
76
|
-
*
|
|
144
|
+
* checkbox group). Prefers the first enabled currently-invalid input, where "first" follows Set
|
|
145
|
+
* insertion order (mount order), and otherwise returns the first enabled input. Disabled inputs are
|
|
146
|
+
* skipped because they don't participate in native constraint validation.
|
|
77
147
|
*/
|
|
78
|
-
function findRepresentativeInput(inputs
|
|
148
|
+
function findRepresentativeInput(inputs) {
|
|
79
149
|
let fallback = null;
|
|
80
|
-
for (const input of inputs
|
|
81
|
-
if (
|
|
150
|
+
for (const input of inputs) {
|
|
151
|
+
if (input.disabled) {
|
|
82
152
|
continue;
|
|
83
153
|
}
|
|
84
154
|
if (!input.validity.valid) {
|
|
@@ -89,14 +159,17 @@ function findRepresentativeInput(inputs, formElement) {
|
|
|
89
159
|
return fallback;
|
|
90
160
|
}
|
|
91
161
|
function clearCustomValidity(element, inputs) {
|
|
92
|
-
|
|
162
|
+
let didClearElement = false;
|
|
163
|
+
for (const input of inputs) {
|
|
93
164
|
input.setCustomValidity('');
|
|
165
|
+
didClearElement ||= input === element;
|
|
166
|
+
}
|
|
167
|
+
if (!didClearElement) {
|
|
168
|
+
element.setCustomValidity('');
|
|
94
169
|
}
|
|
95
|
-
element?.setCustomValidity('');
|
|
96
170
|
}
|
|
97
171
|
function useFieldValidation(params) {
|
|
98
172
|
const {
|
|
99
|
-
elementRef,
|
|
100
173
|
formRef
|
|
101
174
|
} = useCompositeListItem.useFormContext();
|
|
102
175
|
const {
|
|
@@ -108,7 +181,7 @@ function useFieldValidation(params) {
|
|
|
108
181
|
markedDirtyRef,
|
|
109
182
|
state,
|
|
110
183
|
shouldValidateOnChange,
|
|
111
|
-
|
|
184
|
+
getRegisteredFieldId
|
|
112
185
|
} = params;
|
|
113
186
|
const {
|
|
114
187
|
controlId,
|
|
@@ -116,27 +189,32 @@ function useFieldValidation(params) {
|
|
|
116
189
|
} = useCompositeListItem.useLabelableContext();
|
|
117
190
|
const timeout = useScrollLock.useTimeout();
|
|
118
191
|
const inputRef = React__namespace.useRef(null);
|
|
119
|
-
const registeredInputs = useRenderElement.useRefWithInit(() => new
|
|
192
|
+
const registeredInputs = useRenderElement.useRefWithInit(() => new Set()).current;
|
|
120
193
|
const validationCommitIdRef = React__namespace.useRef(0);
|
|
121
194
|
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
195
|
+
// Checkbox groups register several inputs against a single field. Track them so a `required`
|
|
196
|
+
// checkbox can't be satisfied by another input in the group, matching native per-checkbox behavior.
|
|
197
|
+
const registerInput = React__namespace.useCallback(element => {
|
|
198
|
+
if (!element) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
registeredInputs.add(element);
|
|
127
202
|
return () => {
|
|
128
203
|
registeredInputs.delete(element);
|
|
129
204
|
};
|
|
130
205
|
}, [registeredInputs]);
|
|
131
|
-
const getInputControl = useScrollLock.useStableCallback(() => {
|
|
132
|
-
const element = findRepresentativeInput(registeredInputs, elementRef.current);
|
|
133
|
-
return element && registeredInputs.get(element)?.controlRef.current || null;
|
|
134
|
-
});
|
|
135
206
|
const commit = useScrollLock.useStableCallback(async (value, revalidate = false) => {
|
|
207
|
+
// A field can own several inputs (a checkbox group), but only the last-mounted one wins the shared
|
|
208
|
+
// `inputRef`. Validate against the registry instead so every input counts; `inputRef` is the
|
|
209
|
+
// fallback only when no registered input applies (none registered, or all of them disabled).
|
|
210
|
+
const element = findRepresentativeInput(registeredInputs) ?? inputRef.current;
|
|
211
|
+
if (!element) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
136
214
|
validationCommitIdRef.current += 1;
|
|
137
215
|
const validationCommitId = validationCommitIdRef.current;
|
|
138
216
|
function updateRegisteredFieldValidity(nextValidityData, externalInvalid = invalid) {
|
|
139
|
-
const fieldId =
|
|
217
|
+
const fieldId = getRegisteredFieldId() ?? controlId;
|
|
140
218
|
if (fieldId == null) {
|
|
141
219
|
return;
|
|
142
220
|
}
|
|
@@ -150,31 +228,8 @@ function useFieldValidation(params) {
|
|
|
150
228
|
validityData: validityDataWithFormErrors
|
|
151
229
|
});
|
|
152
230
|
}
|
|
153
|
-
function publishAllValid(input, externalInvalid) {
|
|
154
|
-
const nextValidityData = {
|
|
155
|
-
value,
|
|
156
|
-
state: {
|
|
157
|
-
...useCompositeListItem.DEFAULT_VALIDITY_STATE,
|
|
158
|
-
valid: true
|
|
159
|
-
},
|
|
160
|
-
error: '',
|
|
161
|
-
errors: [],
|
|
162
|
-
initialValue: validityData.initialValue
|
|
163
|
-
};
|
|
164
|
-
clearCustomValidity(input, registeredInputs);
|
|
165
|
-
updateRegisteredFieldValidity(nextValidityData, externalInvalid);
|
|
166
|
-
setValidityData(nextValidityData);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// A field can own several inputs (such as a checkbox or radio group), but only the last-mounted
|
|
170
|
-
// one wins the shared `inputRef`. Validate against the registry instead so every input counts;
|
|
171
|
-
// `inputRef` is the fallback only when no inputs are registered.
|
|
172
|
-
const element = registeredInputs.size > 0 ? findRepresentativeInput(registeredInputs, elementRef.current) : inputRef.current;
|
|
173
|
-
// A field with no eligible input has no native constraint, but its custom validator still
|
|
174
|
-
// applies to the logical value at the configured validation boundary.
|
|
175
|
-
|
|
176
231
|
if (revalidate) {
|
|
177
|
-
if (state.valid !== false
|
|
232
|
+
if (state.valid !== false) {
|
|
178
233
|
return;
|
|
179
234
|
}
|
|
180
235
|
const currentNativeValidity = element.validity;
|
|
@@ -182,20 +237,39 @@ function useFieldValidation(params) {
|
|
|
182
237
|
// The 'valueMissing' (required) condition has been resolved by the user typing.
|
|
183
238
|
// Temporarily mark the field as valid for this onChange event.
|
|
184
239
|
// Other native errors (e.g., typeMismatch) will be caught by full validation on blur or submit.
|
|
240
|
+
const nextValidityData = {
|
|
241
|
+
value,
|
|
242
|
+
state: {
|
|
243
|
+
...useCompositeListItem.DEFAULT_VALIDITY_STATE,
|
|
244
|
+
valid: true
|
|
245
|
+
},
|
|
246
|
+
error: '',
|
|
247
|
+
errors: [],
|
|
248
|
+
initialValue: validityData.initialValue
|
|
249
|
+
};
|
|
250
|
+
clearCustomValidity(element, registeredInputs);
|
|
251
|
+
|
|
185
252
|
// The required value is now present; ignore stale external invalid state for this pass.
|
|
186
|
-
|
|
253
|
+
updateRegisteredFieldValidity(nextValidityData, false);
|
|
254
|
+
setValidityData(nextValidityData);
|
|
187
255
|
return;
|
|
188
256
|
}
|
|
189
257
|
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
258
|
+
// Value is still missing, or other conditions apply.
|
|
259
|
+
// Let's use a representation of current validity for isOnlyValueMissing.
|
|
260
|
+
const currentNativeValidityObject = validityKeys.reduce((acc, key) => {
|
|
261
|
+
acc[key] = currentNativeValidity[key];
|
|
262
|
+
return acc;
|
|
263
|
+
}, {});
|
|
264
|
+
|
|
265
|
+
// If it's (still) natively invalid due to something other than just valueMissing,
|
|
266
|
+
// then bail from this revalidation on change to avoid "scolding" for other errors.
|
|
267
|
+
if (!currentNativeValidityObject.valid && !isOnlyValueMissing(currentNativeValidityObject)) {
|
|
268
|
+
return;
|
|
195
269
|
}
|
|
196
270
|
|
|
197
|
-
//
|
|
198
|
-
//
|
|
271
|
+
// If valueMissing is still true AND it's the only issue, or if the field is now natively valid,
|
|
272
|
+
// let it fall through to the main validation logic below.
|
|
199
273
|
}
|
|
200
274
|
function getState(el) {
|
|
201
275
|
const computedState = validityKeys.reduce((acc, key) => {
|
|
@@ -225,16 +299,10 @@ function useFieldValidation(params) {
|
|
|
225
299
|
timeout.clear();
|
|
226
300
|
let result = null;
|
|
227
301
|
let validationErrors = [];
|
|
228
|
-
|
|
229
|
-
// With no representative input the field carries no native constraint, so start from an
|
|
230
|
-
// all-valid native state and let the custom `validate` result below decide the outcome.
|
|
231
|
-
const nextState = element ? getState(element) : {
|
|
232
|
-
...useCompositeListItem.DEFAULT_VALIDITY_STATE,
|
|
233
|
-
valid: true
|
|
234
|
-
};
|
|
302
|
+
const nextState = getState(element);
|
|
235
303
|
let defaultValidationMessage;
|
|
236
304
|
const isValidatingOnChange = shouldValidateOnChange();
|
|
237
|
-
if (element
|
|
305
|
+
if (element.validationMessage && !isValidatingOnChange) {
|
|
238
306
|
// not validating on change, if there is a `validationMessage` from
|
|
239
307
|
// native validity, set errors and skip calling the custom validate fn
|
|
240
308
|
defaultValidationMessage = element.validationMessage;
|
|
@@ -263,20 +331,20 @@ function useFieldValidation(params) {
|
|
|
263
331
|
nextState.customError = true;
|
|
264
332
|
if (Array.isArray(result)) {
|
|
265
333
|
validationErrors = result;
|
|
266
|
-
element
|
|
334
|
+
element.setCustomValidity(result.join('\n'));
|
|
267
335
|
} else if (result) {
|
|
268
336
|
validationErrors = [result];
|
|
269
|
-
element
|
|
337
|
+
element.setCustomValidity(result);
|
|
270
338
|
}
|
|
271
339
|
} else if (isValidatingOnChange) {
|
|
272
340
|
// validate function returned no errors, if validating on change
|
|
273
341
|
// we need to clear the custom validity state
|
|
274
342
|
clearCustomValidity(element, registeredInputs);
|
|
275
343
|
nextState.customError = false;
|
|
276
|
-
if (element
|
|
344
|
+
if (element.validationMessage) {
|
|
277
345
|
defaultValidationMessage = element.validationMessage;
|
|
278
346
|
validationErrors = [element.validationMessage];
|
|
279
|
-
} else if (
|
|
347
|
+
} else if (element.validity.valid && !nextState.valid) {
|
|
280
348
|
nextState.valid = true;
|
|
281
349
|
}
|
|
282
350
|
}
|
|
@@ -311,85 +379,12 @@ function useFieldValidation(params) {
|
|
|
311
379
|
return React__namespace.useMemo(() => ({
|
|
312
380
|
getValidationProps,
|
|
313
381
|
inputRef,
|
|
314
|
-
registeredInputs,
|
|
315
382
|
registerInput,
|
|
316
|
-
getInputControl,
|
|
317
383
|
commit,
|
|
318
384
|
change
|
|
319
|
-
}), [getValidationProps,
|
|
385
|
+
}), [getValidationProps, registerInput, commit, change]);
|
|
320
386
|
}
|
|
321
387
|
|
|
322
|
-
const FieldsetRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
323
|
-
if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
|
|
324
|
-
function useFieldsetRootContext(optional = false) {
|
|
325
|
-
const context = React__namespace.useContext(FieldsetRootContext);
|
|
326
|
-
if (!context && !optional) {
|
|
327
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : useRenderElement.formatErrorMessage(86));
|
|
328
|
-
}
|
|
329
|
-
return context;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const LabelableProvider = function LabelableProvider(props) {
|
|
333
|
-
const defaultId = useScrollLock.useBaseUiId();
|
|
334
|
-
const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
|
|
335
|
-
const [controlId, setControlIdState] = React__namespace.useState(initialControlId);
|
|
336
|
-
const [labelId, setLabelId] = React__namespace.useState(props.labelId);
|
|
337
|
-
const [messageIds, setMessageIds] = React__namespace.useState([]);
|
|
338
|
-
const registrationsRef = useRenderElement.useRefWithInit(() => new Map());
|
|
339
|
-
const {
|
|
340
|
-
messageIds: parentMessageIds
|
|
341
|
-
} = useCompositeListItem.useLabelableContext();
|
|
342
|
-
const registerControlId = useScrollLock.useStableCallback((source, nextId) => {
|
|
343
|
-
const registrations = registrationsRef.current;
|
|
344
|
-
if (nextId === undefined) {
|
|
345
|
-
registrations.delete(source);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
registrations.set(source, nextId);
|
|
349
|
-
|
|
350
|
-
// Only flush when registering, not when unregistering.
|
|
351
|
-
// This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
|
|
352
|
-
// The next registration will pick up the correct state.
|
|
353
|
-
setControlIdState(prev => {
|
|
354
|
-
if (registrations.size === 0) {
|
|
355
|
-
return undefined;
|
|
356
|
-
}
|
|
357
|
-
let nextControlId;
|
|
358
|
-
for (const id of registrations.values()) {
|
|
359
|
-
if (prev !== undefined && id === prev) {
|
|
360
|
-
return prev;
|
|
361
|
-
}
|
|
362
|
-
if (nextControlId === undefined) {
|
|
363
|
-
nextControlId = id;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return nextControlId;
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
const getDescriptionProps = React__namespace.useCallback(externalProps => {
|
|
370
|
-
const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
|
|
371
|
-
ids.push(...parentMessageIds, ...messageIds);
|
|
372
|
-
return {
|
|
373
|
-
...externalProps,
|
|
374
|
-
'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
|
|
375
|
-
};
|
|
376
|
-
}, [parentMessageIds, messageIds]);
|
|
377
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
378
|
-
controlId,
|
|
379
|
-
registerControlId,
|
|
380
|
-
labelId,
|
|
381
|
-
setLabelId,
|
|
382
|
-
messageIds,
|
|
383
|
-
setMessageIds,
|
|
384
|
-
getDescriptionProps
|
|
385
|
-
}), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
|
|
386
|
-
return /*#__PURE__*/jsxRuntime.jsx(useCompositeListItem.LabelableContext.Provider, {
|
|
387
|
-
value: contextValue,
|
|
388
|
-
children: props.children
|
|
389
|
-
});
|
|
390
|
-
};
|
|
391
|
-
if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
|
|
392
|
-
|
|
393
388
|
function useFieldControlRegistration(params) {
|
|
394
389
|
const {
|
|
395
390
|
commit,
|
|
@@ -397,7 +392,7 @@ function useFieldControlRegistration(params) {
|
|
|
397
392
|
markedDirtyRef,
|
|
398
393
|
name,
|
|
399
394
|
setRegisteredFieldName,
|
|
400
|
-
|
|
395
|
+
setRegisteredFieldId,
|
|
401
396
|
setValidityData,
|
|
402
397
|
validityData
|
|
403
398
|
} = params;
|
|
@@ -406,7 +401,7 @@ function useFieldControlRegistration(params) {
|
|
|
406
401
|
} = useCompositeListItem.useFormContext();
|
|
407
402
|
const activeFieldControlSourceRef = React__namespace.useRef(null);
|
|
408
403
|
const registrationRef = React__namespace.useRef(null);
|
|
409
|
-
const
|
|
404
|
+
const fallbackControlRef = React__namespace.useRef(null);
|
|
410
405
|
const getValueForForm = useScrollLock.useStableCallback(() => {
|
|
411
406
|
const registration = registrationRef.current;
|
|
412
407
|
if (!registration) {
|
|
@@ -437,7 +432,7 @@ function useFieldControlRegistration(params) {
|
|
|
437
432
|
formRef.current.fields.set(registration.id, {
|
|
438
433
|
getValue: getValueForForm,
|
|
439
434
|
name: name ?? registration.name,
|
|
440
|
-
controlRef: registration.controlRef,
|
|
435
|
+
controlRef: registration.controlRef ?? fallbackControlRef,
|
|
441
436
|
validityData: getCombinedFieldValidityData(validityData, invalid),
|
|
442
437
|
validate
|
|
443
438
|
});
|
|
@@ -447,23 +442,18 @@ function useFieldControlRegistration(params) {
|
|
|
447
442
|
formRef.current.fields.delete(id);
|
|
448
443
|
}
|
|
449
444
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
// back as a brand new registration. Capturing more than once would turn whichever value the
|
|
454
|
-
// control happens to hold at that point into the initial value, so a modified field would read
|
|
455
|
-
// pristine and its real initial value would read dirty. Consumers that want a fresh baseline
|
|
456
|
-
// remount or key `<Field.Root>` itself.
|
|
457
|
-
function captureInitialValue(registration) {
|
|
458
|
-
if (initialValueCapturedRef.current) {
|
|
445
|
+
function syncInitialValue() {
|
|
446
|
+
const registration = registrationRef.current;
|
|
447
|
+
if (!registration) {
|
|
459
448
|
return;
|
|
460
449
|
}
|
|
461
|
-
initialValueCapturedRef.current = true;
|
|
462
450
|
const initialValue = getRegistrationValue(registration);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
451
|
+
if (validityData.initialValue === null && initialValue !== null) {
|
|
452
|
+
setValidityData(prev => ({
|
|
453
|
+
...prev,
|
|
454
|
+
initialValue
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
467
457
|
}
|
|
468
458
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
469
459
|
const registration = registrationRef.current;
|
|
@@ -474,7 +464,7 @@ function useFieldControlRegistration(params) {
|
|
|
474
464
|
formRef.current.fields.set(registration.id, {
|
|
475
465
|
getValue: getValueForForm,
|
|
476
466
|
name: name ?? registration.name,
|
|
477
|
-
controlRef: registration.controlRef,
|
|
467
|
+
controlRef: registration.controlRef ?? fallbackControlRef,
|
|
478
468
|
validityData: getCombinedFieldValidityData(validityData, invalid),
|
|
479
469
|
validate
|
|
480
470
|
});
|
|
@@ -495,7 +485,7 @@ function useFieldControlRegistration(params) {
|
|
|
495
485
|
deleteRegistration();
|
|
496
486
|
registrationRef.current = null;
|
|
497
487
|
setRegisteredFieldName(undefined);
|
|
498
|
-
|
|
488
|
+
setRegisteredFieldId(undefined);
|
|
499
489
|
}
|
|
500
490
|
return;
|
|
501
491
|
}
|
|
@@ -505,11 +495,11 @@ function useFieldControlRegistration(params) {
|
|
|
505
495
|
if (!name) {
|
|
506
496
|
setRegisteredFieldName(registration.name);
|
|
507
497
|
}
|
|
508
|
-
|
|
498
|
+
setRegisteredFieldId(registration.id);
|
|
509
499
|
if (previousId && previousId !== registration.id) {
|
|
510
500
|
deleteRegistration(previousId);
|
|
511
501
|
}
|
|
512
|
-
|
|
502
|
+
syncInitialValue();
|
|
513
503
|
refreshRegistration();
|
|
514
504
|
});
|
|
515
505
|
return [validate, register];
|
|
@@ -554,6 +544,10 @@ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRo
|
|
|
554
544
|
markedDirtyRef.current = dirtyProp;
|
|
555
545
|
}
|
|
556
546
|
}, [dirtyProp]);
|
|
547
|
+
const getRegisteredFieldId = React__namespace.useCallback(() => registeredFieldIdRef.current, []);
|
|
548
|
+
const setRegisteredFieldId = React__namespace.useCallback(id => {
|
|
549
|
+
registeredFieldIdRef.current = id;
|
|
550
|
+
}, []);
|
|
557
551
|
const setDirty = useScrollLock.useStableCallback(value => {
|
|
558
552
|
if (dirtyProp !== undefined) {
|
|
559
553
|
return;
|
|
@@ -580,11 +574,7 @@ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRo
|
|
|
580
574
|
value: null,
|
|
581
575
|
initialValue: null
|
|
582
576
|
});
|
|
583
|
-
|
|
584
|
-
// App-controlled invalidity (the `invalid` prop and `<Form>` errors) keeps the field marked
|
|
585
|
-
// invalid even while disabled. Only computed validity (native constraints and `validate`)
|
|
586
|
-
// is suppressed when disabled, matching `:disabled` not participating in constraint validation.
|
|
587
|
-
const valid = !invalid && (disabled ? null : validityData.state.valid);
|
|
577
|
+
const valid = disabled ? null : !invalid && validityData.state.valid;
|
|
588
578
|
const state = React__namespace.useMemo(() => ({
|
|
589
579
|
disabled,
|
|
590
580
|
touched,
|
|
@@ -602,7 +592,7 @@ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRo
|
|
|
602
592
|
markedDirtyRef,
|
|
603
593
|
state,
|
|
604
594
|
shouldValidateOnChange,
|
|
605
|
-
|
|
595
|
+
getRegisteredFieldId
|
|
606
596
|
});
|
|
607
597
|
const [validateFieldControl, registerFieldControl] = useFieldControlRegistration({
|
|
608
598
|
commit: validation.commit,
|
|
@@ -610,7 +600,7 @@ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRo
|
|
|
610
600
|
markedDirtyRef,
|
|
611
601
|
name,
|
|
612
602
|
setRegisteredFieldName,
|
|
613
|
-
|
|
603
|
+
setRegisteredFieldId,
|
|
614
604
|
setValidityData,
|
|
615
605
|
validityData
|
|
616
606
|
});
|
|
@@ -623,16 +613,23 @@ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRo
|
|
|
623
613
|
validityData,
|
|
624
614
|
setValidityData,
|
|
625
615
|
disabled,
|
|
616
|
+
touched,
|
|
626
617
|
setTouched,
|
|
618
|
+
dirty,
|
|
627
619
|
setDirty,
|
|
620
|
+
filled,
|
|
628
621
|
setFilled,
|
|
622
|
+
focused,
|
|
629
623
|
setFocused,
|
|
624
|
+
validate,
|
|
630
625
|
validationMode,
|
|
626
|
+
validationDebounceTime,
|
|
631
627
|
shouldValidateOnChange,
|
|
632
628
|
state,
|
|
629
|
+
markedDirtyRef,
|
|
633
630
|
registerFieldControl,
|
|
634
631
|
validation
|
|
635
|
-
}), [invalid, effectiveName, validityData, disabled, setTouched, setDirty, setFilled, setFocused, validationMode, shouldValidateOnChange, state, registerFieldControl, validation]);
|
|
632
|
+
}), [invalid, effectiveName, validityData, disabled, touched, setTouched, dirty, setDirty, filled, setFilled, focused, setFocused, validate, validationMode, validationDebounceTime, shouldValidateOnChange, state, registerFieldControl, validation]);
|
|
636
633
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
637
634
|
ref: forwardedRef,
|
|
638
635
|
state,
|
|
@@ -789,13 +786,13 @@ const FieldError = /*#__PURE__*/React__namespace.forwardRef(function FieldError(
|
|
|
789
786
|
} else if (validityData.errors.length > 1) {
|
|
790
787
|
error = validityData.errors;
|
|
791
788
|
}
|
|
792
|
-
let errorMessage = error;
|
|
789
|
+
let errorMessage = error ?? '';
|
|
793
790
|
if (Array.isArray(error)) {
|
|
794
791
|
errorMessage = error.length > 1 ? /*#__PURE__*/jsxRuntime.jsx("ul", {
|
|
795
792
|
children: error.map(message => /*#__PURE__*/jsxRuntime.jsx("li", {
|
|
796
793
|
children: message
|
|
797
794
|
}, message))
|
|
798
|
-
}) : error[0];
|
|
795
|
+
}) : error[0] ?? '';
|
|
799
796
|
}
|
|
800
797
|
const errorKey = Array.isArray(error) ? JSON.stringify(error) : error;
|
|
801
798
|
if (rendered && errorKey !== lastRenderedMessageKey) {
|