@thomasfosterau/effect-forms-svelte 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -23
- package/dist/ClientValidate.d.ts +3 -3
- package/dist/ClientValidate.js +1 -2
- package/dist/ClientValidate.js.map +1 -1
- package/dist/EnhanceCore.d.ts +41 -10
- package/dist/EnhanceCore.js +107 -40
- package/dist/EnhanceCore.js.map +1 -1
- package/dist/EntityForm.d.ts +17 -18
- package/dist/EntityForm.js +28 -28
- package/dist/EntityForm.js.map +1 -1
- package/dist/FormStore.svelte.d.ts +25 -18
- package/dist/FormStore.svelte.js +95 -62
- package/dist/FormStore.svelte.js.map +1 -1
- package/dist/Listeners.d.ts +6 -6
- package/dist/Listeners.js +3 -2
- package/dist/Listeners.js.map +1 -1
- package/dist/SvelteKit.d.ts +6 -4
- package/dist/SvelteKit.js +5 -2
- package/dist/SvelteKit.js.map +1 -1
- package/dist/Tainted.d.ts +7 -7
- package/dist/Tainted.js +27 -39
- package/dist/Tainted.js.map +1 -1
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/kit/ActionRedirect.d.ts +22 -0
- package/dist/kit/ActionRedirect.js +54 -0
- package/dist/kit/ActionRedirect.js.map +1 -0
- package/dist/kit/CommandFailure.d.ts +52 -0
- package/dist/kit/CommandFailure.js +81 -0
- package/dist/kit/CommandFailure.js.map +1 -0
- package/dist/kit/Enhance.d.ts +30 -0
- package/dist/kit/Enhance.js +57 -0
- package/dist/kit/Enhance.js.map +1 -0
- package/dist/kit/FormAction.d.ts +132 -0
- package/dist/kit/FormAction.js +170 -0
- package/dist/kit/FormAction.js.map +1 -0
- package/dist/kit/FormStateReaders.d.ts +58 -0
- package/dist/kit/FormStateReaders.js +64 -0
- package/dist/kit/FormStateReaders.js.map +1 -0
- package/dist/kit/Pointer.d.ts +23 -0
- package/dist/kit/Pointer.js +38 -0
- package/dist/kit/Pointer.js.map +1 -0
- package/dist/kit/index.d.ts +7 -0
- package/dist/kit/index.js +7 -0
- package/package.json +23 -4
package/dist/FormStore.svelte.js
CHANGED
|
@@ -3,20 +3,23 @@ import { computeDataApplication, objectToFormData, parseActionResult, resultToUp
|
|
|
3
3
|
import { computeTainted, isAnyTainted, isTaintedAt, taintedLeafPaths } from "./Tainted.js";
|
|
4
4
|
import { dispatchChange } from "./Listeners.js";
|
|
5
5
|
import { Constraints, Errors, Field, Form, FormBuilder, Mode, Path, Validate } from "@thomasfosterau/effect-forms";
|
|
6
|
+
import * as Arr from "effect/Array";
|
|
7
|
+
import * as Predicate from "effect/Predicate";
|
|
8
|
+
import * as R from "effect/Record";
|
|
9
|
+
import * as Option from "effect/Option";
|
|
6
10
|
import * as Duration from "effect/Duration";
|
|
7
11
|
import * as Effect from "effect/Effect";
|
|
8
12
|
import * as Fiber from "effect/Fiber";
|
|
9
13
|
import * as Layer from "effect/Layer";
|
|
10
14
|
import * as ManagedRuntime from "effect/ManagedRuntime";
|
|
15
|
+
import * as SchemaParser from "effect/SchemaParser";
|
|
11
16
|
import { createAttachmentKey } from "svelte/attachments";
|
|
12
17
|
//#region src/FormStore.svelte.ts
|
|
13
18
|
/**
|
|
14
|
-
* @copyright Thomas Foster
|
|
15
|
-
*
|
|
16
19
|
* The reactive Svelte 5 form store.
|
|
17
20
|
*
|
|
18
21
|
* {@link createForm} binds a schema to a reactive, rune-backed {@link FormStore}.
|
|
19
|
-
* Give it either `{ schema, defaults }` (it wraps the core's `
|
|
22
|
+
* Give it either `{ schema, defaults }` (it wraps the core's `Form.make` to seed
|
|
20
23
|
* an empty form) or a server-produced {@link FormState} to hydrate from. The
|
|
21
24
|
* store exposes mutable `data` (bind inputs to it), typed `errors`
|
|
22
25
|
* (`form.errors.name`), `submitting` / `delayed` / `message` / `valid`, tainted
|
|
@@ -52,11 +55,20 @@ import { createAttachmentKey } from "svelte/attachments";
|
|
|
52
55
|
* governs what happens *after* a failed post in `onSubmit` mode: fixing a
|
|
53
56
|
* field re-validates it (clearing its error) without a resubmit.
|
|
54
57
|
*
|
|
58
|
+
* @copyright Thomas Foster
|
|
55
59
|
* @module effect-forms-svelte/FormStore
|
|
56
60
|
*/
|
|
57
61
|
const { clearSourceAt, emptySourced, hasErrors, mergeSourced, noErrors, replaceAt, setSourceAt } = Errors;
|
|
58
62
|
const { getAt, setAt } = Path;
|
|
59
63
|
const makeForm = Form.make;
|
|
64
|
+
/** View a runtime {@link FormErrors} tree through the data-shaped {@link TypedFormErrors} lens. */
|
|
65
|
+
const typedErrors = (errors) => {
|
|
66
|
+
return errors;
|
|
67
|
+
};
|
|
68
|
+
/** Forget the data-shaped typing of a {@link TypedFormErrors} tree, back to the runtime {@link FormErrors}. */
|
|
69
|
+
const untypedErrors = (errors) => {
|
|
70
|
+
return errors;
|
|
71
|
+
};
|
|
60
72
|
/**
|
|
61
73
|
* A typed, reactive handle to one field, returned by {@link FormStore.field}.
|
|
62
74
|
* Bundles everything a single input needs — `bind:value={field.value}`,
|
|
@@ -116,17 +128,18 @@ const defaultSubmit = async (body, action) => {
|
|
|
116
128
|
body,
|
|
117
129
|
headers: { accept: "application/json" }
|
|
118
130
|
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
return response.json().then((parsed) => parseActionResult(parsed, response.status), () => ({
|
|
132
|
+
_tag: "Error",
|
|
133
|
+
status: response.status,
|
|
134
|
+
message: response.statusText || "Request failed"
|
|
135
|
+
}));
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Erase a store's type parameters for {@link FieldHandle}, which only calls
|
|
139
|
+
* its path-addressed methods.
|
|
140
|
+
*/
|
|
141
|
+
const eraseStore = (store) => {
|
|
142
|
+
return store;
|
|
130
143
|
};
|
|
131
144
|
/** Whether `index` is a valid position in an array of `length`. */
|
|
132
145
|
const inRange = (index, length) => index >= 0 && index < length;
|
|
@@ -186,23 +199,29 @@ var FormStore = class {
|
|
|
186
199
|
#autoSubmitNode;
|
|
187
200
|
#validateTimer;
|
|
188
201
|
/** Per-field-listener debounce timers, keyed by `"change:<path>"` / `"blur:<path>"`. */
|
|
189
|
-
#listenerTimers =
|
|
202
|
+
#listenerTimers = {};
|
|
190
203
|
/** Per-field validators, keyed by {@link Path.toString}; seeded from `options.validators`. */
|
|
191
204
|
#fieldValidators;
|
|
192
205
|
/** In-flight async-validator fibers, keyed by `"<path>:<trigger>"` (fields) or `""` (whole-form `refineEffect`). */
|
|
193
206
|
#fibers = {};
|
|
194
207
|
/** The error paths the last `refineEffect` run set, so the next run can clear exactly those before merging fresh ones. */
|
|
195
208
|
#lastRefinementPaths = [];
|
|
209
|
+
/**
|
|
210
|
+
* The decoder that turns the form data into the builder's decoded values
|
|
211
|
+
* before its `refineEffect` refinements see them — `None` unless the store
|
|
212
|
+
* was seeded from a {@link FormBuilder}.
|
|
213
|
+
*/
|
|
214
|
+
#decodeForRefinements;
|
|
196
215
|
/** The data snapshot the field-tracking watcher last diffed against. */
|
|
197
216
|
#previousData;
|
|
198
217
|
/** The current nested error tree (server errors merged with client errors), typed to the form data's shape. */
|
|
199
|
-
errors = $derived.by(() => mergeSourced(this.#sourced));
|
|
218
|
+
errors = $derived.by(() => typedErrors(mergeSourced(this.#sourced)));
|
|
200
219
|
/** Client-side-sourced errors only (schema, per-field validators, `refineEffect`). */
|
|
201
|
-
clientErrors = $derived.by(() => this.#sourced.client);
|
|
220
|
+
clientErrors = $derived.by(() => typedErrors(this.#sourced.client));
|
|
202
221
|
/** Server-sourced errors only (the last submission's response). */
|
|
203
|
-
serverErrors = $derived.by(() => this.#sourced.server);
|
|
222
|
+
serverErrors = $derived.by(() => typedErrors(this.#sourced.server));
|
|
204
223
|
/** Whether any async field validator or `refineEffect` run is currently in flight. */
|
|
205
|
-
isValidating = $derived(
|
|
224
|
+
isValidating = $derived(Arr.some(R.values(this.#validating), Boolean));
|
|
206
225
|
/** Whether the form has ever been submitted (attempted). */
|
|
207
226
|
isSubmitted = $derived(this.submissionAttempts > 0);
|
|
208
227
|
/** Whether the most recently *completed* submission succeeded. `false` before any submit completes. */
|
|
@@ -230,6 +249,7 @@ var FormStore = class {
|
|
|
230
249
|
this.#mode = Mode.parse(options.mode);
|
|
231
250
|
this.#runtime = ManagedRuntime.make(options.layer ?? Layer.empty);
|
|
232
251
|
this.#fieldValidators = { ...options.validators };
|
|
252
|
+
this.#decodeForRefinements = Option.map(Option.fromUndefinedOr(options.builder), (builder) => SchemaParser.decodeUnknownEffect(FormBuilder.buildSchema(builder), { errors: "all" }));
|
|
233
253
|
this.data = structuredClone(initial.data);
|
|
234
254
|
this.#sourced = {
|
|
235
255
|
client: noErrors,
|
|
@@ -247,9 +267,13 @@ var FormStore = class {
|
|
|
247
267
|
* progressive-enhancement submit handler via a Svelte attachment.
|
|
248
268
|
*/
|
|
249
269
|
get props() {
|
|
250
|
-
|
|
270
|
+
const action = this.#options.action;
|
|
271
|
+
return action === void 0 ? {
|
|
251
272
|
method: "post",
|
|
252
|
-
|
|
273
|
+
[this.#attachmentKey]: this.#enhanceAttachment
|
|
274
|
+
} : {
|
|
275
|
+
method: "post",
|
|
276
|
+
action,
|
|
253
277
|
[this.#attachmentKey]: this.#enhanceAttachment
|
|
254
278
|
};
|
|
255
279
|
}
|
|
@@ -259,7 +283,7 @@ var FormStore = class {
|
|
|
259
283
|
}
|
|
260
284
|
/** The messages currently attached to `path` (for dynamic / nested paths). */
|
|
261
285
|
errorsAt(path) {
|
|
262
|
-
return Errors.getError(this.errors, path) ?? [];
|
|
286
|
+
return Errors.getError(untypedErrors(this.errors), path) ?? [];
|
|
263
287
|
}
|
|
264
288
|
/** Whether the async validator(s) at `path` are currently running. */
|
|
265
289
|
isValidatingAt(path) {
|
|
@@ -351,7 +375,7 @@ var FormStore = class {
|
|
|
351
375
|
* Path.FieldPath}); a typo'd segment or wrong-shaped path is a compile error.
|
|
352
376
|
*/
|
|
353
377
|
field(path) {
|
|
354
|
-
return new FieldHandle(this, Path.fromString(path));
|
|
378
|
+
return new FieldHandle(eraseStore(this), Path.fromString(path));
|
|
355
379
|
}
|
|
356
380
|
/**
|
|
357
381
|
* Handle a field losing focus: mark it touched, run its `onBlur` /
|
|
@@ -384,11 +408,11 @@ var FormStore = class {
|
|
|
384
408
|
run();
|
|
385
409
|
return;
|
|
386
410
|
}
|
|
387
|
-
clearTimeout(this.#listenerTimers
|
|
388
|
-
this.#listenerTimers
|
|
389
|
-
this.#listenerTimers
|
|
411
|
+
clearTimeout(this.#listenerTimers[key]);
|
|
412
|
+
this.#listenerTimers[key] = setTimeout(() => {
|
|
413
|
+
delete this.#listenerTimers[key];
|
|
390
414
|
run();
|
|
391
|
-
}, Duration.toMillis(debounce))
|
|
415
|
+
}, Duration.toMillis(debounce));
|
|
392
416
|
}
|
|
393
417
|
/**
|
|
394
418
|
* The listeners table to dispatch change events against, with each field's
|
|
@@ -402,11 +426,10 @@ var FormStore = class {
|
|
|
402
426
|
const listeners = this.#options.listeners;
|
|
403
427
|
if (!listeners || listeners.onChange === void 0 && !listeners.fields) return void 0;
|
|
404
428
|
if (!listeners.fields) return listeners;
|
|
405
|
-
const fields = {
|
|
406
|
-
for (const [key, field] of Object.entries(listeners.fields)) fields[key] = field.onChange ? {
|
|
429
|
+
const fields = R.fromEntries(Arr.map(R.toEntries(listeners.fields), ([key, field]) => [key, field.onChange ? {
|
|
407
430
|
...field,
|
|
408
431
|
onChange: (input) => this.#scheduleListener(`change:${key}`, field.debounce, () => field.onChange?.(input))
|
|
409
|
-
} : field;
|
|
432
|
+
} : field]));
|
|
410
433
|
return {
|
|
411
434
|
...listeners,
|
|
412
435
|
fields
|
|
@@ -554,7 +577,7 @@ var FormStore = class {
|
|
|
554
577
|
#defaultItem(path) {
|
|
555
578
|
if (this.#options.schema) return Field.defaultItemAt(this.#options.schema, path);
|
|
556
579
|
const fields = this.#options.fields;
|
|
557
|
-
if (fields && path.length === 1 &&
|
|
580
|
+
if (fields && path.length === 1 && Predicate.isString(path[0])) {
|
|
558
581
|
const def = fields[path[0]];
|
|
559
582
|
if (def && Field.isArrayFieldDef(def)) return Field.defaultValue(def.itemSchema);
|
|
560
583
|
}
|
|
@@ -703,11 +726,15 @@ var FormStore = class {
|
|
|
703
726
|
*/
|
|
704
727
|
#runRefineEffect() {
|
|
705
728
|
const builder = this.#options.builder;
|
|
706
|
-
if (!builder || FormBuilder.asyncRefinements(builder)
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
729
|
+
if (!builder || Arr.isReadonlyArrayEmpty(FormBuilder.asyncRefinements(builder))) return;
|
|
730
|
+
if (Option.isNone(this.#decodeForRefinements)) return;
|
|
731
|
+
const decoded = this.#decodeForRefinements.value(this.#detachedData());
|
|
732
|
+
this.#runValidatorFiber("", decoded.pipe(Effect.matchEffect({
|
|
733
|
+
onFailure: () => Effect.succeed([]),
|
|
734
|
+
onSuccess: (values) => FormBuilder.runAsyncRefinements(builder, values)
|
|
735
|
+
}), Effect.tap((issues) => Effect.sync(() => {
|
|
736
|
+
const cleared = Arr.reduce(this.#lastRefinementPaths, this.#sourcedSnapshot().client, (client, path) => replaceAt(client, path, []));
|
|
737
|
+
const client = Errors.mergeErrors(cleared, Errors.issuesToErrors(issues));
|
|
711
738
|
this.#lastRefinementPaths = issues.map((issue) => issue.path);
|
|
712
739
|
this.#sourced = {
|
|
713
740
|
...this.#sourced,
|
|
@@ -723,7 +750,7 @@ var FormStore = class {
|
|
|
723
750
|
*/
|
|
724
751
|
reset(values) {
|
|
725
752
|
if (values !== void 0) this.#initial = structuredClone(values);
|
|
726
|
-
|
|
753
|
+
Arr.forEach(R.keys(this.#fibers), (key) => this.#interruptFiber(key));
|
|
727
754
|
this.data = structuredClone(this.#initial);
|
|
728
755
|
this.#previousData = this.#detachedData();
|
|
729
756
|
this.#sourced = emptySourced;
|
|
@@ -746,7 +773,7 @@ var FormStore = class {
|
|
|
746
773
|
valid: this.valid,
|
|
747
774
|
posted: this.posted,
|
|
748
775
|
data: this.#detachedData(),
|
|
749
|
-
errors: this.errors,
|
|
776
|
+
errors: untypedErrors(this.errors),
|
|
750
777
|
message: this.message,
|
|
751
778
|
constraints: this.constraints
|
|
752
779
|
};
|
|
@@ -813,14 +840,14 @@ var FormStore = class {
|
|
|
813
840
|
this.posted = true;
|
|
814
841
|
this.#options.onUpdated?.({ form: {
|
|
815
842
|
data: this.data,
|
|
816
|
-
errors: this.errors,
|
|
843
|
+
errors: untypedErrors(this.errors),
|
|
817
844
|
valid: this.valid
|
|
818
845
|
} });
|
|
819
846
|
}
|
|
820
847
|
#applyRedirect(location) {
|
|
821
848
|
this.#lastSubmitOutcome = "success";
|
|
822
849
|
if (this.#options.onRedirect) this.#options.onRedirect({ location });
|
|
823
|
-
else if (
|
|
850
|
+
else if (!Predicate.isUndefined(globalThis.window)) window.location.assign(location);
|
|
824
851
|
}
|
|
825
852
|
#applyError(error) {
|
|
826
853
|
this.#lastSubmitOutcome = "failure";
|
|
@@ -839,11 +866,12 @@ var FormStore = class {
|
|
|
839
866
|
* actually just saved, not the original seed.
|
|
840
867
|
*/
|
|
841
868
|
#applySubmittedData(data, result) {
|
|
869
|
+
const submittedData = $state.snapshot(this.#lastSubmitted ?? this.data);
|
|
842
870
|
const applied = computeDataApplication({
|
|
843
|
-
isSuccess: result
|
|
871
|
+
isSuccess: Predicate.isTagged(result, "Success"),
|
|
844
872
|
appliedData: data,
|
|
845
873
|
initial: this.#initial,
|
|
846
|
-
submittedData
|
|
874
|
+
submittedData,
|
|
847
875
|
resetForm: this.#options.resetForm ?? false,
|
|
848
876
|
autoSubmit: this.#mode.autoSubmit
|
|
849
877
|
});
|
|
@@ -880,7 +908,7 @@ var FormStore = class {
|
|
|
880
908
|
}, delayMs);
|
|
881
909
|
try {
|
|
882
910
|
const submit = this.#options.submit ?? defaultSubmit;
|
|
883
|
-
const action = node.action || (
|
|
911
|
+
const action = node.action || (Predicate.isUndefined(globalThis.location) ? "" : location.href);
|
|
884
912
|
let result;
|
|
885
913
|
if (resolved !== void 0) result = resolved;
|
|
886
914
|
else if (this.#options.handler) result = await this.#options.handler(this.data);
|
|
@@ -888,7 +916,7 @@ var FormStore = class {
|
|
|
888
916
|
this.#options.onResult?.({ result });
|
|
889
917
|
this.#applyUpdate(resultToUpdate(result), result);
|
|
890
918
|
} catch (cause) {
|
|
891
|
-
const message = cause
|
|
919
|
+
const message = Predicate.isError(cause) ? cause.message : "Submission failed";
|
|
892
920
|
this.#lastSubmitOutcome = "failure";
|
|
893
921
|
this.#options.onError?.({ error: message });
|
|
894
922
|
} finally {
|
|
@@ -912,7 +940,7 @@ var FormStore = class {
|
|
|
912
940
|
const beforeUnload = (event) => {
|
|
913
941
|
if (this.#options.taintedMessage && this.isTainted) event.preventDefault();
|
|
914
942
|
};
|
|
915
|
-
if (this.#options.taintedMessage &&
|
|
943
|
+
if (this.#options.taintedMessage && !Predicate.isUndefined(globalThis.window)) window.addEventListener("beforeunload", beforeUnload);
|
|
916
944
|
this.#autoSubmitNode = node;
|
|
917
945
|
this.#options.listeners?.onMount?.({ data: $state.snapshot(this.data) });
|
|
918
946
|
const dispatchListeners = this.#buildDispatchListeners();
|
|
@@ -933,24 +961,31 @@ var FormStore = class {
|
|
|
933
961
|
const snapshot = $state.snapshot(this.data);
|
|
934
962
|
const changed = taintedLeafPaths(computeTainted(this.#previousData, snapshot));
|
|
935
963
|
this.#previousData = snapshot;
|
|
936
|
-
|
|
964
|
+
Arr.forEach(changed, (path) => this.#onFieldChanged(path));
|
|
937
965
|
});
|
|
938
966
|
});
|
|
939
967
|
return { destroy: () => {
|
|
940
968
|
node.removeEventListener("submit", handleSubmit);
|
|
941
|
-
if (
|
|
969
|
+
if (!Predicate.isUndefined(globalThis.window)) window.removeEventListener("beforeunload", beforeUnload);
|
|
942
970
|
stopWatching?.();
|
|
943
971
|
stopFieldWatching?.();
|
|
944
972
|
clearTimeout(this.#validateTimer);
|
|
945
|
-
|
|
946
|
-
this.#listenerTimers
|
|
947
|
-
|
|
973
|
+
Arr.forEach(R.values(this.#listenerTimers), (timer) => clearTimeout(timer));
|
|
974
|
+
this.#listenerTimers = {};
|
|
975
|
+
Arr.forEach(R.keys(this.#fibers), (key) => this.#interruptFiber(key));
|
|
948
976
|
if (this.#autoSubmitNode === node) this.#autoSubmitNode = void 0;
|
|
949
977
|
} };
|
|
950
978
|
};
|
|
951
979
|
/** Attachment form of {@link FormStore.enhance} for {@link FormStore.props}. */
|
|
952
|
-
#enhanceAttachment = (node) =>
|
|
953
|
-
|
|
980
|
+
#enhanceAttachment = (node) => {
|
|
981
|
+
return this.enhance(node).destroy;
|
|
982
|
+
};
|
|
983
|
+
/**
|
|
984
|
+
* Build a {@link FormData} body from the current data (SPA / manual submit).
|
|
985
|
+
*
|
|
986
|
+
* Each value is encoded as `objectToFormData` encodes it: a `File` or
|
|
987
|
+
* `Blob` is appended as a file and a `Date` as its UTC `YYYY-MM-DD`.
|
|
988
|
+
*/
|
|
954
989
|
toFormData() {
|
|
955
990
|
return objectToFormData(this.data);
|
|
956
991
|
}
|
|
@@ -958,10 +993,10 @@ var FormStore = class {
|
|
|
958
993
|
function createForm(source, options = {}) {
|
|
959
994
|
if (FormBuilder.isFormBuilder(source)) {
|
|
960
995
|
const schema = FormBuilder.buildSchema(source);
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
996
|
+
const builderOptions = {};
|
|
997
|
+
if (options.defaults !== void 0) builderOptions.defaults = options.defaults;
|
|
998
|
+
if (options.id !== void 0) builderOptions.id = options.id;
|
|
999
|
+
return new FormStore(Form.fromBuilder(source, builderOptions).empty(), {
|
|
965
1000
|
...options,
|
|
966
1001
|
schema,
|
|
967
1002
|
fields: source.fields,
|
|
@@ -969,13 +1004,11 @@ function createForm(source, options = {}) {
|
|
|
969
1004
|
});
|
|
970
1005
|
}
|
|
971
1006
|
if ("defaults" in source && "schema" in source) {
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
...seed.id !== void 0 ? { id: seed.id } : {}
|
|
976
|
-
}).empty(), {
|
|
1007
|
+
const makeOptions = { defaults: source.defaults };
|
|
1008
|
+
if (source.id !== void 0) makeOptions.id = source.id;
|
|
1009
|
+
return new FormStore(makeForm(source.schema, makeOptions).empty(), {
|
|
977
1010
|
...options,
|
|
978
|
-
schema:
|
|
1011
|
+
schema: source.schema
|
|
979
1012
|
});
|
|
980
1013
|
}
|
|
981
1014
|
return new FormStore(source, options);
|