UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

62 lines (61 loc) 2.83 kB
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useInstance } from "../../react/useInstance.js"; import { useStore } from "../../react/useStore.js"; import { isAsync } from "../../util/async.js"; import { notifySuccess, notifyThrown } from "../util/notice.js"; import styles from "./Form.module.css"; import { FormContext } from "./FormContext.js"; import { FormFields } from "./FormFields.js"; import { FormFooter } from "./FormFooter.js"; import { FormStore } from "./FormStore.js"; export function Form({ schema, data: initialData, onSubmit, submit, messages, children = (_jsxs(_Fragment, { children: [_jsx(FormFields, {}), _jsx(FormFooter, { submit: submit })] })), }) { // Create a form store instance and subscribe to changes in it. const store = useStore(useInstance(FormStore, schema, initialData, messages)); const busy = useStore(store.busy).value; return (_jsx("form", { id: store.id, onSubmit: async (e) => { // Stop the page reloading. e.preventDefault(); // Get relevant elements. const form = e.currentTarget; const dialog = form.closest("dialog"); // Submit the form to the callback. const result = await store.submit(callNotifiedForm, store, form, onSubmit, e); // Close the parent dialog on successful submit. if (result) dialog?.close(); }, className: styles.form, noValidate: true, children: _jsx("fieldset", { className: styles.fieldset, disabled: busy, children: _jsx(FormContext, { value: store, children: children }) }) }, store.key)); } /** Callback that publishes notices to an element (defaults to the window) if it returns or throws "string" */ export function callNotifiedForm(value, store, form, callback, ...args) { try { const result = callback?.(value, ...args); if (isAsync(result)) return awaitNotifiedForm(store, form, result); if (result) notifySuccess(result, form); return true; } catch (thrown) { return notifyThrownForm(store, form, thrown); } } /** Await a value that publishes "success" or "error" notices to a form */ export async function awaitNotifiedForm(store, form, pending) { try { const result = await pending; if (result) notifySuccess(result, form); return true; } catch (thrown) { return notifyThrownForm(store, form, thrown); } } /** Notify the user about a thrown value during a submit (if thrown value is a string then save it as messages instead. */ export function notifyThrownForm(store, form, thrown) { store.reason = thrown; const reason = store.reason; if (reason) notifyThrown(reason, form); return false; }