@inertiajs/svelte 2.2.21 → 2.3.0

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.
@@ -2,8 +2,10 @@
2
2
  formDataToObject,
3
3
  resetFormFields,
4
4
  mergeDataIntoQueryString,
5
- isUrlMethodPair
5
+ isUrlMethodPair,
6
+ UseFormUtils
6
7
  } from "@inertiajs/core";
8
+ import {} from "laravel-precognition";
7
9
  import { isEqual } from "lodash-es";
8
10
  import { onMount } from "svelte";
9
11
  import useForm from "../useForm";
@@ -30,7 +32,24 @@ export let invalidateCacheTags = [];
30
32
  export let resetOnError = false;
31
33
  export let resetOnSuccess = false;
32
34
  export let setDefaultsOnSuccess = false;
33
- const form = useForm({});
35
+ export let validateFiles = false;
36
+ export let validationTimeout = 1500;
37
+ export let withAllErrors = false;
38
+ function getTransformedData() {
39
+ const [_url, data] = getUrlAndData();
40
+ return transform(data);
41
+ }
42
+ const form = useForm({}).withPrecognition(
43
+ () => _method,
44
+ () => getUrlAndData()[0]
45
+ ).setValidationTimeout(validationTimeout);
46
+ if (validateFiles) {
47
+ form.validateFiles();
48
+ }
49
+ if (withAllErrors) {
50
+ form.withAllErrors();
51
+ }
52
+ form.transform(getTransformedData);
34
53
  let formElement;
35
54
  let isDirty = false;
36
55
  let defaultData = new FormData();
