Giter VIP home page Giter VIP logo

sveltekit-superforms's Introduction

Superforms logo

Superforms 💥

Making SvelteKit forms a pleasure to use!

https://superforms.rocks/
Discord   •   API   •   FAQ   •   npm   •   Issues

Feature list

  • Server- and client-side validation with your favorite validation libraries, and more to come: 💥 Arktype 💥 Joi 💥 TypeBox 💥 Valibot 💥 VineJS 💥 Yup 💥 Zod 💥
  • Seamless merging of PageData and ActionData - Forget about which one to use and how, just focus on your form data.
  • Auto-centering and focusing on invalid form fields.
  • Tainted form detection, prevents the user from losing data if navigating away from an unsaved form. Or use snapshots to save the form state.
  • Automatically coerces the FormData into correct types.
  • For advanced data structures, forget about the limitations of FormData - Use nested data structures transparently.
  • Generates default form values from validation schemas.
  • Handles multiple forms on the same page.
  • Works both on the server and with single-page applications (SPA)!
  • Proxy objects for handling data conversions to string and back again.
  • Realtime client-side validation for the best possible UX.
  • Create loading spinners easily with three auto-updating timers, based on human perception research.
  • Hook into a number of events for full control over the validation data and the ActionResult, with a possibility to cancel the update at every step.
  • Complete customization with a huge list of options.
  • No JavaScript required as default, but full support for progressive enhancement.
  • Comes with a Super Debugging Svelte Component: SuperDebug.

Get started

Follow the Get started tutorial on the website to get a hands-on introduction to Superforms: https://superforms.rocks/get-started

You can also watch this excellent introduction video to see what's possible: https://www.youtube.com/watch?v=MiKzH3kcVfs

Help & support

  • If you're using Superforms in non-profit circumstances, support is completely free; a star on Github is more than enough to show your appreciation. Join the #free-support channel on Discord and ask away!
  • If you're making or aiming to make money on your project, a donation proportional to the current profit of the project or the company you work for, will give you a month of commercial support. Donate with one of the options on the website, then ask in the #commercial-support channel on Discord.

Contributing

General feedback, feature requests, bug reports, PR:s, are very welcome as a Github issue or on the Discord server!

Donating

If you appreciate the hard work behind Superforms, please support open source software with a donation.

"Sponsor me on Github" "Buy Me A Coffee" "Support me on Ko-fi"

sveltekit-superforms's People

Contributors

ciscoheat avatar matfire avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sveltekit-superforms's Issues

zod schema with "refine" results in type error

reproduction:

const schema = z
	.object({
		name: z.string(),
		email: z.string().email(),
		password: z.string().min(8),
		confirmPassword: z.string().min(8)
	})
	.refine((data) => data.password === data.confirmPassword, {
		message: "Passwords don't match",
		path: ['confirmPassword']
	});

export const load = (async (event) => {
	const form = await superValidate(event, schema);

	return {
		form
	};
}) satisfies PageServerLoad;

error:
Argument of type 'ZodEffects<ZodObject<{ name: ZodString; email: ZodString; password: ZodString; confirmPassword: ZodString; }, "strip", ZodTypeAny, { name: string; email: string; password: string; confirmPassword: string; }, { ...; }>, { ...; }, { ...; }>' is not assignable to parameter of type 'AnyZodObject'.
Type 'ZodEffects<ZodObject<{ name: ZodString; email: ZodString; password: ZodString; confirmPassword: ZodString; }, "strip", ZodTypeAny, { name: string; email: string; password: string; confirmPassword: string; }, { ...; }>, { ...; }, { ...; }>' is missing the following properties from type 'ZodObject<any, any, any, { [x: string]: any; }, { [x: string]: any; }>': _cached, _getCached, shape, strict, and 14 more.ts(2345)

is this intentional?

Support for SvelteKit snapshots

It should be possible to capture and restore the superForm state, so it can be used in snapshots, a nice quite new SvelteKit feature.

Shouldn't be that hard to add these methods to the output of superForm.

Form does not exist on type "PageData"

When using both page.ts and page.server.ts, TS says form does not exist on type of PageData. however when I remove the page.ts the error disappears.
page.ts

	const { id } = event.params;
	const { supabase } = await event.parent();
	const { data: property, error: err } = await supabase
		.from('property_with_units')
		.select('*')
		.eq('id', id)
		.limit(1)
		.single();
	if (err) {
		throw error(500, {
			message: 'Server Error. Please Try Again Later'
		});
	}
	return {
		property
	};
};

page.server.ts

export const load: PageServerLoad = async (event) => {
	const form = await superValidate(event, formSchema);
	return {
		form
	};
};

Screenshot 2023-03-06 at 17 51 34

Client side validation upgrade

Discussed in https://github.com/ciscoheat/sveltekit-superforms/discussions/45

Originally posted by **alesvaupotic** March 20, 2023

