Mixins / foldkit-mixins-ui

Tour

namespace · packages/mixins-ui/src/tour.ts:1

export * as Tour from './tour.js'

In the guides

Members

Tour.Config

interface · packages/mixins-ui/src/tour.ts:112

interface Config {
  readonly steps: ReadonlyArray<Step>
}

The steps update and the view agree on.

Tour.Ended

const · packages/mixins-ui/src/tour.ts:106

const Ended: Schema.TaggedStruct<
  'Ended',
  { readonly completed: Schema.Boolean }
>

Told to the application as the tour ends: by its last Next (completed), or skipped.

Tour.FocusOpener

const · packages/mixins-ui/src/tour.ts:157

const FocusOpener: Command.CommandDefinitionWithArgs<
  'Tour.FocusOpener',
  { elementId: Schema.String },
  Effect.Effect<{ readonly _tag: 'CompletedFocus' }, never, never>
>

Focuses the element that started the tour, once the tour is drawn away.

Tour.init

function · packages/mixins-ui/src/tour.ts:116

function init(options: { readonly id: string }): Model

Tour.Message

const · packages/mixins-ui/src/tour.ts:91

const Message: MessageUnion<{
  readonly Next: {}
  readonly Back: {}
  readonly Skipped: {}
  readonly Pressed: { readonly key: Schema.String }
  readonly Spotlit: {
    readonly target: Schema.String
    readonly found: Schema.Boolean
  }
  readonly Placed: {}
  readonly CompletedShowStep: {}
  readonly CompletedFocus: {}
}>

Tour.Model

const · packages/mixins-ui/src/tour.ts:78

const Model: Schema.Struct<{
  readonly id: Schema.String
  readonly open: Schema.Boolean
  readonly step: Schema.Number
  readonly missing: Schema.Option<Schema.Number>
  readonly opener: Schema.Option<Schema.String>
}>

Tour.PlaceStep

const · packages/mixins-ui/src/tour.ts:249

const PlaceStep: Mount.MountDefinitionWithArgs<
  'Tour.PlaceStep',
  {
    buttonId: Schema.String
    anchor: Schema.Struct<{
      readonly placement: Schema.optional<
        Schema.Literals<
          readonly [
            'top',
            'right',
            'bottom',
            'left',
            'top-start',
            'top-end',
            'right-start',
            'right-end',
            'bottom-start',
            'bottom-end',
            'left-start',
            'left-end',
          ]
        >
      >
      readonly gap: Schema.optional<Schema.Number>
      readonly offset: Schema.optional<Schema.Number>
      readonly padding: Schema.optional<
        Schema.Union<
          readonly [
            Schema.Number,
            Schema.Struct<{
              readonly top: Schema.optionalKey<Schema.Number>
              readonly right: Schema.optionalKey<Schema.Number>
              readonly bottom: Schema.optionalKey<Schema.Number>
              readonly left: Schema.optionalKey<Schema.Number>
            }>,
          ]
        >
      >
      readonly portal: Schema.optional<Schema.Boolean>
      readonly isPlacementLocked: Schema.optional<Schema.Boolean>
    }>
    arrowId: Schema.String
  },
  { readonly _tag: 'Placed' }
>

Places the step against its target, focusing it once placed.

Tour.Return

type · packages/mixins-ui/src/tour.ts:109

type Return = ReturnWithOutMessage<Model, Message, Ended>

Tour.ShowStep

const · packages/mixins-ui/src/tour.ts:135

const ShowStep: Command.CommandDefinitionWithArgs<
  'Tour.ShowStep',
  { id: Schema.String; target: Schema.Option<Schema.String> },
  Effect.Effect<{ readonly _tag: 'CompletedShowStep' }, never, never>
>

Brings a step's target into the middle of the viewport, smoothly unless the reader asked for reduced motion; a step with no target it focuses once drawn. One with a target is hidden until the anchor first places it, and focus does not land on a hidden element, so the anchor focuses it.

Tour.start

function · packages/mixins-ui/src/tour.ts:177

function start(
  model: Model,
  config: Config,
  options?: {
    readonly opener?: string
  },
): Return

Starts the tour at its first step; opener, the id of what started it, takes focus back when it ends. Starting a tour already running starts it over.

Tour.Step

interface · packages/mixins-ui/src/tour.ts:69

interface Step {
  readonly title: string
  readonly description: string
  readonly target?: string | undefined
  readonly placement?: Placement | undefined
}

A step of the tour.

Tour.TourSlots

const · packages/mixins-ui/src/tour.ts:45

const TourSlots: Slots.Contract<{ readonly layer: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly blocker: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly [Event.EventToken<"click">], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly spotlight: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly panel: Slot.UnnamedSlot<Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>, readonly [Event.EventToken<"keydown">], readonly [Attr.AttrToken<"role">], readonly Slot.RequirementName[], boolean>; readonly arrow: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly [Capability.Capability<"Base", readonly []>]>]>, readonly Slot.EventName[], readonly Slot.AttributeName[], readonly Slot.RequirementName[], boolean>; readonly progress: Slot.UnnamedSlot<Capability.Capability<"Container", readonly [Capability.Capability<"Interactive", readonly …;

A tour, Zag's and Shepherd's: a walk through steps, each a small dialog placed beside the element it explains, with the page dimmed around a cutout over that element. A step without a target, or whose target is not on the page, shows in the middle of the viewport instead. The current step is this Model, which the application keeps and folds with update({ steps }).

start -> step 0 -> ShowStep: the target scrolled into view, the step focused
Next / Back / ArrowRight / ArrowLeft -> step +/- 1; Next on the last -> Ended(completed)
Skip / Escape -> Ended(not completed), focus back to what started it
view: step -> the panel anchored to its target, the cutout following the target

The cutout's place is a browser fact: TrackBox (foldkit-primitives/dom) on the layer follows the target named by its data-target and writes its box as --fk-tour-x, -y, -w and -h, and its corner as --fk-tour-radius, so a stylist reads them and nothing crosses the Model; one layer follows every step, so the cutout can glide between targets. A target not on the page, or gone from it, is told as Spotlit. The dim takes presses outside the cutout, so the page cannot be used mid-step; the target can, unless interactive is false. The tour is drawn in the browser's top layer.

Each step is a non-modal dialog named by its title and described by its text, focused as it shows. Focus is not held in it: a step may ask the reader to use its target, which Tab reaches.

Tour.TourView

interface · packages/mixins-ui/src/tour.ts:271

interface TourView<ParentMessage> {
  readonly model: Model
  readonly config: Config
  readonly onMessage: (message: Message) => NoInfer<ParentMessage>
  readonly padding?: number | undefined
  readonly interactive?: boolean | undefined
  readonly dismissOnOutside?: boolean | undefined
  readonly closeOnEscape?: boolean | undefined
  readonly progressLabel?: ((step: number, count: number) => string) | undefined
  readonly labels?:
    | {
        readonly back?: string
        readonly next?: string
        readonly done?: string
        readonly skip?: string
      }
    | undefined
  readonly direction?: 'ltr' | 'rtl' | undefined
  readonly style?: NamedStyle<typeof TourSlots> | undefined
  readonly mixins?: MixinList<ParentMessage> | undefined
}

Tour.update

function · packages/mixins-ui/src/tour.ts:192

function update(config: Config): (model: Model, message: Message) => Return

The tour's update for config; the same Model when nothing changes.

Tour.view

function · packages/mixins-ui/src/tour.ts:308

function view<ParentMessage>(
  options: TourView<ParentMessage>,
  h: HtmlBuilder<ParentMessage>,
): Html