shelving
Version:
Toolkit for using data in JavaScript.
62 lines (61 loc) • 2.83 kB
JavaScript
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;
}