import { Machine, EventObject, Service } from '@zag-js/core'; import { InteractOutsideHandlers } from '@zag-js/dismissable'; import { Placement } from '@zag-js/popper'; import { PropTypes, RequiredBy, DirectionProperty, CommonProperties } from '@zag-js/types'; import { Point, Rect, Size } from './utils/rect.js'; type StepEffectCleanup = VoidFunction | void; interface StepEffectArgs { next: VoidFunction; goto: (id: string) => void; dismiss: VoidFunction; show: VoidFunction; update: (data: Partial) => void; target?: (() => HTMLElement | null) | undefined; } type StepType = "tooltip" | "dialog" | "wait" | "floating"; type StepActionType = "next" | "prev" | "dismiss" | "skip"; type StepActionFn = (actionMap: StepActionMap) => void; type StepPlacement = Placement | "center"; interface StepAction { /** * The label of the action */ label: string; /** * The action to perform */ action?: StepActionType | StepActionFn | undefined; /** * The attributes to apply to the action trigger */ attrs?: Record | undefined; } interface StepBaseDetails { /** * The type of the step. If no target is provided, * the step will be treated as a modal step. */ type?: StepType | undefined; /** * Function to return the target element to highlight */ target?: (() => HTMLElement | null) | undefined; /** * The title of the step */ title: any; /** * The description of the step */ description: any; /** * The placement of the step */ placement?: StepPlacement | undefined; /** * The offset between the content and the target */ offset?: { mainAxis?: number | undefined; crossAxis?: number | undefined; } | undefined; /** * Additional metadata of the step */ meta?: Record | undefined; /** * Whether to show a backdrop behind the step */ backdrop?: boolean | undefined; /** * Whether to show an arrow tip on the step */ arrow?: boolean | undefined; /** * The actions to perform when the step is completed */ actions?: StepAction[] | undefined; } interface StepDetails extends StepBaseDetails { /** * The unique identifier of the step */ id: string; /** * The effect to run before the step is shown */ effect?: ((args: StepEffectArgs) => StepEffectCleanup) | undefined; } interface StepChangeDetails { stepId: string | null; stepIndex: number; totalSteps: number; complete: boolean; progress: number; } interface StepsChangeDetails { steps: StepDetails[]; } type StepStatus = "idle" | "started" | "skipped" | "completed" | "dismissed" | "not-found"; interface StepActionMap { next: VoidFunction; prev: VoidFunction; dismiss: VoidFunction; skip: VoidFunction; goto: (id: string) => void; } interface StatusChangeDetails { status: StepStatus; stepId: string | null; stepIndex: number; } interface ProgressTextDetails { current: number; total: number; } interface IntlTranslations { progressText?: ((details: ProgressTextDetails) => string) | undefined; nextStep?: string | undefined; prevStep?: string | undefined; close?: string | undefined; skip?: string | undefined; } type ElementIds = Partial<{ content: string; title: string; description: string; positioner: string; backdrop: string; arrow: string; }>; interface TourProps extends DirectionProperty, CommonProperties, InteractOutsideHandlers { /** * The ids of the elements in the tour. Useful for composition. */ ids?: ElementIds | undefined; /** * The steps of the tour */ steps?: StepDetails[] | undefined; /** * The id of the currently highlighted step */ stepId?: string | null | undefined; /** * Callback when the highlighted step changes */ onStepChange?: ((details: StepChangeDetails) => void) | undefined; /** * Callback when the steps change */ onStepsChange?: ((details: StepsChangeDetails) => void) | undefined; /** * Callback when the tour is opened or closed */ onStatusChange?: ((details: StatusChangeDetails) => void) | undefined; /** * Whether to close the tour when the user clicks outside the tour * @default true */ closeOnInteractOutside?: boolean | undefined; /** * Whether to close the tour when the user presses the escape key * @default true */ closeOnEscape?: boolean | undefined; /** * Whether to allow keyboard navigation (right/left arrow keys to navigate between steps) * @default true */ keyboardNavigation?: boolean | undefined; /** * Prevents interaction with the rest of the page while the tour is open * @default false */ preventInteraction?: boolean | undefined; /** * The offsets to apply to the spotlight * @default "{ x: 10, y: 10 }" */ spotlightOffset?: Point | undefined; /** * The radius of the spotlight clip path * @default 4 */ spotlightRadius?: number | undefined; /** * The translations for the tour */ translations?: IntlTranslations | undefined; } type PropsWithDefault = "spotlightOffset" | "spotlightRadius" | "translations" | "closeOnInteractOutside" | "closeOnEscape" | "keyboardNavigation" | "preventInteraction"; interface PrivateContext { /** * The rect of the current step's target element */ targetRect: Rect; /** * The current placement of the menu */ currentPlacement?: StepPlacement | undefined; /** * The size of the boundary element (default to the window size) */ boundarySize: Size; /** * The resolved target element */ resolvedTarget: HTMLElement | null; /** * The id of the current step */ stepId: string | null; /** * The steps of the tour */ steps: StepDetails[]; } interface Refs { /** * The function to cleanup the target attributes */ _targetCleanup?: VoidFunction | undefined; /** * The function to cleanup the step effects */ _effectCleanup?: StepEffectCleanup | undefined; /** * Flag to skip the watch when stepId is changed internally */ _internalChange?: boolean | undefined; /** * The previous target element to detect changes */ _prevTarget?: HTMLElement | null | undefined; } type ComputedContext = Readonly<{ /** * The current step details */ step: StepDetails | null; /** * The index of the current step */ stepIndex: number; /** * Whether there is a next step */ hasNextStep: boolean; /** * Whether there is a previous step */ hasPrevStep: boolean; /** * Whether the current step is the first step */ isFirstStep: boolean; /** * Whether the current step is the last step */ isLastStep: boolean; /** * The progress of the tour */ progress: number; }>; interface TourSchema { tag: "open" | "closed"; state: "tourInactive" | "running.resolving" | "running.scrolling" | "running.waiting" | "running.active"; props: RequiredBy; context: PrivateContext; refs: Refs; computed: ComputedContext; event: EventObject; action: string; guard: string; effect: string; } type TourService = Service; type TourMachine = Machine; interface StepActionTriggerProps { action: StepAction; } interface TourApi { /** * Whether the tour is open */ open: boolean; /** * The total number of steps */ totalSteps: number; /** * The index of the current step */ stepIndex: number; /** * The current step details */ step: StepDetails | null; /** * Whether there is a next step */ hasNextStep: boolean; /** * Whether there is a previous step */ hasPrevStep: boolean; /** * Whether the current step is the first step */ firstStep: boolean; /** * Whether the current step is the last step */ lastStep: boolean; /** * Add a new step to the tour */ addStep: (step: StepDetails) => void; /** * Remove a step from the tour */ removeStep: (id: string) => void; /** * Update a step in the tour with partial details */ updateStep: (id: string, stepOverrides: Partial) => void; /** * Set the steps of the tour */ setSteps: (steps: StepDetails[]) => void; /** * Set the current step of the tour */ setStep: (id: string) => void; /** * Start the tour at a specific step (or the first step if not provided) */ start: (id?: string) => void; /** * Check if a step is valid */ isValidStep: (id: string) => boolean; /** * Check if a step is visible */ isCurrentStep: (id: string) => boolean; /** * Move to the next step */ next: VoidFunction; /** * Move to the previous step */ prev: VoidFunction; /** * Returns the progress text */ getProgressText: () => string; /** * Returns the progress percent */ getProgressPercent: () => number; getBackdropProps: () => T["element"]; getSpotlightProps: () => T["element"]; getProgressTextProps: () => T["element"]; getPositionerProps: () => T["element"]; getArrowProps: () => T["element"]; getArrowTipProps: () => T["element"]; getContentProps: () => T["element"]; getTitleProps: () => T["element"]; getDescriptionProps: () => T["element"]; getCloseTriggerProps: () => T["button"]; getActionTriggerProps: (props: StepActionTriggerProps) => T["button"]; } export { type ElementIds, type IntlTranslations, Point, type ProgressTextDetails, type StatusChangeDetails, type StepAction, type StepActionFn, type StepActionMap, type StepActionTriggerProps, type StepActionType, type StepBaseDetails, type StepChangeDetails, type StepDetails, type StepEffectArgs, type StepEffectCleanup, type StepPlacement, type StepStatus, type StepType, type StepsChangeDetails, type TourApi, type TourMachine, type TourProps, type TourSchema, type TourService };