diff --git a/.changeset/violet-buckets-leave.md b/.changeset/violet-buckets-leave.md new file mode 100644 index 000000000000..76d77ecc6609 --- /dev/null +++ b/.changeset/violet-buckets-leave.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: return `data` to form enhance callback function diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 745cf149317a..5aec9fb832a0 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -2161,8 +2161,11 @@ export type RemoteForm = { /** Use the `enhance` method to influence what happens when the form is submitted. */ enhance( callback: ( - form: Omit, 'enhance' | 'element'> & { + form: Omit, 'enhance' | 'element' | 'data'> & { + /** The
element */ readonly element: HTMLFormElement; + /** The data being submitted */ + readonly data: Input; } ) => MaybePromise ): { diff --git a/packages/kit/src/runtime/client/remote-functions/form.svelte.js b/packages/kit/src/runtime/client/remote-functions/form.svelte.js index 5061951710f4..6ff8740887b9 100644 --- a/packages/kit/src/runtime/client/remote-functions/form.svelte.js +++ b/packages/kit/src/runtime/client/remote-functions/form.svelte.js @@ -45,15 +45,17 @@ function merge_with_server_issues(form_data, current_issues, client_issues) { /** * Client-version of the `form` function from `$app/server`. - * @template {RemoteFormInput} T - * @template U + * @template {RemoteFormInput} TInput + * @template TOutput * @param {string} id - * @returns {RemoteForm} + * @returns {RemoteForm} */ export function form(id) { - /** @type {Map }>} */ + /** @type {Map }>} */ const instances = new Map(); + /** @typedef {Omit, 'enhance' | 'element' | 'data'> & { readonly element: HTMLFormElement, readonly data: TInput }} EnhanceCallbackInstance */ + /** @param {string | number | boolean} [key] */ function create_instance(key) { const action_id_without_key = id; @@ -80,7 +82,7 @@ export function form(id) { let preflight_schema = undefined; /** - * @param {Omit, 'enhance' | 'element'> & { readonly element: HTMLFormElement }} instance + * @param {EnhanceCallbackInstance} instance */ let enhance_callback = async (instance) => { if (await instance.submit()) { @@ -142,10 +144,11 @@ export function form(id) { /** * @param {FormData} form_data + * @param {Record} data * @param {boolean} should_preflight * @returns {Promise & { updates: (...args: any[]) => Promise }} */ - function submit(form_data, should_preflight) { + function submit(form_data, data, should_preflight) { // Store a reference to the current instance and increment the usage count for the duration // of the request. This ensures that the instance is not deleted in case of an optimistic update // (e.g. when deleting an item in a list) that fails and wants to surface an error to the user afterwards. @@ -174,11 +177,11 @@ export function form(id) { } if (should_preflight) { - const valid = await preflight(form_data); + const valid = await preflight(form_data, data); if (!valid) return false; } - const { blob } = serialize_binary_form(convert(form_data), { + const { blob } = serialize_binary_form(data, { remote_refreshes: Array.from(refreshes ?? []) }); @@ -293,23 +296,21 @@ export function form(id) { /** * @param {HTMLFormElement} form * @param {FormData} form_data - * @returns {Omit, 'enhance' | 'element'> & { readonly element: HTMLFormElement }} + * @param {Record} data + * @returns {EnhanceCallbackInstance} */ - function create_enhance_callback_instance(form, form_data) { + function create_enhance_callback_instance(form, form_data, data) { const { enhance: _enhance, ...descriptors } = Object.getOwnPropertyDescriptors(instance); void _enhance; - return /** @type {Omit, 'enhance' | 'element'> & { readonly element: HTMLFormElement }} */ ( + return /** @type {EnhanceCallbackInstance} */ ( Object.defineProperties( {}, { ...descriptors, data: { get() { - // TODO 3.0 remove - throw new Error( - `The \`data\` property has been removed from the \`enhance\` callback argument. Use \`instance.fields.value()\` instead.` - ); + return data; } }, form: { @@ -324,7 +325,7 @@ export function form(id) { value: form }, submit: { - value: () => submit(form_data, false) + value: () => submit(form_data, data, false) } } ) @@ -333,9 +334,9 @@ export function form(id) { /** * @param {FormData} form_data + * @param {Record} data */ - async function preflight(form_data) { - const data = convert(form_data); + async function preflight(form_data, data) { const validated = await preflight_schema?.['~standard'].validate(data); if (validated?.issues) { @@ -360,7 +361,7 @@ export function form(id) { return true; } - /** @type {RemoteForm} */ + /** @type {RemoteForm} */ const instance = {}; instance.method = 'POST'; @@ -417,6 +418,8 @@ export function form(id) { validate_form_data(form_data, clone(form).enctype); } + const data = convert(form_data); + submitted = true; try { @@ -424,10 +427,10 @@ export function form(id) { // the in-progress state during async preflight validation pending_count++; - const valid = await preflight(form_data); + const valid = await preflight(form_data, data); if (!valid) return; - await enhance_callback(create_enhance_callback_instance(form, form_data)); + await enhance_callback(create_enhance_callback_instance(form, form_data, data)); } catch (e) { const error = e instanceof HttpError ? e.body : { message: /** @type {any} */ (e).message }; @@ -580,7 +583,7 @@ export function form(id) { submitted = true; pending_count++; - const submission = submit(form_data, true); + const submission = submit(form_data, convert(form_data), true); void submission.finally(() => { pending_count--; @@ -625,7 +628,7 @@ export function form(id) { get: () => pending_count }, preflight: { - /** @type {RemoteForm['preflight']} */ + /** @type {RemoteForm['preflight']} */ value: (schema) => { preflight_schema = schema; return instance; @@ -700,7 +703,7 @@ export function form(id) { }, enhance: { /** - * @param {(instance: Omit, 'enhance' | 'element'> & { readonly element: HTMLFormElement }) => any} callback + * @param {(instance: EnhanceCallbackInstance) => any} callback */ value: (callback) => { enhance_callback = callback; @@ -715,7 +718,7 @@ export function form(id) { const instance = create_instance(); Object.defineProperty(instance, 'for', { - /** @type {RemoteForm['for']} */ + /** @type {RemoteForm['for']} */ value: (key) => { const entry = instances.get(key) ?? { count: 0, instance: create_instance(key) }; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index fa15b700a746..e0ffc5de64ce 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -2135,8 +2135,11 @@ declare module '@sveltejs/kit' { /** Use the `enhance` method to influence what happens when the form is submitted. */ enhance( callback: ( - form: Omit, 'enhance' | 'element'> & { + form: Omit, 'enhance' | 'element' | 'data'> & { + /** The element */ readonly element: HTMLFormElement; + /** The data being submitted */ + readonly data: Input; } ) => MaybePromise ): {