UNPKG

@ariakit/core

Version:
278 lines (276 loc) 9.02 kB
"use client"; import { createCollectionStore } from "../__chunks/EO4GVUA4.js"; import "../__chunks/DTR5TSDJ.js"; import { createStore, init, setup, sync, throwOnConflictingProps } from "../__chunks/BCALMBPZ.js"; import { applyState, defaultValue, isInteger, isObject } from "../__chunks/PBFD2E7P.js"; import { __spreadProps, __spreadValues } from "../__chunks/3YLGPPWQ.js"; // src/form/form-store.ts function nextFrame() { return new Promise((resolve) => requestAnimationFrame(() => resolve())); } function hasMessages(object) { return Object.keys(object).some((key) => { if (isObject(object[key])) { return hasMessages(object[key]); } return !!object[key]; }); } function get(values, path, defaultValue2) { var _a; const [key, ...rest] = Array.isArray(path) ? path : `${path}`.split("."); if (key == null || !values) { return defaultValue2; } if (!rest.length) { return (_a = values[key]) != null ? _a : defaultValue2; } return get(values[key], rest, defaultValue2); } function set(values, path, value) { const [k, ...rest] = Array.isArray(path) ? path : `${path}`.split("."); if (k == null) return values; const key = k; const isIntegerKey = isInteger(key); const nextValues = isIntegerKey ? values || [] : values || {}; const nestedValues = nextValues[key]; const result = rest.length && (Array.isArray(nestedValues) || isObject(nestedValues)) ? set(nestedValues, rest, value) : value; if (isIntegerKey) { const index = Number(key); if (values && Array.isArray(values)) { return [ ...values.slice(0, index), result, ...values.slice(index + 1) ]; } const nextValues2 = []; nextValues2[index] = result; return nextValues2; } return __spreadProps(__spreadValues({}, values), { [key]: result }); } function setAll(values, value) { const result = {}; const keys = Object.keys(values); for (const key of keys) { const currentValue = values[key]; if (Array.isArray(currentValue)) { result[key] = currentValue.map((v) => { if (isObject(v)) { return setAll(v, value); } return value; }); } else if (isObject(currentValue)) { result[key] = setAll(currentValue, value); } else { result[key] = value; } } return result; } function getNameHandler(cache, prevKeys = []) { const handler = { get(target, key) { if (["toString", "valueOf", Symbol.toPrimitive].includes(key)) { return () => prevKeys.join("."); } const nextKeys = [...prevKeys, key]; const nextKey = nextKeys.join("."); if (cache[nextKey]) { return cache[nextKey]; } const nextProxy = new Proxy(target, getNameHandler(cache, nextKeys)); cache[nextKey] = nextProxy; return nextProxy; } }; return handler; } function getStoreCallbacks(store) { return store == null ? void 0 : store.__unstableCallbacks; } function createNames() { const cache = /* @__PURE__ */ Object.create(null); return new Proxy(/* @__PURE__ */ Object.create(null), getNameHandler(cache)); } function createFormStore(props = {}) { var _a; throwOnConflictingProps(props, props.store); const syncState = (_a = props.store) == null ? void 0 : _a.getState(); const collection = createCollectionStore(props); const values = defaultValue( props.values, syncState == null ? void 0 : syncState.values, props.defaultValues, {} ); const errors = defaultValue( props.errors, syncState == null ? void 0 : syncState.errors, props.defaultErrors, {} ); const touched = defaultValue( props.touched, syncState == null ? void 0 : syncState.touched, props.defaultTouched, {} ); const initialState = __spreadProps(__spreadValues({}, collection.getState()), { values, errors, touched, validating: defaultValue(syncState == null ? void 0 : syncState.validating, false), submitting: defaultValue(syncState == null ? void 0 : syncState.submitting, false), submitSucceed: defaultValue(syncState == null ? void 0 : syncState.submitSucceed, 0), submitFailed: defaultValue(syncState == null ? void 0 : syncState.submitFailed, 0), valid: !hasMessages(errors) }); const form = createStore(initialState, collection, props.store); const syncCallbacks = getStoreCallbacks(props.store); const syncCallbacksState = syncCallbacks == null ? void 0 : syncCallbacks.getState(); const callbacksInitialState = { validate: (syncCallbacksState == null ? void 0 : syncCallbacksState.validate) || [], submit: (syncCallbacksState == null ? void 0 : syncCallbacksState.submit) || [] }; const callbacks = createStore(callbacksInitialState, syncCallbacks); setup(form, () => init(callbacks)); setup( form, () => sync(form, ["validating", "errors"], (state) => { if (state.validating) return; form.setState("valid", !hasMessages(state.errors)); }) ); const validate = async () => { form.setState("validating", true); form.setState("errors", {}); const validateCallbacks = callbacks.getState().validate; try { for (const callback of validateCallbacks) { await callback(form.getState()); } await nextFrame(); return !hasMessages(form.getState().errors); } finally { form.setState("validating", false); } }; return __spreadProps(__spreadValues(__spreadValues({}, collection), form), { names: createNames(), setValues: (values2) => form.setState("values", values2), getValue: (name) => get(form.getState().values, name), setValue: (name, value) => form.setState("values", (values2) => { const prevValue = get(values2, name); const nextValue = applyState(value, prevValue); if (nextValue === prevValue) return values2; return set(values2, name, nextValue); }), pushValue: (name, value) => form.setState("values", (values2) => { const array = get(values2, name, []); return set(values2, name, [...array, value]); }), removeValue: (name, index) => form.setState("values", (values2) => { const array = get(values2, name, []); return set(values2, name, [ ...array.slice(0, index), null, ...array.slice(index + 1) ]); }), setErrors: (errors2) => form.setState("errors", errors2), getError: (name) => get(form.getState().errors, name), setError: (name, error) => form.setState("errors", (errors2) => { const prevError = get(errors2, name); const nextError = applyState(error, prevError); if (nextError === prevError) return errors2; return set(errors2, name, nextError); }), setTouched: (touched2) => form.setState("touched", touched2), getFieldTouched: (name) => !!get(form.getState().touched, name), setFieldTouched: (name, value) => form.setState("touched", (touched2) => { const prevValue = get(touched2, name); const nextValue = applyState(value, prevValue); if (nextValue === prevValue) return touched2; return set(touched2, name, nextValue); }), onValidate: (callback) => { callbacks.setState("validate", (callbacks2) => [...callbacks2, callback]); return () => { callbacks.setState( "validate", (callbacks2) => callbacks2.filter((c) => c !== callback) ); }; }, validate, onSubmit: (callback) => { callbacks.setState("submit", (callbacks2) => [...callbacks2, callback]); return () => { callbacks.setState( "submit", (callbacks2) => callbacks2.filter((c) => c !== callback) ); }; }, submit: async () => { form.setState("submitting", true); form.setState("touched", setAll(form.getState().values, true)); try { if (await validate()) { const submitCallbacks = callbacks.getState().submit; for (const callback of submitCallbacks) { await callback(form.getState()); } await nextFrame(); if (!hasMessages(form.getState().errors)) { form.setState("submitSucceed", (count) => count + 1); return true; } } form.setState("submitFailed", (count) => count + 1); return false; } catch (error) { form.setState("submitFailed", (count) => count + 1); throw error; } finally { form.setState("submitting", false); } }, reset: () => { form.setState("values", values); form.setState("errors", errors); form.setState("touched", touched); form.setState("validating", false); form.setState("submitting", false); form.setState("submitSucceed", 0); form.setState("submitFailed", 0); form.setState("valid", !hasMessages(errors)); }, // @ts-expect-error Internal __unstableCallbacks: callbacks }); } export { createFormStore, get, hasMessages };