@inertiajs/svelte 2.3.16 → 3.0.0-beta.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.
Files changed (48) hide show
  1. package/dist/components/App.svelte +120 -44
  2. package/dist/components/App.svelte.d.ts +10 -19
  3. package/dist/components/Deferred.svelte +68 -9
  4. package/dist/components/Deferred.svelte.d.ts +9 -20
  5. package/dist/components/Form.svelte +358 -242
  6. package/dist/components/Form.svelte.d.ts +51 -96
  7. package/dist/components/InfiniteScroll.svelte +227 -167
  8. package/dist/components/InfiniteScroll.svelte.d.ts +29 -116
  9. package/dist/components/Link.svelte +96 -48
  10. package/dist/components/Link.svelte.d.ts +49 -56
  11. package/dist/components/Render.svelte +62 -21
  12. package/dist/components/Render.svelte.d.ts +9 -25
  13. package/dist/components/WhenVisible.svelte +83 -66
  14. package/dist/components/WhenVisible.svelte.d.ts +11 -26
  15. package/dist/components/createForm.d.ts +8 -0
  16. package/dist/components/createForm.js +4 -0
  17. package/dist/components/formContext.d.ts +3 -3
  18. package/dist/components/formContext.js +9 -3
  19. package/dist/createInertiaApp.d.ts +12 -7
  20. package/dist/createInertiaApp.js +63 -24
  21. package/dist/index.d.ts +8 -5
  22. package/dist/index.js +8 -5
  23. package/dist/layoutProps.svelte.d.ts +6 -0
  24. package/dist/layoutProps.svelte.js +25 -0
  25. package/dist/link.js +13 -2
  26. package/dist/page.svelte.d.ts +10 -0
  27. package/dist/page.svelte.js +14 -0
  28. package/dist/types.d.ts +11 -4
  29. package/dist/types.js +1 -1
  30. package/dist/{useForm.d.ts → useForm.svelte.d.ts} +4 -4
  31. package/dist/useForm.svelte.js +116 -0
  32. package/dist/useFormState.svelte.d.ts +84 -0
  33. package/dist/useFormState.svelte.js +290 -0
  34. package/dist/useHttp.svelte.d.ts +61 -0
  35. package/dist/useHttp.svelte.js +154 -0
  36. package/dist/usePrefetch.svelte.d.ts +7 -0
  37. package/dist/{usePrefetch.js → usePrefetch.svelte.js} +18 -13
  38. package/dist/useRemember.svelte.d.ts +1 -0
  39. package/dist/useRemember.svelte.js +10 -0
  40. package/package.json +14 -13
  41. package/resources/boost/guidelines/core.blade.php +3 -0
  42. package/resources/boost/skills/inertia-svelte-development/SKILL.blade.php +372 -0
  43. package/dist/page.d.ts +0 -13
  44. package/dist/page.js +0 -8
  45. package/dist/useForm.js +0 -356
  46. package/dist/usePrefetch.d.ts +0 -7
  47. package/dist/useRemember.d.ts +0 -1
  48. package/dist/useRemember.js +0 -11
