@ariakit/react-core
Version:
Ariakit React core
139 lines (137 loc) • 4.1 kB
JavaScript
"use client";
import {
FormScopedContextProvider,
useFormContext
} from "../__chunks/ICLJE26C.js";
import "../__chunks/45YOMIF3.js";
import {
createElement,
createHook,
forwardRef
} from "../__chunks/ILRXHV7V.js";
import {
useEvent,
useInitialValue,
useMergeRefs,
useTagName,
useUpdateEffect,
useWrapElement
} from "../__chunks/K2XTQB3X.js";
import "../__chunks/YXGXYGQX.js";
// src/form/form.tsx
import { isTextField } from "@ariakit/core/utils/dom";
import { invariant } from "@ariakit/core/utils/misc";
import { useEffect, useRef, useState } from "react";
import { jsx } from "react/jsx-runtime";
var TagName = "form";
function isField(element, items) {
return items.some(
(item) => item.type === "field" && item.element === element
);
}
function getFirstInvalidField(items) {
return items.find(
(item) => {
var _a;
return item.type === "field" && ((_a = item.element) == null ? void 0 : _a.getAttribute("aria-invalid")) === "true";
}
);
}
var useForm = createHook(function useForm2({
store,
validateOnChange = true,
validateOnBlur = true,
resetOnUnmount = false,
resetOnSubmit = true,
autoFocusOnSubmit = true,
...props
}) {
const context = useFormContext();
store = store || context;
invariant(
store,
process.env.NODE_ENV !== "production" && "Form must receive a `store` prop or be wrapped in a FormProvider component."
);
const ref = useRef(null);
const values = store.useState("values");
const submitSucceed = store.useState("submitSucceed");
const submitFailed = store.useState("submitFailed");
const items = store.useState("items");
const defaultValues = useInitialValue(values);
useEffect(
() => resetOnUnmount ? store == null ? void 0 : store.reset : void 0,
[resetOnUnmount, store]
);
useUpdateEffect(() => {
if (!validateOnChange) return;
if (values === defaultValues) return;
store == null ? void 0 : store.validate();
}, [validateOnChange, values, defaultValues, store]);
useEffect(() => {
if (!resetOnSubmit) return;
if (!submitSucceed) return;
store == null ? void 0 : store.reset();
}, [resetOnSubmit, submitSucceed, store]);
const [shouldFocusOnSubmit, setShouldFocusOnSubmit] = useState(false);
useEffect(() => {
if (!shouldFocusOnSubmit) return;
if (!submitFailed) return;
const field = getFirstInvalidField(items);
const element = field == null ? void 0 : field.element;
if (!element) return;
setShouldFocusOnSubmit(false);
element.focus();
if (isTextField(element)) {
element.select();
}
}, [autoFocusOnSubmit, submitFailed, items]);
const onSubmitProp = props.onSubmit;
const onSubmit = useEvent((event) => {
onSubmitProp == null ? void 0 : onSubmitProp(event);
if (event.defaultPrevented) return;
event.preventDefault();
store == null ? void 0 : store.submit();
if (!autoFocusOnSubmit) return;
setShouldFocusOnSubmit(true);
});
const onBlurProp = props.onBlur;
const onBlur = useEvent((event) => {
onBlurProp == null ? void 0 : onBlurProp(event);
if (event.defaultPrevented) return;
if (!validateOnBlur) return;
if (!store) return;
if (!isField(event.target, store.getState().items)) return;
store.validate();
});
const onResetProp = props.onReset;
const onReset = useEvent((event) => {
onResetProp == null ? void 0 : onResetProp(event);
if (event.defaultPrevented) return;
event.preventDefault();
store == null ? void 0 : store.reset();
});
props = useWrapElement(
props,
(element) => /* @__PURE__ */ jsx(FormScopedContextProvider, { value: store, children: element }),
[store]
);
const tagName = useTagName(ref, TagName);
props = {
role: tagName !== "form" ? "form" : void 0,
noValidate: true,
...props,
ref: useMergeRefs(ref, props.ref),
onSubmit,
onBlur,
onReset
};
return props;
});
var Form = forwardRef(function Form2(props) {
const htmlProps = useForm(props);
return createElement(TagName, htmlProps);
});
export {
Form,
useForm
};