svelte-ux
Version:
- Increment version in `package.json` and commit as `Version bump to x.y.z` - `npm run publish`
78 lines (77 loc) • 3.32 kB
JavaScript
import { writable, get } from 'svelte/store';
import { applyPatches, createDraft, finishDraft, enablePatches, setAutoFreeze, current, } from 'immer';
import { set } from 'lodash-es';
// Needed for finishDraft() patches/inverseChanges - https://immerjs.github.io/immer/patches
enablePatches();
// Disable autofreezing for now (needed for Period layer after saving new hierarchy) - https://immerjs.github.io/immer/freezing/
setAutoFreeze(false);
export default function formStore(initialState, options) {
const stateStore = writable(initialState);
const draftStore = writable(createDraft(initialState));
const errorsStore = writable({}); // TODO: Improve type (`{ [key in keyof T]: string }`?)
const undoList = [];
const storeApi = { subscribe: stateStore.subscribe };
let currentDraftValue = writable(current(get(draftStore)));
const draftApi = {
...draftStore,
set(newState) {
draftStore.set(createDraft(newState));
},
/** Apply draft to state after verifying with schema (if available). Append change to undo stack */
commit() {
const draft = get(draftStore);
if (options === null || options === void 0 ? void 0 : options.schema) {
const result = options.schema.safeParse(draft);
if (result.success === true) {
// Clear errors
errorsStore.set({});
// TODO: Consider using `result.data` in case there are defaults, etc?
}
else {
const errors = {};
for (const issue of result.error.issues) {
set(errors, issue.path, issue.message);
}
errorsStore.set(errors);
return false;
}
}
const newState = finishDraft(draft, (patches, inverseChanges) => {
undoList.push(inverseChanges);
});
stateStore.set(newState);
draftStore.set(createDraft(newState));
return true;
},
/** Revert draft to last committed state */
revert() {
const currentState = get(stateStore);
draftStore.set(createDraft(currentState));
currentDraftValue.set(currentState);
},
/** Revert draft and state to initial state */
revertAll() {
stateStore.set(initialState);
draftStore.set(createDraft(initialState));
currentDraftValue.set(initialState);
},
/** Undo last committed change */
undo() {
if (undoList.length) {
const undo = undoList.pop();
const currentState = get(stateStore);
const newState = applyPatches(currentState, undo);
stateStore.set(newState);
draftStore.set(createDraft(newState));
currentDraftValue.set(newState);
}
},
/** Refresh `current` draft value (un-proxied) */
refresh() {
currentDraftValue.set(current(get(draftStore)));
},
current: currentDraftValue,
};
const errorsApi = { subscribe: errorsStore.subscribe };
return [storeApi, draftApi, errorsApi];
}