Skip to content

Commit 097d704

Browse files
committed
Add nested field array playground to website
1 parent f6d4c9f commit 097d704

File tree

2 files changed

+217
-1
lines changed

2 files changed

+217
-1
lines changed

packages/website/src/routes/playground.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default function PlaygroundLayout() {
77
<FormProvider>
88
<main class="flex w-full max-w-screen-xl flex-1 flex-col self-center lg:flex-row lg:space-x-9">
99
<div class="min-full flex-1 space-y-12 py-12 md:space-y-14 md:py-20 lg:space-y-16 lg:py-32">
10-
<Tabs items={['Login', 'Payment', 'Todos', 'Special']} />
10+
<Tabs items={['Login', 'Payment', 'Todos', 'Special', 'Nested']} />
1111
<Outlet />
1212
</div>
1313
<SideBar>
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import {
2+
createForm,
3+
Field,
4+
FieldArray,
5+
Form,
6+
insert,
7+
move,
8+
remove,
9+
replace,
10+
swap,
11+
} from '@modular-forms/solid';
12+
import { For, onMount } from 'solid-js';
13+
import {
14+
FormHeader,
15+
FormFooter,
16+
TextInput,
17+
Title,
18+
ColorButton,
19+
} from '~/components';
20+
import { useForm } from '~/contexts';
21+
22+
type NestedForm = {
23+
items: {
24+
label: string;
25+
options: string[];
26+
}[];
27+
};
28+
29+
const initialValues = {
30+
items: [
31+
{
32+
label: 'Item 1',
33+
options: ['Option 1'],
34+
},
35+
{
36+
label: 'Item 2',
37+
options: ['Option 1', 'Option 2'],
38+
},
39+
],
40+
};
41+
42+
export default function NestedPage() {
43+
// Create nested form
44+
const nestedForm = createForm<NestedForm>({ initialValues });
45+
46+
// Set nested form in form context
47+
onMount(() => useForm().set(nestedForm));
48+
49+
return (
50+
<>
51+
<Title>Nested form</Title>
52+
53+
<Form
54+
class="space-y-12 md:space-y-14 lg:space-y-16"
55+
of={nestedForm}
56+
onSubmit={(values) => alert(JSON.stringify(values, null, 4))}
57+
>
58+
<FormHeader of={nestedForm} heading="Nested form" />
59+
60+
<div class="space-y-5 px-8 lg:px-10">
61+
<FieldArray of={nestedForm} name="items">
62+
{(fieldArray) => (
63+
<>
64+
<For each={fieldArray.items}>
65+
{(_, index) => (
66+
<div class="flex-1 space-y-5 rounded-2xl border-2 border-slate-200 bg-slate-100/25 py-6 hover:border-slate-300 dark:border-slate-800 dark:bg-slate-800/10 dark:hover:border-slate-700">
67+
<div class="flex space-x-5 px-6">
68+
<Field
69+
of={nestedForm}
70+
name={`${fieldArray.name}.${index()}.label`}
71+
>
72+
{(field) => (
73+
<TextInput
74+
{...field.props}
75+
value={field.value}
76+
error={field.error}
77+
type="text"
78+
class="flex-1"
79+
placeholder="Enter item"
80+
padding="none"
81+
/>
82+
)}
83+
</Field>
84+
85+
<ColorButton
86+
color="red"
87+
label="Delete"
88+
width="auto"
89+
onClick={() =>
90+
remove(nestedForm, fieldArray.name, { at: index() })
91+
}
92+
/>
93+
</div>
94+
95+
<div
96+
class="border-t-2 border-t-slate-200 dark:border-t-slate-800"
97+
role="separator"
98+
/>
99+
100+
<FieldArray
101+
of={nestedForm}
102+
name={`${fieldArray.name}.${index()}.options`}
103+
>
104+
{(fieldArray) => (
105+
<div class="space-y-5 px-6">
106+
<For each={fieldArray.items}>
107+
{(_, index) => (
108+
<div class="flex space-x-5">
109+
<Field
110+
of={nestedForm}
111+
name={`${fieldArray.name}.${index()}`}
112+
>
113+
{(field) => (
114+
<TextInput
115+
{...field.props}
116+
value={field.value}
117+
error={field.error}
118+
class="flex-1"
119+
type="text"
120+
placeholder="Enter option"
121+
padding="none"
122+
/>
123+
)}
124+
</Field>
125+
126+
<ColorButton
127+
color="red"
128+
label="Delete"
129+
width="auto"
130+
onClick={() =>
131+
remove(nestedForm, fieldArray.name, {
132+
at: index(),
133+
})
134+
}
135+
/>
136+
</div>
137+
)}
138+
</For>
139+
140+
<div class="flex flex-wrap gap-4">
141+
<ColorButton
142+
color="green"
143+
label="Add option"
144+
onClick={() =>
145+
insert(nestedForm, fieldArray.name)
146+
}
147+
/>
148+
<ColorButton
149+
color="yellow"
150+
label="Move first to end"
151+
onClick={() =>
152+
move(nestedForm, fieldArray.name, {
153+
from: 0,
154+
to: fieldArray.length - 1,
155+
})
156+
}
157+
/>
158+
<ColorButton
159+
color="purple"
160+
label="Swap first two"
161+
onClick={() =>
162+
swap(nestedForm, fieldArray.name, {
163+
at: 0,
164+
and: 1,
165+
})
166+
}
167+
/>
168+
</div>
169+
</div>
170+
)}
171+
</FieldArray>
172+
</div>
173+
)}
174+
</For>
175+
176+
<div class="flex flex-wrap gap-4">
177+
<ColorButton
178+
color="green"
179+
label="Add item"
180+
onClick={() => insert(nestedForm, fieldArray.name)}
181+
/>
182+
<ColorButton
183+
color="yellow"
184+
label="Move first to end"
185+
onClick={() =>
186+
move(nestedForm, fieldArray.name, {
187+
from: 0,
188+
to: fieldArray.length - 1,
189+
})
190+
}
191+
/>
192+
<ColorButton
193+
color="purple"
194+
label="Swap first two"
195+
onClick={() =>
196+
swap(nestedForm, fieldArray.name, { at: 0, and: 1 })
197+
}
198+
/>
199+
<ColorButton
200+
color="blue"
201+
label="Replace first"
202+
onClick={() =>
203+
replace(nestedForm, fieldArray.name, { at: 0 })
204+
}
205+
/>
206+
</div>
207+
</>
208+
)}
209+
</FieldArray>
210+
</div>
211+
212+
<FormFooter of={nestedForm} />
213+
</Form>
214+
</>
215+
);
216+
}

0 commit comments

Comments
 (0)