Tour
A guided walk through steps beside the elements they explain, the page dimmed around each, with its place, next, back and skip.
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.