Imperative Surface Imperative Surface

Async Workflow

The Promise-based API makes a surface easy to place inside a longer asynchronous workflow.

For example:

async function createProject() {
  const values = await Surface.Dialog.present<ProjectValues>({
    body: ProjectForm,
  });

  if (!values) {
    return;
  }

  const project = await api.projects.create(values);

  const shouldOpen = await Surface.Dialog.present<boolean>({
    body: ({ pop }) => (
      <Surface.Body>
        <Surface.Header
          title="Project created"
          onPop={() => pop(false)}
        />

        <Surface.Content>
          <p>{project.name} is ready.</p>
        </Surface.Content>

        <Surface.Footer>
          <button onClick={() => pop(false)}>
            Stay here
          </button>
          <button onClick={() => pop(true)}>
            Open project
          </button>
        </Surface.Footer>
      </Surface.Body>
    ),
  });

  if (shouldOpen) {
    navigate(`/projects/${project.id}`);
  }
}

This pattern keeps the workflow readable:

  1. Present UI.
  2. Await the user's decision.
  3. Perform asynchronous work.
  4. Present another surface if necessary.
  5. Continue based on the returned result.

The surface itself does not manage application data fetching or navigation. It only manages presentation and result delivery.

On this page