Components

Tour

A guided walk through steps beside the elements they explain, the page dimmed around each, with its place, next, back and skip.

scheme
direction

Basic #

export const TourStyle = forSlots(TourSlots)(Recipes.Tour({}))

/** Folded with `Tour.update(TOUR)`; started with `Tour.start(model, TOUR, { opener })`. */
export const TOUR: Tour.Config = {
  steps: [
    { title: 'Search', description: 'Find any page by its name.', target: 'preview-tour-search' },
    { title: 'Save', description: 'Keep your work as you go.', target: 'preview-tour-save' },
    { title: 'That is all', description: 'Start the tour again from its button.' },
  ],
}

// Each step beside its target, the page dimmed around it; the arrows move on
// and back, Escape skips, and focus returns to the button that started it.
export const tour = <Message>(
  style: NamedStyle<typeof TourSlots>,
  model: Tour.Model,
  onMessage: (message: Tour.Message) => Message,
  started: Message,
  h: HtmlBuilder<Message>,
): Html => {
  // The targets need ids, so they are drawn from the Button's and Input's slots.
  const { button } = SlotView.buildersFor(ButtonSlots, [ButtonStyle.mixin], { input: undefined, h })
  const { input } = SlotView.buildersFor(InputSlots, [InputStyle.mixin], { input: undefined, h })
  return h.div(
    [h.Style({ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', alignItems: 'center' })],
    [
      h.button(button.attrs([h.Id('preview-tour-start'), h.Type('button'), h.OnClick(started)]), [
        'Start the tour',
      ]),
      h.input(
        input.attrs([
          h.Id('preview-tour-search'),
          h.Type('search'),
          h.AriaLabel('Search'),
          h.Placeholder('Search'),
          h.Style({ inlineSize: '12rem' }),
        ]),
      ),
      h.button(button.attrs([h.Id('preview-tour-save'), h.Type('button')]), ['Save']),
      Tour.view({ model, config: TOUR, onMessage, style }, h),
    ],
  )
}

Usage

Each example above names the function that drew it, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.

The recipe ↗This code ↗