UNPKG

@dvcol/neo-svelte

Version:

Neomorphic ui library for svelte 5

92 lines (91 loc) 3.16 kB
import { getUUID } from '@dvcol/common-utils/common/string'; import { getContext, setContext } from 'svelte'; import { SvelteMap } from 'svelte/reactivity'; import { NeoErrorFormDuplicateId, NeoErrorFormMissingId } from '../utils/error.utils.js'; const isArray = (value) => Array.isArray(value); function toRecord(map, key, nullable = true) { return [...map.entries()].sort().reduce((acc, [id, field]) => { const val = key in field ? field[key] : field.state[key]; if (!nullable && (val === undefined || val === null)) return acc; if (field.name) { const name = field.name.replace('[]', ''); const current = acc[name]; if (current !== undefined || field.type === 'radio' || field.name.endsWith('[]')) { if (isArray(current)) acc[name] = [...current, val]; else if (current !== undefined) acc[name] = [current, val]; else acc[name] = [val]; } else acc[name] = val; } else acc[id] = val; return acc; }, {}); } export class NeoFormContext { #id; #fields = new SvelteMap(); #entries = $derived(Object.fromEntries(this.#fields.entries())); #values = $derived(toRecord(this.#fields, 'value')); #initials = $derived(toRecord(this.#fields, 'initial')); #touched = $derived([...this.#fields.values()].some(field => field.state.touched)); #dirty = $derived([...this.#fields.values()].some(field => field.state.dirty)); #valid = $derived([...this.#fields.values()].every(field => field.state.valid)); #messages = $derived(toRecord(this.#fields, 'message', false)); #errors = $derived(toRecord(this.#fields, 'error', false)); get fields() { return this.#entries; } get values() { return this.#values; } get initials() { return this.#initials; } get touched() { return this.#touched; } get dirty() { return this.#dirty; } get valid() { return this.#valid; } get messages() { return this.#messages; } get errors() { return this.#errors; } constructor(id = `neo-form-${getUUID()}`) { this.#id = id; } register(field) { if (field?.form && field.form !== this.#id) return; if (!field?.id) throw new NeoErrorFormMissingId(); if (this.#fields.has(field.id)) throw new NeoErrorFormDuplicateId(); this.#fields.set(field.id, field); } remove(id) { this.#fields.delete(id); } validate() { this.#fields.forEach(field => field.ref?.validate?.()); return { touched: this.touched, dirty: this.dirty, valid: this.valid, value: this.values, initial: this.initials }; } } const NeoFormContextSymbol = Symbol('NeoFormContext'); export function getNeoFormContext() { return getContext(NeoFormContextSymbol); } export function setNeoFormContext(id) { return setContext(NeoFormContextSymbol, new NeoFormContext(id)); }