Skip to content

Commit f24d8cf

Browse files
authored
Merge pull request #62 from x0k/create-sveltekit-form
Create sveltekit form API
2 parents 6b892f9 + 6ec6180 commit f24d8cf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1256
-696
lines changed

.changeset/gorgeous-forks-lie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sjsf/sveltekit": minor
3+
---
4+
5+
Allow usage of separators in additional property key inputs

.changeset/pink-kiwis-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"docs": patch
3+
---
4+
5+
Update SvelteKit integration guide
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sjsf/sveltekit": minor
3+
---
4+
5+
Add `SvelteKitForm` component

.changeset/warm-actors-compare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sjsf/form": patch
3+
---
4+
5+
Fix nested additional properties id's inference

.vscode/launch.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,18 @@
3030
"<node_internals>/**",
3131
"**/node_modules/**"
3232
],
33-
"program": "${workspaceRoot}/packages/sveltekit-integration/node_modules/vitest/vitest.mjs",
33+
"program": "${workspaceRoot}/packages/sveltekit/node_modules/vitest/vitest.mjs",
3434
"args": [
3535
"run",
3636
"../../${relativeFile}",
3737
"-r",
38-
"${workspaceRoot}/packages/sveltekit-integration/"
38+
"${workspaceRoot}/packages/sveltekit/"
3939
],
4040
"env": {
4141
"NODE_ENV": "development",
4242
"VITE_TEST": "true"
4343
},
44-
"cwd": "${workspaceRoot}/packages/sveltekit-integration",
44+
"cwd": "${workspaceRoot}/packages/sveltekit",
4545
"smartStep": true,
4646
"console": "integratedTerminal"
4747
}
Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,20 @@
11
<script lang="ts">
2-
import { Content } from "@sjsf/form";
32
import { createValidator2 } from "@sjsf/ajv8-validator";
43
import { theme } from "@sjsf/form/basic-theme";
54
import { translation } from "@sjsf/form/translations/en";
6-
import { useSvelteKitForm, meta } from "@sjsf/sveltekit/client";
5+
import { SvelteKitForm, createMeta } from "@sjsf/sveltekit/client";
76
87
import type { PageData, ActionData } from "./$types";
98
10-
const { form, enhance } = useSvelteKitForm(
11-
meta<ActionData, PageData>(),
12-
"form",
13-
{
14-
...theme,
15-
validator: createValidator2(),
16-
translation,
17-
}
18-
);
9+
const meta = createMeta<ActionData, PageData, "form">("form");
1910
</script>
2011

21-
<form
22-
use:enhance
23-
method="POST"
24-
novalidate
25-
style="display: flex; flex-direction: column; gap: 1rem"
26-
>
27-
<Content {form} />
28-
<button type="submit" style="padding: 0.5rem;">Submit</button>
29-
</form>
12+
<SvelteKitForm
13+
{...theme}
14+
{meta}
15+
{translation}
16+
validator={createValidator2()}
17+
onSuccess={console.log}
18+
onFailure={console.error}
19+
onSubmitError={console.warn}
20+
/>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script lang="ts">
2+
import { RawForm, setFromContext } from "@sjsf/form";
3+
import { createValidator2 } from "@sjsf/ajv8-validator";
4+
import { theme } from "@sjsf/form/basic-theme";
5+
import { translation } from "@sjsf/form/translations/en";
6+
import {
7+
createMeta,
8+
createSvelteKitForm,
9+
createSvelteKitRequest,
10+
} from "@sjsf/sveltekit/client";
11+
12+
import type { PageData, ActionData } from "./$types.js";
13+
14+
const meta = createMeta<ActionData, PageData, "form">("form");
15+
const request = createSvelteKitRequest(meta, {
16+
onSuccess: console.log,
17+
onFailure: console.error,
18+
});
19+
const form = createSvelteKitForm(meta, {
20+
...theme,
21+
validator: createValidator2(),
22+
translation,
23+
onSubmit: request.run,
24+
onSubmitError: console.warn,
25+
});
26+
setFromContext(form.context);
27+
</script>
28+
29+
<RawForm {form} method="POST" />

