@octanejs/radix 0.1.32 → 0.1.34
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/cjs/AccessibleIcon.cjs +56 -0
- package/dist/cjs/Accordion.cjs +272 -0
- package/dist/cjs/AlertDialog.cjs +144 -0
- package/dist/cjs/Arrow.cjs +43 -0
- package/dist/cjs/AspectRatio.cjs +56 -0
- package/dist/cjs/Avatar.cjs +150 -0
- package/dist/cjs/Checkbox.cjs +281 -0
- package/dist/cjs/Collapsible.cjs +176 -0
- package/dist/cjs/ContextMenu.cjs +315 -0
- package/dist/cjs/Dialog.cjs +291 -0
- package/dist/cjs/DismissableLayer.cjs +382 -0
- package/dist/cjs/DropdownMenu.cjs +296 -0
- package/dist/cjs/FocusScope.cjs +257 -0
- package/dist/cjs/Form.cjs +537 -0
- package/dist/cjs/HoverCard.cjs +309 -0
- package/dist/cjs/Label.cjs +42 -0
- package/dist/cjs/Menu.cjs +925 -0
- package/dist/cjs/Menubar.cjs +475 -0
- package/dist/cjs/NavigationMenu.cjs +942 -0
- package/dist/cjs/OneTimePasswordField.cjs +729 -0
- package/dist/cjs/PasswordToggleField.cjs +377 -0
- package/dist/cjs/Popover.cjs +340 -0
- package/dist/cjs/Popper.cjs +368 -0
- package/dist/cjs/Portal.cjs +40 -0
- package/dist/cjs/Presence.cjs +183 -0
- package/dist/cjs/Primitive.cjs +63 -0
- package/dist/cjs/Progress.cjs +111 -0
- package/dist/cjs/Radio.cjs +240 -0
- package/dist/cjs/RadioGroup.cjs +216 -0
- package/dist/cjs/RovingFocusGroup.cjs +253 -0
- package/dist/cjs/ScrollArea.cjs +828 -0
- package/dist/cjs/Select.cjs +1429 -0
- package/dist/cjs/Separator.cjs +51 -0
- package/dist/cjs/Slider.cjs +634 -0
- package/dist/cjs/Slot.cjs +97 -0
- package/dist/cjs/Switch.cjs +253 -0
- package/dist/cjs/Tabs.cjs +195 -0
- package/dist/cjs/Toast.cjs +733 -0
- package/dist/cjs/Toggle.cjs +54 -0
- package/dist/cjs/ToggleGroup.cjs +174 -0
- package/dist/cjs/Toolbar.cjs +165 -0
- package/dist/cjs/Tooltip.cjs +628 -0
- package/dist/cjs/VisuallyHidden.cjs +52 -0
- package/dist/cjs/collection.cjs +95 -0
- package/dist/cjs/compose-event-handlers.cjs +35 -0
- package/dist/cjs/compose-refs.cjs +68 -0
- package/dist/cjs/context.cjs +96 -0
- package/dist/cjs/direction.cjs +41 -0
- package/dist/cjs/focus-guards.cjs +76 -0
- package/dist/cjs/index.cjs +174 -0
- package/dist/cjs/internal.cjs +51 -0
- package/dist/cjs/scroll-lock.cjs +67 -0
- package/dist/cjs/use-callback-ref.cjs +47 -0
- package/dist/cjs/use-effect-event.cjs +52 -0
- package/dist/cjs/use-is-hydrated.cjs +43 -0
- package/dist/cjs/use-previous.cjs +47 -0
- package/dist/cjs/use-size.cjs +69 -0
- package/dist/cjs/useControllableState.cjs +80 -0
- package/dist/cjs/useId.cjs +36 -0
- package/package.json +14 -7
|
@@ -0,0 +1,537 @@
|
|
|
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
|
+
var Form_exports = {};
|
|
20
|
+
__export(Form_exports, {
|
|
21
|
+
Control: () => Control,
|
|
22
|
+
Field: () => Field,
|
|
23
|
+
Form: () => Root,
|
|
24
|
+
FormControl: () => Control,
|
|
25
|
+
FormField: () => Field,
|
|
26
|
+
FormLabel: () => Label,
|
|
27
|
+
FormMessage: () => Message,
|
|
28
|
+
FormSubmit: () => Submit,
|
|
29
|
+
FormValidityState: () => ValidityState,
|
|
30
|
+
Label: () => Label,
|
|
31
|
+
Message: () => Message,
|
|
32
|
+
Root: () => Root,
|
|
33
|
+
Submit: () => Submit,
|
|
34
|
+
ValidityState: () => ValidityState,
|
|
35
|
+
createFormScope: () => createFormScope
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(Form_exports);
|
|
38
|
+
var import_octane = require("octane");
|
|
39
|
+
var import_compose_event_handlers = require("./compose-event-handlers.cjs");
|
|
40
|
+
var import_compose_refs = require("./compose-refs.cjs");
|
|
41
|
+
var import_context = require("./context.cjs");
|
|
42
|
+
var import_internal = require("./internal.cjs");
|
|
43
|
+
var import_Label = require("./Label.cjs");
|
|
44
|
+
var import_Primitive = require("./Primitive.cjs");
|
|
45
|
+
var import_useId = require("./useId.cjs");
|
|
46
|
+
const [createFormContext, createFormScope] = (0, import_context.createContextScope)("Form");
|
|
47
|
+
const FORM_NAME = "Form";
|
|
48
|
+
const [ValidationProvider, useValidationContext] = createFormContext(FORM_NAME);
|
|
49
|
+
const [AriaDescriptionProvider, useAriaDescriptionContext] = createFormContext(FORM_NAME);
|
|
50
|
+
function Root(props) {
|
|
51
|
+
const slot = (0, import_internal.S)("Form.Root");
|
|
52
|
+
const {
|
|
53
|
+
__scopeForm,
|
|
54
|
+
onClearServerErrors = () => {
|
|
55
|
+
},
|
|
56
|
+
ref: forwardedRef,
|
|
57
|
+
...rootProps
|
|
58
|
+
} = props ?? {};
|
|
59
|
+
const formRef = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "form"));
|
|
60
|
+
const composedFormRef = (0, import_compose_refs.useComposedRefs)(forwardedRef, formRef, (0, import_internal.subSlot)(slot, "refs"));
|
|
61
|
+
const [validityMap, setValidityMap] = (0, import_octane.useState)({}, (0, import_internal.subSlot)(slot, "validity"));
|
|
62
|
+
const getFieldValidity = (0, import_octane.useCallback)(
|
|
63
|
+
(fieldName) => validityMap[fieldName],
|
|
64
|
+
[validityMap],
|
|
65
|
+
(0, import_internal.subSlot)(slot, "getValidity")
|
|
66
|
+
);
|
|
67
|
+
const handleFieldValidityChange = (0, import_octane.useCallback)(
|
|
68
|
+
(fieldName, validity) => setValidityMap((prevValidityMap) => ({
|
|
69
|
+
...prevValidityMap,
|
|
70
|
+
[fieldName]: { ...prevValidityMap[fieldName] ?? {}, ...validity }
|
|
71
|
+
})),
|
|
72
|
+
[],
|
|
73
|
+
(0, import_internal.subSlot)(slot, "validityChange")
|
|
74
|
+
);
|
|
75
|
+
const handleFieldValiditionClear = (0, import_octane.useCallback)(
|
|
76
|
+
(fieldName) => {
|
|
77
|
+
setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: void 0 }));
|
|
78
|
+
setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));
|
|
79
|
+
},
|
|
80
|
+
[],
|
|
81
|
+
(0, import_internal.subSlot)(slot, "validityClear")
|
|
82
|
+
);
|
|
83
|
+
const [customMatcherEntriesMap, setCustomMatcherEntriesMap] = (0, import_octane.useState)({}, (0, import_internal.subSlot)(slot, "matchers"));
|
|
84
|
+
const getFieldCustomMatcherEntries = (0, import_octane.useCallback)(
|
|
85
|
+
(fieldName) => customMatcherEntriesMap[fieldName] ?? [],
|
|
86
|
+
[customMatcherEntriesMap],
|
|
87
|
+
(0, import_internal.subSlot)(slot, "getMatchers")
|
|
88
|
+
);
|
|
89
|
+
const handleFieldCustomMatcherAdd = (0, import_octane.useCallback)(
|
|
90
|
+
(fieldName, matcherEntry) => {
|
|
91
|
+
setCustomMatcherEntriesMap((prev) => ({
|
|
92
|
+
...prev,
|
|
93
|
+
[fieldName]: [...prev[fieldName] ?? [], matcherEntry]
|
|
94
|
+
}));
|
|
95
|
+
},
|
|
96
|
+
[],
|
|
97
|
+
(0, import_internal.subSlot)(slot, "matcherAdd")
|
|
98
|
+
);
|
|
99
|
+
const handleFieldCustomMatcherRemove = (0, import_octane.useCallback)(
|
|
100
|
+
(fieldName, matcherEntryId) => {
|
|
101
|
+
setCustomMatcherEntriesMap((prev) => ({
|
|
102
|
+
...prev,
|
|
103
|
+
[fieldName]: (prev[fieldName] ?? []).filter((entry) => entry.id !== matcherEntryId)
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
[],
|
|
107
|
+
(0, import_internal.subSlot)(slot, "matcherRemove")
|
|
108
|
+
);
|
|
109
|
+
const [customErrorsMap, setCustomErrorsMap] = (0, import_octane.useState)({}, (0, import_internal.subSlot)(slot, "errors"));
|
|
110
|
+
const getFieldCustomErrors = (0, import_octane.useCallback)(
|
|
111
|
+
(fieldName) => customErrorsMap[fieldName] ?? {},
|
|
112
|
+
[customErrorsMap],
|
|
113
|
+
(0, import_internal.subSlot)(slot, "getErrors")
|
|
114
|
+
);
|
|
115
|
+
const handleFieldCustomErrorsChange = (0, import_octane.useCallback)(
|
|
116
|
+
(fieldName, customErrors) => {
|
|
117
|
+
setCustomErrorsMap((prev) => ({
|
|
118
|
+
...prev,
|
|
119
|
+
[fieldName]: { ...prev[fieldName] ?? {}, ...customErrors }
|
|
120
|
+
}));
|
|
121
|
+
},
|
|
122
|
+
[],
|
|
123
|
+
(0, import_internal.subSlot)(slot, "errorsChange")
|
|
124
|
+
);
|
|
125
|
+
const [messageIdsMap, setMessageIdsMap] = (0, import_octane.useState)(
|
|
126
|
+
{},
|
|
127
|
+
(0, import_internal.subSlot)(slot, "messages")
|
|
128
|
+
);
|
|
129
|
+
const handleFieldMessageIdAdd = (0, import_octane.useCallback)(
|
|
130
|
+
(fieldName, id) => {
|
|
131
|
+
setMessageIdsMap((prev) => {
|
|
132
|
+
const fieldDescriptionIds = new Set(prev[fieldName]).add(id);
|
|
133
|
+
return { ...prev, [fieldName]: fieldDescriptionIds };
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
[],
|
|
137
|
+
(0, import_internal.subSlot)(slot, "messageAdd")
|
|
138
|
+
);
|
|
139
|
+
const handleFieldMessageIdRemove = (0, import_octane.useCallback)(
|
|
140
|
+
(fieldName, id) => {
|
|
141
|
+
setMessageIdsMap((prev) => {
|
|
142
|
+
const fieldDescriptionIds = new Set(prev[fieldName]);
|
|
143
|
+
fieldDescriptionIds.delete(id);
|
|
144
|
+
return { ...prev, [fieldName]: fieldDescriptionIds };
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
[],
|
|
148
|
+
(0, import_internal.subSlot)(slot, "messageRemove")
|
|
149
|
+
);
|
|
150
|
+
const getFieldDescription = (0, import_octane.useCallback)(
|
|
151
|
+
(fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(" ") || void 0,
|
|
152
|
+
[messageIdsMap],
|
|
153
|
+
(0, import_internal.subSlot)(slot, "getDescription")
|
|
154
|
+
);
|
|
155
|
+
return (0, import_octane.createElement)(ValidationProvider, {
|
|
156
|
+
scope: __scopeForm,
|
|
157
|
+
getFieldValidity,
|
|
158
|
+
onFieldValidityChange: handleFieldValidityChange,
|
|
159
|
+
getFieldCustomMatcherEntries,
|
|
160
|
+
onFieldCustomMatcherEntryAdd: handleFieldCustomMatcherAdd,
|
|
161
|
+
onFieldCustomMatcherEntryRemove: handleFieldCustomMatcherRemove,
|
|
162
|
+
getFieldCustomErrors,
|
|
163
|
+
onFieldCustomErrorsChange: handleFieldCustomErrorsChange,
|
|
164
|
+
onFieldValiditionClear: handleFieldValiditionClear,
|
|
165
|
+
children: (0, import_octane.createElement)(AriaDescriptionProvider, {
|
|
166
|
+
scope: __scopeForm,
|
|
167
|
+
onFieldMessageIdAdd: handleFieldMessageIdAdd,
|
|
168
|
+
onFieldMessageIdRemove: handleFieldMessageIdRemove,
|
|
169
|
+
getFieldDescription,
|
|
170
|
+
children: (0, import_octane.createElement)(import_Primitive.Primitive.form, {
|
|
171
|
+
...rootProps,
|
|
172
|
+
ref: composedFormRef,
|
|
173
|
+
// focus first invalid control when the form is submitted
|
|
174
|
+
onInvalid: (0, import_compose_event_handlers.composeEventHandlers)(props?.onInvalid, (event) => {
|
|
175
|
+
const firstInvalidControl = getFirstInvalidControl(
|
|
176
|
+
event.currentTarget
|
|
177
|
+
);
|
|
178
|
+
if (firstInvalidControl === event.target) firstInvalidControl.focus();
|
|
179
|
+
event.preventDefault();
|
|
180
|
+
}),
|
|
181
|
+
// clear server errors when the form is re-submitted
|
|
182
|
+
onSubmit: (0, import_compose_event_handlers.composeEventHandlers)(props?.onSubmit, onClearServerErrors, {
|
|
183
|
+
checkForDefaultPrevented: false
|
|
184
|
+
}),
|
|
185
|
+
// clear server errors when the form is reset
|
|
186
|
+
onReset: (0, import_compose_event_handlers.composeEventHandlers)(props?.onReset, onClearServerErrors)
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const FIELD_NAME = "FormField";
|
|
192
|
+
const [FormFieldProvider, useFormFieldContext] = createFormContext(FIELD_NAME);
|
|
193
|
+
function Field(props) {
|
|
194
|
+
const slot = (0, import_internal.S)("Form.Field");
|
|
195
|
+
const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props ?? {};
|
|
196
|
+
const validationContext = useValidationContext(FIELD_NAME, __scopeForm);
|
|
197
|
+
const validity = validationContext.getFieldValidity(name);
|
|
198
|
+
const id = (0, import_useId.useId)((0, import_internal.subSlot)(slot, "id"));
|
|
199
|
+
return (0, import_octane.createElement)(FormFieldProvider, {
|
|
200
|
+
scope: __scopeForm,
|
|
201
|
+
id,
|
|
202
|
+
name,
|
|
203
|
+
serverInvalid,
|
|
204
|
+
children: (0, import_octane.createElement)(import_Primitive.Primitive.div, {
|
|
205
|
+
"data-valid": getValidAttribute(validity, serverInvalid),
|
|
206
|
+
"data-invalid": getInvalidAttribute(validity, serverInvalid),
|
|
207
|
+
...fieldProps
|
|
208
|
+
})
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function Label(props) {
|
|
212
|
+
const { __scopeForm, ...labelProps } = props ?? {};
|
|
213
|
+
const validationContext = useValidationContext("FormLabel", __scopeForm);
|
|
214
|
+
const fieldContext = useFormFieldContext("FormLabel", __scopeForm);
|
|
215
|
+
const htmlFor = labelProps.htmlFor || fieldContext.id;
|
|
216
|
+
const validity = validationContext.getFieldValidity(fieldContext.name);
|
|
217
|
+
return (0, import_octane.createElement)(import_Label.Root, {
|
|
218
|
+
"data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
|
|
219
|
+
"data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
|
|
220
|
+
...labelProps,
|
|
221
|
+
htmlFor
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
const CONTROL_NAME = "FormControl";
|
|
225
|
+
function Control(props) {
|
|
226
|
+
const slot = (0, import_internal.S)("Form.Control");
|
|
227
|
+
const { __scopeForm, ref: forwardedRef, ...controlProps } = props ?? {};
|
|
228
|
+
const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);
|
|
229
|
+
const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);
|
|
230
|
+
const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);
|
|
231
|
+
const ref = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "ref"));
|
|
232
|
+
const composedRef = (0, import_compose_refs.useComposedRefs)(forwardedRef, ref, (0, import_internal.subSlot)(slot, "refs"));
|
|
233
|
+
const name = controlProps.name || fieldContext.name;
|
|
234
|
+
const id = controlProps.id || fieldContext.id;
|
|
235
|
+
const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);
|
|
236
|
+
const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } = validationContext;
|
|
237
|
+
const updateControlValidity = (0, import_octane.useCallback)(
|
|
238
|
+
async (control) => {
|
|
239
|
+
if (hasBuiltInError(control.validity)) {
|
|
240
|
+
const controlValidity = validityStateToObject(control.validity);
|
|
241
|
+
onFieldValidityChange(name, controlValidity);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const formData = control.form ? new FormData(control.form) : new FormData();
|
|
245
|
+
const matcherArgs = [control.value, formData];
|
|
246
|
+
const syncCustomMatcherEntries = [];
|
|
247
|
+
const asyncCustomMatcherEntries = [];
|
|
248
|
+
customMatcherEntries.forEach((customMatcherEntry) => {
|
|
249
|
+
if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
|
|
250
|
+
asyncCustomMatcherEntries.push(customMatcherEntry);
|
|
251
|
+
} else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
|
|
252
|
+
syncCustomMatcherEntries.push(customMatcherEntry);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
const syncCustomErrors = syncCustomMatcherEntries.map(({ id: id2, match }) => {
|
|
256
|
+
return [id2, match(...matcherArgs)];
|
|
257
|
+
});
|
|
258
|
+
const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
|
|
259
|
+
const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
|
|
260
|
+
control.setCustomValidity(hasSyncCustomErrors ? DEFAULT_INVALID_MESSAGE : "");
|
|
261
|
+
onFieldValidityChange(
|
|
262
|
+
name,
|
|
263
|
+
validityStateToObject(control.validity)
|
|
264
|
+
);
|
|
265
|
+
onFieldCustomErrorsChange(name, syncCustomErrorsById);
|
|
266
|
+
if (!hasSyncCustomErrors && asyncCustomMatcherEntries.length > 0) {
|
|
267
|
+
const promisedCustomErrors = asyncCustomMatcherEntries.map(
|
|
268
|
+
({ id: id2, match }) => match(...matcherArgs).then((matches) => [id2, matches])
|
|
269
|
+
);
|
|
270
|
+
const asyncCustomErrors = await Promise.all(promisedCustomErrors);
|
|
271
|
+
const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
|
|
272
|
+
const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
|
|
273
|
+
control.setCustomValidity(hasAsyncCustomErrors ? DEFAULT_INVALID_MESSAGE : "");
|
|
274
|
+
onFieldValidityChange(
|
|
275
|
+
name,
|
|
276
|
+
validityStateToObject(control.validity)
|
|
277
|
+
);
|
|
278
|
+
onFieldCustomErrorsChange(name, asyncCustomErrorsById);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
[customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange],
|
|
282
|
+
(0, import_internal.subSlot)(slot, "update")
|
|
283
|
+
);
|
|
284
|
+
(0, import_octane.useEffect)(
|
|
285
|
+
() => {
|
|
286
|
+
const control = ref.current;
|
|
287
|
+
if (control) {
|
|
288
|
+
const handleChange = () => void updateControlValidity(control);
|
|
289
|
+
control.addEventListener("change", handleChange);
|
|
290
|
+
return () => control.removeEventListener("change", handleChange);
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
[updateControlValidity],
|
|
294
|
+
(0, import_internal.subSlot)(slot, "e:change")
|
|
295
|
+
);
|
|
296
|
+
const resetControlValidity = (0, import_octane.useCallback)(
|
|
297
|
+
() => {
|
|
298
|
+
const control = ref.current;
|
|
299
|
+
if (control) {
|
|
300
|
+
control.setCustomValidity("");
|
|
301
|
+
onFieldValiditionClear(name);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
[name, onFieldValiditionClear],
|
|
305
|
+
(0, import_internal.subSlot)(slot, "reset")
|
|
306
|
+
);
|
|
307
|
+
(0, import_octane.useEffect)(
|
|
308
|
+
() => {
|
|
309
|
+
const form = ref.current?.form;
|
|
310
|
+
if (form) {
|
|
311
|
+
form.addEventListener("reset", resetControlValidity);
|
|
312
|
+
return () => form.removeEventListener("reset", resetControlValidity);
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
[resetControlValidity],
|
|
316
|
+
(0, import_internal.subSlot)(slot, "e:reset")
|
|
317
|
+
);
|
|
318
|
+
(0, import_octane.useEffect)(
|
|
319
|
+
() => {
|
|
320
|
+
const control = ref.current;
|
|
321
|
+
const form = control?.closest("form");
|
|
322
|
+
if (form && fieldContext.serverInvalid) {
|
|
323
|
+
const firstInvalidControl = getFirstInvalidControl(form);
|
|
324
|
+
if (firstInvalidControl === control) firstInvalidControl.focus();
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
[fieldContext.serverInvalid],
|
|
328
|
+
(0, import_internal.subSlot)(slot, "e:server")
|
|
329
|
+
);
|
|
330
|
+
const validity = validationContext.getFieldValidity(name);
|
|
331
|
+
return (0, import_octane.createElement)(import_Primitive.Primitive.input, {
|
|
332
|
+
"data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
|
|
333
|
+
"data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
|
|
334
|
+
"aria-invalid": fieldContext.serverInvalid ? true : void 0,
|
|
335
|
+
"aria-describedby": ariaDescriptionContext.getFieldDescription(name),
|
|
336
|
+
// disable default browser behaviour of showing built-in error message on hover
|
|
337
|
+
title: "",
|
|
338
|
+
...controlProps,
|
|
339
|
+
ref: composedRef,
|
|
340
|
+
id,
|
|
341
|
+
name,
|
|
342
|
+
onInvalid: (0, import_compose_event_handlers.composeEventHandlers)(props?.onInvalid, (event) => {
|
|
343
|
+
const control = event.currentTarget;
|
|
344
|
+
void updateControlValidity(control);
|
|
345
|
+
}),
|
|
346
|
+
// octane adaptation: the source resets on React's `onChange`, which is the
|
|
347
|
+
// native `input` event (each edit) — NOT the native `change` (commit) the
|
|
348
|
+
// validate-on-change listener above uses. Binding this to octane's native
|
|
349
|
+
// onChange would fire on the SAME event and stomp the freshly-captured
|
|
350
|
+
// validity.
|
|
351
|
+
onInput: (0, import_compose_event_handlers.composeEventHandlers)(props?.onInput, () => {
|
|
352
|
+
resetControlValidity();
|
|
353
|
+
})
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const _validityMatchers = [
|
|
357
|
+
"badInput",
|
|
358
|
+
"patternMismatch",
|
|
359
|
+
"rangeOverflow",
|
|
360
|
+
"rangeUnderflow",
|
|
361
|
+
"stepMismatch",
|
|
362
|
+
"tooLong",
|
|
363
|
+
"tooShort",
|
|
364
|
+
"typeMismatch",
|
|
365
|
+
"valid",
|
|
366
|
+
"valueMissing"
|
|
367
|
+
];
|
|
368
|
+
const DEFAULT_INVALID_MESSAGE = "This value is not valid";
|
|
369
|
+
const DEFAULT_BUILT_IN_MESSAGES = {
|
|
370
|
+
badInput: DEFAULT_INVALID_MESSAGE,
|
|
371
|
+
patternMismatch: "This value does not match the required pattern",
|
|
372
|
+
rangeOverflow: "This value is too large",
|
|
373
|
+
rangeUnderflow: "This value is too small",
|
|
374
|
+
stepMismatch: "This value does not match the required step",
|
|
375
|
+
tooLong: "This value is too long",
|
|
376
|
+
tooShort: "This value is too short",
|
|
377
|
+
typeMismatch: "This value does not match the required type",
|
|
378
|
+
valid: void 0,
|
|
379
|
+
valueMissing: "This value is missing"
|
|
380
|
+
};
|
|
381
|
+
const MESSAGE_NAME = "FormMessage";
|
|
382
|
+
function Message(props) {
|
|
383
|
+
const { match, name: nameProp, ...messageProps } = props ?? {};
|
|
384
|
+
const fieldContext = useFormFieldContext(MESSAGE_NAME, props?.__scopeForm);
|
|
385
|
+
const name = nameProp ?? fieldContext.name;
|
|
386
|
+
if (match === void 0) {
|
|
387
|
+
return (0, import_octane.createElement)(FormMessageImpl, {
|
|
388
|
+
...messageProps,
|
|
389
|
+
name,
|
|
390
|
+
children: props?.children || DEFAULT_INVALID_MESSAGE
|
|
391
|
+
});
|
|
392
|
+
} else if (typeof match === "function") {
|
|
393
|
+
return (0, import_octane.createElement)(FormCustomMessage, { match, ...messageProps, name });
|
|
394
|
+
} else {
|
|
395
|
+
return (0, import_octane.createElement)(FormBuiltInMessage, { match, ...messageProps, name });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
function FormBuiltInMessage(props) {
|
|
399
|
+
const { match, forceMatch = false, name, children, ...messageProps } = props;
|
|
400
|
+
const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
|
|
401
|
+
const validity = validationContext.getFieldValidity(name);
|
|
402
|
+
const matches = forceMatch || validity?.[match];
|
|
403
|
+
if (matches) {
|
|
404
|
+
return (0, import_octane.createElement)(FormMessageImpl, {
|
|
405
|
+
...messageProps,
|
|
406
|
+
name,
|
|
407
|
+
children: children ?? DEFAULT_BUILT_IN_MESSAGES[match]
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
function FormCustomMessage(props) {
|
|
413
|
+
const slot = (0, import_internal.S)("Form.CustomMessage");
|
|
414
|
+
const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;
|
|
415
|
+
const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
|
|
416
|
+
const _id = (0, import_useId.useId)((0, import_internal.subSlot)(slot, "id"));
|
|
417
|
+
const id = idProp ?? _id;
|
|
418
|
+
const customMatcherEntry = { id, match };
|
|
419
|
+
const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;
|
|
420
|
+
(0, import_octane.useEffect)(
|
|
421
|
+
() => {
|
|
422
|
+
onFieldCustomMatcherEntryAdd(name, customMatcherEntry);
|
|
423
|
+
return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);
|
|
424
|
+
},
|
|
425
|
+
[id, match, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove],
|
|
426
|
+
(0, import_internal.subSlot)(slot, "e:matcher")
|
|
427
|
+
);
|
|
428
|
+
const validity = validationContext.getFieldValidity(name);
|
|
429
|
+
const customErrors = validationContext.getFieldCustomErrors(name);
|
|
430
|
+
const hasMatchingCustomError = customErrors[id];
|
|
431
|
+
const matches = forceMatch || validity && !hasBuiltInError(validity) && hasMatchingCustomError;
|
|
432
|
+
if (matches) {
|
|
433
|
+
return (0, import_octane.createElement)(FormMessageImpl, {
|
|
434
|
+
id,
|
|
435
|
+
...messageProps,
|
|
436
|
+
name,
|
|
437
|
+
children: children ?? DEFAULT_INVALID_MESSAGE
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
function FormMessageImpl(props) {
|
|
443
|
+
const slot = (0, import_internal.S)("Form.MessageImpl");
|
|
444
|
+
const { __scopeForm, id: idProp, name, ...messageProps } = props;
|
|
445
|
+
const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);
|
|
446
|
+
const _id = (0, import_useId.useId)((0, import_internal.subSlot)(slot, "id"));
|
|
447
|
+
const id = idProp ?? _id;
|
|
448
|
+
const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;
|
|
449
|
+
(0, import_octane.useEffect)(
|
|
450
|
+
() => {
|
|
451
|
+
onFieldMessageIdAdd(name, id);
|
|
452
|
+
return () => onFieldMessageIdRemove(name, id);
|
|
453
|
+
},
|
|
454
|
+
[name, id, onFieldMessageIdAdd, onFieldMessageIdRemove],
|
|
455
|
+
(0, import_internal.subSlot)(slot, "e:id")
|
|
456
|
+
);
|
|
457
|
+
return (0, import_octane.createElement)(import_Primitive.Primitive.span, { id, ...messageProps });
|
|
458
|
+
}
|
|
459
|
+
function ValidityState(props) {
|
|
460
|
+
const { __scopeForm, name: nameProp, children } = props ?? {};
|
|
461
|
+
const validationContext = useValidationContext("FormValidityState", __scopeForm);
|
|
462
|
+
const fieldContext = useFormFieldContext("FormValidityState", __scopeForm);
|
|
463
|
+
const name = nameProp ?? fieldContext.name;
|
|
464
|
+
const validity = validationContext.getFieldValidity(name);
|
|
465
|
+
return children(validity);
|
|
466
|
+
}
|
|
467
|
+
function Submit(props) {
|
|
468
|
+
const { __scopeForm, ...submitProps } = props ?? {};
|
|
469
|
+
return (0, import_octane.createElement)(import_Primitive.Primitive.button, { type: "submit", ...submitProps });
|
|
470
|
+
}
|
|
471
|
+
function validityStateToObject(validity) {
|
|
472
|
+
const object = {};
|
|
473
|
+
for (const key in validity) {
|
|
474
|
+
object[key] = validity[key];
|
|
475
|
+
}
|
|
476
|
+
return object;
|
|
477
|
+
}
|
|
478
|
+
function isHTMLElement(element) {
|
|
479
|
+
return element instanceof HTMLElement;
|
|
480
|
+
}
|
|
481
|
+
function isFormControl(element) {
|
|
482
|
+
return "validity" in element;
|
|
483
|
+
}
|
|
484
|
+
function isInvalid(control) {
|
|
485
|
+
return isFormControl(control) && (control.validity.valid === false || control.getAttribute("aria-invalid") === "true");
|
|
486
|
+
}
|
|
487
|
+
function getFirstInvalidControl(form) {
|
|
488
|
+
const elements = form.elements;
|
|
489
|
+
const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
|
|
490
|
+
return firstInvalidControl;
|
|
491
|
+
}
|
|
492
|
+
function isAsyncCustomMatcherEntry(entry, args) {
|
|
493
|
+
return entry.match.constructor.name === "AsyncFunction" || returnsPromise(entry.match, args);
|
|
494
|
+
}
|
|
495
|
+
function isSyncCustomMatcherEntry(entry) {
|
|
496
|
+
return entry.match.constructor.name === "Function";
|
|
497
|
+
}
|
|
498
|
+
function returnsPromise(func, args) {
|
|
499
|
+
return func(...args) instanceof Promise;
|
|
500
|
+
}
|
|
501
|
+
function hasBuiltInError(validity) {
|
|
502
|
+
let error = false;
|
|
503
|
+
for (const validityKey in validity) {
|
|
504
|
+
const key = validityKey;
|
|
505
|
+
if (key !== "valid" && key !== "customError" && validity[key]) {
|
|
506
|
+
error = true;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return error;
|
|
511
|
+
}
|
|
512
|
+
function getValidAttribute(validity, serverInvalid) {
|
|
513
|
+
if (validity?.valid === true && !serverInvalid) return true;
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
function getInvalidAttribute(validity, serverInvalid) {
|
|
517
|
+
if (validity?.valid === false || serverInvalid) return true;
|
|
518
|
+
return void 0;
|
|
519
|
+
}
|
|
520
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
521
|
+
0 && (module.exports = {
|
|
522
|
+
Control,
|
|
523
|
+
Field,
|
|
524
|
+
Form,
|
|
525
|
+
FormControl,
|
|
526
|
+
FormField,
|
|
527
|
+
FormLabel,
|
|
528
|
+
FormMessage,
|
|
529
|
+
FormSubmit,
|
|
530
|
+
FormValidityState,
|
|
531
|
+
Label,
|
|
532
|
+
Message,
|
|
533
|
+
Root,
|
|
534
|
+
Submit,
|
|
535
|
+
ValidityState,
|
|
536
|
+
createFormScope
|
|
537
|
+
});
|