@@ -42,11 +61,14 @@ export function getFormData() {
42
61
  export function getData() {
43
62
  return formDataToObject(getFormData());
44
63
  }
64
+ function getUrlAndData() {
65
+ return mergeDataIntoQueryString(_method, _action, getData(), queryStringArrayFormat);
66
+ }
45
67
  function updateDirtyState(event) {
46
68
  isDirty = event.type === "reset" ? false : !isEqual(getData(), formDataToObject(defaultData));
47
69
  }
48
70
  export function submit() {
49
- const [url, _data] = mergeDataIntoQueryString(_method, _action, getData(), queryStringArrayFormat);
71
+ const [url, _data] = getUrlAndData();
50
72
  const maybeReset = (resetOption) => {
51
73
  if (!resetOption) {
52
74
  return;
@@ -106,33 +128,57 @@ function handleReset(event) {
106
128
  }
107
129
  export function reset(...fields) {
108
130
  resetFormFields(formElement, defaultData, fields);
131
+ form.reset(...fields);
109
132
  }
110
133
  export function clearErrors(...fields) {
111
134
  $form.clearErrors(...fields);
112
135
  }
113
136
  export function resetAndClearErrors(...fields) {
114
- $form.clearErrors(...fields);
137
+ clearErrors(...fields);
115
138
  reset(...fields);
116
139
  }
117
- export function setError(field, value) {
118
- if (typeof field === "string") {
119
- $form.setError(field, value);
120
- } else {
121
- $form.setError(field);
122
- }
140
+ export function setError(fieldOrFields, maybeValue) {
141
+ $form.setError(typeof fieldOrFields === "string" ? { [fieldOrFields]: maybeValue } : fieldOrFields);
123
142
  }
124
143
  export function defaults() {
125
144
  defaultData = getFormData();
126
145
  isDirty = false;
127
146
  }
147
+ export function validate(field, config) {
148
+ return form.validate(...UseFormUtils.mergeHeadersForValidation(field, config, headers));
149
+ }
150
+ export function valid(field) {
151
+ return form.valid(field);
152
+ }
153
+ export function invalid(field) {
154
+ return form.invalid(field);
155
+ }
156
+ export function touch(field, ...fields) {
157
+ return form.touch(field, ...fields);
158
+ }
159
+ export function touched(field) {
160
+ return form.touched(field);
161
+ }
162
+ export function validator() {
163
+ return form.validator();
164
+ }
128
165
  onMount(() => {
129
166
  defaultData = getFormData();
167
+ form.defaults(getData());
130
168
  const formEvents = ["input", "change", "reset"];
131
169
  formEvents.forEach((e) => formElement.addEventListener(e, updateDirtyState));
132
170
  return () => {
133
171
  formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState));
134
172
  };
135
173
  });
174
+ $: {
175
+ form.setValidationTimeout(validationTimeout);
176
+ if (validateFiles) {
177
+ form.validateFiles();
178
+ } else {
179
+ form.withoutFileValidation();
180
+ }
181
+ }
136
182
  $: slotErrors = $form.errors;
137
183
  </script>
138
184
 
@@ -158,7 +204,15 @@ $: slotErrors = $form.errors;
158
204
  {isDirty}
159
205
  {submit}
160
206
  {defaults}
207
+ {reset}
161
208
  {getData}
162
209
  {getFormData}
210
+ {validator}
211
+ {validate}
212
+ {touch}
213
+ validating={$form.validating}
214
+ valid={$form.valid}
215
+ invalid={$form.invalid}
216
+ touched={$form.touched}
163
217
  />
164
218
  </form>
@@ -1,5 +1,6 @@
1
1
  import { SvelteComponent } from "svelte";
2
2
  import { type Errors, type Method, type FormDataConvertible } from '@inertiajs/core';
3
+ import { type NamedInputEvent, type ValidationConfig, type Validator } from 'laravel-precognition';
3
4
  declare const __propDef: {
4
5
  props: {
5
6
  [x: string]: any;
@@ -25,14 +26,23 @@ declare const __propDef: {
25
26
  resetOnError?: boolean | string[] | undefined;
26
27
  resetOnSuccess?: boolean | string[] | undefined;
27
28
  setDefaultsOnSuccess?: boolean | undefined;
29
+ validateFiles?: boolean | undefined;
30
+ validationTimeout?: number | undefined;
31
+ withAllErrors?: boolean | undefined;
28
32
  getFormData?: (() => FormData) | undefined;
29
33
  getData?: (() => Record<string, FormDataConvertible>) | undefined;
30
34
  submit?: (() => void) | undefined;
31
35
  reset?: ((...fields: string[]) => void) | undefined;
32
36
  clearErrors?: ((...fields: string[]) => void) | undefined;
33
37
  resetAndClearErrors?: ((...fields: string[]) => void) | undefined;
34
- setError?: ((field: string | object, value?: string) => void) | undefined;
38
+ setError?: ((fieldOrFields: string | Record<string, string>, maybeValue?: string) => void) | undefined;
35
39
  defaults?: (() => void) | undefined;
40
+ validate?: ((field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>) | undefined;
41
+ valid?: ((field: string) => boolean) | undefined;
42
+ invalid?: ((field: string) => boolean) | undefined;
43
+ touch?: ((field: string | NamedInputEvent | string[], ...fields: string[]) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>) | undefined;
44
+ touched?: ((field?: string) => boolean) | undefined;
45
+ validator?: (() => Validator) | undefined;
36
46
  };
37
47
  events: {
38
48
  [evt: string]: CustomEvent<any>;
@@ -47,12 +57,20 @@ declare const __propDef: {
47
57
  recentlySuccessful: boolean;
48
58
  clearErrors: (...fields: string[]) => void;
49
59
  resetAndClearErrors: (...fields: string[]) => void;
50
- setError: (field: string | object, value?: string) => void;
60
+ setError: (fieldOrFields: string | Record<string, string>, maybeValue?: string) => void;
51
61
  isDirty: boolean;
52
62
  submit: () => void;
53
63
  defaults: () => void;
64
+ reset: (...fields: string[]) => void;
54
65
  getData: () => Record<string, FormDataConvertible>;
55
66
  getFormData: () => FormData;
67
+ validator: () => Validator;
68
+ validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>;
69
+ touch: (field: string | NamedInputEvent | string[], ...fields: string[]) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>;
70
+ validating: boolean;
71
+ valid: <K extends string>(field: K) => boolean;
72
+ invalid: <K extends string>(field: K) => boolean;
73
+ touched: <K extends string>(field?: K | undefined) => boolean;
56
74
  };
57
75
  };
58
76
  exports?: undefined;
@@ -68,7 +86,13 @@ export default class Form extends SvelteComponent<FormProps, FormEvents, FormSlo
68
86
  get reset(): (...fields: string[]) => void;
69
87
  get clearErrors(): (...fields: string[]) => void;
70
88
  get resetAndClearErrors(): (...fields: string[]) => void;
71
- get setError(): (field: string | object, value?: string) => void;
89
+ get setError(): (fieldOrFields: string | Record<string, string>, maybeValue?: string) => void;
72
90
  get defaults(): () => void;
91
+ get validate(): (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>;
92
+ get valid(): (field: string) => boolean;
93
+ get invalid(): (field: string) => boolean;
94
+ get touch(): (field: string | NamedInputEvent | string[], ...fields: string[]) => import("svelte/store").Writable<import("../useForm").InertiaPrecognitiveForm<Record<string, any>>> & import("../useForm").InertiaFormProps<Record<string, any>> & Record<string, any> & import("../useForm").InertiaFormValidationProps<Record<string, any>>;
95
+ get touched(): (field?: string) => boolean;
96
+ get validator(): () => Validator;
73
97
  }
74
98
  export {};
@@ -30,16 +30,16 @@ declare const __propDef: {
30
30
  mouseout: MouseEvent;
31
31
  mouseover: MouseEvent;
32
32
  mouseup: MouseEvent;
33
- 'cancel-token': Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
34
- before: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
35
- start: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
33
+ 'cancel-token': Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
34
+ before: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
35
+ start: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
36
36
  progress: ProgressEvent<EventTarget>;
37
- finish: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
37
+ finish: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
38
38
  cancel: Event;
39
- success: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
39
+ success: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
40
40
  error: ErrorEvent;
41
- prefetching: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
42
- prefetched: Event | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | UIEvent | AnimationEvent | PointerEvent | MouseEvent | InputEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
41
+ prefetching: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
42
+ prefetched: Event | InputEvent | UIEvent | ProgressEvent<EventTarget> | SubmitEvent | ErrorEvent | FormDataEvent | AnimationEvent | PointerEvent | MouseEvent | ToggleEvent | FocusEvent | CompositionEvent | ClipboardEvent | DragEvent | KeyboardEvent | SecurityPolicyViolationEvent | TouchEvent | TransitionEvent | WheelEvent;
43
43
  } & {
44
44
  [evt: string]: CustomEvent<any>;
45
45
  };
@@ -11,16 +11,9 @@ let fetching = false;
11
11
  let el;
12
12
  let observer = null;
13
13
  const page = usePage();
14
- $: {
15
- if (Array.isArray(data)) {
16
- if (data.some((key) => $page.props[key] === void 0)) {
17
- loaded = false;
18
- }
19
- } else if ($page.props[data] === void 0) {
20
- loaded = false;
21
- }
22
- }
23
- $: if (el) {
14
+ $: keys = data ? Array.isArray(data) ? data : [data] : [];
15
+ $: loaded = keys.length > 0 && keys.every((key) => $page.props[key] !== void 0);
16
+ $: if (el && (!loaded || always)) {
24
17
  registerObserver();
25
18
  }
26
19
  function registerObserver() {
package/dist/useForm.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import type { ErrorValue, FormDataErrors, FormDataKeys, FormDataType, FormDataValues, Method, Progress, UrlMethodPair, VisitOptions } from '@inertiajs/core';
1
+ import type { ErrorValue, FormDataErrors, FormDataKeys, FormDataType, FormDataValues, Method, Progress, UrlMethodPair, UseFormSubmitArguments, UseFormSubmitOptions, UseFormTransformCallback, UseFormWithPrecognitionArguments } from '@inertiajs/core';
2
+ import type { NamedInputEvent, ValidationConfig, Validator } from 'laravel-precognition';
2
3
  import { type Writable } from 'svelte/store';
3
4
  type InertiaFormStore<TForm extends object> = Writable<InertiaForm<TForm>> & InertiaForm<TForm>;
4
- type FormOptions = Omit<VisitOptions, 'data'>;
5
- type SubmitArgs = [Method, string, FormOptions?] | [UrlMethodPair, FormOptions?];
6
- type TransformCallback<TForm> = (data: TForm) => object;
5
+ type InertiaPrecognitiveFormStore<TForm extends object> = Writable<InertiaPrecognitiveForm<TForm>> & InertiaPrecognitiveForm<TForm>;
6
+ type PrecognitionValidationConfig<TKeys> = ValidationConfig & {
7
+ only?: TKeys[] | Iterable<TKeys> | ArrayLike<TKeys>;
8
+ };
7
9
  export interface InertiaFormProps<TForm extends object> {
8
10
  isDirty: boolean;
9
11
  errors: FormDataErrors<TForm>;
@@ -15,7 +17,7 @@ export interface InertiaFormProps<TForm extends object> {
15
17
  setStore(data: TForm): void;
16
18
  setStore<T extends FormDataKeys<TForm>>(key: T, value: FormDataValues<TForm, T>): void;
17
19
  data(): TForm;
18
- transform(callback: TransformCallback<TForm>): this;
20
+ transform(callback: UseFormTransformCallback<TForm>): this;
19
21
  defaults(): this;
20
22
  defaults(fields: Partial<TForm>): this;
21
23
  defaults<T extends FormDataKeys<TForm>>(field: T, value: FormDataValues<TForm, T>): this;
@@ -24,15 +26,34 @@ export interface InertiaFormProps<TForm extends object> {
24
26
  resetAndClearErrors<K extends FormDataKeys<TForm>>(...fields: K[]): this;
25
27
  setError<K extends FormDataKeys<TForm>>(field: K, value: ErrorValue): this;
26
28
  setError(errors: FormDataErrors<TForm>): this;
27
- submit: (...args: SubmitArgs) => void;
28
- get(url: string, options?: FormOptions): void;
29
- post(url: string, options?: FormOptions): void;
30
- put(url: string, options?: FormOptions): void;
31
- patch(url: string, options?: FormOptions): void;
32
- delete(url: string, options?: FormOptions): void;
29
+ submit: (...args: UseFormSubmitArguments) => void;
30
+ get(url: string, options?: UseFormSubmitOptions): void;
31
+ post(url: string, options?: UseFormSubmitOptions): void;
32
+ put(url: string, options?: UseFormSubmitOptions): void;
33
+ patch(url: string, options?: UseFormSubmitOptions): void;
34
+ delete(url: string, options?: UseFormSubmitOptions): void;
33
35
  cancel(): void;
36
+ withPrecognition: (...args: UseFormWithPrecognitionArguments) => InertiaPrecognitiveFormStore<TForm>;
37
+ }
38
+ export interface InertiaFormValidationProps<TForm extends object> {
39
+ invalid<K extends FormDataKeys<TForm>>(field: K): boolean;
40
+ setValidationTimeout(duration: number): this;
41
+ touch<K extends FormDataKeys<TForm>>(field: K | NamedInputEvent | Array<K>, ...fields: K[]): this;
42
+ touched<K extends FormDataKeys<TForm>>(field?: K): boolean;
43
+ valid<K extends FormDataKeys<TForm>>(field: K): boolean;
44
+ validate<K extends FormDataKeys<TForm>>(field?: K | NamedInputEvent | PrecognitionValidationConfig<K>, config?: PrecognitionValidationConfig<K>): this;
45
+ validateFiles(): this;
46
+ validating: boolean;
47
+ validator: () => Validator;
48
+ withAllErrors(): this;
49
+ withoutFileValidation(): this;
50
+ setErrors(errors: FormDataErrors<TForm> | Record<string, string | string[]>): this;
51
+ forgetError<K extends FormDataKeys<TForm> | NamedInputEvent>(field: K): this;
34
52
  }
35
53
  export type InertiaForm<TForm extends object> = InertiaFormProps<TForm> & TForm;
36
- export default function useForm<TForm extends FormDataType<TForm>>(data: TForm | (() => TForm)): InertiaFormStore<TForm>;
54
+ export type InertiaPrecognitiveForm<TForm extends object> = InertiaForm<TForm> & InertiaFormValidationProps<TForm>;
55
+ export default function useForm<TForm extends FormDataType<TForm>>(method: Method | (() => Method), url: string | (() => string), data: TForm | (() => TForm)): InertiaPrecognitiveFormStore<TForm>;
56
+ export default function useForm<TForm extends FormDataType<TForm>>(urlMethodPair: UrlMethodPair | (() => UrlMethodPair), data: TForm | (() => TForm)): InertiaPrecognitiveFormStore<TForm>;
37
57
  export default function useForm<TForm extends FormDataType<TForm>>(rememberKey: string, data: TForm | (() => TForm)): InertiaFormStore<TForm>;
58
+ export default function useForm<TForm extends FormDataType<TForm>>(data: TForm | (() => TForm)): InertiaFormStore<TForm>;
38
59
  export {};
package/dist/useForm.js CHANGED
@@ -1,11 +1,13 @@
1
- import { router } from '@inertiajs/core';
1
+ import { router, UseFormUtils } from '@inertiajs/core';
2
+ import { createValidator, resolveName, toSimpleValidationErrors } from 'laravel-precognition';
2
3
  import { cloneDeep, get, has, isEqual, set } from 'lodash-es';
3
- import { writable } from 'svelte/store';
4
+ import { get as getStore, writable } from 'svelte/store';
4
5
  import { config } from '.';
5
- export default function useForm(rememberKeyOrData, maybeData) {
6
- const rememberKey = typeof rememberKeyOrData === 'string' ? rememberKeyOrData : null;
7
- const inputData = (typeof rememberKeyOrData === 'string' ? maybeData : rememberKeyOrData) ?? {};
8
- const data = typeof inputData === 'function' ? inputData() : inputData;
6
+ export default function useForm(...args) {
7
+ const parsedArgs = UseFormUtils.parseUseFormArguments(...args);
8
+ const { rememberKey, data: initialData } = parsedArgs;
9
+ let precognitionEndpoint = parsedArgs.precognitionEndpoint;
10
+ const data = typeof initialData === 'function' ? initialData() : initialData;
9
11
  const restored = rememberKey
10
12
  ? router.restore(rememberKey)
11
13
  : null;
@@ -14,8 +16,101 @@ export default function useForm(rememberKeyOrData, maybeData) {
14
16
  let recentlySuccessfulTimeoutId = null;
15
17
  let transform = (data) => data;
16
18
  let defaultsCalledInOnSuccess = false;
17
- const setFormState = (key, value) => {
18
- store.update((form) => ({ ...form, [key]: value }));
19
+ let validatorRef = null;
20
+ let setFormState;
21
+ const withPrecognition = (...args) => {
22
+ precognitionEndpoint = UseFormUtils.createWayfinderCallback(...args);
23
+ const formWithPrecognition = () => getStore(store);
24
+ let withAllErrors = false;
25
+ if (!validatorRef) {
26
+ const validator = createValidator((client) => {
27
+ const { method, url } = precognitionEndpoint();
28
+ const form = formWithPrecognition();
29
+ const transformedData = transform(form.data());
30
+ return client[method](url, transformedData);
31
+ }, cloneDeep(defaults));
32
+ validatorRef = validator;
33
+ validator
34
+ .on('validatingChanged', () => {
35
+ setFormState('validating', validator.validating());
36
+ })
37
+ .on('validatedChanged', () => {
38
+ setFormState('__valid', validator.valid());
39
+ })
40
+ .on('touchedChanged', () => {
41
+ setFormState('__touched', validator.touched());
42
+ })
43
+ .on('errorsChanged', () => {
44
+ const validationErrors = withAllErrors ? validator.errors() : toSimpleValidationErrors(validator.errors());
45
+ setFormState('errors', {});
46
+ formWithPrecognition().setError(validationErrors);
47
+ setFormState('__valid', validator.valid());
48
+ });
49
+ }
50
+ const tap = (value, callback) => {
51
+ callback(value);
52
+ return value;
53
+ };
54
+ if (validatorRef) {
55
+ Object.assign(store, {});
56
+ }
57
+ store.update((form) => {
58
+ return Object.assign(store, {
59
+ ...form,
60
+ __touched: [],
61
+ __valid: [],
62
+ validating: false,
63
+ validator: () => validatorRef,
64
+ validate: (field, config) => {
65
+ const form = formWithPrecognition();
66
+ if (typeof field === 'object' && !('target' in field)) {
67
+ config = field;
68
+ field = undefined;
69
+ }
70
+ if (field === undefined) {
71
+ validatorRef.validate(config);
72
+ }
73
+ else {
74
+ field = resolveName(field);
75
+ const transformedData = transform(form.data());
76
+ validatorRef.validate(field, get(transformedData, field), config);
77
+ }
78
+ return form;
79
+ },
80
+ touch: (field, ...fields) => {
81
+ const form = formWithPrecognition();
82
+ if (Array.isArray(field)) {
83
+ validatorRef?.touch(field);
84
+ }
85
+ else if (typeof field === 'string') {
86
+ validatorRef?.touch([field, ...fields]);
87
+ }
88
+ else {
89
+ validatorRef?.touch(field);
90
+ }
91
+ return form;
92
+ },
93
+ validateFiles: () => tap(formWithPrecognition(), () => validatorRef?.validateFiles()),
94
+ setValidationTimeout: (duration) => tap(formWithPrecognition(), () => validatorRef.setTimeout(duration)),
95
+ withAllErrors: () => tap(formWithPrecognition(), () => (withAllErrors = true)),
96
+ withoutFileValidation: () => tap(formWithPrecognition(), () => validatorRef?.withoutFileValidation()),
97
+ valid: (field) => formWithPrecognition().__valid.includes(field),
98
+ invalid: (field) => field in formWithPrecognition().errors,
99
+ touched: (field) => {
100
+ const touched = formWithPrecognition().__touched;
101
+ return typeof field === 'string' ? touched.includes(field) : touched.length > 0;
102
+ },
103
+ setErrors: (errors) => tap(formWithPrecognition(), () => {
104
+ const form = formWithPrecognition();
105
+ form.setError(errors);
106
+ }),
107
+ forgetError: (field) => tap(formWithPrecognition(), () => {
108
+ const form = formWithPrecognition();
109
+ form.clearErrors(resolveName(field));
110
+ }),
111
+ });
112
+ });
113
+ return store;
19
114
  };
20
115
  const store = writable({
21
116
  ...(restored ? restored.data : data),
@@ -51,6 +146,7 @@ export default function useForm(rememberKeyOrData, maybeData) {
51
146
  ? set(cloneDeep(defaults), fieldOrFields, maybeValue)
52
147
  : Object.assign(cloneDeep(defaults), fieldOrFields);
53
148
  }
149
+ validatorRef?.defaults(defaults);
54
150
  return this;
55
151
  },
56
152
  reset(...fields) {
@@ -65,13 +161,16 @@ export default function useForm(rememberKeyOrData, maybeData) {
65
161
  return set(carry, key, get(clonedData, key));
66
162
  }, {}));
67
163
  }
164
+ validatorRef?.reset(...fields);
68
165
  return this;
69
166
  },
70
167
  setError(fieldOrFields, maybeValue) {
168
+ const errors = typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields;
71
169
  setFormState('errors', {
72
170
  ...this.errors,
73
- ...(typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields),
171
+ ...errors,
74
172
  });
173
+ validatorRef?.setErrors(errors);
75
174
  return this;
76
175
  },
77
176
  clearErrors(...fields) {
@@ -79,6 +178,14 @@ export default function useForm(rememberKeyOrData, maybeData) {
79
178
  ...carry,
80
179
  ...(fields.length > 0 && !fields.includes(field) ? { [field]: this.errors[field] } : {}),
81
180
  }), {}));
181
+ if (validatorRef) {
182
+ if (fields.length === 0) {
183
+ validatorRef.setErrors({});
184
+ }
185
+ else {
186
+ fields.forEach(validatorRef.forgetError);
187
+ }
188
+ }
82
189
  return this;
83
190
  },
84
191
  resetAndClearErrors(...fields) {
@@ -87,10 +194,7 @@ export default function useForm(rememberKeyOrData, maybeData) {
87
194
  return this;
88
195
  },
89
196
  submit(...args) {
90
- const objectPassed = args[0] !== null && typeof args[0] === 'object';
91
- const method = objectPassed ? args[0].method : args[0];
92
- const url = objectPassed ? args[0].url : args[1];
93
- const options = (objectPassed ? args[1] : args[2]) ?? {};
197
+ const { method, url, options } = UseFormUtils.parseSubmitArguments(args, precognitionEndpoint);
94
198
  defaultsCalledInOnSuccess = false;
95
199
  const data = transform(this.data());
96
200
  const _options = {
@@ -132,10 +236,7 @@ export default function useForm(rememberKeyOrData, maybeData) {
132
236
  recentlySuccessfulTimeoutId = setTimeout(() => setFormState('recentlySuccessful', false), config.get('form.recentlySuccessfulDuration'));
133
237
  const onSuccess = options.onSuccess ? await options.onSuccess(page) : null;
134
238
  if (!defaultsCalledInOnSuccess) {
135
- store.update((form) => {
136
- this.defaults(cloneDeep(form.data()));
137
- return form;
138
- });
239
+ this.defaults(cloneDeep(getStore(store).data()));
139
240
  }
140
241
  return onSuccess;
141
242
  },
@@ -188,7 +289,14 @@ export default function useForm(rememberKeyOrData, maybeData) {
188
289
  cancel() {
189
290
  cancelToken?.cancel();
190
291
  },
292
+ withPrecognition,
293
+ });
294
+ Object.assign(store, {
295
+ withPrecognition,
191
296
  });
297
+ setFormState = (key, value) => {
298
+ store.update((form) => ({ ...form, [key]: value }));
299
+ };
192
300
  store.subscribe((form) => {
193
301
  if (form.isDirty === isEqual(form.data(), defaults)) {
194
302
  setFormState('isDirty', !form.isDirty);
@@ -201,5 +309,7 @@ export default function useForm(rememberKeyOrData, maybeData) {
201
309
  router.remember({ data: form.data(), errors: form.errors }, rememberKey);
202
310
  }
203
311
  });
204
- return store;
312
+ return precognitionEndpoint
313
+ ? store.withPrecognition(precognitionEndpoint)
314
+ : store;
205
315
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inertiajs/svelte",
3
- "version": "2.2.21",
3
+ "version": "2.3.0",
4
4
  "license": "MIT",
5
5
  "description": "The Svelte adapter for Inertia.js",
6
6
  "contributors": [
@@ -53,8 +53,9 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@types/lodash-es": "^4.17.12",
56
+ "laravel-precognition": "^1.0.0",
56
57
  "lodash-es": "^4.17.21",
57
- "@inertiajs/core": "2.2.21"
58
+ "@inertiajs/core": "2.3.0"
58
59
  },
59
60
  "scripts": {
60
61
  "build": "pnpm package && svelte-check --tsconfig ./tsconfig.json && publint",