apps/docs/src/content/docs/integrations/_sveltekit-server.api.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createValidator2 } from "@sjsf/ajv8-validator";
33
import {
44
initForm,
55
makeFormDataParser,
6-
validateForm,
6+
validateForm2,
77
} from "@sjsf/sveltekit/server";
88

99
import type { Actions } from "./$types";
@@ -37,15 +37,16 @@ export const load = async () => {
3737

3838
export const actions = {
3939
default: async ({ request }) => {
40+
const data = await parseFormData({
41+
schema,
42+
request,
43+
});
4044
return {
41-
form: validateForm({
45+
form: await validateForm2({
46+
request,
4247
schema,
4348
validator,
44-
data: await parseFormData({
45-
schema,
46-
request,
47-
}),
48-
sendData: true,
49+
data,
4950
}),
5051
};
5152
},

apps/docs/src/content/docs/integrations/sveltekit.mdx

Lines changed: 22 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ sidebar:
66

77
import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
88
import { DEFAULT_ID_SEPARATOR, DEFAULT_PSEUDO_ID_SEPARATOR } from '@sjsf/form';
9+
import { IDENTIFIABLE_FIELD_ELEMENTS } from '@sjsf/sveltekit'
910

1011
import Npm from '@/components/npm.astro';
1112

1213
import clientCode from './_sveltekit-client.api.svelte?raw';
14+
import clientFlexCode from './_sveltekit-flex-client.api.svelte?raw'
1315
import serverCode from './_sveltekit-server.api.ts?raw';
1416

1517
:::caution
@@ -20,7 +22,7 @@ SvelteKit integration is experimental
2022

2123
Since this is a `Svelte` library, you may want to use it with the `SvelteKit`.
2224

23-
With this package you will be able to perform server-side validation of form data
25+
With this package you will be able to perform server-side validation of the form data
2426
even if the user has `JavaScript` disabled.
2527

2628
## Installation
@@ -29,6 +31,8 @@ even if the user has `JavaScript` disabled.
2931

3032
## Example
3133

34+
See details in the sections below
35+
3236
<Tabs>
3337
<TabItem label='+page.svelte' >
3438
<Code code={clientCode} lang='svelte' />
@@ -41,38 +45,11 @@ even if the user has `JavaScript` disabled.
4145
## Server
4246

4347
On the server side you should implement at least one [action](https://svelte.dev/docs/kit/form-actions)
44-
which will always return the result of `validateForm` function (`redirect` and `error` helpers are allowed).
48+
which will always return the result of `validateForm2` function (`redirect` and `error` helpers are allowed).
4549

4650
If the form data is passed as `FormData`, you need to create a parser for it.
4751

48-
```typescript
49-
import { makeFormDataParser, validateForm } from '@sjsf/sveltekit/server';
50-
51-
const validator = createValidator();
52-
53-
const parseFormData = makeFormDataParser({
54-
validator
55-
});
56-
57-
export const actions = {
58-
default: async (event) => {
59-
const form = validateForm({
60-
schema,
61-
validator,
62-
data: await parseFormData({
63-
schema,
64-
request,
65-
}),
66-
})
67-
if (!form.isValid) {
68-
return fail(400, { form });
69-
}
70-
return {
71-
form,
72-
};
73-
},
74-
} satisfies Actions;
75-
```
52+
<Code code={serverCode} lang="typescript" />
7653

7754
:::note
7855

@@ -101,46 +78,30 @@ The name of the `initForm` function result should match the name from the `actio
10178

10279
## Client
10380

104-
On the client side you should call `useSvelteKitForm`.
105-
106-
```typescript
107-
import { useSvelteKitForm, meta } from '@sjsf/sveltekit/client';
108-
109-
import type { PageData, ActionData } from './$types';
81+
On the client side you can use `SvelteKitForm` component (see example).
82+
Or use more flexible solution:
11083

111-
const { form, mutation, enhance } = useSvelteKitForm(
112-
meta<ActionData, PageData>(), "form", { /* form options */ }
113-
);
114-
```
84+
<Code code={clientFlexCode} lang='svelte' />
11585

11686
:::note
11787

118-
The error type will be inferred from `ActionData` and the form data type from `PageData`.
88+
The error type will be inferred from the `ActionData` type and the form data type from the `PageData` type.
11989

12090
If you did not use `initForm` in the `load` function,
121-
the third generic parameter of the `meta` function will be used as the form data type
122-
(the default is `SchemaValue`).
91+
the fourth generic parameter of the `createMeta` function will be used as the form data type
92+
(default type is `SchemaValue`).
12393

12494
:::
12595

12696
According to Svelte documentation your form should always use `POST` requests.
12797

128-
```svelte
129-
<form use:enhance method="POST" novalidate style="display: flex; flex-direction: column; gap: 1rem">
130-
<FormContent bind:value={form.formValue} />
131-
<button type="submit" style="padding: 0.5rem;">Submit</button>
132-
</form>
133-
```
134-
13598
### Progressive enhancement
13699

137-
You should always use `enhance` action on your forms.
138-
139-
But if you really want the form to work with `JavaScript` disabled, you should consider the following limitation:
100+
By default, the form will work even with JavaScript disabled, but you should consider the following limitations of this mode of operation:
140101

141-
- `validateForm` should be called with `sendData: true`
142-
- Form elements for `oneOf`, `anyOf`, `dependencies`, `additionalProperties` and `additionalItems`
143-
will not update their state.
102+
- `validateForm2` should be called with `sendData: true` to persist form data between page updates
103+
- Form fields for `oneOf`, `anyOf`, `dependencies`, `additionalProperties` and `additionalItems`
104+
will not expand/switch their state.
144105
- Some widgets (like multiselect, depends on the theme) may will not work, because they require `JavaScript`.
145106
- Conversion from `FormData` to `JSON` can happen with data loss.
146107
This conversion relies on the field names computation algorithm and
@@ -155,8 +116,12 @@ it may lead to ambiguous results if the following conditions are violated:
155116
- `isPseudoSeparator` - <code>{DEFAULT_PSEUDO_ID_SEPARATOR}</code>
156117
- If your schema contains `additionalProperties`:
157118
- Keys of initial object values must not contain the separators.
158-
- If you provide some initial value for `additionalProperties` or `JavaScript` is enabled but the form is used without `enhance`:
119+
- If you provide some initial value for `additionalProperties` or `JavaScript` is enabled but the raw `form` element is used (without `use:form.enhance`):
159120
- You should provide `additionalPropertyKeyValidationError` or `additionalPropertyKeyValidator` options to `useSvelteKitForm` for preventing the user to input invalid keys.
121+
Additional property name is invalid if:
122+
- `additionalProperties` schema is an object or an array schema and name contains `idSeparator`
123+
- `additionalProperties` schema is neither an object schema nor an array schema and name has a suffix consisting of a `isPseudoSeparator`
124+
and a keyword: {IDENTIFIABLE_FIELD_ELEMENTS.map(el => <><code>{el}</code><span> </span></>)}
160125
- You may produce these checks at runtime with the `staticAnalysis` and other functions from `@sjsf/form/static-analysis` submodule.
161126
Functions from this submodule returns an iterable of errors, so you can:
162127
- Throw an error on the first error or list all errors (in a dev environment)

apps/docs/src/content/docs/migration-guides/current.mdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ sidebar:
44
order: 0
55
---
66

7+
### @sjsf/form
8+
79
- Replace `<FormContent bind:value={form.formValue} />` with `<Content {form} />` from `@sjsf/form` package
810

911
- Replace `SimpleForm` with `RawForm` from `@sjsf/form` package
@@ -20,8 +22,19 @@ sidebar:
2022
- Replace `import { omitExtraData2 } from "@sjsf/form/legacy-omit-extra-data"`
2123
with `import { omitExtraData } from "@sjsf/form/omit-extra-data"`
2224

25+
### @sjsf/sveltekit
26+
27+
- Upgrade SvelteKit package at least up to `2.12.0`
28+
29+
- Migrate from `meta` and `useSvelteKitForm` to `createMeta`, `createSvelteKitRequest` and `createSvelteKitForm`
30+
- In simple cases you may use only `createMeta` and `SvelteKitForm` component
31+
32+
- Migrate from `validateForm` to `validateForm2` (support async validators)
33+
2334
## 1.8.0
2435

36+
### @sjsf/form
37+
2538
- Replace `useForm2` with `createForm3`
2639

2740
- If custom form is used it should call `setFormContext(form.context)`

0 commit comments

Comments
 (0)