Nova · Composition

Modal

A dialog is an action pushed onto a canvas of its own, opened with a fragment that carries the frame and its Cancel. The form inside knows nothing of the frame. Saving says so on a channel the page listens to, and closes itself.

The shell, as it is written
{
  canvases: [
    { id: 'modal.page', initial: 'modal.guests' },
    { id: 'modal.over' },
  ],
  actions: {
    modal.guests: {
      id: 'modal.guests',
      data: { guests: ['Ada'] },
      layout: {
        component: 'Stack',
        children: [
          { component: 'Text', children: 'Guests' },
          {
            for: '$.guests',
            as: 'guest',
            do: { component: 'Text', children: '$guest' },
          },
          {
            component: 'Button',
            ref: 'new',
            children: 'Add a guest',
          },
        ],
      },
      triggers: [
        {
          event: 'ui:click',
          ref: 'new',
          do: [
            {
              push: {
                action: 'modal.form',
                canvas: 'modal.over',
                with: ['modal.frame'],
              },
            },
          ],
        },
        {
          message: 'modal.saved',
          do: [{ push: 'guests', value: '@event.payload' }],
        },
      ],
    },
    modal.form: {
      id: 'modal.form',
      data: { name: '' },
      layout: {
        component: 'Stack',
        children: [
          {
            component: 'Input',
            ref: 'name',
            model: '$.name',
            props: { placeholder: 'Their name' },
          },
          { component: 'Button', ref: 'save', children: 'Save' },
        ],
      },
      triggers: [
        {
          event: 'ui:click',
          ref: 'save',
          do: [
            { emit: { channel: 'modal.saved', payload: '$.name' } },
            { pop: true },
          ],
        },
      ],
    },
  },
  fragments: {
    modal.frame: {
      kind: 'fragment',
      id: 'modal.frame',
      layout: {
        component: 'Stack',
        children: [
          { component: 'Text', children: 'New guest' },
          { slot: 'body' },
          {
            component: 'Button',
            ref: 'cancel',
            children: 'Cancel',
          },
        ],
      },
      triggers: [
        { event: 'ui:click', ref: 'cancel', do: [{ pop: true }] },
      ],
    },
  },
}
Running herepress it

Guests

Ada

What is done to it
press new
type 'Grace' into name, on modal.over
press save, on modal.over
What then stands on each canvas
{ modal.page: ['modal.guests'], modal.over: [] }
What it then says
Guests
Ada
Grace
Add a guest
Output matches the expected value

Left: the action as the package ships it. Right: the same action running in this page, rendered with this site’s components. Below: the action run as the example specifies, on the installed package.