@apollovisionlabs/guide-core 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -14
- package/dist/index.cjs +318 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -4
- package/dist/index.d.ts +92 -4
- package/dist/index.mjs +320 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/storage.ts","../src/matchRoute.ts","../src/tourMachine.ts","../src/useTargetElement.ts","../src/selector.ts","../src/useElementRect.ts","../src/a11y.ts","../src/GuideProvider.tsx","../src/validateTour.ts","../src/useTour.ts","../src/useGuideStep.ts"],"sourcesContent":["export * from './types'\nexport * from './storage'\nexport * from './matchRoute'\nexport * from './tourMachine'\nexport * from './useTargetElement'\nexport * from './useElementRect'\nexport * from './a11y'\nexport * from './GuideProvider'\nexport * from './useTour'\nexport * from './validateTour'\nexport * from './useGuideStep'\n","import type { GuideStorage, TourProgress } from './types'\n\nexport function createMemoryStorage(\n initial: Record<string, TourProgress> = {},\n): GuideStorage {\n const store = new Map<string, TourProgress>(Object.entries(initial))\n return {\n async read(tourId) {\n return store.get(tourId) ?? null\n },\n async write(tourId, progress) {\n store.set(tourId, progress)\n },\n }\n}\n\nexport function createBrowserStorage(namespace = 'guide'): GuideStorage {\n const key = (tourId: string) => `${namespace}:${tourId}`\n const available = () => typeof window !== 'undefined' && !!window.localStorage\n\n return {\n async read(tourId) {\n if (!available()) return null\n try {\n const raw = window.localStorage.getItem(key(tourId))\n return raw ? (JSON.parse(raw) as TourProgress) : null\n } catch {\n return null\n }\n },\n async write(tourId, progress) {\n if (!available()) return\n try {\n window.localStorage.setItem(key(tourId), JSON.stringify(progress))\n } catch {\n // quota exceeded or storage blocked: persistence is optional\n }\n },\n }\n}\n","function segments(value: string): string[] {\n const path = value.split('?')[0] ?? ''\n const trimmed = path.replace(/\\/+$/, '')\n return (trimmed === '' ? '/' : trimmed).split('/')\n}\n\nexport function isLiteralRoute(pattern: string): boolean {\n return !pattern.includes(':') && !pattern.includes('*')\n}\n\nexport function matchRoute(pattern: string, pathname: string): boolean {\n const expected = segments(pattern)\n const actual = segments(pathname)\n\n for (let index = 0; index < expected.length; index += 1) {\n const segment = expected[index]\n if (segment === '*') return true\n\n const candidate = actual[index]\n if (candidate === undefined) return false\n\n if (segment?.startsWith(':')) {\n if (candidate === '') return false\n continue\n }\n\n if (segment !== candidate) return false\n }\n\n return expected.length === actual.length\n}\n","import type { TourStatus } from './types'\n\nexport interface TourState {\n tourId: string | null\n stepIndex: number\n status: TourStatus\n}\n\nexport type TourAction =\n | { type: 'START'; tourId: string; stepIndex: number }\n | { type: 'NEXT'; stepCount: number }\n | { type: 'PREVIOUS' }\n | { type: 'PAUSE' }\n | { type: 'RESUME' }\n | { type: 'STOP' }\n\nexport const initialTourState: TourState = {\n tourId: null,\n stepIndex: 0,\n status: 'idle',\n}\n\nexport function tourReducer(state: TourState, action: TourAction): TourState {\n switch (action.type) {\n case 'START':\n return { tourId: action.tourId, stepIndex: action.stepIndex, status: 'running' }\n\n // Navigating away from a paused tour resumes it: next() and previous() are public API, and calling them is an explicit request to move on.\n case 'NEXT': {\n if (state.status !== 'running' && state.status !== 'paused') return state\n const isLast = state.stepIndex >= action.stepCount - 1\n return isLast\n ? { ...state, status: 'completed' }\n : { ...state, stepIndex: state.stepIndex + 1, status: 'running' }\n }\n\n case 'PREVIOUS':\n if (state.status !== 'running' && state.status !== 'paused') return state\n return { ...state, stepIndex: Math.max(0, state.stepIndex - 1), status: 'running' }\n\n case 'PAUSE':\n return state.status === 'running' ? { ...state, status: 'paused' } : state\n\n case 'RESUME':\n return state.status === 'paused' ? { ...state, status: 'running' } : state\n\n case 'STOP':\n return initialTourState\n\n default:\n return state\n }\n}\n","import { useEffect, useState } from 'react'\nimport { targetSelector } from './selector'\n\nconst DEFAULT_TIMEOUT_MS = 5000\n\nexport interface UseTargetElementOptions {\n timeoutMs?: number\n attribute?: string\n}\n\ninterface TargetState {\n target: string | null\n element: HTMLElement | null\n timedOut: boolean\n}\n\nconst EMPTY: TargetState = { target: null, element: null, timedOut: false }\n\nexport function useTargetElement(\n target: string | null,\n options: UseTargetElementOptions = {},\n): { element: HTMLElement | null; timedOut: boolean } {\n const { timeoutMs = DEFAULT_TIMEOUT_MS, attribute = 'data-guide' } = options\n const [state, setState] = useState<TargetState>(EMPTY)\n\n useEffect(() => {\n if (!target || typeof document === 'undefined') {\n setState({ target, element: null, timedOut: false })\n return\n }\n\n const selector = targetSelector(target, attribute)\n const find = () => document.querySelector<HTMLElement>(selector)\n\n const found = find()\n if (found) {\n setState({ target, element: found, timedOut: false })\n return\n }\n\n setState({ target, element: null, timedOut: false })\n\n let timer: ReturnType<typeof setTimeout> | undefined\n\n const observer = new MutationObserver(() => {\n const candidate = find()\n if (!candidate) return\n observer.disconnect()\n if (timer) clearTimeout(timer)\n setState({ target, element: candidate, timedOut: false })\n })\n\n observer.observe(document.body, { childList: true, subtree: true, attributes: true })\n\n timer = setTimeout(() => {\n // Do not disconnect: the wait policy must be able to resume if the target appears later.\n // The observer callback and the cleanup take care of disconnecting.\n setState({ target, element: null, timedOut: true })\n }, timeoutMs)\n\n return () => {\n observer.disconnect()\n if (timer) clearTimeout(timer)\n }\n }, [target, timeoutMs, attribute])\n\n // Only expose the state when it matches the requested target: otherwise the caller would read\n // the previous step's state until the effect runs, and would skip twice.\n const current = state.target === target ? state : EMPTY\n return { element: current.element, timedOut: current.timedOut }\n}\n","// Target selector construction, shared by runtime resolution and by development-time\n// validation: a target containing a quote must be escaped on both paths, otherwise validation\n// throws a SyntaxError where resolution works.\nexport function escapeAttributeValue(value: string): string {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/[\"\\\\]/g, '\\\\$&')\n}\n\nexport function targetSelector(target: string, attribute: string): string {\n return `[${attribute}=\"${escapeAttributeValue(target)}\"]`\n}\n","import { useEffect, useLayoutEffect, useState } from 'react'\nimport type { Rect } from './types'\n\n// Measure before paint: on a step change, a plain useEffect would let one frame through with\n// the spotlight still on the previous step's target.\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\nfunction sameRect(a: Rect, b: DOMRect): boolean {\n return a.top === b.top && a.left === b.left && a.width === b.width && a.height === b.height\n}\n\nexport function useElementRect(element: HTMLElement | null): Rect | null {\n const [rect, setRect] = useState<Rect | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!element) {\n setRect(null)\n return\n }\n\n const measure = () => {\n const next = element.getBoundingClientRect()\n setRect((previous) =>\n previous && sameRect(previous, next)\n ? previous\n : { top: next.top, left: next.left, width: next.width, height: next.height },\n )\n }\n\n measure()\n\n const observer =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null\n observer?.observe(element)\n\n window.addEventListener('scroll', measure, true)\n window.addEventListener('resize', measure)\n\n return () => {\n observer?.disconnect()\n window.removeEventListener('scroll', measure, true)\n window.removeEventListener('resize', measure)\n }\n }, [element])\n\n return rect\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nconst FOCUSABLE =\n 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nexport interface UseFocusTrapOptions {\n /**\n * Element that receives focus on entry. 'first' takes the first focusable element; 'container'\n * takes the container itself, which must then carry tabIndex={-1}. Defaults to 'first'.\n */\n initialFocus?: 'first' | 'container'\n}\n\nexport function useFocusTrap(\n container: HTMLElement | null,\n active: boolean,\n options: UseFocusTrapOptions = {},\n): void {\n const { initialFocus = 'first' } = options\n\n useEffect(() => {\n if (!container || !active) return\n\n const previouslyFocused = document.activeElement as HTMLElement | null\n // No visibility filter: the selector already excludes disabled elements and elements out of\n // the tab order, and the popover mounts or unmounts its controls rather than hiding them.\n const focusable = () => Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE))\n\n // 'container' avoids putting focus on an actionable button: a reflex Enter after an arrow\n // key must not close the tour.\n const first = initialFocus === 'container' ? undefined : focusable()[0]\n if (first) first.focus()\n else container.focus()\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab') return\n const elements = focusable()\n if (elements.length === 0) return\n\n const firstElement = elements[0]!\n const lastElement = elements[elements.length - 1]!\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault()\n lastElement.focus()\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault()\n firstElement.focus()\n }\n }\n\n document.addEventListener('keydown', onKeyDown, true)\n\n return () => {\n document.removeEventListener('keydown', onKeyDown, true)\n previouslyFocused?.focus?.()\n }\n }, [container, active, initialFocus])\n}\n\nfunction announcerNode(): HTMLElement {\n const existing = document.querySelector<HTMLElement>('[data-guide-announcer]')\n if (existing) return existing\n\n const node = document.createElement('div')\n node.setAttribute('data-guide-announcer', '')\n node.setAttribute('aria-live', 'polite')\n node.setAttribute('aria-atomic', 'true')\n node.style.position = 'absolute'\n node.style.width = '1px'\n node.style.height = '1px'\n node.style.overflow = 'hidden'\n node.style.clip = 'rect(0 0 0 0)'\n node.style.whiteSpace = 'nowrap'\n document.body.appendChild(node)\n return node\n}\n\nexport function useAnnouncer(): (message: string) => void {\n return useCallback((message: string) => {\n if (typeof document === 'undefined') return\n announcerNode().textContent = message\n }, [])\n}\n\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) return\n const query = window.matchMedia('(prefers-reduced-motion: reduce)')\n setReduced(query.matches)\n const onChange = (event: MediaQueryListEvent) => setReduced(event.matches)\n query.addEventListener('change', onChange)\n return () => query.removeEventListener('change', onChange)\n }, [])\n\n return reduced\n}\n","'use client'\n\nimport {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport type {\n GuideEvent,\n GuideStorage,\n MissingTargetPolicy,\n Rect,\n Step,\n Tour,\n TourProgress,\n Translate,\n} from './types'\nimport { initialTourState, tourReducer, type TourState } from './tourMachine'\nimport { isLiteralRoute, matchRoute } from './matchRoute'\nimport { useTargetElement } from './useTargetElement'\nimport { useElementRect } from './useElementRect'\nimport { useAnnouncer } from './a11y'\nimport { findMissingTargets } from './validateTour'\n\nexport interface ActiveStep {\n tourId: string\n step: Step\n stepIndex: number\n stepCount: number\n element: HTMLElement | null\n rect: Rect | null\n title: string\n body: string\n isFirst: boolean\n isLast: boolean\n next: () => void\n previous: () => void\n stop: () => void\n}\n\nexport interface GuideContextValue {\n state: TourState\n activeStep: ActiveStep | null\n start: (tourId: string, options?: { from?: number; resume?: boolean }) => Promise<void>\n next: () => void\n previous: () => void\n stop: () => void\n}\n\nexport const GuideContext = createContext<GuideContextValue | null>(null)\n\nexport interface GuideProviderProps {\n tours: Tour[]\n children: ReactNode\n navigate?: (path: string) => void\n location?: string\n storage?: GuideStorage\n translate?: Translate\n onEvent?: (event: GuideEvent) => void\n onMissingTarget?: MissingTargetPolicy\n targetTimeoutMs?: number\n}\n\nfunction resolveText(\n value: string | undefined,\n key: string | undefined,\n translate: Translate | undefined,\n): string {\n if (value !== undefined) return value\n if (key === undefined) return ''\n return translate ? translate(key) : key\n}\n\nexport function GuideProvider({\n tours,\n children,\n navigate,\n location,\n storage,\n translate,\n onEvent,\n onMissingTarget = 'wait',\n targetTimeoutMs = 5000,\n}: GuideProviderProps) {\n const toursById = useMemo(() => {\n const map = new Map<string, Tour>()\n for (const candidate of tours) {\n if (map.has(candidate.id)) {\n throw new Error(`[guide] duplicate tour id: ${candidate.id}`)\n }\n map.set(candidate.id, candidate)\n }\n return map\n }, [tours])\n\n const [state, dispatch] = useReducer(tourReducer, initialTourState)\n const announce = useAnnouncer()\n\n // Element that held focus when the tour started: the popover unmounts and remounts on every\n // step, so its own focus trap cannot restore focus to that origin.\n const focusOriginRef = useRef<HTMLElement | null>(null)\n const storageWarnedRef = useRef(false)\n\n const warnStorageFailure = useCallback((error: unknown) => {\n if (storageWarnedRef.current) return\n storageWarnedRef.current = true\n console.warn('[guide] storage failed; tour progress will not be persisted', error)\n }, [])\n\n const onEventRef = useRef(onEvent)\n onEventRef.current = onEvent\n const emit = useCallback((event: GuideEvent) => onEventRef.current?.(event), [])\n\n const tour = state.tourId ? (toursById.get(state.tourId) ?? null) : null\n const step = tour ? (tour.steps[state.stepIndex] ?? null) : null\n const isActive = state.status === 'running' || state.status === 'paused'\n\n const routeMatches =\n !step?.route || location === undefined || matchRoute(step.route, location)\n\n const { element, timedOut: targetTimedOut } = useTargetElement(\n isActive && routeMatches && step ? step.target : null,\n { timeoutMs: targetTimeoutMs },\n )\n const rect = useElementRect(element)\n\n // A step whose route never matches requests no target, so no timeout is running. Without this\n // timer, a wrong route pattern or a failed navigation would leave the tour running, invisible\n // and with no way out. The timer armed here is what makes the policy apply.\n const waitingForRoute = isActive && !!step && !routeMatches\n // The expired step is stored rather than a boolean: otherwise the next step would inherit the\n // previous one's expiry for one render and the policy would apply twice.\n const [routeTimeoutStep, setRouteTimeoutStep] = useState<Step | null>(null)\n\n useEffect(() => {\n if (!waitingForRoute) {\n setRouteTimeoutStep(null)\n return\n }\n const timer = setTimeout(() => setRouteTimeoutStep(step), targetTimeoutMs)\n return () => clearTimeout(timer)\n }, [waitingForRoute, step, targetTimeoutMs])\n\n const timedOut = targetTimedOut || (waitingForRoute && routeTimeoutStep === step)\n\n const next = useCallback(() => {\n if (!tour) return\n const isLast = state.stepIndex >= tour.steps.length - 1\n dispatch({ type: 'NEXT', stepCount: tour.steps.length })\n if (isLast) emit({ type: 'tour:complete', tourId: tour.id })\n }, [tour, state.stepIndex, emit])\n\n const previous = useCallback(() => dispatch({ type: 'PREVIOUS' }), [])\n\n const stop = useCallback(() => {\n if (tour) emit({ type: 'tour:stop', tourId: tour.id, stepIndex: state.stepIndex })\n dispatch({ type: 'STOP' })\n }, [tour, state.stepIndex, emit])\n\n // Delegated navigation: the step lives elsewhere, so we ask for the move.\n // The destination already requested for the current step is kept in a ref: without it, if the\n // route never matches, this effect would call navigate again on every render.\n const navigationRef = useRef<{ step: Step | null; destination: string | null }>({\n step: null,\n destination: null,\n })\n\n const start = useCallback(\n async (tourId: string, options?: { from?: number; resume?: boolean }) => {\n // Reentrancy: a second call while this same tour is running would re-read persistence and\n // could move the progress backwards. Switching to another tour stays allowed.\n if (state.tourId === tourId && state.status === 'running') return\n\n const target = toursById.get(tourId)\n if (!target) throw new Error(`[guide] unknown tour: ${tourId}`)\n if (target.steps.length === 0) {\n throw new Error(`[guide] tour has no steps: ${tourId}`)\n }\n\n if (typeof document !== 'undefined') {\n focusOriginRef.current = document.activeElement as HTMLElement | null\n }\n\n let stepIndex = options?.from ?? 0\n if (options?.from === undefined && options?.resume !== false && storage) {\n // Storage that fails must not block the tour: we start from the beginning.\n let progress: TourProgress | null = null\n try {\n progress = await storage.read(tourId)\n } catch (error) {\n warnStorageFailure(error)\n }\n if (progress?.status === 'in-progress') stepIndex = progress.stepIndex\n }\n\n if (process.env.NODE_ENV !== 'production') {\n const missing = findMissingTargets(target, location)\n if (missing.length > 0) {\n console.warn(\n `[guide] tour \"${tourId}\" declares targets that are not present on this page: ${missing.join(', ')}`,\n )\n }\n }\n\n // Restarting the same tour on the same step must navigate again: without this reset, the\n // destination already requested would stay remembered and the effect would skip navigate.\n navigationRef.current = { step: null, destination: null }\n\n dispatch({ type: 'START', tourId, stepIndex })\n emit({ type: 'tour:start', tourId, stepIndex })\n },\n [toursById, storage, location, emit, state.tourId, state.status, warnStorageFailure],\n )\n\n useEffect(() => {\n if (!isActive || !step || routeMatches) return\n\n if (navigationRef.current.step !== step) {\n navigationRef.current = { step, destination: null }\n }\n\n const destination =\n step.navigateTo ?? (step.route && isLiteralRoute(step.route) ? step.route : null)\n\n if (!destination) return\n if (navigationRef.current.destination === destination) return\n if (!navigate) {\n console.warn('[guide] a step declares a route but no navigate function was provided')\n return\n }\n navigationRef.current.destination = destination\n navigate(destination)\n }, [isActive, step, routeMatches, navigate])\n\n // Target not found: apply the policy.\n useEffect(() => {\n if (!timedOut || !tour || !step) return\n\n emit({\n type: 'target:missing',\n tourId: tour.id,\n stepIndex: state.stepIndex,\n target: step.target,\n })\n\n const policy = step.onMissingTarget ?? onMissingTarget\n if (policy === 'skip') dispatch({ type: 'NEXT', stepCount: tour.steps.length })\n else if (policy === 'error') dispatch({ type: 'STOP' })\n else dispatch({ type: 'PAUSE' })\n }, [timedOut, tour, step, state.stepIndex, onMissingTarget, emit])\n\n // Automatic resume when the target reappears after a pause.\n useEffect(() => {\n if (state.status === 'paused' && element) dispatch({ type: 'RESUME' })\n }, [state.status, element])\n\n // Step actually on screen.\n useEffect(() => {\n if (state.status !== 'running' || !tour || !step || !element) return\n emit({\n type: 'step:show',\n tourId: tour.id,\n stepIndex: state.stepIndex,\n target: step.target,\n })\n announce(`${state.stepIndex + 1} / ${tour.steps.length}`)\n }, [state.status, state.stepIndex, tour, step, element, emit, announce])\n\n // Progress persistence. A write that fails breaks nothing: the progress is simply not kept.\n useEffect(() => {\n if (!storage || !state.tourId) return\n const status =\n state.status === 'running'\n ? 'in-progress'\n : state.status === 'completed'\n ? 'completed'\n : null\n if (!status) return\n try {\n void Promise.resolve(\n storage.write(state.tourId, { status, stepIndex: state.stepIndex }),\n ).catch(warnStorageFailure)\n } catch (error) {\n warnStorageFailure(error)\n }\n }, [storage, state.tourId, state.status, state.stepIndex, warnStorageFailure])\n\n // Focus returns to its origin once the tour is stopped or completed.\n useEffect(() => {\n if (state.status !== 'idle' && state.status !== 'completed') return\n const origin = focusOriginRef.current\n if (!origin) return\n focusOriginRef.current = null\n if (typeof document !== 'undefined' && document.contains(origin)) origin.focus()\n }, [state.status])\n\n const activeStep = useMemo<ActiveStep | null>(() => {\n if (!tour || !step || !isActive) return null\n return {\n tourId: tour.id,\n step,\n stepIndex: state.stepIndex,\n stepCount: tour.steps.length,\n element,\n rect,\n title: resolveText(step.title, step.titleKey, translate),\n body: resolveText(step.body, step.bodyKey, translate),\n isFirst: state.stepIndex === 0,\n isLast: state.stepIndex === tour.steps.length - 1,\n next,\n previous,\n stop,\n }\n }, [tour, step, isActive, state.stepIndex, element, rect, translate, next, previous, stop])\n\n const value = useMemo<GuideContextValue>(\n () => ({ state, activeStep, start, next, previous, stop }),\n [state, activeStep, start, next, previous, stop],\n )\n\n return <GuideContext.Provider value={value}>{children}</GuideContext.Provider>\n}\n","import type { Tour } from './types'\nimport { matchRoute } from './matchRoute'\nimport { targetSelector } from './selector'\n\nexport function findMissingTargets(\n tour: Tour,\n location: string | undefined,\n attribute = 'data-guide',\n): string[] {\n if (typeof document === 'undefined') return []\n\n return tour.steps\n .filter((step) => !step.route || location === undefined || matchRoute(step.route, location))\n .map((step) => step.target)\n .filter((target) => !document.querySelector(targetSelector(target, attribute)))\n}\n","'use client'\n\nimport { useContext, useMemo } from 'react'\nimport { GuideContext } from './GuideProvider'\nimport type { TourStatus } from './types'\n\nexport interface UseTourResult {\n start: (options?: { from?: number; resume?: boolean }) => Promise<void>\n next: () => void\n previous: () => void\n stop: () => void\n status: TourStatus\n stepIndex: number\n}\n\nexport function useTour(tourId: string): UseTourResult {\n const context = useContext(GuideContext)\n if (!context) throw new Error('[guide] useTour must be used inside a GuideProvider')\n\n const { state, start, next, previous, stop } = context\n const isCurrent = state.tourId === tourId\n\n return useMemo(\n () => ({\n start: (options) => start(tourId, options),\n next,\n previous,\n stop,\n status: isCurrent ? state.status : 'idle',\n stepIndex: isCurrent ? state.stepIndex : 0,\n }),\n [tourId, start, next, previous, stop, isCurrent, state.status, state.stepIndex],\n )\n}\n","'use client'\n\nimport { useContext } from 'react'\nimport { GuideContext, type ActiveStep } from './GuideProvider'\n\nexport function useGuideStep(): ActiveStep | null {\n const context = useContext(GuideContext)\n if (!context) throw new Error('[guide] useGuideStep must be used inside a GuideProvider')\n return context.activeStep\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/storage.ts","../src/matchRoute.ts","../src/tourMachine.ts","../src/useTargetElement.ts","../src/selector.ts","../src/useElementRect.ts","../src/a11y.ts","../src/GuideProvider.tsx","../src/validateTour.ts","../src/resolveText.ts","../src/useTour.ts","../src/useGuideStep.ts","../src/ChecklistProvider.tsx","../src/useChecklist.ts"],"sourcesContent":["export * from './types'\nexport * from './storage'\nexport * from './matchRoute'\nexport * from './tourMachine'\nexport * from './useTargetElement'\nexport * from './useElementRect'\nexport * from './a11y'\nexport * from './GuideProvider'\nexport * from './useTour'\nexport * from './validateTour'\nexport * from './useGuideStep'\nexport * from './resolveText'\nexport * from './ChecklistProvider'\nexport * from './useChecklist'\n","import type { ChecklistProgress, GuideStorage, TourProgress } from './types'\n\nexport function createMemoryStorage(\n initial: Record<string, unknown> = {},\n): GuideStorage {\n const store = new Map<string, unknown>(Object.entries(initial))\n return {\n async read<T>(key: string) {\n return (store.get(key) ?? null) as T | null\n },\n async write<T>(key: string, value: T) {\n store.set(key, value)\n },\n }\n}\n\nexport function createBrowserStorage(namespace = 'guide'): GuideStorage {\n const key = (storageKey: string) => `${namespace}:${storageKey}`\n const available = () => typeof window !== 'undefined' && !!window.localStorage\n\n return {\n async read<T>(storageKey: string) {\n if (!available()) return null\n try {\n const raw = window.localStorage.getItem(key(storageKey))\n return raw ? (JSON.parse(raw) as T) : null\n } catch {\n return null\n }\n },\n async write<T>(storageKey: string, value: T) {\n if (!available()) return\n try {\n window.localStorage.setItem(key(storageKey), JSON.stringify(value))\n } catch {\n // quota exceeded or storage blocked: persistence is optional\n }\n },\n }\n}\n\n/**\n * A stored value survives code changes, browser extensions and hand editing,\n * so nothing read back is trusted until its shape is checked.\n */\nexport function isTourProgress(value: unknown): value is TourProgress {\n if (typeof value !== 'object' || value === null) return false\n const candidate = value as Record<string, unknown>\n return (\n typeof candidate.stepIndex === 'number' &&\n Number.isInteger(candidate.stepIndex) &&\n candidate.stepIndex >= 0 &&\n (candidate.status === 'in-progress' || candidate.status === 'completed')\n )\n}\n\n/**\n * Same defensive posture as isTourProgress: a stored checklist value is\n * never trusted until its shape is checked.\n */\nexport function isChecklistProgress(value: unknown): value is ChecklistProgress {\n if (typeof value !== 'object' || value === null) return false\n const candidate = value as Record<string, unknown>\n return (\n Array.isArray(candidate.completed) &&\n candidate.completed.every((entry) => typeof entry === 'string') &&\n typeof candidate.dismissed === 'boolean'\n )\n}\n","function segments(value: string): string[] {\n const path = value.split('?')[0] ?? ''\n const trimmed = path.replace(/\\/+$/, '')\n return (trimmed === '' ? '/' : trimmed).split('/')\n}\n\nexport function isLiteralRoute(pattern: string): boolean {\n return !pattern.includes(':') && !pattern.includes('*')\n}\n\nexport function matchRoute(pattern: string, pathname: string): boolean {\n const expected = segments(pattern)\n const actual = segments(pathname)\n\n for (let index = 0; index < expected.length; index += 1) {\n const segment = expected[index]\n if (segment === '*') return true\n\n const candidate = actual[index]\n if (candidate === undefined) return false\n\n if (segment?.startsWith(':')) {\n if (candidate === '') return false\n continue\n }\n\n if (segment !== candidate) return false\n }\n\n return expected.length === actual.length\n}\n","import type { TourStatus } from './types'\n\nexport interface TourState {\n tourId: string | null\n stepIndex: number\n status: TourStatus\n}\n\nexport type TourAction =\n | { type: 'START'; tourId: string; stepIndex: number }\n | { type: 'NEXT'; stepCount: number }\n | { type: 'PREVIOUS' }\n | { type: 'PAUSE' }\n | { type: 'RESUME' }\n | { type: 'STOP' }\n\nexport const initialTourState: TourState = {\n tourId: null,\n stepIndex: 0,\n status: 'idle',\n}\n\nexport function tourReducer(state: TourState, action: TourAction): TourState {\n switch (action.type) {\n case 'START':\n return { tourId: action.tourId, stepIndex: action.stepIndex, status: 'running' }\n\n // Navigating away from a paused tour resumes it: next() and previous() are public API, and calling them is an explicit request to move on.\n case 'NEXT': {\n if (state.status !== 'running' && state.status !== 'paused') return state\n const isLast = state.stepIndex >= action.stepCount - 1\n return isLast\n ? { ...state, status: 'completed' }\n : { ...state, stepIndex: state.stepIndex + 1, status: 'running' }\n }\n\n case 'PREVIOUS':\n if (state.status !== 'running' && state.status !== 'paused') return state\n return { ...state, stepIndex: Math.max(0, state.stepIndex - 1), status: 'running' }\n\n case 'PAUSE':\n return state.status === 'running' ? { ...state, status: 'paused' } : state\n\n case 'RESUME':\n return state.status === 'paused' ? { ...state, status: 'running' } : state\n\n case 'STOP':\n return initialTourState\n\n default:\n return state\n }\n}\n","import { useEffect, useState } from 'react'\nimport { targetSelector } from './selector'\n\nconst DEFAULT_TIMEOUT_MS = 5000\n\nexport interface UseTargetElementOptions {\n timeoutMs?: number\n attribute?: string\n}\n\ninterface TargetState {\n target: string | null\n element: HTMLElement | null\n timedOut: boolean\n}\n\nconst EMPTY: TargetState = { target: null, element: null, timedOut: false }\n\nexport function useTargetElement(\n target: string | null,\n options: UseTargetElementOptions = {},\n): { element: HTMLElement | null; timedOut: boolean } {\n const { timeoutMs = DEFAULT_TIMEOUT_MS, attribute = 'data-guide' } = options\n const [state, setState] = useState<TargetState>(EMPTY)\n\n useEffect(() => {\n if (!target || typeof document === 'undefined') {\n setState({ target, element: null, timedOut: false })\n return\n }\n\n const selector = targetSelector(target, attribute)\n const find = () => document.querySelector<HTMLElement>(selector)\n\n const found = find()\n if (found) {\n setState({ target, element: found, timedOut: false })\n return\n }\n\n setState({ target, element: null, timedOut: false })\n\n let timer: ReturnType<typeof setTimeout> | undefined\n\n const observer = new MutationObserver(() => {\n const candidate = find()\n if (!candidate) return\n observer.disconnect()\n if (timer) clearTimeout(timer)\n setState({ target, element: candidate, timedOut: false })\n })\n\n observer.observe(document.body, { childList: true, subtree: true, attributes: true })\n\n timer = setTimeout(() => {\n // Do not disconnect: the wait policy must be able to resume if the target appears later.\n // The observer callback and the cleanup take care of disconnecting.\n setState({ target, element: null, timedOut: true })\n }, timeoutMs)\n\n return () => {\n observer.disconnect()\n if (timer) clearTimeout(timer)\n }\n }, [target, timeoutMs, attribute])\n\n // Only expose the state when it matches the requested target: otherwise the caller would read\n // the previous step's state until the effect runs, and would skip twice.\n const current = state.target === target ? state : EMPTY\n return { element: current.element, timedOut: current.timedOut }\n}\n","// Target selector construction, shared by runtime resolution and by development-time\n// validation: a target containing a quote must be escaped on both paths, otherwise validation\n// throws a SyntaxError where resolution works.\nexport function escapeAttributeValue(value: string): string {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/[\"\\\\]/g, '\\\\$&')\n}\n\nexport function targetSelector(target: string, attribute: string): string {\n return `[${attribute}=\"${escapeAttributeValue(target)}\"]`\n}\n","import { useEffect, useLayoutEffect, useState } from 'react'\nimport type { Rect } from './types'\n\n// Measure before paint: on a step change, a plain useEffect would let one frame through with\n// the spotlight still on the previous step's target.\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\nfunction sameRect(a: Rect, b: DOMRect): boolean {\n return a.top === b.top && a.left === b.left && a.width === b.width && a.height === b.height\n}\n\nexport function useElementRect(element: HTMLElement | null): Rect | null {\n const [rect, setRect] = useState<Rect | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!element) {\n setRect(null)\n return\n }\n\n const measure = () => {\n const next = element.getBoundingClientRect()\n setRect((previous) =>\n previous && sameRect(previous, next)\n ? previous\n : { top: next.top, left: next.left, width: next.width, height: next.height },\n )\n }\n\n measure()\n\n const observer =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null\n observer?.observe(element)\n\n window.addEventListener('scroll', measure, true)\n window.addEventListener('resize', measure)\n\n return () => {\n observer?.disconnect()\n window.removeEventListener('scroll', measure, true)\n window.removeEventListener('resize', measure)\n }\n }, [element])\n\n return rect\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nconst FOCUSABLE =\n 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nexport interface UseFocusTrapOptions {\n /**\n * Element that receives focus on entry. 'first' takes the first focusable element; 'container'\n * takes the container itself, which must then carry tabIndex={-1}. Defaults to 'first'.\n */\n initialFocus?: 'first' | 'container'\n}\n\nexport function useFocusTrap(\n container: HTMLElement | null,\n active: boolean,\n options: UseFocusTrapOptions = {},\n): void {\n const { initialFocus = 'first' } = options\n\n useEffect(() => {\n if (!container || !active) return\n\n const previouslyFocused = document.activeElement as HTMLElement | null\n // No visibility filter: the selector already excludes disabled elements and elements out of\n // the tab order, and the popover mounts or unmounts its controls rather than hiding them.\n const focusable = () => Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE))\n\n // 'container' avoids putting focus on an actionable button: a reflex Enter after an arrow\n // key must not close the tour.\n const first = initialFocus === 'container' ? undefined : focusable()[0]\n if (first) first.focus()\n else container.focus()\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab') return\n const elements = focusable()\n if (elements.length === 0) return\n\n const firstElement = elements[0]!\n const lastElement = elements[elements.length - 1]!\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault()\n lastElement.focus()\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault()\n firstElement.focus()\n }\n }\n\n document.addEventListener('keydown', onKeyDown, true)\n\n return () => {\n document.removeEventListener('keydown', onKeyDown, true)\n previouslyFocused?.focus?.()\n }\n }, [container, active, initialFocus])\n}\n\nfunction announcerNode(): HTMLElement {\n const existing = document.querySelector<HTMLElement>('[data-guide-announcer]')\n if (existing) return existing\n\n const node = document.createElement('div')\n node.setAttribute('data-guide-announcer', '')\n node.setAttribute('aria-live', 'polite')\n node.setAttribute('aria-atomic', 'true')\n node.style.position = 'absolute'\n node.style.width = '1px'\n node.style.height = '1px'\n node.style.overflow = 'hidden'\n node.style.clip = 'rect(0 0 0 0)'\n node.style.whiteSpace = 'nowrap'\n document.body.appendChild(node)\n return node\n}\n\nexport function useAnnouncer(): (message: string) => void {\n return useCallback((message: string) => {\n if (typeof document === 'undefined') return\n announcerNode().textContent = message\n }, [])\n}\n\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) return\n const query = window.matchMedia('(prefers-reduced-motion: reduce)')\n setReduced(query.matches)\n const onChange = (event: MediaQueryListEvent) => setReduced(event.matches)\n query.addEventListener('change', onChange)\n return () => query.removeEventListener('change', onChange)\n }, [])\n\n return reduced\n}\n","'use client'\n\nimport {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport type {\n GuideEvent,\n GuideStorage,\n MissingTargetPolicy,\n Rect,\n Step,\n Tour,\n TourProgress,\n Translate,\n} from './types'\nimport { initialTourState, tourReducer, type TourState } from './tourMachine'\nimport { isLiteralRoute, matchRoute } from './matchRoute'\nimport { useTargetElement } from './useTargetElement'\nimport { useElementRect } from './useElementRect'\nimport { useAnnouncer } from './a11y'\nimport { findMissingTargets } from './validateTour'\nimport { isTourProgress } from './storage'\nimport { resolveText } from './resolveText'\n\nexport interface ActiveStep {\n tourId: string\n step: Step\n stepIndex: number\n stepCount: number\n element: HTMLElement | null\n rect: Rect | null\n title: string\n body: string\n isFirst: boolean\n isLast: boolean\n next: () => void\n previous: () => void\n stop: () => void\n}\n\nexport interface GuideContextValue {\n state: TourState\n activeStep: ActiveStep | null\n start: (tourId: string, options?: { from?: number; resume?: boolean }) => Promise<void>\n next: () => void\n previous: () => void\n stop: () => void\n}\n\nexport const GuideContext = createContext<GuideContextValue | null>(null)\n\nexport interface GuideProviderProps {\n tours: Tour[]\n children: ReactNode\n navigate?: (path: string) => void\n location?: string\n storage?: GuideStorage\n translate?: Translate\n onEvent?: (event: GuideEvent) => void\n onMissingTarget?: MissingTargetPolicy\n targetTimeoutMs?: number\n}\n\nexport function GuideProvider({\n tours,\n children,\n navigate,\n location,\n storage,\n translate,\n onEvent,\n onMissingTarget = 'wait',\n targetTimeoutMs = 5000,\n}: GuideProviderProps) {\n const toursById = useMemo(() => {\n const map = new Map<string, Tour>()\n for (const candidate of tours) {\n if (map.has(candidate.id)) {\n throw new Error(`[guide] duplicate tour id: ${candidate.id}`)\n }\n map.set(candidate.id, candidate)\n }\n return map\n }, [tours])\n\n const [state, dispatch] = useReducer(tourReducer, initialTourState)\n const announce = useAnnouncer()\n\n // Element that held focus when the tour started: the popover unmounts and remounts on every\n // step, so its own focus trap cannot restore focus to that origin.\n const focusOriginRef = useRef<HTMLElement | null>(null)\n const storageWarnedRef = useRef(false)\n\n const warnStorageFailure = useCallback((error: unknown) => {\n if (storageWarnedRef.current) return\n storageWarnedRef.current = true\n console.warn('[guide] storage failed; tour progress will not be persisted', error)\n }, [])\n\n const onEventRef = useRef(onEvent)\n onEventRef.current = onEvent\n const emit = useCallback((event: GuideEvent) => onEventRef.current?.(event), [])\n\n const tour = state.tourId ? (toursById.get(state.tourId) ?? null) : null\n const step = tour ? (tour.steps[state.stepIndex] ?? null) : null\n const isActive = state.status === 'running' || state.status === 'paused'\n\n const routeMatches =\n !step?.route || location === undefined || matchRoute(step.route, location)\n\n const { element, timedOut: targetTimedOut } = useTargetElement(\n isActive && routeMatches && step ? step.target : null,\n { timeoutMs: targetTimeoutMs },\n )\n const rect = useElementRect(element)\n\n // A step whose route never matches requests no target, so no timeout is running. Without this\n // timer, a wrong route pattern or a failed navigation would leave the tour running, invisible\n // and with no way out. The timer armed here is what makes the policy apply.\n const waitingForRoute = isActive && !!step && !routeMatches\n // The expired step is stored rather than a boolean: otherwise the next step would inherit the\n // previous one's expiry for one render and the policy would apply twice.\n const [routeTimeoutStep, setRouteTimeoutStep] = useState<Step | null>(null)\n\n useEffect(() => {\n if (!waitingForRoute) {\n setRouteTimeoutStep(null)\n return\n }\n const timer = setTimeout(() => setRouteTimeoutStep(step), targetTimeoutMs)\n return () => clearTimeout(timer)\n }, [waitingForRoute, step, targetTimeoutMs])\n\n const timedOut = targetTimedOut || (waitingForRoute && routeTimeoutStep === step)\n\n const next = useCallback(() => {\n if (!tour) return\n const isLast = state.stepIndex >= tour.steps.length - 1\n dispatch({ type: 'NEXT', stepCount: tour.steps.length })\n if (isLast) emit({ type: 'tour:complete', tourId: tour.id })\n }, [tour, state.stepIndex, emit])\n\n const previous = useCallback(() => dispatch({ type: 'PREVIOUS' }), [])\n\n const stop = useCallback(() => {\n if (tour) emit({ type: 'tour:stop', tourId: tour.id, stepIndex: state.stepIndex })\n dispatch({ type: 'STOP' })\n }, [tour, state.stepIndex, emit])\n\n // Delegated navigation: the step lives elsewhere, so we ask for the move.\n // The destination already requested for the current step is kept in a ref: without it, if the\n // route never matches, this effect would call navigate again on every render.\n const navigationRef = useRef<{ step: Step | null; destination: string | null }>({\n step: null,\n destination: null,\n })\n\n const start = useCallback(\n async (tourId: string, options?: { from?: number; resume?: boolean }) => {\n // Reentrancy: a second call while this same tour is running would re-read persistence and\n // could move the progress backwards. Switching to another tour stays allowed.\n if (state.tourId === tourId && state.status === 'running') return\n\n const target = toursById.get(tourId)\n if (!target) throw new Error(`[guide] unknown tour: ${tourId}`)\n if (target.steps.length === 0) {\n throw new Error(`[guide] tour has no steps: ${tourId}`)\n }\n\n if (typeof document !== 'undefined') {\n focusOriginRef.current = document.activeElement as HTMLElement | null\n }\n\n let stepIndex = options?.from ?? 0\n if (options?.from === undefined && options?.resume !== false && storage) {\n // Storage that fails must not block the tour: we start from the beginning.\n let progress: TourProgress | null = null\n try {\n const stored = await storage.read<unknown>(`tour:${tourId}`)\n progress = isTourProgress(stored) ? stored : null\n } catch (error) {\n warnStorageFailure(error)\n }\n if (progress?.status === 'in-progress') stepIndex = progress.stepIndex\n }\n\n if (process.env.NODE_ENV !== 'production') {\n const missing = findMissingTargets(target, location)\n if (missing.length > 0) {\n console.warn(\n `[guide] tour \"${tourId}\" declares targets that are not present on this page: ${missing.join(', ')}`,\n )\n }\n }\n\n // Restarting the same tour on the same step must navigate again: without this reset, the\n // destination already requested would stay remembered and the effect would skip navigate.\n navigationRef.current = { step: null, destination: null }\n\n dispatch({ type: 'START', tourId, stepIndex })\n emit({ type: 'tour:start', tourId, stepIndex })\n },\n [toursById, storage, location, emit, state.tourId, state.status, warnStorageFailure],\n )\n\n useEffect(() => {\n if (!isActive || !step || routeMatches) return\n\n if (navigationRef.current.step !== step) {\n navigationRef.current = { step, destination: null }\n }\n\n const destination =\n step.navigateTo ?? (step.route && isLiteralRoute(step.route) ? step.route : null)\n\n if (!destination) return\n if (navigationRef.current.destination === destination) return\n if (!navigate) {\n console.warn('[guide] a step declares a route but no navigate function was provided')\n return\n }\n navigationRef.current.destination = destination\n navigate(destination)\n }, [isActive, step, routeMatches, navigate])\n\n // Target not found: apply the policy.\n useEffect(() => {\n if (!timedOut || !tour || !step) return\n\n emit({\n type: 'target:missing',\n tourId: tour.id,\n stepIndex: state.stepIndex,\n target: step.target,\n })\n\n const policy = step.onMissingTarget ?? onMissingTarget\n if (policy === 'skip') dispatch({ type: 'NEXT', stepCount: tour.steps.length })\n else if (policy === 'error') dispatch({ type: 'STOP' })\n else dispatch({ type: 'PAUSE' })\n }, [timedOut, tour, step, state.stepIndex, onMissingTarget, emit])\n\n // Automatic resume when the target reappears after a pause.\n useEffect(() => {\n if (state.status === 'paused' && element) dispatch({ type: 'RESUME' })\n }, [state.status, element])\n\n // Step actually on screen.\n useEffect(() => {\n if (state.status !== 'running' || !tour || !step || !element) return\n emit({\n type: 'step:show',\n tourId: tour.id,\n stepIndex: state.stepIndex,\n target: step.target,\n })\n announce(`${state.stepIndex + 1} / ${tour.steps.length}`)\n }, [state.status, state.stepIndex, tour, step, element, emit, announce])\n\n // Progress persistence. A write that fails breaks nothing: the progress is simply not kept.\n useEffect(() => {\n if (!storage || !state.tourId) return\n const status =\n state.status === 'running'\n ? 'in-progress'\n : state.status === 'completed'\n ? 'completed'\n : null\n if (!status) return\n try {\n void Promise.resolve(\n storage.write(`tour:${state.tourId}`, { status, stepIndex: state.stepIndex }),\n ).catch(warnStorageFailure)\n } catch (error) {\n warnStorageFailure(error)\n }\n }, [storage, state.tourId, state.status, state.stepIndex, warnStorageFailure])\n\n // Focus returns to its origin once the tour is stopped or completed.\n useEffect(() => {\n if (state.status !== 'idle' && state.status !== 'completed') return\n const origin = focusOriginRef.current\n if (!origin) return\n focusOriginRef.current = null\n if (typeof document !== 'undefined' && document.contains(origin)) origin.focus()\n }, [state.status])\n\n const activeStep = useMemo<ActiveStep | null>(() => {\n if (!tour || !step || !isActive) return null\n return {\n tourId: tour.id,\n step,\n stepIndex: state.stepIndex,\n stepCount: tour.steps.length,\n element,\n rect,\n title: resolveText(step.title, step.titleKey, translate),\n body: resolveText(step.body, step.bodyKey, translate),\n isFirst: state.stepIndex === 0,\n isLast: state.stepIndex === tour.steps.length - 1,\n next,\n previous,\n stop,\n }\n }, [tour, step, isActive, state.stepIndex, element, rect, translate, next, previous, stop])\n\n const value = useMemo<GuideContextValue>(\n () => ({ state, activeStep, start, next, previous, stop }),\n [state, activeStep, start, next, previous, stop],\n )\n\n return <GuideContext.Provider value={value}>{children}</GuideContext.Provider>\n}\n","import type { Tour } from './types'\nimport { matchRoute } from './matchRoute'\nimport { targetSelector } from './selector'\n\nexport function findMissingTargets(\n tour: Tour,\n location: string | undefined,\n attribute = 'data-guide',\n): string[] {\n if (typeof document === 'undefined') return []\n\n return tour.steps\n .filter((step) => !step.route || location === undefined || matchRoute(step.route, location))\n .map((step) => step.target)\n .filter((target) => !document.querySelector(targetSelector(target, attribute)))\n}\n","import type { Translate } from './types'\n\nexport function resolveText(\n value: string | undefined,\n key: string | undefined,\n translate: Translate | undefined,\n): string {\n if (value !== undefined) return value\n if (key === undefined) return ''\n return translate ? translate(key) : key\n}\n","'use client'\n\nimport { useContext, useMemo } from 'react'\nimport { GuideContext } from './GuideProvider'\nimport type { TourStatus } from './types'\n\nexport interface UseTourResult {\n start: (options?: { from?: number; resume?: boolean }) => Promise<void>\n next: () => void\n previous: () => void\n stop: () => void\n status: TourStatus\n stepIndex: number\n}\n\nexport function useTour(tourId: string): UseTourResult {\n const context = useContext(GuideContext)\n if (!context) throw new Error('[guide] useTour must be used inside a GuideProvider')\n\n const { state, start, next, previous, stop } = context\n const isCurrent = state.tourId === tourId\n\n return useMemo(\n () => ({\n start: (options) => start(tourId, options),\n next,\n previous,\n stop,\n status: isCurrent ? state.status : 'idle',\n stepIndex: isCurrent ? state.stepIndex : 0,\n }),\n [tourId, start, next, previous, stop, isCurrent, state.status, state.stepIndex],\n )\n}\n","'use client'\n\nimport { useContext } from 'react'\nimport { GuideContext, type ActiveStep } from './GuideProvider'\n\nexport function useGuideStep(): ActiveStep | null {\n const context = useContext(GuideContext)\n if (!context) throw new Error('[guide] useGuideStep must be used inside a GuideProvider')\n return context.activeStep\n}\n","'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport type {\n Checklist,\n ChecklistProgress,\n GuideEvent,\n GuideStorage,\n Translate,\n} from './types'\nimport { GuideContext } from './GuideProvider'\nimport { isChecklistProgress } from './storage'\n\nexport interface ChecklistContextValue {\n checklists: Checklist[]\n progress: Record<string, ChecklistProgress>\n translate?: Translate\n activate: (checklistId: string, itemId: string) => void\n toggle: (checklistId: string, itemId: string) => void\n complete: (checklistId: string, itemId: string) => void\n dismiss: (checklistId: string) => void\n reset: (checklistId: string) => void\n}\n\nexport const ChecklistContext = createContext<ChecklistContextValue | null>(null)\n\nexport interface ChecklistProviderProps {\n checklists: Checklist[]\n children: ReactNode\n storage?: GuideStorage\n translate?: Translate\n navigate?: (path: string) => void\n onEvent?: (event: GuideEvent) => void\n}\n\nconst emptyProgress: ChecklistProgress = { completed: [], dismissed: false }\n\nexport function ChecklistProvider({\n checklists,\n children,\n storage,\n translate,\n navigate,\n onEvent,\n}: ChecklistProviderProps) {\n const checklistsById = useMemo(() => {\n const map = new Map<string, Checklist>()\n for (const candidate of checklists) map.set(candidate.id, candidate)\n return map\n }, [checklists])\n\n const [progress, setProgress] = useState<Record<string, ChecklistProgress>>(() => {\n const initial: Record<string, ChecklistProgress> = {}\n for (const candidate of checklists) initial[candidate.id] = emptyProgress\n return initial\n })\n\n // Synchronous mirror of `progress`, used by complete/toggle/dismiss/reset to read the current\n // state instead of the render-time `progress` closure. Two of those calls can happen back to\n // back in the same tick with no render in between (completeItemsForTour ticking two items that\n // share a tourId is the case that surfaced this): reading the stale closure would make the\n // second call compute its next value from a snapshot that does not include the first call's\n // write, silently dropping it. progressRef is updated synchronously by applyProgress below, so\n // consecutive calls compose correctly.\n const progressRef = useRef(progress)\n\n const guide = useContext(GuideContext)\n\n const storageWarnedRef = useRef(false)\n const warnStorageFailure = useCallback((error: unknown) => {\n if (storageWarnedRef.current) return\n storageWarnedRef.current = true\n console.warn('[guide] storage failed; checklist progress will not be persisted', error)\n }, [])\n\n const noGuideWarnedRef = useRef(false)\n const warnNoGuide = useCallback(() => {\n if (noGuideWarnedRef.current) return\n noGuideWarnedRef.current = true\n console.warn('[guide] a checklist item needs a GuideProvider to launch a tour')\n }, [])\n\n // guide.start rejects for a tour id the GuideProvider does not hold (a typo in an item's\n // tourId being the obvious way to hit this). Without a catch here that rejection is\n // unhandled: nothing warns and the failure is invisible. Same once-only shape as\n // warnNoGuide and warnStorageFailure above.\n const tourStartFailedWarnedRef = useRef(false)\n const warnTourStartFailure = useCallback((error: unknown) => {\n if (tourStartFailedWarnedRef.current) return\n tourStartFailedWarnedRef.current = true\n console.warn('[guide] starting a tour for a checklist item failed', error)\n }, [])\n\n // Same once-only shape as warnNoGuide and warnTourStartFailure: a missing navigate function\n // is a host wiring mistake, so repeating the warning on every activation only buries it.\n const noNavigateWarnedRef = useRef(false)\n const warnNoNavigate = useCallback(() => {\n if (noNavigateWarnedRef.current) return\n noNavigateWarnedRef.current = true\n console.warn('[guide] a checklist item declares an href but no navigate function was provided')\n }, [])\n\n const onEventRef = useRef(onEvent)\n onEventRef.current = onEvent\n const emit = useCallback((event: GuideEvent) => onEventRef.current?.(event), [])\n\n // Restore persisted progress once on mount: later checklist prop changes are not re-read.\n useEffect(() => {\n if (!storage) return\n let cancelled = false\n void (async () => {\n const restored: Record<string, ChecklistProgress> = {}\n for (const candidate of checklists) {\n try {\n const stored = await storage.read<unknown>(`checklist:${candidate.id}`)\n if (isChecklistProgress(stored)) restored[candidate.id] = stored\n } catch (error) {\n warnStorageFailure(error)\n }\n }\n if (!cancelled && Object.keys(restored).length > 0) {\n // A read that was already in flight must never undo something the user did while it\n // was running. With a server-backed storage the read can take hundreds of\n // milliseconds, and the list is on screen and interactive for all of it.\n //\n // Merging entry by entry rather than replacing them is what makes that true. Every\n // checklist starts empty at mount, so the moves a user makes before the read lands are\n // one-way in practice: ticking an item and dismissing the list. The union of the stored\n // completions with the live ones, dismissed if either side says so, keeps both. Replacing\n // the live entry instead erased a tick the user could see on screen, and the next toggle\n // persisted the erased state.\n //\n // The union cannot subtract, so the two moves that do subtract lose against a read still\n // in flight: unticking an item the stored value has ticked, and reset. Both come back\n // when the read lands. That window is bounded by one read at mount and it is strictly\n // better than the replace it replaced, which lost these too and lost ticks besides. If a\n // deliberate clearing ever has to survive the window, it needs to be sequenced against\n // the read rather than merged with it.\n const merged = { ...progressRef.current }\n for (const [checklistId, stored] of Object.entries(restored)) {\n const live = merged[checklistId] ?? emptyProgress\n merged[checklistId] = {\n completed: live.completed.concat(\n stored.completed.filter((id) => !live.completed.includes(id)),\n ),\n dismissed: live.dismissed || stored.dismissed,\n }\n }\n progressRef.current = merged\n setProgress(merged)\n }\n })()\n return () => {\n cancelled = true\n }\n // Reads only on mount and when storage itself changes: the checklists prop is not\n // watched, so a later change to it does not trigger a re-read of persisted progress.\n }, [storage])\n\n // Applies one checklist's next progress. Reads and writes go through progressRef, not a\n // setProgress updater function, so this composes correctly across synchronous calls (see\n // progressRef above) without ever putting decision logic or emit calls inside a React updater:\n // Strict Mode invokes updater functions passed to setState twice to catch impurities, and an\n // emit inside one would double-fire.\n const applyProgress = useCallback(\n (checklistId: string, next: ChecklistProgress) => {\n const merged = { ...progressRef.current, [checklistId]: next }\n progressRef.current = merged\n setProgress(merged)\n if (!storage) return\n try {\n void Promise.resolve(storage.write(`checklist:${checklistId}`, next)).catch(\n warnStorageFailure,\n )\n } catch (error) {\n warnStorageFailure(error)\n }\n },\n [storage, warnStorageFailure],\n )\n\n // Shared lookup for every action below: one place to warn on an unknown checklist or item id,\n // so toggle, complete, activate, dismiss and reset all reject bad ids the same way.\n const resolveChecklist = useCallback(\n (checklistId: string): Checklist | null => {\n const checklist = checklistsById.get(checklistId)\n if (!checklist) {\n console.warn(`[guide] unknown checklist \"${checklistId}\"`)\n return null\n }\n return checklist\n },\n [checklistsById],\n )\n\n const resolveItem = useCallback(\n (checklistId: string, itemId: string) => {\n const checklist = resolveChecklist(checklistId)\n if (!checklist) return null\n const item = checklist.items.find((candidate) => candidate.id === itemId)\n if (!item) {\n console.warn(`[guide] unknown checklist item \"${itemId}\"`)\n return null\n }\n return { checklist, item }\n },\n [resolveChecklist],\n )\n\n // Idempotent: ticking an item that is already ticked does nothing and emits nothing. This is\n // the one place item-complete and checklist-complete are emitted, so toggle's ticking half and\n // activate's plain-item branch both delegate here rather than duplicating that logic.\n const complete = useCallback(\n (checklistId: string, itemId: string) => {\n const resolved = resolveItem(checklistId, itemId)\n if (!resolved) return\n const { checklist } = resolved\n\n const current = progressRef.current[checklistId] ?? emptyProgress\n if (current.completed.includes(itemId)) return\n\n const wasComplete =\n checklist.items.length > 0 &&\n checklist.items.every((candidate) => current.completed.includes(candidate.id))\n\n const nextCompleted = [...current.completed, itemId]\n applyProgress(checklistId, { ...current, completed: nextCompleted })\n emit({ type: 'checklist:item-complete', checklistId, itemId })\n\n const isNowComplete =\n checklist.items.length > 0 &&\n checklist.items.every((candidate) => nextCompleted.includes(candidate.id))\n if (isNowComplete && !wasComplete) emit({ type: 'checklist:complete', checklistId })\n },\n [resolveItem, applyProgress, emit],\n )\n\n // Marks every item across every checklist whose tourId matches the finished tour. Delegates to\n // complete, which is idempotent, so an item already ticked produces no event.\n const completeItemsForTour = useCallback(\n (tourId: string) => {\n for (const candidate of checklists) {\n for (const item of candidate.items) {\n if (item.tourId === tourId) complete(candidate.id, item.id)\n }\n }\n },\n [checklists, complete],\n )\n\n // Watches the tour state for a finished run and ticks the matching item. The guard is keyed by\n // tourId rather than a plain boolean: leaving the completed state (STOP, or starting another\n // tour) clears it, so running the same tour again after a reset can tick it again.\n //\n // Correctness does not depend on this guard. `complete` is idempotent, so deleting the ref\n // entirely leaves every test green; it only saves a repeated walk of the checklists while a\n // completed tour stays on screen. Do not read it as the thing that prevents a double tick.\n const handledCompletionRef = useRef<string | null>(null)\n useEffect(() => {\n const state = guide?.state\n if (!state || state.status !== 'completed' || !state.tourId) {\n handledCompletionRef.current = null\n return\n }\n if (handledCompletionRef.current === state.tourId) return\n handledCompletionRef.current = state.tourId\n completeItemsForTour(state.tourId)\n }, [guide?.state, completeItemsForTour])\n\n const toggle = useCallback(\n (checklistId: string, itemId: string) => {\n const resolved = resolveItem(checklistId, itemId)\n if (!resolved) return\n\n const current = progressRef.current[checklistId] ?? emptyProgress\n if (current.completed.includes(itemId)) {\n const nextCompleted = current.completed.filter((id) => id !== itemId)\n applyProgress(checklistId, { ...current, completed: nextCompleted })\n return\n }\n\n complete(checklistId, itemId)\n },\n [resolveItem, applyProgress, complete],\n )\n\n const dismiss = useCallback(\n (checklistId: string) => {\n if (!resolveChecklist(checklistId)) return\n const current = progressRef.current[checklistId] ?? emptyProgress\n applyProgress(checklistId, { ...current, dismissed: true })\n emit({ type: 'checklist:dismiss', checklistId })\n },\n [resolveChecklist, applyProgress, emit],\n )\n\n const reset = useCallback(\n (checklistId: string) => {\n if (!resolveChecklist(checklistId)) return\n applyProgress(checklistId, { completed: [], dismissed: false })\n },\n [resolveChecklist, applyProgress],\n )\n\n const activate = useCallback(\n (checklistId: string, itemId: string) => {\n const resolved = resolveItem(checklistId, itemId)\n if (!resolved) return\n const { item } = resolved\n\n if (item.tourId) {\n if (!guide) {\n warnNoGuide()\n return\n }\n void guide.start(item.tourId).catch(warnTourStartFailure)\n return\n }\n\n if (item.href) {\n if (!navigate) {\n warnNoNavigate()\n return\n }\n navigate(item.href)\n return\n }\n\n toggle(checklistId, itemId)\n },\n [resolveItem, guide, navigate, toggle, warnNoGuide, warnNoNavigate, warnTourStartFailure],\n )\n\n const value = useMemo<ChecklistContextValue>(\n () => ({ checklists, progress, translate, activate, toggle, complete, dismiss, reset }),\n [checklists, progress, translate, activate, toggle, complete, dismiss, reset],\n )\n\n return <ChecklistContext.Provider value={value}>{children}</ChecklistContext.Provider>\n}\n","'use client'\n\nimport { useContext, useMemo } from 'react'\nimport { ChecklistContext } from './ChecklistProvider'\nimport { resolveText } from './resolveText'\nimport type { ResolvedChecklistItem } from './types'\n\nexport interface UseChecklistResult {\n items: ResolvedChecklistItem[]\n completedCount: number\n total: number\n isComplete: boolean\n dismissed: boolean\n activate: (itemId: string) => void\n toggle: (itemId: string) => void\n complete: (itemId: string) => void\n dismiss: () => void\n reset: () => void\n}\n\nexport function useChecklist(checklistId: string): UseChecklistResult {\n const context = useContext(ChecklistContext)\n if (!context)\n throw new Error('[guide] useChecklist must be used inside a ChecklistProvider')\n\n const checklist = context.checklists.find((entry) => entry.id === checklistId)\n if (!checklist) throw new Error(`[guide] unknown checklist \"${checklistId}\"`)\n\n const progress = context.progress[checklistId]\n const completed = progress?.completed ?? []\n const dismissed = progress?.dismissed ?? false\n const translate = context.translate\n\n const items = useMemo<ResolvedChecklistItem[]>(\n () =>\n checklist.items.map((item) => ({\n id: item.id,\n title: resolveText(item.title, item.titleKey, translate),\n body: resolveText(item.body, item.bodyKey, translate),\n completed: completed.includes(item.id),\n tourId: item.tourId,\n href: item.href,\n })),\n [checklist, completed, translate],\n )\n\n const total = checklist.items.length\n const completedCount = items.filter((item) => item.completed).length\n const isComplete = total > 0 && completedCount === total\n\n const { activate, toggle, complete, dismiss, reset } = context\n\n return useMemo(\n () => ({\n items,\n completedCount,\n total,\n isComplete,\n dismissed,\n activate: (itemId: string) => activate(checklistId, itemId),\n toggle: (itemId: string) => toggle(checklistId, itemId),\n complete: (itemId: string) => complete(checklistId, itemId),\n dismiss: () => dismiss(checklistId),\n reset: () => reset(checklistId),\n }),\n [\n items,\n completedCount,\n total,\n isComplete,\n dismissed,\n activate,\n toggle,\n complete,\n dismiss,\n reset,\n checklistId,\n ],\n )\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -35,9 +35,40 @@ interface TourProgress {
|
|
|
35
35
|
status: 'in-progress' | 'completed';
|
|
36
36
|
stepIndex: number;
|
|
37
37
|
}
|
|
38
|
+
interface ChecklistItem {
|
|
39
|
+
id: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
titleKey?: string;
|
|
42
|
+
body?: string;
|
|
43
|
+
bodyKey?: string;
|
|
44
|
+
/** Tour launched when the item is activated. Completing it completes the item. */
|
|
45
|
+
tourId?: string;
|
|
46
|
+
/** Path navigated to when the item is activated and carries no tour. */
|
|
47
|
+
href?: string;
|
|
48
|
+
}
|
|
49
|
+
interface Checklist {
|
|
50
|
+
id: string;
|
|
51
|
+
items: ChecklistItem[];
|
|
52
|
+
}
|
|
53
|
+
interface ChecklistProgress {
|
|
54
|
+
completed: string[];
|
|
55
|
+
dismissed: boolean;
|
|
56
|
+
}
|
|
57
|
+
interface ResolvedChecklistItem {
|
|
58
|
+
id: string;
|
|
59
|
+
title: string;
|
|
60
|
+
body: string;
|
|
61
|
+
completed: boolean;
|
|
62
|
+
tourId?: string;
|
|
63
|
+
href?: string;
|
|
64
|
+
}
|
|
38
65
|
interface GuideStorage {
|
|
39
|
-
|
|
40
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Reads a previously written value. The key is namespaced by the caller,
|
|
68
|
+
* `tour:<id>` or `checklist:<id>`, so one storage serves both.
|
|
69
|
+
*/
|
|
70
|
+
read<T>(key: string): Promise<T | null>;
|
|
71
|
+
write<T>(key: string, value: T): Promise<void>;
|
|
41
72
|
}
|
|
42
73
|
type GuideEvent = {
|
|
43
74
|
type: 'tour:start';
|
|
@@ -60,11 +91,31 @@ type GuideEvent = {
|
|
|
60
91
|
tourId: string;
|
|
61
92
|
stepIndex: number;
|
|
62
93
|
target: string;
|
|
94
|
+
} | {
|
|
95
|
+
type: 'checklist:item-complete';
|
|
96
|
+
checklistId: string;
|
|
97
|
+
itemId: string;
|
|
98
|
+
} | {
|
|
99
|
+
type: 'checklist:complete';
|
|
100
|
+
checklistId: string;
|
|
101
|
+
} | {
|
|
102
|
+
type: 'checklist:dismiss';
|
|
103
|
+
checklistId: string;
|
|
63
104
|
};
|
|
64
105
|
type Translate = (key: string) => string;
|
|
65
106
|
|
|
66
|
-
declare function createMemoryStorage(initial?: Record<string,
|
|
107
|
+
declare function createMemoryStorage(initial?: Record<string, unknown>): GuideStorage;
|
|
67
108
|
declare function createBrowserStorage(namespace?: string): GuideStorage;
|
|
109
|
+
/**
|
|
110
|
+
* A stored value survives code changes, browser extensions and hand editing,
|
|
111
|
+
* so nothing read back is trusted until its shape is checked.
|
|
112
|
+
*/
|
|
113
|
+
declare function isTourProgress(value: unknown): value is TourProgress;
|
|
114
|
+
/**
|
|
115
|
+
* Same defensive posture as isTourProgress: a stored checklist value is
|
|
116
|
+
* never trusted until its shape is checked.
|
|
117
|
+
*/
|
|
118
|
+
declare function isChecklistProgress(value: unknown): value is ChecklistProgress;
|
|
68
119
|
|
|
69
120
|
declare function isLiteralRoute(pattern: string): boolean;
|
|
70
121
|
declare function matchRoute(pattern: string, pathname: string): boolean;
|
|
@@ -172,4 +223,41 @@ declare function findMissingTargets(tour: Tour, location: string | undefined, at
|
|
|
172
223
|
|
|
173
224
|
declare function useGuideStep(): ActiveStep | null;
|
|
174
225
|
|
|
175
|
-
|
|
226
|
+
declare function resolveText(value: string | undefined, key: string | undefined, translate: Translate | undefined): string;
|
|
227
|
+
|
|
228
|
+
interface ChecklistContextValue {
|
|
229
|
+
checklists: Checklist[];
|
|
230
|
+
progress: Record<string, ChecklistProgress>;
|
|
231
|
+
translate?: Translate;
|
|
232
|
+
activate: (checklistId: string, itemId: string) => void;
|
|
233
|
+
toggle: (checklistId: string, itemId: string) => void;
|
|
234
|
+
complete: (checklistId: string, itemId: string) => void;
|
|
235
|
+
dismiss: (checklistId: string) => void;
|
|
236
|
+
reset: (checklistId: string) => void;
|
|
237
|
+
}
|
|
238
|
+
declare const ChecklistContext: react.Context<ChecklistContextValue | null>;
|
|
239
|
+
interface ChecklistProviderProps {
|
|
240
|
+
checklists: Checklist[];
|
|
241
|
+
children: ReactNode;
|
|
242
|
+
storage?: GuideStorage;
|
|
243
|
+
translate?: Translate;
|
|
244
|
+
navigate?: (path: string) => void;
|
|
245
|
+
onEvent?: (event: GuideEvent) => void;
|
|
246
|
+
}
|
|
247
|
+
declare function ChecklistProvider({ checklists, children, storage, translate, navigate, onEvent, }: ChecklistProviderProps): react.JSX.Element;
|
|
248
|
+
|
|
249
|
+
interface UseChecklistResult {
|
|
250
|
+
items: ResolvedChecklistItem[];
|
|
251
|
+
completedCount: number;
|
|
252
|
+
total: number;
|
|
253
|
+
isComplete: boolean;
|
|
254
|
+
dismissed: boolean;
|
|
255
|
+
activate: (itemId: string) => void;
|
|
256
|
+
toggle: (itemId: string) => void;
|
|
257
|
+
complete: (itemId: string) => void;
|
|
258
|
+
dismiss: () => void;
|
|
259
|
+
reset: () => void;
|
|
260
|
+
}
|
|
261
|
+
declare function useChecklist(checklistId: string): UseChecklistResult;
|
|
262
|
+
|
|
263
|
+
export { type ActiveStep, type Checklist, ChecklistContext, type ChecklistContextValue, type ChecklistItem, type ChecklistProgress, ChecklistProvider, type ChecklistProviderProps, GuideContext, type GuideContextValue, type GuideEvent, GuideProvider, type GuideProviderProps, type GuideStorage, type MissingTargetPolicy, type Placement, type Rect, type ResolvedChecklistItem, type Step, type Tour, type TourAction, type TourProgress, type TourState, type TourStatus, type Translate, type UseChecklistResult, type UseFocusTrapOptions, type UseTargetElementOptions, type UseTourResult, createBrowserStorage, createMemoryStorage, findMissingTargets, initialTourState, isChecklistProgress, isLiteralRoute, isTourProgress, matchRoute, resolveText, tourReducer, useAnnouncer, useChecklist, useElementRect, useFocusTrap, useGuideStep, usePrefersReducedMotion, useTargetElement, useTour };
|
package/dist/index.d.ts
CHANGED
|
@@ -35,9 +35,40 @@ interface TourProgress {
|
|
|
35
35
|
status: 'in-progress' | 'completed';
|
|
36
36
|
stepIndex: number;
|
|
37
37
|
}
|
|
38
|
+
interface ChecklistItem {
|
|
39
|
+
id: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
titleKey?: string;
|
|
42
|
+
body?: string;
|
|
43
|
+
bodyKey?: string;
|
|
44
|
+
/** Tour launched when the item is activated. Completing it completes the item. */
|
|
45
|
+
tourId?: string;
|
|
46
|
+
/** Path navigated to when the item is activated and carries no tour. */
|
|
47
|
+
href?: string;
|
|
48
|
+
}
|
|
49
|
+
interface Checklist {
|
|
50
|
+
id: string;
|
|
51
|
+
items: ChecklistItem[];
|
|
52
|
+
}
|
|
53
|
+
interface ChecklistProgress {
|
|
54
|
+
completed: string[];
|
|
55
|
+
dismissed: boolean;
|
|
56
|
+
}
|
|
57
|
+
interface ResolvedChecklistItem {
|
|
58
|
+
id: string;
|
|
59
|
+
title: string;
|
|
60
|
+
body: string;
|
|
61
|
+
completed: boolean;
|
|
62
|
+
tourId?: string;
|
|
63
|
+
href?: string;
|
|
64
|
+
}
|
|
38
65
|
interface GuideStorage {
|
|
39
|
-
|
|
40
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Reads a previously written value. The key is namespaced by the caller,
|
|
68
|
+
* `tour:<id>` or `checklist:<id>`, so one storage serves both.
|
|
69
|
+
*/
|
|
70
|
+
read<T>(key: string): Promise<T | null>;
|
|
71
|
+
write<T>(key: string, value: T): Promise<void>;
|
|
41
72
|
}
|
|
42
73
|
type GuideEvent = {
|
|
43
74
|
type: 'tour:start';
|
|
@@ -60,11 +91,31 @@ type GuideEvent = {
|
|
|
60
91
|
tourId: string;
|
|
61
92
|
stepIndex: number;
|
|
62
93
|
target: string;
|
|
94
|
+
} | {
|
|
95
|
+
type: 'checklist:item-complete';
|
|
96
|
+
checklistId: string;
|
|
97
|
+
itemId: string;
|
|
98
|
+
} | {
|
|
99
|
+
type: 'checklist:complete';
|
|
100
|
+
checklistId: string;
|
|
101
|
+
} | {
|
|
102
|
+
type: 'checklist:dismiss';
|
|
103
|
+
checklistId: string;
|
|
63
104
|
};
|
|
64
105
|
type Translate = (key: string) => string;
|
|
65
106
|
|
|
66
|
-
declare function createMemoryStorage(initial?: Record<string,
|
|
107
|
+
declare function createMemoryStorage(initial?: Record<string, unknown>): GuideStorage;
|
|
67
108
|
declare function createBrowserStorage(namespace?: string): GuideStorage;
|
|
109
|
+
/**
|
|
110
|
+
* A stored value survives code changes, browser extensions and hand editing,
|
|
111
|
+
* so nothing read back is trusted until its shape is checked.
|
|
112
|
+
*/
|
|
113
|
+
declare function isTourProgress(value: unknown): value is TourProgress;
|
|
114
|
+
/**
|
|
115
|
+
* Same defensive posture as isTourProgress: a stored checklist value is
|
|
116
|
+
* never trusted until its shape is checked.
|
|
117
|
+
*/
|
|
118
|
+
declare function isChecklistProgress(value: unknown): value is ChecklistProgress;
|
|
68
119
|
|
|
69
120
|
declare function isLiteralRoute(pattern: string): boolean;
|
|
70
121
|
declare function matchRoute(pattern: string, pathname: string): boolean;
|
|
@@ -172,4 +223,41 @@ declare function findMissingTargets(tour: Tour, location: string | undefined, at
|
|
|
172
223
|
|
|
173
224
|
declare function useGuideStep(): ActiveStep | null;
|
|
174
225
|
|
|
175
|
-
|
|
226
|
+
declare function resolveText(value: string | undefined, key: string | undefined, translate: Translate | undefined): string;
|
|
227
|
+
|
|
228
|
+
interface ChecklistContextValue {
|
|
229
|
+
checklists: Checklist[];
|
|
230
|
+
progress: Record<string, ChecklistProgress>;
|
|
231
|
+
translate?: Translate;
|
|
232
|
+
activate: (checklistId: string, itemId: string) => void;
|
|
233
|
+
toggle: (checklistId: string, itemId: string) => void;
|
|
234
|
+
complete: (checklistId: string, itemId: string) => void;
|
|
235
|
+
dismiss: (checklistId: string) => void;
|
|
236
|
+
reset: (checklistId: string) => void;
|
|
237
|
+
}
|
|
238
|
+
declare const ChecklistContext: react.Context<ChecklistContextValue | null>;
|
|
239
|
+
interface ChecklistProviderProps {
|
|
240
|
+
checklists: Checklist[];
|
|
241
|
+
children: ReactNode;
|
|
242
|
+
storage?: GuideStorage;
|
|
243
|
+
translate?: Translate;
|
|
244
|
+
navigate?: (path: string) => void;
|
|
245
|
+
onEvent?: (event: GuideEvent) => void;
|
|
246
|
+
}
|
|
247
|
+
declare function ChecklistProvider({ checklists, children, storage, translate, navigate, onEvent, }: ChecklistProviderProps): react.JSX.Element;
|
|
248
|
+
|
|
249
|
+
interface UseChecklistResult {
|
|
250
|
+
items: ResolvedChecklistItem[];
|
|
251
|
+
completedCount: number;
|
|
252
|
+
total: number;
|
|
253
|
+
isComplete: boolean;
|
|
254
|
+
dismissed: boolean;
|
|
255
|
+
activate: (itemId: string) => void;
|
|
256
|
+
toggle: (itemId: string) => void;
|
|
257
|
+
complete: (itemId: string) => void;
|
|
258
|
+
dismiss: () => void;
|
|
259
|
+
reset: () => void;
|
|
260
|
+
}
|
|
261
|
+
declare function useChecklist(checklistId: string): UseChecklistResult;
|
|
262
|
+
|
|
263
|
+
export { type ActiveStep, type Checklist, ChecklistContext, type ChecklistContextValue, type ChecklistItem, type ChecklistProgress, ChecklistProvider, type ChecklistProviderProps, GuideContext, type GuideContextValue, type GuideEvent, GuideProvider, type GuideProviderProps, type GuideStorage, type MissingTargetPolicy, type Placement, type Rect, type ResolvedChecklistItem, type Step, type Tour, type TourAction, type TourProgress, type TourState, type TourStatus, type Translate, type UseChecklistResult, type UseFocusTrapOptions, type UseTargetElementOptions, type UseTourResult, createBrowserStorage, createMemoryStorage, findMissingTargets, initialTourState, isChecklistProgress, isLiteralRoute, isTourProgress, matchRoute, resolveText, tourReducer, useAnnouncer, useChecklist, useElementRect, useFocusTrap, useGuideStep, usePrefersReducedMotion, useTargetElement, useTour };
|