@dvcol/neo-svelte
Version:
Neomorphic ui library for svelte 5
92 lines (91 loc) • 3.16 kB
JavaScript
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));
}