@thomasfosterau/effect-forms-svelte 0.2.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 +19 -19
- package/dist/ClientValidate.d.ts +1 -0
- package/dist/EnhanceCore.d.ts +34 -2
- package/dist/EnhanceCore.js +105 -37
- package/dist/EnhanceCore.js.map +1 -1
- package/dist/EntityForm.js +28 -28
- package/dist/EntityForm.js.map +1 -1
- package/dist/FormStore.svelte.d.ts +10 -2
- package/dist/FormStore.svelte.js +93 -59
- package/dist/FormStore.svelte.js.map +1 -1
- package/dist/Listeners.d.ts +1 -0
- package/dist/Listeners.js +3 -2
- package/dist/Listeners.js.map +1 -1
- package/dist/SvelteKit.d.ts +1 -0
- package/dist/SvelteKit.js +2 -1
- package/dist/SvelteKit.js.map +1 -1
- package/dist/Tainted.d.ts +1 -0
- package/dist/Tainted.js +27 -39
- package/dist/Tainted.js.map +1 -1
- package/dist/kit/ActionRedirect.js +11 -13
- package/dist/kit/ActionRedirect.js.map +1 -1
- package/dist/kit/CommandFailure.js +14 -15
- package/dist/kit/CommandFailure.js.map +1 -1
- package/dist/kit/FormAction.js +36 -30
- package/dist/kit/FormAction.js.map +1 -1
- package/dist/kit/FormStateReaders.js +3 -2
- package/dist/kit/FormStateReaders.js.map +1 -1
- package/package.json +6 -6
|
@@ -108,7 +108,9 @@ export interface FormOptions<S extends Schema.Top, A, Message, R = never> {
|
|
|
108
108
|
/**
|
|
109
109
|
* The builder itself, set automatically when {@link createForm} is given a
|
|
110
110
|
* {@link FormBuilder}. Its `refineEffect` refinements run client-side as a
|
|
111
|
-
* whole-form async validator whenever {@link FormStore.validate} runs
|
|
111
|
+
* whole-form async validator whenever {@link FormStore.validate} runs, on the
|
|
112
|
+
* form data decoded through the builder's schema (as on the server); while
|
|
113
|
+
* the data doesn't decode they don't run, and the field errors say why.
|
|
112
114
|
*/
|
|
113
115
|
readonly builder?: FormBuilder.FormBuilder<Field.FieldsRecord, R>;
|
|
114
116
|
/** The action URL the form posts to (defaults to the current page's action). */
|
|
@@ -346,7 +348,12 @@ export declare class FormStore<S extends Schema.Top, A = S["Type"], Message = un
|
|
|
346
348
|
enhance: (node: HTMLFormElement) => {
|
|
347
349
|
destroy: () => void;
|
|
348
350
|
};
|
|
349
|
-
/**
|
|
351
|
+
/**
|
|
352
|
+
* Build a {@link FormData} body from the current data (SPA / manual submit).
|
|
353
|
+
*
|
|
354
|
+
* Each value is encoded as `objectToFormData` encodes it: a `File` or
|
|
355
|
+
* `Blob` is appended as a file and a `Date` as its UTC `YYYY-MM-DD`.
|
|
356
|
+
*/
|
|
350
357
|
toFormData(): FormData;
|
|
351
358
|
}
|
|
352
359
|
/** A schema plus its blank-form defaults — what {@link createForm} wraps `Form.make` over. */
|
|
@@ -377,4 +384,5 @@ export declare function createForm<TFields extends Field.FieldsRecord, R, Messag
|
|
|
377
384
|
export declare function createForm<S extends Schema.Top, Message = unknown, R = never>(seed: FormSeed<S>, options?: FormOptions<S, S["Type"], Message, R>): FormStore<S, S["Type"], Message, R>;
|
|
378
385
|
export declare function createForm<S extends Schema.Top, A = S["Type"], Message = unknown, R = never>(initial: FormState<A, Message>, options: FormOptions<S, A, Message, R>): FormStore<S, A, Message, R>;
|
|
379
386
|
//#endregion
|
|
387
|
+
export {};
|
|
380
388
|
//# sourceMappingURL=FormStore.svelte.d.ts.map
|
package/dist/FormStore.svelte.js
CHANGED
|
@@ -3,11 +3,16 @@ 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
|
/**
|
|
@@ -56,6 +61,14 @@ import { createAttachmentKey } from "svelte/attachments";
|
|
|
56
61
|
const { clearSourceAt, emptySourced, hasErrors, mergeSourced, noErrors, replaceAt, setSourceAt } = Errors;
|
|
57
62
|
const { getAt, setAt } = Path;
|
|
58
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
|
+
};
|
|
59
72
|
/**
|
|
60
73
|
* A typed, reactive handle to one field, returned by {@link FormStore.field}.
|
|
61
74
|
* Bundles everything a single input needs — `bind:value={field.value}`,
|
|
@@ -115,17 +128,18 @@ const defaultSubmit = async (body, action) => {
|
|
|
115
128
|
body,
|
|
116
129
|
headers: { accept: "application/json" }
|
|
117
130
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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;
|
|
129
143
|
};
|
|
130
144
|
/** Whether `index` is a valid position in an array of `length`. */
|
|
131
145
|
const inRange = (index, length) => index >= 0 && index < length;
|
|
@@ -185,23 +199,29 @@ var FormStore = class {
|
|
|
185
199
|
#autoSubmitNode;
|
|
186
200
|
#validateTimer;
|
|
187
201
|
/** Per-field-listener debounce timers, keyed by `"change:<path>"` / `"blur:<path>"`. */
|
|
188
|
-
#listenerTimers =
|
|
202
|
+
#listenerTimers = {};
|
|
189
203
|
/** Per-field validators, keyed by {@link Path.toString}; seeded from `options.validators`. */
|
|
190
204
|
#fieldValidators;
|
|
191
205
|
/** In-flight async-validator fibers, keyed by `"<path>:<trigger>"` (fields) or `""` (whole-form `refineEffect`). */
|
|
192
206
|
#fibers = {};
|
|
193
207
|
/** The error paths the last `refineEffect` run set, so the next run can clear exactly those before merging fresh ones. */
|
|
194
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;
|
|
195
215
|
/** The data snapshot the field-tracking watcher last diffed against. */
|
|
196
216
|
#previousData;
|
|
197
217
|
/** The current nested error tree (server errors merged with client errors), typed to the form data's shape. */
|
|
198
|
-
errors = $derived.by(() => mergeSourced(this.#sourced));
|
|
218
|
+
errors = $derived.by(() => typedErrors(mergeSourced(this.#sourced)));
|
|
199
219
|
/** Client-side-sourced errors only (schema, per-field validators, `refineEffect`). */
|
|
200
|
-
clientErrors = $derived.by(() => this.#sourced.client);
|
|
220
|
+
clientErrors = $derived.by(() => typedErrors(this.#sourced.client));
|
|
201
221
|
/** Server-sourced errors only (the last submission's response). */
|
|
202
|
-
serverErrors = $derived.by(() => this.#sourced.server);
|
|
222
|
+
serverErrors = $derived.by(() => typedErrors(this.#sourced.server));
|
|
203
223
|
/** Whether any async field validator or `refineEffect` run is currently in flight. */
|
|
204
|
-
isValidating = $derived(
|
|
224
|
+
isValidating = $derived(Arr.some(R.values(this.#validating), Boolean));
|
|
205
225
|
/** Whether the form has ever been submitted (attempted). */
|
|
206
226
|
isSubmitted = $derived(this.submissionAttempts > 0);
|
|
207
227
|
/** Whether the most recently *completed* submission succeeded. `false` before any submit completes. */
|
|
@@ -229,6 +249,7 @@ var FormStore = class {
|
|
|
229
249
|
this.#mode = Mode.parse(options.mode);
|
|
230
250
|
this.#runtime = ManagedRuntime.make(options.layer ?? Layer.empty);
|
|
231
251
|
this.#fieldValidators = { ...options.validators };
|
|
252
|
+
this.#decodeForRefinements = Option.map(Option.fromUndefinedOr(options.builder), (builder) => SchemaParser.decodeUnknownEffect(FormBuilder.buildSchema(builder), { errors: "all" }));
|
|
232
253
|
this.data = structuredClone(initial.data);
|
|
233
254
|
this.#sourced = {
|
|
234
255
|
client: noErrors,
|
|
@@ -246,9 +267,13 @@ var FormStore = class {
|
|
|
246
267
|
* progressive-enhancement submit handler via a Svelte attachment.
|
|
247
268
|
*/
|
|
248
269
|
get props() {
|
|
249
|
-
|
|
270
|
+
const action = this.#options.action;
|
|
271
|
+
return action === void 0 ? {
|
|
272
|
+
method: "post",
|
|
273
|
+
[this.#attachmentKey]: this.#enhanceAttachment
|
|
274
|
+
} : {
|
|
250
275
|
method: "post",
|
|
251
|
-
|
|
276
|
+
action,
|
|
252
277
|
[this.#attachmentKey]: this.#enhanceAttachment
|
|
253
278
|
};
|
|
254
279
|
}
|
|
@@ -258,7 +283,7 @@ var FormStore = class {
|
|
|
258
283
|
}
|
|
259
284
|
/** The messages currently attached to `path` (for dynamic / nested paths). */
|
|
260
285
|
errorsAt(path) {
|
|
261
|
-
return Errors.getError(this.errors, path) ?? [];
|
|
286
|
+
return Errors.getError(untypedErrors(this.errors), path) ?? [];
|
|
262
287
|
}
|
|
263
288
|
/** Whether the async validator(s) at `path` are currently running. */
|
|
264
289
|
isValidatingAt(path) {
|
|
@@ -350,7 +375,7 @@ var FormStore = class {
|
|
|
350
375
|
* Path.FieldPath}); a typo'd segment or wrong-shaped path is a compile error.
|
|
351
376
|
*/
|
|
352
377
|
field(path) {
|
|
353
|
-
return new FieldHandle(this, Path.fromString(path));
|
|
378
|
+
return new FieldHandle(eraseStore(this), Path.fromString(path));
|
|
354
379
|
}
|
|
355
380
|
/**
|
|
356
381
|
* Handle a field losing focus: mark it touched, run its `onBlur` /
|
|
@@ -383,11 +408,11 @@ var FormStore = class {
|
|
|
383
408
|
run();
|
|
384
409
|
return;
|
|
385
410
|
}
|
|
386
|
-
clearTimeout(this.#listenerTimers
|
|
387
|
-
this.#listenerTimers
|
|
388
|
-
this.#listenerTimers
|
|
411
|
+
clearTimeout(this.#listenerTimers[key]);
|
|
412
|
+
this.#listenerTimers[key] = setTimeout(() => {
|
|
413
|
+
delete this.#listenerTimers[key];
|
|
389
414
|
run();
|
|
390
|
-
}, Duration.toMillis(debounce))
|
|
415
|
+
}, Duration.toMillis(debounce));
|
|
391
416
|
}
|
|
392
417
|
/**
|
|
393
418
|
* The listeners table to dispatch change events against, with each field's
|
|
@@ -401,11 +426,10 @@ var FormStore = class {
|
|
|
401
426
|
const listeners = this.#options.listeners;
|
|
402
427
|
if (!listeners || listeners.onChange === void 0 && !listeners.fields) return void 0;
|
|
403
428
|
if (!listeners.fields) return listeners;
|
|
404
|
-
const fields = {
|
|
405
|
-
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 ? {
|
|
406
430
|
...field,
|
|
407
431
|
onChange: (input) => this.#scheduleListener(`change:${key}`, field.debounce, () => field.onChange?.(input))
|
|
408
|
-
} : field;
|
|
432
|
+
} : field]));
|
|
409
433
|
return {
|
|
410
434
|
...listeners,
|
|
411
435
|
fields
|
|
@@ -553,7 +577,7 @@ var FormStore = class {
|
|
|
553
577
|
#defaultItem(path) {
|
|
554
578
|
if (this.#options.schema) return Field.defaultItemAt(this.#options.schema, path);
|
|
555
579
|
const fields = this.#options.fields;
|
|
556
|
-
if (fields && path.length === 1 &&
|
|
580
|
+
if (fields && path.length === 1 && Predicate.isString(path[0])) {
|
|
557
581
|
const def = fields[path[0]];
|
|
558
582
|
if (def && Field.isArrayFieldDef(def)) return Field.defaultValue(def.itemSchema);
|
|
559
583
|
}
|
|
@@ -702,11 +726,15 @@ var FormStore = class {
|
|
|
702
726
|
*/
|
|
703
727
|
#runRefineEffect() {
|
|
704
728
|
const builder = this.#options.builder;
|
|
705
|
-
if (!builder || FormBuilder.asyncRefinements(builder)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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));
|
|
710
738
|
this.#lastRefinementPaths = issues.map((issue) => issue.path);
|
|
711
739
|
this.#sourced = {
|
|
712
740
|
...this.#sourced,
|
|
@@ -722,7 +750,7 @@ var FormStore = class {
|
|
|
722
750
|
*/
|
|
723
751
|
reset(values) {
|
|
724
752
|
if (values !== void 0) this.#initial = structuredClone(values);
|
|
725
|
-
|
|
753
|
+
Arr.forEach(R.keys(this.#fibers), (key) => this.#interruptFiber(key));
|
|
726
754
|
this.data = structuredClone(this.#initial);
|
|
727
755
|
this.#previousData = this.#detachedData();
|
|
728
756
|
this.#sourced = emptySourced;
|
|
@@ -745,7 +773,7 @@ var FormStore = class {
|
|
|
745
773
|
valid: this.valid,
|
|
746
774
|
posted: this.posted,
|
|
747
775
|
data: this.#detachedData(),
|
|
748
|
-
errors: this.errors,
|
|
776
|
+
errors: untypedErrors(this.errors),
|
|
749
777
|
message: this.message,
|
|
750
778
|
constraints: this.constraints
|
|
751
779
|
};
|
|
@@ -812,14 +840,14 @@ var FormStore = class {
|
|
|
812
840
|
this.posted = true;
|
|
813
841
|
this.#options.onUpdated?.({ form: {
|
|
814
842
|
data: this.data,
|
|
815
|
-
errors: this.errors,
|
|
843
|
+
errors: untypedErrors(this.errors),
|
|
816
844
|
valid: this.valid
|
|
817
845
|
} });
|
|
818
846
|
}
|
|
819
847
|
#applyRedirect(location) {
|
|
820
848
|
this.#lastSubmitOutcome = "success";
|
|
821
849
|
if (this.#options.onRedirect) this.#options.onRedirect({ location });
|
|
822
|
-
else if (
|
|
850
|
+
else if (!Predicate.isUndefined(globalThis.window)) window.location.assign(location);
|
|
823
851
|
}
|
|
824
852
|
#applyError(error) {
|
|
825
853
|
this.#lastSubmitOutcome = "failure";
|
|
@@ -838,11 +866,12 @@ var FormStore = class {
|
|
|
838
866
|
* actually just saved, not the original seed.
|
|
839
867
|
*/
|
|
840
868
|
#applySubmittedData(data, result) {
|
|
869
|
+
const submittedData = $state.snapshot(this.#lastSubmitted ?? this.data);
|
|
841
870
|
const applied = computeDataApplication({
|
|
842
|
-
isSuccess: result
|
|
871
|
+
isSuccess: Predicate.isTagged(result, "Success"),
|
|
843
872
|
appliedData: data,
|
|
844
873
|
initial: this.#initial,
|
|
845
|
-
submittedData
|
|
874
|
+
submittedData,
|
|
846
875
|
resetForm: this.#options.resetForm ?? false,
|
|
847
876
|
autoSubmit: this.#mode.autoSubmit
|
|
848
877
|
});
|
|
@@ -879,7 +908,7 @@ var FormStore = class {
|
|
|
879
908
|
}, delayMs);
|
|
880
909
|
try {
|
|
881
910
|
const submit = this.#options.submit ?? defaultSubmit;
|
|
882
|
-
const action = node.action || (
|
|
911
|
+
const action = node.action || (Predicate.isUndefined(globalThis.location) ? "" : location.href);
|
|
883
912
|
let result;
|
|
884
913
|
if (resolved !== void 0) result = resolved;
|
|
885
914
|
else if (this.#options.handler) result = await this.#options.handler(this.data);
|
|
@@ -887,7 +916,7 @@ var FormStore = class {
|
|
|
887
916
|
this.#options.onResult?.({ result });
|
|
888
917
|
this.#applyUpdate(resultToUpdate(result), result);
|
|
889
918
|
} catch (cause) {
|
|
890
|
-
const message = cause
|
|
919
|
+
const message = Predicate.isError(cause) ? cause.message : "Submission failed";
|
|
891
920
|
this.#lastSubmitOutcome = "failure";
|
|
892
921
|
this.#options.onError?.({ error: message });
|
|
893
922
|
} finally {
|
|
@@ -911,7 +940,7 @@ var FormStore = class {
|
|
|
911
940
|
const beforeUnload = (event) => {
|
|
912
941
|
if (this.#options.taintedMessage && this.isTainted) event.preventDefault();
|
|
913
942
|
};
|
|
914
|
-
if (this.#options.taintedMessage &&
|
|
943
|
+
if (this.#options.taintedMessage && !Predicate.isUndefined(globalThis.window)) window.addEventListener("beforeunload", beforeUnload);
|
|
915
944
|
this.#autoSubmitNode = node;
|
|
916
945
|
this.#options.listeners?.onMount?.({ data: $state.snapshot(this.data) });
|
|
917
946
|
const dispatchListeners = this.#buildDispatchListeners();
|
|
@@ -932,24 +961,31 @@ var FormStore = class {
|
|
|
932
961
|
const snapshot = $state.snapshot(this.data);
|
|
933
962
|
const changed = taintedLeafPaths(computeTainted(this.#previousData, snapshot));
|
|
934
963
|
this.#previousData = snapshot;
|
|
935
|
-
|
|
964
|
+
Arr.forEach(changed, (path) => this.#onFieldChanged(path));
|
|
936
965
|
});
|
|
937
966
|
});
|
|
938
967
|
return { destroy: () => {
|
|
939
968
|
node.removeEventListener("submit", handleSubmit);
|
|
940
|
-
if (
|
|
969
|
+
if (!Predicate.isUndefined(globalThis.window)) window.removeEventListener("beforeunload", beforeUnload);
|
|
941
970
|
stopWatching?.();
|
|
942
971
|
stopFieldWatching?.();
|
|
943
972
|
clearTimeout(this.#validateTimer);
|
|
944
|
-
|
|
945
|
-
this.#listenerTimers
|
|
946
|
-
|
|
973
|
+
Arr.forEach(R.values(this.#listenerTimers), (timer) => clearTimeout(timer));
|
|
974
|
+
this.#listenerTimers = {};
|
|
975
|
+
Arr.forEach(R.keys(this.#fibers), (key) => this.#interruptFiber(key));
|
|
947
976
|
if (this.#autoSubmitNode === node) this.#autoSubmitNode = void 0;
|
|
948
977
|
} };
|
|
949
978
|
};
|
|
950
979
|
/** Attachment form of {@link FormStore.enhance} for {@link FormStore.props}. */
|
|
951
|
-
#enhanceAttachment = (node) =>
|
|
952
|
-
|
|
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
|
+
*/
|
|
953
989
|
toFormData() {
|
|
954
990
|
return objectToFormData(this.data);
|
|
955
991
|
}
|
|
@@ -957,10 +993,10 @@ var FormStore = class {
|
|
|
957
993
|
function createForm(source, options = {}) {
|
|
958
994
|
if (FormBuilder.isFormBuilder(source)) {
|
|
959
995
|
const schema = FormBuilder.buildSchema(source);
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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(), {
|
|
964
1000
|
...options,
|
|
965
1001
|
schema,
|
|
966
1002
|
fields: source.fields,
|
|
@@ -968,13 +1004,11 @@ function createForm(source, options = {}) {
|
|
|
968
1004
|
});
|
|
969
1005
|
}
|
|
970
1006
|
if ("defaults" in source && "schema" in source) {
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
...seed.id !== void 0 ? { id: seed.id } : {}
|
|
975
|
-
}).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(), {
|
|
976
1010
|
...options,
|
|
977
|
-
schema:
|
|
1011
|
+
schema: source.schema
|
|
978
1012
|
});
|
|
979
1013
|
}
|
|
980
1014
|
return new FormStore(source, options);
|