alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
159 lines (157 loc) • 4.53 kB
JavaScript
import {
unwrap
} from "../../chunks/chunk-ZHH24SIG.js";
import {
atom
} from "../../chunks/chunk-OBOPLPUQ.js";
import {
Doc,
YMap
} from "../../chunks/chunk-OYP4EJOA.js";
import "../../chunks/chunk-O6EXLFU2.js";
import "../../chunks/chunk-U5RRZUYZ.js";
// src/dashboard/atoms/FormAtoms.tsx
import {
Field,
ROOT_KEY,
Section,
Type,
applyEntryData,
track
} from "alinea/core";
import { entries } from "alinea/core/util/Objects";
import { createContext, useContext, useMemo } from "react";
import { jsx } from "react/jsx-runtime";
var FormAtoms = class {
constructor(type, container, options = { readOnly: false }) {
this.type = type;
this.container = container;
this.options = options;
for (const section of Type.sections(type)) {
for (const [key, field] of entries(Section.fields(section))) {
const ref = Field.ref(field);
const shape = Field.shape(field);
const defaultOptions = Field.options(field);
const optionsTracker = track.optionTrackerOf(field);
shape.init(container, key);
const mutator = shape.mutator(container, key, false);
const options2 = optionsTracker ? unwrap(
atom((get) => {
const tracked = optionsTracker(this.getter(get));
if (tracked instanceof Promise)
return tracked.then((partial) => {
return { ...defaultOptions, ...partial };
});
return { ...defaultOptions, ...tracked };
}),
(prev) => prev ?? defaultOptions
) : atom(defaultOptions);
const valueTracker = track.valueTrackerOf(field);
const value = this.valueAtom(field, key, valueTracker);
this.fieldInfo.set(ref, {
key,
field,
value,
mutator,
options: options2
});
}
}
}
fieldInfo = /* @__PURE__ */ new Map();
data() {
return Type.shape(this.type).fromY(this.container);
}
getter = (get) => (field) => {
const info = this.fieldInfo.get(Field.ref(field));
if (!info)
throw new Error(`Field not found: ${Field.label(field)}`);
return get(info.value);
};
valueAtom(field, key, tracker) {
const shape = Field.shape(field);
const revision = atom(0);
revision.onMount = (setAtom) => {
const onChange = () => setAtom((x) => x + 1);
const watch = shape.watch(this.container, key);
onChange();
return watch(onChange);
};
return atom((g) => {
g(revision);
const current = shape.fromY(this.container.get(key));
const next = tracker ? tracker(this.getter(g)) : current;
if (next !== current)
shape.applyY(next, this.container, key);
return next;
});
}
fieldByKey(key) {
for (const info of this.fieldInfo.values())
if (info.key === key)
return info.field;
throw new Error(`Field not found: "${key}"`);
}
keyOf(field) {
const res = this.fieldInfo.get(Field.ref(field));
const label = Field.label(field);
if (!res)
throw new Error(`Field not found: ${label}`);
return res.key;
}
atomsOf(field) {
const res = this.fieldInfo.get(Field.ref(field));
const label = Field.label(field);
if (!res)
throw new Error(`Field not found: ${label}`);
return res;
}
};
var formAtomsContext = createContext(void 0);
function useForm(type, options = {}) {
return useMemo(() => {
const doc = options.doc ?? new Doc();
if (options.initialValue) {
applyEntryData(doc, type, { data: options.initialValue });
}
return new FormAtoms(type, doc.getMap(ROOT_KEY));
}, [type, options.doc]);
}
function useFormContext() {
const formAtoms = useContext(formAtomsContext);
if (!formAtoms)
throw new Error("FormAtoms is not provided");
return formAtoms;
}
function FormProvider({
children,
form
}) {
return /* @__PURE__ */ jsx(formAtomsContext.Provider, { value: form, children });
}
function FormRow({
children,
field,
type,
rowId
}) {
const form = useFormContext();
const rowForm = useMemo(() => {
const key = form.keyOf(field);
const inner = form.container.get(key);
if (rowId) {
if (!inner.has(rowId))
inner.set(rowId, new YMap());
}
const row = rowId ? inner.get(rowId) : inner;
return new FormAtoms(type, row);
}, [form, rowId]);
return /* @__PURE__ */ jsx(FormProvider, { form: rowForm, children });
}
export {
FormAtoms,
FormProvider,
FormRow,
useForm,
useFormContext
};