Hey! 0.6 is great improvement, love it. Question on client side validation: validation happens on submit, errors are set and with defaultValidator: 'clear' they go away as soon as input is correct.

But, if I return to an already validated input and enter incorrect value, the error doesn't return until I submit the form again. I must be missing something here as revalidations don't run on input change from valid to error but they do run from error to valid?

The main issue

The problem with making validation work with a pattern like reward early, validate late is that Superforms aren't using any form events, it knows nothing about the form that you're using its store properties on. This is what makes it easy to use, but poses a problem when it comes to events like on:blur and on:input. Adding those events manually to every form field is not viable, so the next option would be to add those events to the form itself, using the bubbling phase to determine what happened.

This would have worked fine for top-level fields, but the data can be nested, so if you're outputting an array of tags:

{#each $form.user.tags as _, i}
  Name: <input bind:value={$form.user.tags[i]} />
{/each}

Then the input event don't know that the changed field is bound to $form.user.tags[i], which is what is needed to locate the correct validator, which could look like:

const { form } = superForm(page.data, {
  validators: {
    user: {
      tags: (tag) => tag.length < 1 ? 'Tag must have a name' : null
    }
  }
})

The $tainted store comes to mind, which accurately keeps track of each field that has changed. Maybe it can be used on each input/blur/etc event to diff its previous state, thereby determining which field(s) changed on each event.

Any ideas about this is appreciated!

💡 ideas for improved DX

Hey I was reading a bit of the documentation. First thing first this library seems great and I can't wait to try it out.

While I was reading tho I had some ideas on how to improve the developer experience and if you are ok with it I can even give you a hand developing this changes.

Basically the main pain point I see is that I have to remember to always return the form object. Also I always have to pass the event to the superValidate function. And on the .svelte side I have to remember to pass data.form to superForm.

I think all of this can be avoided. How? Just make superValidate an higher order function that takes in the actual load/action function do his things and than calls the actual load function. I did something similar for sveltekit-defer.

//+page.server.ts

export const load = superValidate(schema, (event, form)=>{
    // Here the user can just do whatever he wants and
    // Return whatever he wants. He also has access to form, the current return value of superValidate
});

Under the hood you will do something like this

export function superValidate(schema, load){
    return (event)=>{
        //Do your thing here, you have access to schema and event
        const returnVal = await load();
        return {
            ...returnVal,
            form, //here you return form so that the user doesn't have to
        }
    }
}

On the .svelte side you can avoid let the user pass in data.form because in the store you have access to $page which contains $page.data which basically the same of data. So they can call the store simply by doing.

const form = superForm();

And under the hood you access the form through $page.data.form (I know it's not recommended in the sveltekit documentation because than you are tied to sveltekit...but this library already is tied to sveltekit so we might just smooth the DX).

Obviously the same thing is valid for the actions, the user can simply wrap them with the superValidate HOC and you could even auto-throw the fail if the form is not valid.

Live Validation?

Thx for this library. I was wondering if there's also a way to have live validation, e.g. onBlur of a field, instead of submit of the whole form ?

Throwing error for a specific field

This is more of a discussion than an issue, but since discussions are not enabled here, I'm posing as an issue.

I am not sure if this is something I missed in the documentation, or we don't have this feature, but I can't find a way to throw an error for a specific field.

In my case, if the user tries to save an existing value for a unique field, I want to be able to throw an error for that field specifically, which should show up in $errors.

Is there currently a way to do that?

Thank you.

Multiple forms with use:enhance

Description
I got 2 forms and I did according the docs. The first form works fine but when I include use:enhance to the second one. It blocks actions. I gave

1. First Form
<form method="POST" action="?/addBooking" use:enhance>
Result: OK.

3. Second Form
<form method="POST" action="?/updateUser" use:enhance>
Resutl: Nothing. Tried to log the form from actions but nope.

If the form is invalid, my whole form gets cleared

+page.server.ts

import type { ServerLoadEvent, Actions } from '@sveltejs/kit/types';
import type { PageServerLoad } from './$types';
import { fail } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import { Listing } from 'src/types/listing';
import z from 'zod';
import { error, redirect } from '@sveltejs/kit';

const listingCrudSchema = Listing.extend({
	id: Listing.shape.id.optional()
});

const listingId = () => String(Math.random()).slice(2);

export const load = (async ({ url }) => {
	// READ listing
	// For simplicity, use the id query parameter instead of a route.
	const id = url.searchParams.get('id');
	// const listing = id ? listings.find((l) => l.id === id) : null;
	const listing = listings[0];
	console.log(listings);

	if (id && !listing) throw error(404, 'Listing not found');

	// If we're editing a listing, prefill the form with the listing data.
	const form = await superValidate(listing, listingCrudSchema);

	// Always return { form } in load and form actions.
	return { form };
}) satisfies PageServerLoad;

export const actions = {
	default: async (event) => {
		const form = await superValidate(event, listingCrudSchema);

		if (!form.valid) {
			console.log('form invalid');
			console.log('errors', form.errors);
			console.log('message', form.message);
			return fail(400, { form });
		}

		if (!form.data.id) {
			// CREATE user
			const listing = { ...form.data, id: listingId() };
			listings.push(listing);

			console.log('listing id', listing.id);
			throw redirect(303, '?id=' + listing.id);
		} else {
			// UPDATE user
			const listing = listings.find((u) => u.id == form.data.id);
			if (!listing) throw error(404, 'Listing not found.');

			listings[listings.indexOf(listing)] = { ...form.data, id: listing.id };

			form.message = 'Listing updated!';
			console.log(form.message);
			return { form };
		}
	}
} satisfies Actions;

// A simple listing "database"
const listings: z.infer<typeof Listing>[] = [];

When the form is invalid and submitted, the whole form gets cleared :( how to prevent this?

Form Payload size

Description
When submitting a form with a payload above a certain size (aprox. 1MB) the __superform_json serialized object gets trimmed and the parsing and validation fail.

Form starts as tainted with Zod enums and select elements

I have an address form with the state property of the Zod schema defined like:

	state: z.nativeEnum(State)

In the form, the state field is a select element with the first option defined as:

			<option value="">Select</option>

The problem is that superValidate generates undefined as the value of $form.state, but when bound to the select element, that immediately gets changed to the empty string, which marks the form as tainted. This means even without touching the form, if the user attempts to navigate away, they will see the taintedMessage alert.

To avoid this problem, it would be helpful to be able to specify the default value for enums as being the empty string rather than undefined (possibly via a configuration option). For example, the following schema works as expected:

	state: z.nativeEnum(State).or(z.literal('')).default(''),

Of course, it's not ideal to have to specify the schema that way, as it is not obvious why it is written that way, and technically it would allow an empty string to be submitted even though that value should not be allowed.

Would adding an option to handle this case be possible, or is there a better solution?

Error: Unsupported type for strict values on field "x": ZodEnum.

Error: Unsupported type for strict values on field "interestMethod": ZodEnum. Add default, optional or nullable to the schema, or use the "defaults" option.

i have zod Enums, but the validation fails with above error.

the validation also fails for ZodUnion. for Unsupported type for strict values on field "createdAt": ZodUnion.

I am doing something wrongly?

Potential subscription memory leak from Superform client

It's hard to prove this one way or the other (I don't know of any tools which will detect or validate these), but while I was working with superforms, I noticed a couple subscriptions in the client that don't appear to be cleaned up.

The Data.subscribe and page.subscribe calls here: https://github.com/ciscoheat/sveltekit-superforms/blob/main/src/lib/client/index.ts#L405 and https://github.com/ciscoheat/sveltekit-superforms/blob/main/src/lib/client/index.ts#L447

We probably want to take the return values of the subscription calls, add them to an array, then return an unsubscribe function which runs them all. The developer is then responsible for calling onDestroy(unsubscribe) in their page component.

Make fields work for nested data

A bit tougher to handle than #70, making fields work for any nested form data, instead of just top level, would be a nice update.

The problem is that it needs to traverse three data structures (form, errors, constraints), taking undefined values into account. Metadata needs to be either converted to a nested structure, or skipped for non-top level fields. It's a bit of work.

redirect via actionResult() with sveltekit-flash-message

Is your feature request related to a problem? Please describe.
Hi, have been enjoying sveltekit-superforms a lot; thanks for the library! Had a use case come up recently that left me a bit stumped. We're using superforms with sveltekit-flash-message, and most of the integration seems to be working well. That said, there was one flow which I don't think is currently possible given the current state of the two libraries.

Specifically, when POSTing to an API endpoint (+server.js) with superforms, it doesn't appear possible to return an actionResult('redirect') call and simultaneously set a flash message. (actionResult() with "redirect" as its first parameter only accepts a location and status as the second and third parameters, respectively).

The different parts of this all seem to work in isolation.

  • Throwing a redirect() from sveltekit-flash-message in an endpoint works (and properly sets the flash message).
  • Returning an actionResult('redirect') in an endpoint also works, but there's no way to set the flash.

Throwing the redirect() from sveltekit-flash-message in the endpoint doesn't work, however, when it's called via SuperForms (which is actually documented here, as SuperForms expects an ActionResult).

Describe the solution you'd like
It seems like it should be possible to setup a redirect with a flash message in an endpoint, unless there's something I'm not understanding. Would be nice to potentially extend the actionResult() function from this package to accept a message parameter.

Admittedly, I understand that such a message parameter on actionResult() would only be useful in the context of implementing the sveltekit-flash-message package, and furthermore that the package maintainers might prefer to keep superforms and flash-message as independent as possible (besides the fact that they work so well together).

But still, would be nice to have them work together in this instance. Interested to hear your thoughts. Thanks in advance for the consideration.

Fix ESM imports to allow moduleResolution NodeNext

Description
Since this package is using the sveltekit packaging tooling, it would be nice to allow consumers to use moduleResolution set to NodeNext or Node16.

Currently if consumers set moduleResolution to node everything works just fine, however if a consumer sets moduleResolution to NodeNext or Node16 certain imports will fail. Documentation on SvelteKit site: https://kit.svelte.dev/docs/packaging#caveats

In this example the moduleResolution is set to node. Typings on the form works (+page.server.ts line 28).
Screenshot 2023-03-27 at 11 03 05 AM

If I change this example to moduleResolution to NodeNext typings are not imported correctly and I receive any
Screenshot 2023-03-27 at 11 03 28 AM

To fix this, the library will need to change imports and follow the ESM standard. (index.d.ts line 2 and 4)
Screenshot 2023-03-27 at 11 03 54 AM

Error processing enum type

Hello,

I'm not sure if I'm doing something wrong, or there's a bug, but I can't include enum in my schema. This single like makes the code silently break and nothing gets passed to the form object on the server on submit:

gender: z.enum(["male", "female", "other"]).nullish()

Am I using this wrong?

Error on validation Array on server

where i try validate a response of users(and array of users)

[
{
id: 1,
name: 'Important Customer',
email: '[email protected]'
},
{
id: 2,
name: 'Super Customer',
email: '[email protected]'
}
]

const form = await superValidate(users, crudSchema);

I get the following error
Argument of type 'User[]' is not assignable to parameter of type 'RequestEvent<Partial<Record<string, string>>, string | null> | Request | FormData | Partial<Record<string, unknown>> | null | undefined'.
Type 'User[]' is not assignable to type 'Partial<Record<string, unknown>>'.

Use Superforms in SPA mode

It should be possible to use the server-side part of the library in a +page.ts, so it can be used in a SPA.

On the client, all that's needed is to construct a Validation<T, M> object from data which could be coming from another source than the SvelteKit server. An experiment is made here (also check the +page.ts in the same folder).

zod schema with native enum results in internal error

reproduction:

const schema = z.object({
	title: z.string(),
	value: z.coerce.number().min(1),
	kind: z.nativeEnum({GRAY: "GRAY", GREEN: "GREEN"}),
	description: z.string().optional()
});

export const load = (async (event) => {
	const form = await superValidate(event, schema);

	return {
		form
	};
}) satisfies PageServerLoad;

if i set a .default("GRAY") to the enum field, it works ok

not sure if this is intentional, but one problem i noted with setting a default value is that it removes the required constraint.

tried submitting the form and got the following error: Error: Unsupported Zod default type: ZodNativeEnum

tried using z.enum and it works ok

Is there a plan on adding native enum support? the motivation for this support could be, for example, using the Enum Objects auto generated by prisma when defining an Enum Schema.

use z.input<> instead of z.infer<> to infer field types

i have the following schema:

const schema = z.object({
  tags: z
    .string()
    .nullish()
    .transform((v, ctx) => {
      const commaDelimitedListRegex = /(\d+)(,\s*\d+)*/;

      if (!v) return;

      if (!commaDelimitedListRegex.test(v)) {
        ctx.addIssue({
          code: 'custom',
          message: 'Tags must be separated by comma'
        });
      }

      return v.split(',');
    }),
});

when doing

const { form } = superForm(data.form);

on the client, form.tags is inferred as string[], which is the "output", instead of string, which is the input

this is bad because when doing

<input type="text" bind:value={$form.tags} />

typescript complains that it cant bind string to string[]

a way to get this working would be to do the transformation on the post request (similar to #11).

superValidate loses Zod types with top-level transforms

With schemas that look like z.object({...}).transform(...), superValidate loses the precise Zod types that Zod would be able to infer via schema.parse. For example:

		const schema1 = z.object({
			first_name: z.string(),
			last_name: z.string()
		});
		const form1 = await superValidate(request, schema1);
		form1.data; // inferred type: { first_name: string, last_name: string }

		// When adding a single transform, superValidate fails to pick up the properties added by the transform.
		const schema2 = schema1.transform((v) => {
			return { ...v, full_name: `${v.first_name} ${v.last_name}` };
		})
		const form2 = await superValidate(request, schema2);
		form1.data; // inferred type: { first_name: string, last_name: string } -- missing full_name

		// When adding a second transform, superValidate loses all typing information, falling back to `{ [key: string]: any }`.
		const schema3 = schema2.transform((v) => {
			return { ...v, initials: `${v.first_name[0]}${v.last_name[0]}` };
		});
		const form3 = await superValidate(request, schema3);
		form3.data; // inferred type: { [key: string]: any }

Note, Zod itself does not have any problem with this:

		const form3 = schema3.safeParse({});
		if (form3.success) form3.data // inferred type: { first_name: string, last_name: string, full_name: string, initials: string }

Array of strings values defaults to empty array

First of all, great lib !

I am trying to group several inputs into an array of values, an array of strings. For the example, the array will be of size 2.

const schema = z.object({
  string_array: z.string().array().nonempty(),
});
    <input type="text" name="string_array" />
    <input type="text" name="string_array" />

image

When submitting the form, I get empty arrays instead of strings.

image
With one of the inputs filled in:
image
image

I may have made a mistake somewhere, and if so please tell me how to do it the right way!

Reproduction repo : https://github.com/oganexon/superform-string-url-array-bug

how to return custom errors (eg prisma errors)

the form validation works great but how can i return an error unrelated to data validation? do i have to use export let form?

my case is this:

return fail(409, { usernameAlreadyExists: true, form });

i cannot seem to find the usernameAlreadyExists error anywhere except on form coming from sveltekit? I have a feeling i am doing something wrong but am not totally sure, any help would be appreciated

Select all content in field when focused

An additional option to superForm for selecting all text when an error field is focused, instead of just focusing and the cursor is set at the end of the text.

Binding with forms does not seem to work

Not sure if this is Superforms specific.

I have a component inside of a form:

					<PhoneNumber
						name="phoneNumber"
						bind:phone={$form.phoneNumber}
						label="Your mobile number"
						errors={$errors.phoneNumber}
						{...$constraints.phoneNumber}
					/>

I have the debugging form available. I see that $form.phoneNumber is updated with a specific value, however, on submit of the form, the value in form.data.phoneNumber on page.server does not reflect the value of $form.phoneNumber

Example:

CleanShot 2023-03-15 at 12 45 53@2x

as you can see the phone number has a value starting with 31.

However, when I submit, I get 654654654 as the value of phoneNumber in the page.server form.data.phoneNumber

Any ideas? In the component itself I change the phone value based upon the dropdown and the entered number. So I compose two values in the phone variable. But as you can see, the form values are correct client side.

sveltekit warning (or error) message

not sure how to reproduce it, but i got the following warning:

Error: Cannot subscribe to 'page' store on the server outside of a Svelte component, as it is bound to the current request via component context. This prevents state from leaking between users.For more information, see https://kit.svelte.dev/docs/state-management#avoid-shared-state-on-the-server

this is the trace: (highlighted the line where superforms appear)
at get_store (/node_modules/@sveltejs/kit/src/runtime/app/stores.js:68:9)
at Object.subscribe (/node_modules/@sveltejs/kit/src/runtime/app/stores.js:26:24)
at subscribe (/node_modules/svelte/internal/index.mjs:57:25)
at Module.get_store_value (/node_modules/svelte/internal/index.mjs:62:5)
at Module.superForm (/node_modules/sveltekit-superforms/dist/client/index.js:59:23)
at +page.svelte:13:60
at Object.$$render (/node_modules/svelte/internal/index.mjs:1892:22)
at Object.default (root.svelte:48:44)
at eval (/node_modules/@sveltejs/kit/src/runtime/components/layout.svelte:8:41)
at Object.$$render (/node_modules/svelte/internal/index.mjs:1892:22)

ActionData didn't return a Validation object. Make sure you return { form } from form actions.

I am returning a form from my action like so

 const { locals } = event;

  const form = await superValidate(event, schema);

  console.log(form);

  if (!form.valid) {
    return fail(400, { form });
  }

with the schema:

const schema = z.object({
  firstName: z.string(),
  lastName: z.string(),
  password: z.string(),
  email: z.string().email()
});

However I get the error: ActionData didn't return a Validation object. Make sure you return { form } from form actions.
unless I change the fail line to
return fail(400, { form: { ...form, success: false } })

I am using the form in my page like so const { form, errors } = superForm(data.form);

Am I missing that I should have to manually set success because the docs don't show that. I am using sveltekit 1.8.3

Nested objects defaults not working/Nested Errors are flattened into an array of strings

Thanks for the great module, I'm a bit new so not sure if this is a superforms issue or a zod issue but, I have the following types:

If there are validation issues on the ListingProject (which is a nested zod object), the errors show up as [error1, error2, error3] so in the form it's a bit difficult to show the error on the nested object.

Plus I assumed that superforms assumes the defaults based on the object type, for the ListingProject object, there's a couple of fields that are arrays of strings or objects, when trying to build forms that use these fields you get "cannot read attribute of undefined (reading length).

so what I do is in the nested object definition I put .default({ array1: [], array2: []} is this the best way to go about it?

Thanks for the great work!

import { z } from 'zod';

export const SocialNetworks = z.enum([
	'twitter',
	'discord',
	'telegram',
	'facebook',
	'instagram',
	'others'
]);

const SocialData = z.object({
	network: SocialNetworks,
	handle: z.string().min(1).max(100),
	members: z.number().min(0)
});

export type ListingType = z.infer<typeof Listing>;

export const ProjectTypes = ['NFT', 'DeFi', 'DAO', 'DEX', 'Games', 'Others'];

export const ListingProject = z.object({
	name: z.string().min(1).max(100),
	helloMoonCollectionId: z
		.string()
		.min(1)
		.max(50)
		// .optional()
		.default('040de757c0d2b75dcee999ddd47689c4'),
	collectionName: z.string().min(1).max(100),
	launchDate: z.date(),
	launchPrice: z.number().min(0),
	socials: z.record(SocialData).default({}),
	links: z.record(z.string().url()),
	floorPriceAtListing: z.number().min(0),
	listingsAtListing: z.number().min(0),
	volumeAtListing: z.number().min(0),
	ownersAtListing: z.number().min(0),
	supply: z.number().min(1),
	description: z.string().min(1).max(500),
	image: z.string().url(),
	website: z.string().url(),
	categories: z.array(z.enum(ProjectTypes)).default([]),
	network: z
		.enum(['Solana', 'Ethereum', 'Binance Smart Chain', 'Polygon', 'Solana', 'Others'])
		.default('Solana')
});

export const ProjectAddressTypes = z.nativeEnum({
	royalty: 'Royalty',
	treasury: 'Treasury',
	creatorAddress: 'Creator Address',
	updateAuthority: 'Update Authority',
	mintAuthority: 'Mint Authority',
	freezeAuthority: 'Freeze Authority',
	claimAuthority: 'Claim Authority',
	others: 'Others'
});

export const ProjectAddress = z.object({
	network: z.enum(['Solana', 'Ethereum', 'Binance Smart Chain', 'Polygon', 'Solana', 'Others']),
	address: z.string().min(1).max(100),
	balance: z.number().min(0).optional(),
	type: ProjectAddressTypes,
	note: z.string().min(1).max(100)
});

const ProjectFinancials = z.object({
	// item
	item: z.string().min(1).max(100),
	// item value
	value: z.number().min(0),
	// item value unit
	unit: z.enum(['SOL', 'USD', 'ETH', 'BNB', 'MATIC', 'others']).default('SOL')
});

export const TechStackItem = z.object({
	name: z.string().min(1).max(100),
	description: z.string().min(1).max(1000),
	type: z.enum(['backend', 'frontend', 'database', 'others']),
	url: z.string().url(),
	technology: z.string().min(1).max(100),
	version: z.string().min(1).max(100).default('latest')
});

export enum ListingPurpose {
	takeoverFull = 'takeoverFull',
	takeoverPartial = 'takeoverPartial',
	funding = 'funding',
	others = 'others'
}

export const PricingUnits = ['SOL', 'USD', 'ETH', 'BNB', 'MATIC'];

export const ListingPurposes = z.enum(['takeoverFull', 'takeoverPartial', 'funding', 'others']);

export const Listing = z.object({
	id: z.string().uuid(),
	user: z.string().min(1).max(50),
	created: z.date().default(() => new Date()),
	updated: z.date().nullable(),
	financials: ProjectFinancials,
	techStack: z.array(TechStackItem),
	project: ListingProject.default({ socials: {}, network: 'Solana', categories: [] }),
	headline: z.string().min(1).max(100),
	reason: z.string().min(1).max(1000),
	// purpose options ['takeover-full', 'takeover-partial', 'funding', 'others'] array
	purpose: z.array(ListingPurposes),
	partialTakeoverPercentage: z.number().min(0).max(100).optional(),
	overview: z.string().min(1).max(1000),
	addresses: z.array(ProjectAddress),
	price: z.number(),

	priceUnit: z.enum(PricingUnits).default('SOL'),
	priceIncludes: z.array(z.string().min(1).max(100)),
	type: z.enum(['auction', 'fixedPrice', 'others']).default('fixedPrice')
});

No known conditions for "./server" specifier

If I just have the two files:

  • routes/search/+page.server.ts
  • routes/search/page.svelte

I get the error below. If I rename +page.server.ts to +server.ts, this error goes away

Internal server error: No known conditions for "./server" specifier in "sveltekit-superforms" package
 ...
     at eval (/src/routes/search/+page.server.ts:5:37)

routes/search/+page.server.ts:

import type { Actions } from './$types';
import { fail } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import { z } from 'zod';

const schema = z.object({
	search: z.string()
});

export const actions = {
	default: async (event) => {
		// Same syntax as in the load function
		const form = await superValidate(event, schema);
		console.log('POST', form);

		// Convenient validation check:
		if (!form.valid) {
			// Again, always return { form } and you'll be fine.
			return fail(400, { form });
		}

		// Yep, here too
		return { form };
	}
} satisfies Actions;

routes/search/page.svelte:

<script lang="ts">
	import type { PageData } from './$types'
	import { superForm } from 'sveltekit-superforms/client'
	import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte'

	export let data: PageData

	// This is where the magic happens.
	const { form } = superForm(data.form)
	console.log(data)
</script>

<SuperDebug data={$form} />

<div class="container mx-auto p-8 space-y-8">
	<form method="POST" action="?/search">
		<div class="input-group input-group-divider grid-cols-[auto_1fr_auto]">
			<div class="input-group-shim">Search:</div>
			<input
				name="search"
				type="search"
				placeholder="What are you interested in ..."
				bind:value={$form.search}
			/>
			<button type="submit" class="variant-filled-secondary">Submit</button>
		</div>
	</form>
</div>

Feature request: Add form attributes to server API

It would be convenient to be able to do something like this:

// +page.server.ts
const fooForm = await superValidate(event, schema, { id: 'fooForm', action: '?/foo'})
const barForm = await superValidate(event, schema, { id: 'barForm', action: '?/bar', method: 'GET'})
// ...
<!-- +page.svelte -->
<form {...$fooForm.formAttrs}>
  <!-- fields -->
</form>

Primarily, I'm interested in passing along the action attribute from server to client. This is useful in case the action URL changes. In that case, it would only need to be updated on the server-side and not in the .svelte code as well.


Also, I just started using this lib and I'm liking it so far. Thank you!

Boolean in zod's schema doesn't persist in form after action result?

When I enter a string value into a text field (e.g. email, password) and action is submitted, the page refreshes and the values stay in the form (bind:value works fine)
However, the boolean field always refreshes to the default state (false).
I've checked with SuperDebug to confirm the checked state is correctly passed into the form variable (it updates when I check/uncheck the checkbox). But after an action event (form submission), the boolean value becomes false, while all other fields remain as they were before the submission.

+page.server.ts:

...
const formSchema = z.object({
    firstName: z
        .string({ required_error: "First name is required" })
        .min(1, { message: "First name must be at least 1 characters long" }),
    lastName: z
        .string({ required_error: "Last name is required" })
        .min(1, { message: "Last name must be at least 1 characters long" }),
    email: z
        .string({ required_error: "Email is required" })
        .email({ message: "Enter a valid email address" }),
    password: z
        .string({ required_error: "Password is required" })
        .min(6, { message: "Password must be at least 6 characters long" }),
    acceptedTos:
        z.boolean({ required_error: "You must accept the Terms of Service" })
});
...

+page.svelte

...
export let data: PageData;

    let success: boolean = false;
    const { form, errors, message, submitting, constraints, enhance } = superForm(data.form,
        {
            autoFocusOnError: 'detect',
            clearOnSubmit: 'none',
            multipleSubmits: 'prevent',
            onResult(event) {
                if(event.result.type == "success")
                {
                    success = true;
                    setTimeout(() => {
                        window.location.href = "/";
                    }, 500);
                }
            },
        }
    );
...

<input id="terms" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800" bind:checked={$form.acceptedTos}>

Cannot deploy to Cloudflare because of crypto

hi,

I am deploying my sveltekit app to Cloudflare Pages.
However, when I use your library I get error on the crypto module.
(I think from there

import crypto from 'crypto';
)

I get this build error through GitHub actions:

Using @sveltejs/adapter-cloudflare
Error: R] Could not resolve "crypto"
    .svelte-kit/output/server/entries/pages/auth/login/_page.server.ts.js:5:19:
      5 │ import crypto from "crypto";
        ╵                    ~~~~~~~~

  The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
error during build:
Error: Build failed with 1 error:
.svelte-kit/output/server/entries/pages/auth/login/_page.server.ts.js:5:19: ERROR: Could not resolve "crypto"

Feature Request: Submit function

Sometimes I want to submit a form when the input value changes, not when the button is pressed.
ex:

<script lang="ts">
  import type { PageData } from './$types';
  import { superForm } from 'sveltekit-superforms/client';

  export let data: PageData;
  let button: HTMLButtonElement

  // Client API:
  const { form } = superForm(data.form);
</script>

<form method="POST" on:change={()=>button.click()}>
	<input type="text"  bind:value={$form.text}>
	<button type="submit" hidden  bind:this={button}/>
</form>

If you create a submit function like

const { form, submit } = superForm(data.form);

It makes my life easier!!

Feature Request: Pass options to use:enhance

Hello,

Really enjoying using the library. I am having some trouble where I want to be able to create the form at the top level and pass it down to components that handle using it. However these components want to set the options like onUpdate or onResult so I just have to pass the validation down to the component and create the form there.

If there is a better way to handle this that I am missing let me know. It is also hard to pass the form/validation all the way down to where the form actually is in my components since it may be deep in a component.

Zod and form-level errors

According to the documentation, errors is of type Record<string, string[]>. However, if a refine or transform is added to the top-level Zod schema and results in a validation failure, errors becomes a string[]. For example:

const form = await superValidate(request, schema.refine((v) => false, 'Form-level error');

Given the above, errors will end up being ['Form-level error'] rather than an object.

This works fine and is a useful way of managing form-level errors (i.e., errors not associated with a specific field in the form), but if this is intentional, it would be a good idea to document it so it can be relied upon as a way of checking for form-level errors (e.g., a check for Array.isArray($errors) indicates there are form-level errors).

If this is not the expected behavior and will be changed, is there an alternative way of handling form-level errors? One alternative I have considered is something like:

  form.valid = false;
  form.message = 'There was a problem';
  return fail(400, { form });

and then checking for !$valid && $message in the template.

Console error using window.fetch on form submission

When i submit my form, I am getting the console warning below. Am i doing something wrong here?

Loading http://localhost:5173/consumption/input?/create using `window.fetch`. For best results, use the `fetch` that is passed to your `load` function: https://kit.svelte.dev/docs/load#making-fetch-requests

+page.server.ts

import type { Actions } from './$types';
import { CREATE_CONSUMPTION } from '$lib/server/queries';
import { GRAPHQL_URL } from '$env/static/private';
import { error, fail } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import { z } from 'zod';

export const prerender = false;

const inputSchema = z.object({
	price: z.number().gt(0).lt(100).default(NaN),
	gallons: z.number().gt(0).lt(50).default(NaN),
	miles: z.number().gt(0).lt(1000).default(NaN),
	notes: z.string()
});

export const load = async () => {
	const form = await superValidate(inputSchema);
	return { form };
};

export const actions: Actions = {
	create: async ({ request }) => {
		const form = await superValidate(request, inputSchema);
                console.log(form)
	}
};

Error on forms with redirect

Hi,

I have a login form, where I use the superforms component.
When I execute the login action on the server, I do something like
if (callResponse.requestId) throw redirect(302, '/auth/verify/' + callResponse.requestId);
to go to a next page with a request id.

This works, however, I now see following error appearing:

Uncaught (in promise) Error: No form data found in $page.data (PageData). Make sure you return { form } in the form actions and load function.

Any idea what I should do...

remove empty fields

I have to implement this lib for following common usecases , because my backend(Hasura GraphQL) set missing fields during create time to database specific defaults (created_at, created_by …)
Similarly I have to set empty fields to null during updates. To prevent replacing data fields with nulls.

  • Preprocess FormData/URLSearchParams/Params with remove empty fields (for CRUD create operation)
  • Preprocess FormData/URLSearchParams/Params with set empty fields to null (for CRUD update operation)

wonder if capability is natively available in super forms ?

Make the resetForm option accept a function as argument

Discussed in https://github.com/ciscoheat/sveltekit-superforms/discussions/102

Originally posted by benny856694 April 20, 2023
I want to dynamically decide whether the form should be reset or not.
use case:
I have a form to create one or multiple objects. when the user clicks the 'Create multiple objects' button, I don't want to reset the form. but when the user clicks the 'create single object' button, I want to reset the form.

Add an async callback function to options.resetForm that takes the form validation data and should return a boolean.

Exclude Form Fields And Fail

Is your feature request related to a problem? Please describe.
When dealing with form submissions on the server, we often want to prevent sensitive data (e.g. passwords) from being sent back to the client.

Describe the solution you'd like
A simple helper method that resets specified fields and returns SvelteKit's native fail.

Maybe something like this on the server:

function excludeFieldsAndFail(form, fields: array, status = 400) {
    for (const field of fields) {
        form[field] = ''
    }
    return fail(status, { form })
}

and on the client side:

if (!form.valid) {
    return excludeFieldsAndFail(form, ['password', 'passwordConfirmation'], 401)
}

Thoughts? :)

How to use reset method form superForm function

While looking through the interface the superForm function I saw that it returns a reset method. Which does reset the form to the initial value set in the load function, but only one time - after that it no longer resets.

I did try looking through the docs, but did not find a section on this - so I wanted to know if this was ready for usage, or if I was using it incorrectly

For the code below, when I bring up the page the name field has foobar. If I change it to foobar1 and click the reset button, it goes back to foobar. However if I repeat the steps the reset button does not return it to foobar; it stays foobar1. If I reload the page the reset button works again, but only for the 1st time.

Hope that makes sense; let me know if I can do add anything else

+page.svelte

<script lang="ts">
	import type { PageData } from './$types';
	import { superForm } from 'sveltekit-superforms/client';
	import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
	export let data: PageData;
	const { form, enhance, reset } = superForm(data.form);
</script>

<button on:click={() => reset()}>Reset</button>
<SuperDebug data={$form} />
<form method="POST" use:enhance>
	<label for="name">Name</label>
	<input type="text" name="name" bind:value={$form.name} />
	<div><button>Submit</button></div>
</form>

+page.server.ts

import type { PageServerLoad } from './$types';
import { z } from 'zod';
import { superValidate } from 'sveltekit-superforms/server';

const schema = z.object({ name: z.string() });

export const load = (async () => {
	const form = await superValidate({ name: 'foobar' }, schema);
	return { form };
}) satisfies PageServerLoad;

Edit: also I just realized this I filed under Feature Request/enhancement; my apologies, I think I should've done Something Else` - sadly can't seem to change it on my end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.