@@ -265,6 +265,80 @@ defmodule ComponentsGuideWeb.ReactEditorController do
265
265
render_source ( conn , source )
266
266
end
267
267
268
+ def show ( conn , % { "id" => "form-reducer-validation" } ) do
269
+ source = ~s"""
270
+ function formDataFrom(element) {
271
+ if (element instanceof HTMLFormElement) {
272
+ return new FormData(element);
273
+ }
274
+
275
+ const formData = new FormData();
276
+ if (element instanceof HTMLInputElement) {
277
+ formData.set(element.name, element.value);
278
+ }
279
+ return formData;
280
+ }
281
+
282
+ function reducer(state, event) {
283
+ if (event.type === "submit") {
284
+ event.preventDefault();
285
+ }
286
+
287
+ const errors = new Map(state.errors);
288
+ for (const [name, value] of formDataFrom(event.target)) {
289
+ // TODO: add more advanced validation here
290
+ if (value.trim() === "") {
291
+ errors.set(name, "Required");
292
+ }
293
+ }
294
+
295
+ return { ...state, errors };
296
+ }
297
+
298
+ function Field({ name, label, error, type = "text" }) {
299
+ const id = useId();
300
+ return (
301
+ <div class="flex items-center gap-2">
302
+ <label for={id}>{label}</label>
303
+ <input id={id} name={name} type={type} />
304
+ <span class="italic">{error}</span>
305
+ </div>
306
+ );
307
+ }
308
+
309
+ export default function App() {
310
+ const [state, dispatch] = useReducer(reducer, { errors: new Map() });
311
+
312
+ return (
313
+ <form onBlur={dispatch} onSubmit={dispatch} class="flex flex-col items-start gap-4">
314
+ <p class="italic">Fields will individually validate on blur, or every field will validate on submit.</p>
315
+ <fieldset class="flex flex-col gap-2">
316
+ <Field
317
+ name="firstName"
318
+ label="First name"
319
+ error={state.errors.get("firstName")}
320
+ />
321
+ <Field
322
+ name="lastName"
323
+ label="Last name"
324
+ error={state.errors.get("lastName")}
325
+ />
326
+ <Field
327
+ name="email"
328
+ label="Email"
329
+ type="email"
330
+ error={state.errors.get("email")}
331
+ />
332
+ </fieldset>
333
+ <button class="px-3 py-1 bg-blue-300 rounded">Save</button>
334
+ </form>
335
+ );
336
+ }
337
+ """
338
+
339
+ render_source ( conn , source )
340
+ end
341
+
268
342
def show ( conn , % { "id" => "yieldmachine" } ) do
269
343
source = ~s"""
270
344
import { start, on } from "https://unpkg.com/[email protected] /dist/yieldmachine.module.js"
0 commit comments