Skip to content

Commit e3b49ce

Browse files
authored
Merge pull request #2 from withastro-utils/feat/view-state
feat: form@3.3
2 parents 263e625 + 03b9d4b commit e3b49ce

File tree

13 files changed

+294
-121
lines changed

13 files changed

+294
-121
lines changed

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

astro.config.mjs

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,54 @@
1-
import { defineConfig } from 'astro/config';
1+
import {defineConfig} from 'astro/config';
22
import starlight from '@astrojs/starlight';
33

44
import expressiveCode from "astro-expressive-code";
55

66
// https://astro.build/config
77
export default defineConfig({
8-
site: 'https://withastro-utils.github.io',
9-
base: '/docs',
10-
integrations: [expressiveCode(), starlight({
11-
editLink: {
12-
baseUrl: 'https://github.com/withastro-utils/docs/tree/main/',
13-
},
14-
lastUpdated: true,
15-
favicon: '/favicon.png',
16-
title: 'Astro Utils',
17-
logo: {
18-
src: '/src/assets/logo.png'
19-
},
20-
social: {
21-
github: 'https://github.com/withastro-utils/utils'
22-
},
23-
sidebar: [{
24-
label: 'Guides',
25-
autogenerate: {
26-
directory: 'guides'
27-
}
28-
}, {
29-
label: 'Reference',
30-
autogenerate: {
31-
directory: 'reference'
32-
}
33-
}],
34-
customCss: ['./src/styles/home.css', './src/styles/code-margin.css']
35-
})]
8+
site: 'https://withastro-utils.github.io',
9+
base: '/docs',
10+
integrations: [expressiveCode(), starlight({
11+
editLink: {
12+
baseUrl: 'https://github.com/withastro-utils/docs/tree/main/',
13+
},
14+
lastUpdated: true,
15+
favicon: '/favicon.png',
16+
title: 'Astro Utils',
17+
logo: {
18+
src: '/src/assets/logo.png'
19+
},
20+
social: {
21+
github: 'https://github.com/withastro-utils/utils'
22+
},
23+
sidebar: [{
24+
label: 'Guides',
25+
items: [{
26+
label: 'Forms',
27+
items: [
28+
{
29+
label: 'Getting Started',
30+
link: '/guides/forms/getting-started'
31+
}, {
32+
label: 'Data Binding',
33+
link: '/guides/forms/data-binding'
34+
}, {
35+
label: 'JS Helpers',
36+
link: '/guides/forms/js-helpers'
37+
}
38+
]
39+
}, {
40+
label: 'Context',
41+
link: '/guides/context'
42+
}, {
43+
label: 'Express Endpoints',
44+
link: '/guides/express-endpoints'
45+
}]
46+
}, {
47+
label: 'Reference',
48+
autogenerate: {
49+
directory: 'reference/forms'
50+
}
51+
}],
52+
customCss: ['./src/styles/home.css', './src/styles/code-margin.css']
53+
})]
3654
});
19.4 KB
Loading
12.8 KB
Loading
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
title: Binding & Validation
3+
description: Using data binding with Astro Forms
4+
---
5+
6+
# Introduction
7+
8+
With Astro Forms you can easily create forms with data binding and validation. It also provides a simple way to handle form submissions and preserve state between postbacks.
9+
10+
## Data Binding
11+
12+
Astro Forms supports two-way data binding. This means that you can bind a form field to a property on `Bind` instance and the value of the property will be updated when the field changes and vice versa.
13+
14+
### Example
15+
16+
```astro
17+
---
18+
import { Bind, BindForm, BButton, BInput } from "@astro-utils/forms/forms.js";
19+
import Layout from "../layouts/Layout.astro";
20+
21+
type Form = {
22+
name: string;
23+
age: number;
24+
}
25+
26+
const form = Bind<Form>();
27+
28+
let showSubmitText: string;
29+
function formSubmit(){
30+
showSubmitText = `You name is ${form.name}, you are ${form.age} years old. `;
31+
form.age++;
32+
}
33+
---
34+
<Layout>
35+
<BindForm bind={form}>
36+
{showSubmitText}
37+
38+
<h4>What you name*</h4>
39+
<BInput type="text" name="name" maxlength={20} required/>
40+
41+
<h4>Enter age*</h4>
42+
<BInput type="int" name="age" min={10} required/>
43+
44+
<BButton onClick={formSubmit} whenFormOK>Submit</BButton>
45+
</BindForm>
46+
</Layout>
47+
```
48+
49+
In this example, the `Bind` instance is bound to the form fields.
50+
- When the user changes the value of the `name` or `age` fields and submit, the `Bind` instance will be updated.
51+
- The `formSubmit` function will be called when the user clicks the `Submit` button and the form is valid.
52+
- After `formSubmit` the `age` property will be incremented and the `showSubmitText` will be updated.
53+
54+
## View State
55+
56+
Astro Forms also supports view state. This means that the values of the form fields will be preserved between postbacks.
57+
58+
### Example
59+
60+
```astro
61+
---
62+
type Form = {
63+
counter: number;
64+
}
65+
66+
const form = Bind<Form>({counter: 0});
67+
68+
function incCounter(){
69+
form.counter++;
70+
}
71+
---
72+
<Layout>
73+
<BindForm bind={form}>
74+
Counter: {form.counter}
75+
76+
<BButton onClick={formSubmit}>Increase counter</BButton>
77+
</BindForm>
78+
</Layout>
79+
```
80+
81+
What happens here is that the `counter` property of the `Bind` instance will be incremented every time the user clicks the `Increase counter` button.
82+
83+
The `Bind` state will persist between postbacks, by storing the data on the client side compressed and __encrypted__.
84+
85+
### Valid values
86+
87+
The state of the `Bind` instance must be serlizable, but you can use more then just JSON.
88+
89+
You can use any valid [SuperJSON](https://github.com/blitz-js/superjson) value in the `Bind` instance.
90+
Meaning also `Date`, `Map`, `URL`, `Set`, `RegExp`, `BigInt`, `undefined` are supported.
91+
92+
93+
### Button State
94+
95+
You can use state per `BButton` component. You can also change the `BButton` props easily each time the button is clicked.
96+
97+
Special props:
98+
- **state**: any - store state per button
99+
- **extra**: any - store extra data per button (cannot be changed in the `onClick` function)
100+
- **innerText**: string - the text of the button (overides the children)
101+
- **innerHTML**: string - the HTML of the button (overides the children)
102+
- **remove**: boolean - remove the button from the HTML
103+
104+
```astro
105+
---
106+
import { BButton, Bind, BindForm } from '@astro-utils/forms/forms.js';
107+
import Layout from '../layouts/Layout.astro';
108+
109+
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink', 'black', 'white', 'gray'];
110+
111+
function changeColor() {
112+
this.state.color++;
113+
114+
if (this.state.color >= colors.length) {
115+
this.state.color = this.extra;
116+
}
117+
this.style = `color: ${colors[this.state.color]}`;
118+
}
119+
---
120+
121+
<Layout>
122+
<BindForm>
123+
{
124+
colors.map((_, i) => (
125+
<BButton onClick={changeColor} extra={i} state={{ color: i }}>
126+
Button {i}
127+
</BButton>
128+
))
129+
}
130+
</BindForm>
131+
</Layout>
132+
```
133+
134+
In this example, the `changeColor` will change the button color each time it is clicked for a different color in the `colors` array.
135+
136+
If the button is clicked more times then the length of the `colors` array, it will start from the beginning.
137+
138+
#### Initial state
139+
140+
![Initial state](../../../../assets/change-color/initial-state.png)
141+
142+
143+
#### After some clicks
144+
145+
![After clicks](../../../../assets/change-color/after-clicks.png)

src/content/docs/guides/forms.mdx renamed to src/content/docs/guides/forms/getting-started.mdx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Forms - Getting started
2+
title: Getting started
33
description: How to use astro forms
44
---
55

@@ -8,15 +8,13 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
88
# Introduction
99

1010
Astro-Utils Forms is a set of tools to help you build forms in Astro.
11-
11+
It provides similar functionality to ASP.NET Web Forms, but with a modern approach.
1212

1313
Some of the features:
1414

1515
- ✅ Client & Server side form validation
1616
- ✅ Forms [CSRF](https://developer.mozilla.org/en-US/docs/Glossary/CSRF) protection
17-
- ✅ Data binding
18-
- ✅ File upload (support for multipart forms)
19-
- ✅ Web controls
17+
- ✅ Web Controls (Data Binding) + View State
2018
- ✅ JWT session
2119

2220
## Installation
@@ -30,6 +28,13 @@ First install the package
3028
npm install @astro-utils/forms
3129
```
3230

31+
</TabItem>
32+
<TabItem label="bun">
33+
34+
```sh
35+
bun i @astro-utils/forms
36+
```
37+
3338
</TabItem>
3439
<TabItem label="pnpm">
3540

@@ -60,8 +65,8 @@ export default defineConfig({
6065
integrations: [formDebug]
6166
});
6267
```
63-
This integration will easy you're debugging by avoiding the browser popups every vite reload.
6468

69+
This integration will simplify your debugging process by eliminating the browser pop-ups during every Vite reload
6570

6671
Edit
6772
`src/middleware.ts` to add the middleware
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
title: JS Helpers
3+
description: SSR JS for client actions
4+
---
5+
6+
# Introduction
7+
8+
Astro forms ship with some utility functions to handle forms.
9+
Some functionality works by sending the script to the client and running it there.
10+
11+
You can access them via `Astro.locals.forms`.
12+
13+
### Controllers
14+
15+
```ts
16+
class FormsReact {
17+
scriptToRun: string;
18+
overrideResponse: Response | null;
19+
20+
// server side redirect
21+
redirect(location: string, status?: ValidRedirectStatus): void;
22+
updateSearchParams(): {
23+
search: URLSearchParams;
24+
redirect(status?: ValidRedirectStatus): void;
25+
};
26+
updateOneSearchParam(key: string, value?: string, status?: ValidRedirectStatus): void;
27+
28+
// client side redirect
29+
redirectTimeoutSeconds(location: string, timeoutSec = 2): void;
30+
31+
alert(message: string): void;
32+
consoleLog(...messages: any[]): void;
33+
console(type: keyof Console, ...messages: any[]): void;
34+
callFunction(func: string, ...args: any[]): void;
35+
}
36+
```
37+
38+
### Example
39+
40+
```astro
41+
---
42+
import { Bind, BindForm, BButton, BInput } from "@astro-utils/forms/forms.js";
43+
import Layout from "../layouts/Layout.astro";
44+
45+
type Form = {
46+
name: string;
47+
age: number;
48+
}
49+
50+
const form = Bind<Form>();
51+
52+
let showSubmitText: string;
53+
function formSubmit(){
54+
showSubmitText = `You name is ${form.name}, you are ${form.age} years old. `;
55+
56+
// Redirect to home page after 2 seconds
57+
Astro.locals.forms.redirectTimeoutSeconds('/');
58+
}
59+
---
60+
<Layout>
61+
<BindForm bind={form}>
62+
{showSubmitText}
63+
64+
<h4>What you name*</h4>
65+
<BInput type="text" name="name" maxlength={20} required/>
66+
67+
<h4>Enter age*</h4>
68+
<BInput type="int" name="age" min={10} required/>
69+
70+
<BButton onClick={formSubmit} whenFormOK>Submit</BButton>
71+
</BindForm>
72+
</Layout>
73+
```

src/content/docs/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ hero:
1111
file: ../../assets/logo.png
1212
actions:
1313
- text: Get started
14-
link: guides/forms/
14+
link: /docs/guides/forms/getting-started
1515
icon: right-arrow
1616
variant: primary
1717
- text: View on GitHub

0 commit comments

Comments
 (0)