UNPKG

@ariakit/react-core

Version:

Ariakit React core

139 lines (137 loc) 4.1 kB
"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 };