@@ -1,258 +1,374 @@
1
- <script>import {
2
- config,
3
- formDataToObject,
4
- FormComponentResetSymbol,
5
- resetFormFields,
6
- mergeDataIntoQueryString,
7
- isUrlMethodPair,
8
- UseFormUtils
9
- } from "@inertiajs/core";
10
- import {} from "laravel-precognition";
11
- import { isEqual } from "lodash-es";
12
- import { onMount, setContext } from "svelte";
13
- import { writable } from "svelte/store";
14
- import { FormContextKey } from "./formContext";
15
- import useForm from "../useForm";
16
- const noop = () => void 0;
17
- export let action = "";
18
- export let method = "get";
19
- export let headers = {};
20
- export let queryStringArrayFormat = "brackets";
21
- export let errorBag = null;
22
- export let showProgress = true;
23
- export let transform = (data) => data;
24
- export let options = {};
25
- export let onCancelToken = noop;
26
- export let onBefore = noop;
27
- export let onStart = noop;
28
- export let onProgress = noop;
29
- export let onFinish = noop;
30
- export let onCancel = noop;
31
- export let onSuccess = noop;
32
- export let onError = noop;
33
- export let onSubmitComplete = noop;
34
- export let disableWhileProcessing = false;
35
- export let invalidateCacheTags = [];
36
- export let resetOnError = false;
37
- export let resetOnSuccess = false;
38
- export let setDefaultsOnSuccess = false;
39
- export let validateFiles = false;
40
- export let validationTimeout = 1500;
41
- export let withAllErrors = null;
42
- const getTransformedData = () => {
43
- const [_url, data] = getUrlAndData();
44
- return transform(data);
45
- };
46
- const form = useForm({}).withPrecognition(
47
- () => _method,
48
- () => getUrlAndData()[0]
49
- ).setValidationTimeout(validationTimeout);
50
- if (validateFiles) {
51
- form.validateFiles();
52
- }
53
- if (withAllErrors ?? config.get("form.withAllErrors")) {
54
- form.withAllErrors();
55
- }
56
- form.transform(getTransformedData);
57
- let formElement;
58
- let isDirty = false;
59
- let defaultData = new FormData();
60
- $: _method = isUrlMethodPair(action) ? action.method : (method ?? "get").toLowerCase();
61
- $: _action = isUrlMethodPair(action) ? action.url : action;
62
- export function getFormData(submitter) {
63
- return new FormData(formElement, submitter);
64
- }
65
- export function getData(submitter) {
66
- return formDataToObject(getFormData(submitter));
67
- }
68
- function getUrlAndData(submitter) {
69
- return mergeDataIntoQueryString(_method, _action, getData(submitter), queryStringArrayFormat);
70
- }
71
- function updateDirtyState(event) {
72
- if (event.type === "reset" && event.detail?.[FormComponentResetSymbol]) {
73
- event.preventDefault();
1
+ <script lang="ts">
2
+ import {
3
+ formDataToObject,
4
+ FormComponentResetSymbol,
5
+ resetFormFields,
6
+ mergeDataIntoQueryString,
7
+ type Errors,
8
+ type FormComponentProps,
9
+ type FormComponentRef,
10
+ type FormComponentSlotProps,
11
+ type Method,
12
+ type FormDataConvertible,
13
+ type VisitOptions,
14
+ isUrlMethodPair,
15
+ resolveUrlMethodPairComponent,
16
+ UseFormUtils,
17
+ } from '@inertiajs/core'
18
+ import { type NamedInputEvent, type ValidationConfig, type Validator } from 'laravel-precognition'
19
+ import { isEqual } from 'lodash-es'
20
+ import { onMount } from 'svelte'
21
+ import { setFormContext } from './formContext'
22
+ import useForm from '../useForm.svelte'
23
+
24
+ const noop = () => undefined
25
+
26
+ interface Props {
27
+ action?: FormComponentProps['action']
28
+ method?: FormComponentProps['method']
29
+ headers?: FormComponentProps['headers']
30
+ queryStringArrayFormat?: FormComponentProps['queryStringArrayFormat']
31
+ errorBag?: FormComponentProps['errorBag']
32
+ showProgress?: FormComponentProps['showProgress']
33
+ transform?: FormComponentProps['transform']
34
+ options?: FormComponentProps['options']
35
+ onCancelToken?: FormComponentProps['onCancelToken']
36
+ onBefore?: FormComponentProps['onBefore']
37
+ onStart?: FormComponentProps['onStart']
38
+ onProgress?: FormComponentProps['onProgress']
39
+ onFinish?: FormComponentProps['onFinish']
40
+ onCancel?: FormComponentProps['onCancel']
41
+ onSuccess?: FormComponentProps['onSuccess']
42
+ onError?: FormComponentProps['onError']
43
+ onSubmitComplete?: FormComponentProps['onSubmitComplete']
44
+ disableWhileProcessing?: boolean
45
+ invalidateCacheTags?: FormComponentProps['invalidateCacheTags']
46
+ resetOnError?: FormComponentProps['resetOnError']
47
+ resetOnSuccess?: FormComponentProps['resetOnSuccess']
48
+ setDefaultsOnSuccess?: FormComponentProps['setDefaultsOnSuccess']
49
+ validateFiles?: FormComponentProps['validateFiles']
50
+ validationTimeout?: FormComponentProps['validationTimeout']
51
+ optimistic?: FormComponentProps['optimistic']
52
+ withAllErrors?: FormComponentProps['withAllErrors']
53
+ component?: FormComponentProps['component']
54
+ instant?: FormComponentProps['instant']
55
+ children?: import('svelte').Snippet<[FormComponentSlotProps]>
56
+ [key: string]: any
57
+ }
58
+
59
+ let {
60
+ action = $bindable(''),
61
+ method = 'get',
62
+ headers = {},
63
+ queryStringArrayFormat = 'brackets',
64
+ errorBag = null,
65
+ showProgress = true,
66
+ transform = (data) => data,
67
+ options = {},
68
+ onCancelToken = noop,
69
+ onBefore = noop,
70
+ onStart = noop,
71
+ onProgress = noop,
72
+ onFinish = noop,
73
+ onCancel = noop,
74
+ onSuccess = noop,
75
+ onError = noop,
76
+ onSubmitComplete = noop,
77
+ disableWhileProcessing = false,
78
+ invalidateCacheTags = [],
79
+ resetOnError = false,
80
+ resetOnSuccess = false,
81
+ setDefaultsOnSuccess = false,
82
+ validateFiles = false,
83
+ validationTimeout = 1500,
84
+ optimistic,
85
+ withAllErrors = false,
86
+ component = undefined,
87
+ instant = false,
88
+ children,
89
+ ...rest
90
+ }: Props = $props()
91
+
92
+ type FormSubmitOptions = Omit<VisitOptions, 'data' | 'onPrefetched' | 'onPrefetching'>
93
+ type FormSubmitter = HTMLElement | null
94
+
95
+ const getTransformedData = (): Record<string, FormDataConvertible> => {
96
+ const [_url, data] = getUrlAndData()
97
+ return transform!(data)
98
+ }
99
+
100
+ const form = useForm<Record<string, any>>({}).withPrecognition(
101
+ () => _method,
102
+ () => getUrlAndData()[0],
103
+ )
104
+
105
+ form.transform(getTransformedData)
106
+
107
+ let formElement: HTMLFormElement = $state(null!)
108
+ let isDirty = $state(false)
109
+ let defaultData: FormData = new FormData()
110
+
111
+ const _method = $derived(isUrlMethodPair(action) ? action.method : ((method ?? 'get').toLowerCase() as Method))
112
+ const _action = $derived(isUrlMethodPair(action) ? action.url : (action as string))
113
+ const resolvedComponent = $derived(
114
+ component ? component : instant && isUrlMethodPair(action) ? resolveUrlMethodPairComponent(action) : null,
115
+ )
116
+
117
+ export function getFormData(submitter?: FormSubmitter): FormData {
118
+ return new FormData(formElement, submitter)
74
119
  }
75
- isDirty = event.type === "reset" ? false : !isEqual(getData(), formDataToObject(defaultData));
76
- }
77
- export function submit(submitter) {
78
- const [url, data] = getUrlAndData(submitter);
79
- const formTarget = submitter?.getAttribute("formtarget");
80
- if (formTarget === "_blank" && _method === "get") {
81
- window.open(url, "_blank");
82
- return;
120
+
121
+ // Convert the FormData to an object because we can't compare two FormData
122
+ // instances directly (which is needed for isDirty), mergeDataIntoQueryString()
123
+ // expects an object, and submitting a FormData instance directly causes problems with nested objects.
124
+ export function getData(submitter?: FormSubmitter): Record<string, FormDataConvertible> {
125
+ return formDataToObject(getFormData(submitter))
126
+ }
127
+
128
+ function getUrlAndData(submitter?: FormSubmitter): [string, Record<string, FormDataConvertible>] {
129
+ return mergeDataIntoQueryString(_method, _action, getData(submitter), queryStringArrayFormat)
83
130
  }
84
- const maybeReset = (resetOption) => {
85
- if (!resetOption) {
86
- return;
131
+
132
+ function updateDirtyState(event: Event) {
133
+ if (event.type === 'reset' && (event as CustomEvent).detail?.[FormComponentResetSymbol]) {
134
+ // When the form is reset programmatically, prevent native reset behavior
135
+ event.preventDefault()
87
136
  }
88
- if (resetOption === true) {
89
- reset();
90
- } else if (resetOption.length > 0) {
91
- reset(...resetOption);
137
+
138
+ isDirty = event.type === 'reset' ? false : !isEqual(getData(), formDataToObject(defaultData))
139
+ }
140
+
141
+ export function submit(submitter?: FormSubmitter) {
142
+ const [url, data] = getUrlAndData(submitter)
143
+ const formTarget = (submitter as HTMLButtonElement | HTMLInputElement | null)?.getAttribute('formtarget')
144
+
145
+ if (formTarget === '_blank' && _method === 'get') {
146
+ window.open(url, '_blank')
147
+ return
92
148
  }
93
- };
94
- const submitOptions = {
95
- headers,
96
- queryStringArrayFormat,
97
- errorBag,
98
- showProgress,
99
- invalidateCacheTags,
100
- onCancelToken,
101
- onBefore,
102
- onStart,
103
- onProgress,
104
- onFinish,
105
- onCancel,
106
- onSuccess: (...args) => {
107
- if (onSuccess) {
108
- onSuccess(...args);
109
- }
110
- if (onSubmitComplete) {
111
- onSubmitComplete({
112
- reset,
113
- defaults
114
- });
115
- }
116
- maybeReset(resetOnSuccess);
117
- if (setDefaultsOnSuccess === true) {
118
- defaults();
149
+
150
+ const maybeReset = (resetOption: boolean | string[] | undefined) => {
151
+ if (!resetOption) {
152
+ return
119
153
  }
120
- },
121
- onError: (...args) => {
122
- if (onError) {
123
- onError(...args);
154
+
155
+ if (resetOption === true) {
156
+ reset()
157
+ } else if (resetOption.length > 0) {
158
+ reset(...resetOption)
124
159
  }
125
- maybeReset(resetOnError);
126
- },
127
- ...options
128
- };
129
- $form.transform(() => transform(data)).submit(_method, url, submitOptions);
130
- $form.transform(getTransformedData);
131
- }
132
- function handleSubmit(event) {
133
- event.preventDefault();
134
- submit(event.submitter);
135
- }
136
- function handleReset(event) {
137
- if (event.isTrusted) {
138
- event.preventDefault();
139
- reset();
160
+ }
161
+
162
+ const submitOptions: FormSubmitOptions = {
163
+ headers,
164
+ queryStringArrayFormat,
165
+ errorBag,
166
+ showProgress,
167
+ invalidateCacheTags,
168
+ component: resolvedComponent,
169
+ optimistic: optimistic ? (pageProps) => optimistic(pageProps, data) : undefined,
170
+ onCancelToken,
171
+ onBefore,
172
+ onStart,
173
+ onProgress,
174
+ onFinish,
175
+ onCancel,
176
+ onSuccess: (...args) => {
177
+ if (onSuccess) {
178
+ onSuccess(...args)
179
+ }
180
+
181
+ if (onSubmitComplete) {
182
+ onSubmitComplete({
183
+ reset,
184
+ defaults,
185
+ })
186
+ }
187
+
188
+ maybeReset(resetOnSuccess)
189
+
190
+ if (setDefaultsOnSuccess === true) {
191
+ defaults()
192
+ }
193
+ },
194
+ onError: (...args) => {
195
+ if (onError) {
196
+ onError(...args)
197
+ }
198
+
199
+ maybeReset(resetOnError)
200
+ },
201
+ ...options,
202
+ }
203
+
204
+ // We need transform because we can't override the default data with different keys (by design)
205
+ form.transform(() => transform!(data)).submit(_method, url, submitOptions)
206
+
207
+ // Reset the transformer back so the submitter is not used for future submissions
208
+ form.transform(getTransformedData)
209
+ }
210
+
211
+ function handleSubmit(event: SubmitEvent) {
212
+ event.preventDefault()
213
+ submit(event.submitter)
214
+ }
215
+
216
+ function handleReset(event: Event) {
217
+ // Only intercept native reset events (from reset buttons/inputs)
218
+ if (event.isTrusted) {
219
+ event.preventDefault()
220
+ reset()
221
+ }
222
+ }
223
+
224
+ export function reset(...fields: string[]) {
225
+ resetFormFields(formElement, defaultData, fields)
226
+
227
+ form.reset(...fields)
228
+ }
229
+
230
+ export function clearErrors(...fields: string[]) {
231
+ form.clearErrors(...fields)
232
+ }
233
+
234
+ export function resetAndClearErrors(...fields: string[]) {
235
+ clearErrors(...fields)
236
+ reset(...fields)
237
+ }
238
+
239
+ export function setError(fieldOrFields: string | Record<string, string>, maybeValue?: string) {
240
+ form.setError((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as Errors)
241
+ }
242
+
243
+ export function defaults() {
244
+ defaultData = getFormData()
245
+ isDirty = false
140
246
  }
141
- }
142
- export function reset(...fields) {
143
- resetFormFields(formElement, defaultData, fields);
144
- form.reset(...fields);
145
- }
146
- export function clearErrors(...fields) {
147
- $form.clearErrors(...fields);
148
- }
149
- export function resetAndClearErrors(...fields) {
150
- clearErrors(...fields);
151
- reset(...fields);
152
- }
153
- export function setError(fieldOrFields, maybeValue) {
154
- $form.setError(typeof fieldOrFields === "string" ? { [fieldOrFields]: maybeValue } : fieldOrFields);
155
- }
156
- export function defaults() {
157
- defaultData = getFormData();
158
- isDirty = false;
159
- }
160
- export function validate(field, config2) {
161
- return form.validate(...UseFormUtils.mergeHeadersForValidation(field, config2, headers));
162
- }
163
- export function valid(field) {
164
- return form.valid(field);
165
- }
166
- export function invalid(field) {
167
- return form.invalid(field);
168
- }
169
- export function touch(field, ...fields) {
170
- return form.touch(field, ...fields);
171
- }
172
- export function touched(field) {
173
- return form.touched(field);
174
- }
175
- export function validator() {
176
- return form.validator();
177
- }
178
- onMount(() => {
179
- defaultData = getFormData();
180
- form.defaults(getData());
181
- const formEvents = ["input", "change", "reset"];
182
- formEvents.forEach((e) => formElement.addEventListener(e, updateDirtyState));
183
- return () => {
184
- formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState));
185
- };
186
- });
187
- $: {
188
- form.setValidationTimeout(validationTimeout);
189
- if (validateFiles) {
190
- form.validateFiles();
191
- } else {
192
- form.withoutFileValidation();
247
+
248
+ export function validate(field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) {
249
+ return form.validate(...UseFormUtils.mergeHeadersForValidation(field, config, headers!))
250
+ }
251
+
252
+ export function valid(field: string) {
253
+ return form.valid(field)
254
+ }
255
+
256
+ export function invalid(field: string) {
257
+ return form.invalid(field)
193
258
  }
194
- }
195
- $: slotErrors = $form.errors;
196
- const formContextStore = writable(void 0);
197
- $: formContextStore.set({
198
- errors: $form.errors,
199
- hasErrors: $form.hasErrors,
200
- processing: $form.processing,
201
- progress: $form.progress,
202
- wasSuccessful: $form.wasSuccessful,
203
- recentlySuccessful: $form.recentlySuccessful,
204
- isDirty,
205
- clearErrors,
206
- resetAndClearErrors,
207
- setError,
208
- reset,
209
- submit,
210
- defaults,
211
- getData,
212
- getFormData,
213
- // Precognition
214
- validator,
215
- validate,
216
- touch,
217
- validating: $form.validating,
218
- valid,
219
- invalid,
220
- touched
221
- });
222
- setContext(FormContextKey, formContextStore);
259
+
260
+ export function touch(field: string | NamedInputEvent | string[], ...fields: string[]) {
261
+ return form.touch(field, ...fields)
262
+ }
263
+
264
+ export function touched(field?: string) {
265
+ return form.touched(field)
266
+ }
267
+
268
+ export function validator(): Validator {
269
+ return form.validator()
270
+ }
271
+
272
+ onMount(() => {
273
+ defaultData = getFormData()
274
+
275
+ form.defaults(getData())
276
+
277
+ const formEvents: Array<keyof HTMLElementEventMap> = ['input', 'change', 'reset']
278
+
279
+ formEvents.forEach((e) => formElement.addEventListener(e, updateDirtyState))
280
+
281
+ return () => {
282
+ formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState))
283
+ }
284
+ })
285
+
286
+ $effect(() => {
287
+ form.setValidationTimeout(validationTimeout!)
288
+
289
+ if (validateFiles) {
290
+ form.validateFiles()
291
+ } else {
292
+ form.withoutFileValidation()
293
+ }
294
+
295
+ if (withAllErrors) {
296
+ form.withAllErrors()
297
+ }
298
+ })
299
+
300
+ const slotErrors = $derived(form.errors as Errors)
301
+
302
+ // Form context for child components
303
+ function createFormContext(): FormComponentRef {
304
+ return {
305
+ errors: form.errors,
306
+ hasErrors: form.hasErrors,
307
+ processing: form.processing,
308
+ progress: form.progress,
309
+ wasSuccessful: form.wasSuccessful,
310
+ recentlySuccessful: form.recentlySuccessful,
311
+ isDirty,
312
+ clearErrors,
313
+ resetAndClearErrors,
314
+ setError,
315
+ reset,
316
+ submit,
317
+ defaults,
318
+ getData,
319
+ getFormData,
320
+ // Precognition
321
+ validator,
322
+ validate,
323
+ touch,
324
+ validating: form.validating,
325
+ valid,
326
+ invalid,
327
+ touched,
328
+ }
329
+ }
330
+
331
+ let formContextStore = $state<FormComponentRef>(createFormContext())
332
+
333
+ $effect(() => {
334
+ Object.assign(formContextStore, createFormContext())
335
+ })
336
+
337
+ setFormContext(formContextStore)
223
338
  </script>
224
339
 
340
+ {/* @ts-expect-error method type does not match here*/ null}
225
341
  <form
226
342
  bind:this={formElement}
227
343
  action={_action}
228
344
  method={_method}
229
- on:submit={handleSubmit}
230
- on:reset={handleReset}
231
- {...$$restProps}
232
- inert={disableWhileProcessing && $form.processing ? true : undefined}
345
+ onsubmit={handleSubmit}
346
+ onreset={handleReset}
347
+ {...rest}
348
+ inert={disableWhileProcessing && form.processing ? true : undefined}
233
349
  >
234
- <slot
235
- errors={slotErrors}
236
- hasErrors={$form.hasErrors}
237
- processing={$form.processing}
238
- progress={$form.progress}
239
- wasSuccessful={$form.wasSuccessful}
240
- recentlySuccessful={$form.recentlySuccessful}
241
- {clearErrors}
242
- {resetAndClearErrors}
243
- {setError}
244
- {isDirty}
245
- {submit}
246
- {defaults}
247
- {reset}
248
- {getData}
249
- {getFormData}
250
- {validator}
251
- {validate}
252
- {touch}
253
- validating={$form.validating}
254
- valid={$form.valid}
255
- invalid={$form.invalid}
256
- touched={$form.touched}
257
- />
350
+ {@render children?.({
351
+ errors: slotErrors,
352
+ hasErrors: form.hasErrors,
353
+ processing: form.processing,
354
+ progress: form.progress,
355
+ wasSuccessful: form.wasSuccessful,
356
+ recentlySuccessful: form.recentlySuccessful,
357
+ clearErrors,
358
+ resetAndClearErrors,
359
+ setError,
360
+ isDirty,
361
+ submit,
362
+ defaults,
363
+ reset,
364
+ getData,
365
+ getFormData,
366
+ validator,
367
+ validate,
368
+ touch,
369
+ validating: form.validating,
370
+ valid: form.valid,
371
+ invalid: form.invalid,
372
+ touched: form.touched,
373
+ })}
258
374
  </form>