Skip to content
kerfjsGitHub

SyncedForm

A form whose named fields are shared live with everyone in it.

SourcePackage @kerf-js/veneer

Preview

tsx
import { state } from '@kerf-js/core'import {  Button,  Input,  Row,  Select,  Stack,  Switch,  SyncedForm} from '@kerf-js/veneer'import type { Peer } from '@kerf-js/veneer'export function Runbook() {  const ops = state<    {      seq: number      name: string      value: string | boolean      peer: Peer    }[]  >([])  const remote = (    name: string,    value: string | boolean,  ) =>    (ops.value = [      ...ops.value,      {        seq: ops.value.length + 1,        name,        value,        peer: JUN,      },    ])  return (    <Stack gap="group">      <SyncedForm        ops={ops}        label="Runbook details"      >        <Input          label="Title"          name="title"          defaultValue="Rollback runbook"        />        <Select          label="Owner"          name="owner"          options={OWNERS}          defaultValue="sam"        />        <Switch          name="notify"          defaultChecked        >          Tell #incidents        </Switch>      </SyncedForm>      <Row gap="tight">        <Button          size="sm"          emphasis="outline"          tone="neutral"          onClick={() =>            remote('title', 'Rollback runbook v2')          }        >          Jun edits the title        </Button>        <Button          size="sm"          emphasis="outline"          tone="neutral"          onClick={() => remote('notify', false)}        >          Jun flips the switch        </Button>      </Row>    </Stack>  )}const PEOPLE = [  {    id: 'mara',    name: 'Mara Lindqvist',    email: 'mara@kerf.dev',    role: 'Owner',    team: 'Platform',    initials: 'ML',  },  {    id: 'jun',    name: 'Jun Tanaka',    email: 'jun@kerf.dev',    role: 'Admin',    team: 'Platform',    initials: 'JT',  },  {    id: 'priya',    name: 'Priya Raman',    email: 'priya@kerf.dev',    role: 'Member',    team: 'Web',    initials: 'PR',  },  {    id: 'tomas',    name: 'Tomás Oliveira',    email: 'tomas@kerf.dev',    role: 'Member',    team: 'Web',    initials: 'TO',  },  {    id: 'lena',    name: 'Lena Fischer',    email: 'lena@kerf.dev',    role: 'Member',    team: 'Data',    initials: 'LF',  },  {    id: 'noor',    name: 'Noor Haddad',    email: 'noor@kerf.dev',    role: 'Viewer',    team: 'Data',    initials: 'NH',  },  {    id: 'sam',    name: 'Sam Okafor',    email: 'sam@kerf.dev',    role: 'Member',    team: 'Mobile',    initials: 'SO',  },  {    id: 'ines',    name: 'Inés Vidal',    email: 'ines@kerf.dev',    role: 'Viewer',    team: 'Mobile',    initials: 'IV',  },]const PEERS: Peer[] = PEOPLE.map((p, i) => ({  id: p.id,  name: p.name,  color: i + 1,}))const [  MARA,  JUN,  PRIYA,  TOMAS,  LENA,  NOOR,  SAM,  INES,] = PEERS as [  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,]const OWNERS = [  { value: 'jun', label: 'Jun Tanaka' },  { value: 'sam', label: 'Sam Okafor' },]

Installation

npm install @kerf-js/veneer

Usage

tsx
import { SyncedForm } from '@kerf-js/veneer'

Accessibility

  • This has no shortcuts of its own: controls inside it use Tab, Enter and Space as usual, and veneer's parts keep their roles and labels.

API Reference

PropTypeDefaultDescription
opsLive<FormOp[]>—Other people's edits, oldest first.
labelstring—Names the form.
childrenunknown—What it contains.
EventTypeDefaultDescription
onSend((name: string, value: string | boolean) => void)—Called with each local edit.

RelatedData integrityConflict alert