Skip to content

@jsvision/forms / formDialog

Function: formDialog()

Documented in: Form Dialog

formDialog<S, I>(host, options): Promise<output<S> | null>

Defined in: form-dialog.ts:192

Run a form in a modal dialog and resolve to the coerced values on OK, or null on Cancel / Esc / close-box / a quit-close.

The dialog creates the form (via createForm), hands it to body(form) to bind widgets, then runs modally. OK marks every field touched, validates (force-running any async validators), runs the optional onSubmit inside the gate, and — only if all of that passes — closes and resolves the coerced z.output<S>. An invalid OK keeps the dialog open with errors revealed. The dialog is sealed while a submit is in flight (Cancel / Esc / quit are inert). The form is always disposed on close, on every path (including a body or onSubmit that throws).

Type Parameters

S

S extends ZodObject<Readonly<{[k: string]: $ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>; }>, $strip>

I

I extends Record<keyof output<S>, unknown>

Parameters

host

ModalDialogHost

A modal host — the createApplication result satisfies it directly.

options

FormDialogOptions<S, I>

The schema, raw initial values, the body(form) builder, and optional onSubmit / okText / async options; width and height are required.

Returns

Promise<output<S> | null>

The coerced values on OK, or null on any other close.

Example

ts
import { formDialog } from '@jsvision/forms';
import { at, createApplication, Group, Input, Label } from '@jsvision/ui';
import { resolveCapabilities } from '@jsvision/core';
import { z } from 'zod';

const app = createApplication({ caps: resolveCapabilities().profile });
const api = { save: async (v: { name: string; port: number }): Promise<void> => void v };

const schema = z.object({ name: z.string().min(1, 'Required'), port: z.coerce.number().int().min(1) });

const values = await formDialog(app, {
  schema,
  initial: { name: '', port: '8080' }, // RAW editing values (port edited as a string)
  title: ' Edit server ',
  width: 44,
  height: 9,
  body: (form) => {
    const g = new Group();
    const input = at(new Input({ value: form.field('name').value }), 13, 1, 24, 1);
    const label = at(new Label('~N~ame', input), 2, 1, 10, 1);
    g.add(label);
    g.add(input);
    return g;
  },
  onSubmit: async (v) => { await api.save(v); }, // runs INSIDE the gate; reject → the dialog stays open
});
if (values) console.log('saved', values.name, values.port); // null on Cancel/Esc