react-headless-tour 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/TourContext.tsx","../src/motion.ts","../src/useTargetRect.ts","../src/TourOverlay.tsx","../src/TourPopover.tsx","../src/DefaultCard.tsx"],"sourcesContent":["export { TourProvider, useTour } from \"./TourContext\";\nexport { DefaultCard } from \"./DefaultCard\";\nexport type {\n TourStep,\n TourControls,\n TourCardProps,\n TourArrowProps,\n TourComponents,\n TourClassNames,\n TourProviderProps,\n TourStopReason,\n TargetRect,\n Placement,\n} from \"./types\";\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEntered, useReducedMotion } from \"./motion\";\nimport type { TourControls, TourProviderProps, TourStep, TourStopReason } from \"./types\";\nimport { resolveTarget, useTargetRect } from \"./useTargetRect\";\nimport { TourOverlay } from \"./TourOverlay\";\nimport { TourPopover } from \"./TourPopover\";\n\nconst TourContext = createContext<TourControls | null>(null);\n\n/** How long the closing fade runs before the tour UI unmounts, in ms. */\nconst EXIT_DURATION_MS = 220;\n\n/** Read tour state and control the tour from anywhere under <TourProvider>. */\nexport function useTour(): TourControls {\n const ctx = useContext(TourContext);\n if (!ctx) throw new Error(\"useTour must be used within a <TourProvider>\");\n return ctx;\n}\n\ntype Phase = \"idle\" | \"active\" | \"closing\";\n\n/** Fixed full-viewport layer that fades the tour UI in and out. */\nfunction TourLayer({\n closing,\n zIndex,\n className,\n theme,\n children,\n}: {\n closing: boolean;\n zIndex: number;\n className?: string;\n theme?: CSSProperties;\n children: ReactNode;\n}) {\n const entered = useEntered();\n const reducedMotion = useReducedMotion();\n return (\n <div\n data-tour-root=\"\"\n className={className}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: `var(--tour-z-index, ${zIndex})` as unknown as number,\n pointerEvents: \"none\",\n opacity: entered && !closing ? 1 : 0,\n transition: reducedMotion ? undefined : `opacity ${EXIT_DURATION_MS}ms ease`,\n ...theme,\n }}\n >\n {children}\n </div>\n );\n}\n\nexport function TourProvider(props: TourProviderProps) {\n const {\n children,\n steps,\n autoStart = false,\n stepIndex: controlledIndex,\n onStepChange,\n onStart,\n onStop,\n keyboard = true,\n lockScroll = false,\n scrollIntoViewOptions = { behavior: \"smooth\", block: \"center\", inline: \"nearest\" },\n portalContainer,\n } = props;\n\n const [mounted, setMounted] = useState(false);\n const [phase, setPhase] = useState<Phase>(\"idle\");\n const [internalIndex, setInternalIndex] = useState(0);\n const isControlled = controlledIndex !== undefined;\n\n const isActive = phase === \"active\";\n const stepIndex = isActive ? (isControlled ? controlledIndex! : internalIndex) : -1;\n const step: TourStep | null =\n stepIndex >= 0 && stepIndex < steps.length ? steps[stepIndex] : null;\n\n // Snapshot of the last step so the closing fade can keep rendering it.\n const closingSnapshot = useRef<{ step: TourStep; stepIndex: number } | null>(null);\n const exitTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Keep latest values in refs so control callbacks stay referentially stable.\n const stateRef = useRef({ steps, stepIndex, step, phase, onStepChange, onStart, onStop });\n stateRef.current = { steps, stepIndex, step, phase, onStepChange, onStart, onStop };\n\n useEffect(() => setMounted(true), []);\n useEffect(\n () => () => {\n if (exitTimer.current) clearTimeout(exitTimer.current);\n },\n []\n );\n\n const setIndex = useCallback(\n (index: number) => {\n const s = stateRef.current;\n const clamped = Math.max(0, Math.min(index, s.steps.length - 1));\n if (clamped === s.stepIndex) return;\n s.step?.onExit?.(s.step, s.stepIndex);\n if (!isControlled) setInternalIndex(clamped);\n s.onStepChange?.(clamped, s.steps[clamped]);\n },\n [isControlled]\n );\n\n const start = useCallback(\n (atIndex = 0) => {\n const s = stateRef.current;\n if (s.phase === \"active\" || s.steps.length === 0) return;\n if (exitTimer.current) clearTimeout(exitTimer.current);\n const clamped = Math.max(0, Math.min(atIndex, s.steps.length - 1));\n if (!isControlled) setInternalIndex(clamped);\n else s.onStepChange?.(clamped, s.steps[clamped]);\n setPhase(\"active\");\n s.onStart?.();\n },\n [isControlled]\n );\n\n const stop = useCallback((reason: TourStopReason = \"programmatic\") => {\n const s = stateRef.current;\n if (s.phase !== \"active\") return;\n s.step?.onExit?.(s.step, s.stepIndex);\n if (s.step) closingSnapshot.current = { step: s.step, stepIndex: s.stepIndex };\n setPhase(\"closing\");\n if (exitTimer.current) clearTimeout(exitTimer.current);\n exitTimer.current = setTimeout(() => {\n closingSnapshot.current = null;\n setPhase(\"idle\");\n }, EXIT_DURATION_MS);\n s.onStop?.(reason, s.stepIndex);\n }, []);\n\n const next = useCallback(() => {\n const s = stateRef.current;\n if (s.phase !== \"active\") return;\n if (s.stepIndex >= s.steps.length - 1) stop(\"finished\");\n else setIndex(s.stepIndex + 1);\n }, [setIndex, stop]);\n\n const prev = useCallback(() => {\n const s = stateRef.current;\n if (s.phase !== \"active\" || s.stepIndex <= 0) return;\n setIndex(s.stepIndex - 1);\n }, [setIndex]);\n\n const goTo = useCallback((index: number) => setIndex(index), [setIndex]);\n\n // Auto-start once mounted.\n const autoStartedRef = useRef(false);\n useEffect(() => {\n if (autoStart && mounted && !autoStartedRef.current) {\n autoStartedRef.current = true;\n start(0);\n }\n }, [autoStart, mounted, start]);\n\n // Step lifecycle: onEnter + scroll into view.\n useEffect(() => {\n if (!isActive || !step) return;\n step.onEnter?.(step, stepIndex);\n if (!step.disableScroll) {\n const el = resolveTarget(step);\n const reducedMotion =\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n el?.scrollIntoView(\n reducedMotion ? { ...scrollIntoViewOptions, behavior: \"auto\" } : scrollIntoViewOptions\n );\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isActive, stepIndex]);\n\n // Keyboard navigation.\n useEffect(() => {\n if (!isActive || !keyboard) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") stop(\"escape\");\n else if (e.key === \"ArrowRight\" || e.key === \"Enter\") next();\n else if (e.key === \"ArrowLeft\") prev();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [isActive, keyboard, next, prev, stop]);\n\n // Optional body scroll lock.\n useEffect(() => {\n if (!isActive || !lockScroll) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previous;\n };\n }, [isActive, lockScroll]);\n\n // While closing, keep rendering the last step so the fade-out has content.\n const renderStep = step ?? closingSnapshot.current?.step ?? null;\n const renderIndex = step ? stepIndex : closingSnapshot.current?.stepIndex ?? -1;\n const targetRect = useTargetRect(renderStep, phase !== \"idle\");\n\n const controls = useMemo<TourControls>(\n () => ({\n isActive,\n stepIndex,\n totalSteps: steps.length,\n step,\n isFirst: stepIndex <= 0,\n isLast: stepIndex === steps.length - 1,\n start,\n stop,\n next,\n prev,\n goTo,\n }),\n [isActive, stepIndex, steps.length, step, start, stop, next, prev, goTo]\n );\n\n const container =\n portalContainer ?? (typeof document !== \"undefined\" ? document.body : null);\n\n const zIndex = props.zIndex ?? 10000;\n const closing = phase === \"closing\";\n\n return (\n <TourContext.Provider value={controls}>\n {children}\n {mounted &&\n container &&\n phase !== \"idle\" &&\n renderStep &&\n createPortal(\n <TourLayer\n closing={closing}\n zIndex={zIndex}\n className={props.classNames?.root}\n theme={props.theme}\n >\n {(props.showOverlay ?? true) && (\n <TourOverlay\n rect={targetRect}\n step={renderStep}\n interactive={!closing}\n padding={renderStep.spotlightPadding ?? props.spotlightPadding ?? 8}\n radius={renderStep.spotlightRadius ?? props.spotlightRadius ?? 8}\n color={props.overlayColor}\n blur={props.overlayBlur ?? 0}\n className={props.classNames?.overlay}\n onMaskClick={props.closeOnMaskClick ? () => stop(\"mask\") : undefined}\n />\n )}\n <TourPopover\n key={renderIndex}\n rect={targetRect}\n controls={controls}\n step={renderStep}\n interactive={!closing}\n offset={props.offset ?? 12}\n padding={renderStep.spotlightPadding ?? props.spotlightPadding ?? 8}\n components={props.components}\n classNames={props.classNames}\n labels={props.labels}\n />\n </TourLayer>,\n container\n )}\n </TourContext.Provider>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/** Spring-like easing for movement (slight decelerating overshoot). */\nexport const EASE_SPRING = \"cubic-bezier(0.22, 1, 0.36, 1)\";\n\n/**\n * False on first paint, true one frame later — lets CSS transitions animate\n * an element from its \"initial\" styles to its \"entered\" styles on mount.\n */\nexport function useEntered(): boolean {\n const [entered, setEntered] = useState(false);\n useEffect(() => {\n let inner = 0;\n const outer = requestAnimationFrame(() => {\n inner = requestAnimationFrame(() => setEntered(true));\n });\n return () => {\n cancelAnimationFrame(outer);\n cancelAnimationFrame(inner);\n };\n }, []);\n return entered;\n}\n\n/**\n * True while any scrolling is happening (window or nested containers),\n * falling back to false after `idleMs` without a scroll event. Used to make\n * the spotlight track its target 1:1 during scrolls instead of transitioning\n * toward a moving destination.\n */\nexport function useIsScrolling(idleMs = 150): boolean {\n const [scrolling, setScrolling] = useState(false);\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n const onScroll = () => {\n setScrolling(true);\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => setScrolling(false), idleMs);\n };\n window.addEventListener(\"scroll\", onScroll, { capture: true, passive: true });\n return () => {\n window.removeEventListener(\"scroll\", onScroll, { capture: true });\n if (timer) clearTimeout(timer);\n };\n }, [idleMs]);\n return scrolling;\n}\n\n/** Tracks the user's prefers-reduced-motion setting (SSR-safe, live-updating). */\nexport function useReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false);\n useEffect(() => {\n const mq = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n setReduced(mq.matches);\n const onChange = (e: MediaQueryListEvent) => setReduced(e.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, []);\n return reduced;\n}\n","import { useEffect, useState } from \"react\";\nimport type { TargetRect, TourStep } from \"./types\";\n\nexport function resolveTarget(step: TourStep | null): Element | null {\n if (!step?.target) return null;\n if (typeof step.target === \"function\") return step.target();\n if (typeof document === \"undefined\") return null;\n return document.querySelector(step.target);\n}\n\nfunction readRect(el: Element): TargetRect {\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, width: r.width, height: r.height };\n}\n\nfunction rectsEqual(a: TargetRect | null, b: TargetRect | null) {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;\n}\n\n/**\n * Tracks the viewport-relative rect of the active step's target, staying in\n * sync through scrolling, window resizes, element resizes and layout shifts.\n */\nexport function useTargetRect(step: TourStep | null, active: boolean): TargetRect | null {\n const [rect, setRect] = useState<TargetRect | null>(null);\n\n useEffect(() => {\n if (!active || !step) {\n setRect(null);\n return;\n }\n\n let el = resolveTarget(step);\n let frame = 0;\n let current: TargetRect | null = null;\n\n const update = () => {\n // Re-resolve in case the element mounted late (e.g. after a route change).\n if (!el || !el.isConnected) el = resolveTarget(step);\n const next = el ? readRect(el) : null;\n if (!rectsEqual(current, next)) {\n current = next;\n setRect(next);\n }\n };\n\n // A light rAF loop is the only approach that survives every way an element\n // can move (animations, sticky headers, virtualized lists, font loading).\n const tick = () => {\n update();\n frame = requestAnimationFrame(tick);\n };\n frame = requestAnimationFrame(tick);\n update();\n\n return () => cancelAnimationFrame(frame);\n }, [step, active]);\n\n return rect;\n}\n","import { useId } from \"react\";\nimport { EASE_SPRING, useIsScrolling, useReducedMotion } from \"./motion\";\nimport type { TargetRect, TourStep } from \"./types\";\n\ninterface TourOverlayProps {\n rect: TargetRect | null;\n step: TourStep;\n /** False while the tour is fading out — blockers must stop eating clicks. */\n interactive: boolean;\n padding: number;\n radius: number;\n color?: string;\n blur: number;\n className?: string;\n onMaskClick?: () => void;\n}\n\n/**\n * Dimming overlay with an animated spotlight \"hole\" cut out via an SVG mask.\n * The hole glides smoothly between targets as steps change (CSS transitions\n * on the SVG geometry properties — no animation library needed).\n */\nexport function TourOverlay({\n rect,\n step,\n interactive,\n padding,\n radius,\n color,\n blur,\n className,\n onMaskClick,\n}: TourOverlayProps) {\n const maskId = useId();\n const reducedMotion = useReducedMotion();\n const scrolling = useIsScrolling();\n\n const hole = rect\n ? {\n x: rect.x - padding,\n y: rect.y - padding,\n width: rect.width + padding * 2,\n height: rect.height + padding * 2,\n }\n : null;\n\n const fill = color ?? \"var(--tour-overlay-color, rgba(0, 0, 0, 0.55))\";\n const interactable = Boolean(step.interactable && hole);\n\n // While the page scrolls (auto scroll-into-view or the user's own), the\n // hole must stick to the target exactly — transitioning toward a moving\n // destination reads as lag. The glide only plays for stationary changes.\n const holeTransition =\n reducedMotion || scrolling\n ? undefined\n : [\"x\", \"y\", \"width\", \"height\", \"rx\"].map((p) => `${p} 350ms ${EASE_SPRING}`).join(\", \");\n\n const blockerStyle: React.CSSProperties = {\n position: \"absolute\",\n pointerEvents: interactive ? \"auto\" : \"none\",\n cursor: onMaskClick ? \"pointer\" : \"default\",\n };\n\n return (\n <div\n data-tour-overlay=\"\"\n className={className}\n style={{ position: \"absolute\", inset: 0, pointerEvents: \"none\" }}\n >\n <svg\n width=\"100%\"\n height=\"100%\"\n style={{\n position: \"absolute\",\n inset: 0,\n backdropFilter: blur ? `blur(${blur}px)` : undefined,\n WebkitBackdropFilter: blur ? `blur(${blur}px)` : undefined,\n }}\n aria-hidden=\"true\"\n >\n <defs>\n <mask id={maskId}>\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill=\"#fff\" />\n {hole && (\n <rect\n x={hole.x}\n y={hole.y}\n width={hole.width}\n height={hole.height}\n rx={radius}\n fill=\"#000\"\n style={{ transition: holeTransition }}\n />\n )}\n </mask>\n </defs>\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill={fill} mask={`url(#${maskId})`} />\n </svg>\n\n {/* Click interception. When the step is interactable we block only the\n dimmed region (four rects around the hole), leaving the target live. */}\n {interactable && hole ? (\n <>\n <div style={{ ...blockerStyle, left: 0, top: 0, right: 0, height: Math.max(0, hole.y) }} onClick={onMaskClick} />\n <div style={{ ...blockerStyle, left: 0, top: hole.y + hole.height, right: 0, bottom: 0 }} onClick={onMaskClick} />\n <div style={{ ...blockerStyle, left: 0, top: hole.y, width: Math.max(0, hole.x), height: hole.height }} onClick={onMaskClick} />\n <div style={{ ...blockerStyle, left: hole.x + hole.width, top: hole.y, right: 0, height: hole.height }} onClick={onMaskClick} />\n </>\n ) : (\n <div style={{ ...blockerStyle, inset: 0 }} onClick={onMaskClick} />\n )}\n </div>\n );\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n arrow,\n autoUpdate,\n flip,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { EASE_SPRING, useEntered, useReducedMotion } from \"./motion\";\nimport type {\n TargetRect,\n TourCardProps,\n TourClassNames,\n TourComponents,\n TourControls,\n TourProviderProps,\n TourStep,\n} from \"./types\";\nimport { DefaultCard } from \"./DefaultCard\";\n\ninterface TourPopoverProps {\n rect: TargetRect | null;\n step: TourStep;\n controls: TourControls;\n /** False while the tour is fading out. */\n interactive: boolean;\n offset: number;\n padding: number;\n components?: TourComponents;\n classNames?: TourClassNames;\n labels?: TourProviderProps[\"labels\"];\n}\n\nexport function TourPopover({\n rect,\n step,\n controls,\n interactive,\n offset: offsetDistance,\n padding,\n components,\n classNames,\n labels,\n}: TourPopoverProps) {\n const arrowRef = useRef<HTMLDivElement | null>(null);\n const popoverRef = useRef<HTMLDivElement | null>(null);\n const hasTarget = Boolean(rect);\n // Enter animation: this component remounts per step (keyed by index), so\n // `entered` flips false → true on every step change.\n const entered = useEntered();\n const reducedMotion = useReducedMotion();\n\n // Move focus into the popover on each step so screen readers announce it\n // and keyboard users can reach its controls immediately.\n useEffect(() => {\n if (interactive) popoverRef.current?.focus({ preventScroll: true });\n }, [interactive]);\n // Space actually available for the popover, kept in sync by the size()\n // middleware so large targets / small viewports can't push the card\n // off-screen.\n const [maxSize, setMaxSize] = useState<{ width: number; height: number } | null>(null);\n const maxSizeRef = useRef(maxSize);\n maxSizeRef.current = maxSize;\n\n const { refs, floatingStyles, middlewareData, placement, update, isPositioned } = useFloating({\n placement: step.placement ?? \"bottom\",\n strategy: \"fixed\",\n whileElementsMounted: autoUpdate,\n middleware: [\n offset(offsetDistance + padding),\n // If neither side of the preferred axis fits (e.g. a full-width target\n // with placement \"right\"), try the other axis too.\n flip({ padding: 12, fallbackAxisSideDirection: \"start\" }),\n // crossAxis lets shift pull the popover back into view even when that\n // means overlapping a large target.\n shift({ padding: 12, crossAxis: true }),\n size({\n padding: 12,\n apply({ availableWidth, availableHeight }) {\n const next = {\n width: Math.max(120, Math.floor(availableWidth)),\n height: Math.max(80, Math.floor(availableHeight)),\n };\n const current = maxSizeRef.current;\n if (!current || Math.abs(current.width - next.width) > 1 || Math.abs(current.height - next.height) > 1) {\n setMaxSize(next);\n }\n },\n }),\n arrow({ element: arrowRef, padding: 12 }),\n ],\n });\n\n // Anchor floating-ui to the tracked rect via a virtual element.\n useEffect(() => {\n if (!rect) return;\n refs.setReference({\n getBoundingClientRect: () => ({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.y,\n left: rect.x,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height,\n }),\n });\n update();\n }, [rect, refs, update]);\n\n const side = placement.split(\"-\")[0] as \"top\" | \"bottom\" | \"left\" | \"right\";\n\n const arrowNode = useMemo(() => {\n if (!hasTarget) return null;\n const { x, y } = middlewareData.arrow ?? {};\n const staticSide = { top: \"bottom\", bottom: \"top\", left: \"right\", right: \"left\" }[side];\n const ArrowComponent = components?.Arrow;\n return (\n <div\n ref={arrowRef}\n data-tour-arrow=\"\"\n className={classNames?.arrow}\n style={{\n position: \"absolute\",\n left: x != null ? x : undefined,\n top: y != null ? y : undefined,\n [staticSide]: \"calc(var(--tour-arrow-size, 12px) / -2)\",\n pointerEvents: \"none\",\n }}\n >\n {ArrowComponent ? (\n <ArrowComponent side={side} />\n ) : (\n <div\n style={{\n width: \"var(--tour-arrow-size, 12px)\",\n height: \"var(--tour-arrow-size, 12px)\",\n transform: \"rotate(45deg)\",\n background: \"var(--tour-bg, #ffffff)\",\n borderRadius: 2,\n }}\n />\n )}\n </div>\n );\n }, [hasTarget, middlewareData.arrow, side, components?.Arrow, classNames?.arrow]);\n\n const CustomCard = components?.Card;\n const cardProps: TourCardProps = { ...controls, step, arrow: arrowNode };\n\n const positionStyles: React.CSSProperties = hasTarget\n ? floatingStyles\n : {\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n };\n\n return (\n <div\n ref={(node) => {\n refs.setFloating(node);\n popoverRef.current = node;\n }}\n tabIndex={-1}\n data-tour-popover=\"\"\n className={classNames?.popover}\n style={{\n ...positionStyles,\n // Never paint before Floating UI has computed a real position — a\n // freshly mounted popover would otherwise flash at a stale spot.\n visibility: hasTarget && !isPositioned ? \"hidden\" : undefined,\n pointerEvents: interactive ? \"auto\" : \"none\",\n maxWidth: hasTarget && maxSize ? Math.min(maxSize.width, window.innerWidth - 24) : \"calc(100vw - 24px)\",\n maxHeight: hasTarget && maxSize ? maxSize.height : \"calc(100vh - 24px)\",\n overflowY: \"auto\",\n }}\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label={`Tour step ${controls.stepIndex + 1} of ${controls.totalSteps}${\n typeof step.title === \"string\" ? `: ${step.title}` : \"\"\n }`}\n >\n <div\n style={{\n opacity: entered ? 1 : 0,\n transform: entered\n ? \"none\"\n : `scale(0.96) translateY(${side === \"top\" ? 6 : -6}px)`,\n transition: reducedMotion\n ? undefined\n : `opacity 200ms ease, transform 250ms ${EASE_SPRING}`,\n }}\n >\n {CustomCard ? (\n <CustomCard {...cardProps} />\n ) : (\n <DefaultCard {...cardProps} labels={labels} classNames={classNames} />\n )}\n </div>\n </div>\n );\n}\n","import type { CSSProperties } from \"react\";\nimport type { TourCardProps, TourClassNames, TourProviderProps } from \"./types\";\n\n/**\n * The zero-config default card. Every visual decision is a CSS variable with a\n * neutral fallback, so it can be re-themed without touching a line of code:\n *\n * --tour-bg, --tour-fg, --tour-muted, --tour-accent, --tour-accent-fg,\n * --tour-radius, --tour-shadow, --tour-border, --tour-font,\n * --tour-max-width, --tour-padding, --tour-arrow-size\n *\n * For full control, replace it entirely via <TourProvider components={{ Card }}>.\n */\nexport function DefaultCard(\n props: TourCardProps & {\n labels?: TourProviderProps[\"labels\"];\n classNames?: TourClassNames;\n }\n) {\n const { step, stepIndex, totalSteps, isFirst, isLast, next, prev, stop, arrow, labels, classNames } = props;\n\n const buttonBase: CSSProperties = {\n font: \"inherit\",\n fontSize: \"0.875em\",\n fontWeight: 500,\n border: \"var(--tour-border, 1px solid rgba(0,0,0,0.12))\",\n borderRadius: \"calc(var(--tour-radius, 12px) * 0.6)\",\n padding: \"0.45em 0.9em\",\n cursor: \"pointer\",\n background: \"transparent\",\n color: \"inherit\",\n };\n\n return (\n <div\n data-tour-card=\"\"\n className={classNames?.card}\n style={{\n position: \"relative\",\n background: \"var(--tour-bg, #ffffff)\",\n color: \"var(--tour-fg, #1a1a1a)\",\n fontFamily: \"var(--tour-font, inherit)\",\n borderRadius: \"var(--tour-radius, 12px)\",\n boxShadow: \"var(--tour-shadow, 0 10px 38px -10px rgba(0,0,0,0.35), 0 10px 20px -15px rgba(0,0,0,0.2))\",\n padding: \"var(--tour-padding, 16px)\",\n width: \"max-content\",\n maxWidth: \"min(var(--tour-max-width, 320px), 100%)\",\n boxSizing: \"border-box\",\n }}\n >\n {arrow}\n {step.title != null && (\n <div\n data-tour-title=\"\"\n className={classNames?.title}\n style={{ fontWeight: 600, fontSize: \"1em\", marginBottom: 6 }}\n >\n {step.title}\n </div>\n )}\n {step.content != null && (\n <div\n data-tour-content=\"\"\n className={classNames?.content}\n style={{ fontSize: \"0.9em\", lineHeight: 1.5, color: \"var(--tour-muted, #555)\" }}\n >\n {step.content}\n </div>\n )}\n <div\n data-tour-footer=\"\"\n className={classNames?.footer}\n style={{ display: \"flex\", alignItems: \"center\", gap: 8, marginTop: 14 }}\n >\n <span\n data-tour-progress=\"\"\n className={classNames?.progress}\n style={{ fontSize: \"0.8em\", color: \"var(--tour-muted, #888)\", marginRight: \"auto\" }}\n >\n {labels?.progress ? labels.progress(stepIndex, totalSteps) : `${stepIndex + 1} / ${totalSteps}`}\n </span>\n <button\n type=\"button\"\n data-tour-skip=\"\"\n className={classNames?.skipButton}\n onClick={() => stop(\"skipped\")}\n style={{ ...buttonBase, border: \"none\", color: \"var(--tour-muted, #888)\" }}\n >\n {labels?.skip ?? \"Skip\"}\n </button>\n {!isFirst && (\n <button\n type=\"button\"\n data-tour-prev=\"\"\n className={classNames?.navButton}\n onClick={prev}\n style={buttonBase}\n >\n {labels?.prev ?? \"Back\"}\n </button>\n )}\n <button\n type=\"button\"\n data-tour-next=\"\"\n className={classNames?.primaryButton}\n onClick={next}\n style={{\n ...buttonBase,\n border: \"none\",\n background: \"var(--tour-accent, #1a1a1a)\",\n color: \"var(--tour-accent-fg, #ffffff)\",\n }}\n >\n {isLast ? labels?.finish ?? \"Finish\" : labels?.next ?? \"Next\"}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_react_dom","import_react","import_react","import_react","import_jsx_runtime","arrow","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,173 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties } from 'react';
3
+ import { Placement } from '@floating-ui/react-dom';
4
+ export { Placement } from '@floating-ui/react-dom';
5
+
6
+ /** A single step of the tour. */
7
+ interface TourStep {
8
+ /**
9
+ * The element to highlight: a CSS selector or a function returning the
10
+ * element. Omit it to show a centered, modal-style step (great for
11
+ * welcome/outro screens).
12
+ */
13
+ target?: string | (() => Element | null);
14
+ /** Rendered by the default Card. Custom Cards receive the whole step. */
15
+ title?: ReactNode;
16
+ /** Rendered by the default Card. Custom Cards receive the whole step. */
17
+ content?: ReactNode;
18
+ /** Preferred popover placement relative to the target. Default: "bottom". */
19
+ placement?: Placement;
20
+ /** Extra space around the target inside the spotlight, in px. */
21
+ spotlightPadding?: number;
22
+ /** Corner radius of the spotlight hole, in px. */
23
+ spotlightRadius?: number;
24
+ /** Let the user interact (click/type) with the highlighted element. */
25
+ interactable?: boolean;
26
+ /** Skip auto-scrolling the target into view for this step. */
27
+ disableScroll?: boolean;
28
+ /** Anything you want to pass through to a custom Card. */
29
+ data?: unknown;
30
+ /** Called when the step becomes active. */
31
+ onEnter?: (step: TourStep, index: number) => void;
32
+ /** Called when the step is left (next, prev, goTo or stop). */
33
+ onExit?: (step: TourStep, index: number) => void;
34
+ }
35
+ type TourStopReason = "finished" | "skipped" | "escape" | "mask" | "programmatic";
36
+ /** Everything a custom Card (or any consumer of useTour) can read and do. */
37
+ interface TourControls {
38
+ isActive: boolean;
39
+ /** Index of the active step, or -1 when the tour is off. */
40
+ stepIndex: number;
41
+ totalSteps: number;
42
+ /** The active step object, or null when the tour is off. */
43
+ step: TourStep | null;
44
+ isFirst: boolean;
45
+ isLast: boolean;
46
+ start: (atIndex?: number) => void;
47
+ stop: (reason?: TourStopReason) => void;
48
+ next: () => void;
49
+ prev: () => void;
50
+ goTo: (index: number) => void;
51
+ }
52
+ /** Props handed to a custom Card component. */
53
+ interface TourCardProps extends TourControls {
54
+ step: TourStep;
55
+ /**
56
+ * Pre-positioned arrow node. Render it anywhere inside your card (or don't,
57
+ * for an arrowless design).
58
+ */
59
+ arrow: ReactNode;
60
+ }
61
+ /** Props handed to a custom Arrow component. */
62
+ interface TourArrowProps {
63
+ /** Which side of the target the popover ended up on. */
64
+ side: "top" | "bottom" | "left" | "right";
65
+ }
66
+ interface TourComponents {
67
+ /** Replace the entire step card. You own 100% of the markup and styling. */
68
+ Card?: React.ComponentType<TourCardProps>;
69
+ /** Replace just the arrow of the default card. */
70
+ Arrow?: React.ComponentType<TourArrowProps>;
71
+ }
72
+ interface TourClassNames {
73
+ /** The fixed, full-viewport root that hosts overlay + popover. */
74
+ root?: string;
75
+ /** The SVG dimming overlay. */
76
+ overlay?: string;
77
+ /** The floating popover wrapper (positioning only — style your Card instead). */
78
+ popover?: string;
79
+ /** Default card parts (ignored when you supply your own Card). */
80
+ card?: string;
81
+ title?: string;
82
+ content?: string;
83
+ footer?: string;
84
+ progress?: string;
85
+ navButton?: string;
86
+ primaryButton?: string;
87
+ skipButton?: string;
88
+ arrow?: string;
89
+ }
90
+ interface TourProviderProps {
91
+ children: ReactNode;
92
+ steps: TourStep[];
93
+ /** Start the tour automatically on mount. Default: false. */
94
+ autoStart?: boolean;
95
+ /** Controlled step index. Pair with onStepChange. */
96
+ stepIndex?: number;
97
+ /** Fires whenever the active step changes (including via keyboard). */
98
+ onStepChange?: (index: number, step: TourStep) => void;
99
+ /** Fires when the tour starts. */
100
+ onStart?: () => void;
101
+ /** Fires when the tour stops, with the reason. */
102
+ onStop?: (reason: TourStopReason, lastIndex: number) => void;
103
+ /** Swap in your own components. This is the "bring your own theme" lever. */
104
+ components?: TourComponents;
105
+ /** Class hooks for every part — style with Tailwind, CSS modules, anything. */
106
+ classNames?: TourClassNames;
107
+ /**
108
+ * Inline CSS-variable overrides (e.g. { "--tour-accent": "#7c3aed" }).
109
+ * Applied to the tour root, so they win over global CSS.
110
+ */
111
+ theme?: CSSProperties & Record<`--${string}`, string | number>;
112
+ /** Overlay color. Default: rgba(0,0,0,0.55). Also themeable via --tour-overlay-color. */
113
+ overlayColor?: string;
114
+ /** Overlay blur radius in px (frosted-glass effect). Default: 0. */
115
+ overlayBlur?: number;
116
+ /** Default spotlight padding for all steps. Default: 8. */
117
+ spotlightPadding?: number;
118
+ /** Default spotlight corner radius for all steps. Default: 8. */
119
+ spotlightRadius?: number;
120
+ /** Render the dimming overlay at all. Default: true. */
121
+ showOverlay?: boolean;
122
+ /** Clicking the dimmed area stops the tour. Default: false. */
123
+ closeOnMaskClick?: boolean;
124
+ /** Escape stops, arrow keys navigate. Default: true. */
125
+ keyboard?: boolean;
126
+ /** Distance between target and popover, in px. Default: 12. */
127
+ offset?: number;
128
+ /** Options for scrolling targets into view. */
129
+ scrollIntoViewOptions?: ScrollIntoViewOptions;
130
+ /** Lock body scroll while the tour is active. Default: false. */
131
+ lockScroll?: boolean;
132
+ /** Where to portal the tour UI. Default: document.body. */
133
+ portalContainer?: Element | null;
134
+ /** z-index of the tour root. Default: 10000. Also --tour-z-index. */
135
+ zIndex?: number;
136
+ /** Labels for the default card — plain strings or your own nodes/i18n. */
137
+ labels?: {
138
+ next?: ReactNode;
139
+ prev?: ReactNode;
140
+ finish?: ReactNode;
141
+ skip?: ReactNode;
142
+ /** Progress formatter. Default: (i, n) => `${i + 1} / ${n}` */
143
+ progress?: (index: number, total: number) => ReactNode;
144
+ };
145
+ }
146
+ /** Viewport-relative rect of the highlighted target. */
147
+ interface TargetRect {
148
+ x: number;
149
+ y: number;
150
+ width: number;
151
+ height: number;
152
+ }
153
+
154
+ /** Read tour state and control the tour from anywhere under <TourProvider>. */
155
+ declare function useTour(): TourControls;
156
+ declare function TourProvider(props: TourProviderProps): react.JSX.Element;
157
+
158
+ /**
159
+ * The zero-config default card. Every visual decision is a CSS variable with a
160
+ * neutral fallback, so it can be re-themed without touching a line of code:
161
+ *
162
+ * --tour-bg, --tour-fg, --tour-muted, --tour-accent, --tour-accent-fg,
163
+ * --tour-radius, --tour-shadow, --tour-border, --tour-font,
164
+ * --tour-max-width, --tour-padding, --tour-arrow-size
165
+ *
166
+ * For full control, replace it entirely via <TourProvider components={{ Card }}>.
167
+ */
168
+ declare function DefaultCard(props: TourCardProps & {
169
+ labels?: TourProviderProps["labels"];
170
+ classNames?: TourClassNames;
171
+ }): react.JSX.Element;
172
+
173
+ export { DefaultCard, type TargetRect, type TourArrowProps, type TourCardProps, type TourClassNames, type TourComponents, type TourControls, TourProvider, type TourProviderProps, type TourStep, type TourStopReason, useTour };
@@ -0,0 +1,173 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties } from 'react';
3
+ import { Placement } from '@floating-ui/react-dom';
4
+ export { Placement } from '@floating-ui/react-dom';
5
+
6
+ /** A single step of the tour. */
7
+ interface TourStep {
8
+ /**
9
+ * The element to highlight: a CSS selector or a function returning the
10
+ * element. Omit it to show a centered, modal-style step (great for
11
+ * welcome/outro screens).
12
+ */
13
+ target?: string | (() => Element | null);
14
+ /** Rendered by the default Card. Custom Cards receive the whole step. */
15
+ title?: ReactNode;
16
+ /** Rendered by the default Card. Custom Cards receive the whole step. */
17
+ content?: ReactNode;
18
+ /** Preferred popover placement relative to the target. Default: "bottom". */
19
+ placement?: Placement;
20
+ /** Extra space around the target inside the spotlight, in px. */
21
+ spotlightPadding?: number;
22
+ /** Corner radius of the spotlight hole, in px. */
23
+ spotlightRadius?: number;
24
+ /** Let the user interact (click/type) with the highlighted element. */
25
+ interactable?: boolean;
26
+ /** Skip auto-scrolling the target into view for this step. */
27
+ disableScroll?: boolean;
28
+ /** Anything you want to pass through to a custom Card. */
29
+ data?: unknown;
30
+ /** Called when the step becomes active. */
31
+ onEnter?: (step: TourStep, index: number) => void;
32
+ /** Called when the step is left (next, prev, goTo or stop). */
33
+ onExit?: (step: TourStep, index: number) => void;
34
+ }
35
+ type TourStopReason = "finished" | "skipped" | "escape" | "mask" | "programmatic";
36
+ /** Everything a custom Card (or any consumer of useTour) can read and do. */
37
+ interface TourControls {
38
+ isActive: boolean;
39
+ /** Index of the active step, or -1 when the tour is off. */
40
+ stepIndex: number;
41
+ totalSteps: number;
42
+ /** The active step object, or null when the tour is off. */
43
+ step: TourStep | null;
44
+ isFirst: boolean;
45
+ isLast: boolean;
46
+ start: (atIndex?: number) => void;
47
+ stop: (reason?: TourStopReason) => void;
48
+ next: () => void;
49
+ prev: () => void;
50
+ goTo: (index: number) => void;
51
+ }
52
+ /** Props handed to a custom Card component. */
53
+ interface TourCardProps extends TourControls {
54
+ step: TourStep;
55
+ /**
56
+ * Pre-positioned arrow node. Render it anywhere inside your card (or don't,
57
+ * for an arrowless design).
58
+ */
59
+ arrow: ReactNode;
60
+ }
61
+ /** Props handed to a custom Arrow component. */
62
+ interface TourArrowProps {
63
+ /** Which side of the target the popover ended up on. */
64
+ side: "top" | "bottom" | "left" | "right";
65
+ }
66
+ interface TourComponents {
67
+ /** Replace the entire step card. You own 100% of the markup and styling. */
68
+ Card?: React.ComponentType<TourCardProps>;
69
+ /** Replace just the arrow of the default card. */
70
+ Arrow?: React.ComponentType<TourArrowProps>;
71
+ }
72
+ interface TourClassNames {
73
+ /** The fixed, full-viewport root that hosts overlay + popover. */
74
+ root?: string;
75
+ /** The SVG dimming overlay. */
76
+ overlay?: string;
77
+ /** The floating popover wrapper (positioning only — style your Card instead). */
78
+ popover?: string;
79
+ /** Default card parts (ignored when you supply your own Card). */
80
+ card?: string;
81
+ title?: string;
82
+ content?: string;
83
+ footer?: string;
84
+ progress?: string;
85
+ navButton?: string;
86
+ primaryButton?: string;
87
+ skipButton?: string;
88
+ arrow?: string;
89
+ }
90
+ interface TourProviderProps {
91
+ children: ReactNode;
92
+ steps: TourStep[];
93
+ /** Start the tour automatically on mount. Default: false. */
94
+ autoStart?: boolean;
95
+ /** Controlled step index. Pair with onStepChange. */
96
+ stepIndex?: number;
97
+ /** Fires whenever the active step changes (including via keyboard). */
98
+ onStepChange?: (index: number, step: TourStep) => void;
99
+ /** Fires when the tour starts. */
100
+ onStart?: () => void;
101
+ /** Fires when the tour stops, with the reason. */
102
+ onStop?: (reason: TourStopReason, lastIndex: number) => void;
103
+ /** Swap in your own components. This is the "bring your own theme" lever. */
104
+ components?: TourComponents;
105
+ /** Class hooks for every part — style with Tailwind, CSS modules, anything. */
106
+ classNames?: TourClassNames;
107
+ /**
108
+ * Inline CSS-variable overrides (e.g. { "--tour-accent": "#7c3aed" }).
109
+ * Applied to the tour root, so they win over global CSS.
110
+ */
111
+ theme?: CSSProperties & Record<`--${string}`, string | number>;
112
+ /** Overlay color. Default: rgba(0,0,0,0.55). Also themeable via --tour-overlay-color. */
113
+ overlayColor?: string;
114
+ /** Overlay blur radius in px (frosted-glass effect). Default: 0. */
115
+ overlayBlur?: number;
116
+ /** Default spotlight padding for all steps. Default: 8. */
117
+ spotlightPadding?: number;
118
+ /** Default spotlight corner radius for all steps. Default: 8. */
119
+ spotlightRadius?: number;
120
+ /** Render the dimming overlay at all. Default: true. */
121
+ showOverlay?: boolean;
122
+ /** Clicking the dimmed area stops the tour. Default: false. */
123
+ closeOnMaskClick?: boolean;
124
+ /** Escape stops, arrow keys navigate. Default: true. */
125
+ keyboard?: boolean;
126
+ /** Distance between target and popover, in px. Default: 12. */
127
+ offset?: number;
128
+ /** Options for scrolling targets into view. */
129
+ scrollIntoViewOptions?: ScrollIntoViewOptions;
130
+ /** Lock body scroll while the tour is active. Default: false. */
131
+ lockScroll?: boolean;
132
+ /** Where to portal the tour UI. Default: document.body. */
133
+ portalContainer?: Element | null;
134
+ /** z-index of the tour root. Default: 10000. Also --tour-z-index. */
135
+ zIndex?: number;
136
+ /** Labels for the default card — plain strings or your own nodes/i18n. */
137
+ labels?: {
138
+ next?: ReactNode;
139
+ prev?: ReactNode;
140
+ finish?: ReactNode;
141
+ skip?: ReactNode;
142
+ /** Progress formatter. Default: (i, n) => `${i + 1} / ${n}` */
143
+ progress?: (index: number, total: number) => ReactNode;
144
+ };
145
+ }
146
+ /** Viewport-relative rect of the highlighted target. */
147
+ interface TargetRect {
148
+ x: number;
149
+ y: number;
150
+ width: number;
151
+ height: number;
152
+ }
153
+
154
+ /** Read tour state and control the tour from anywhere under <TourProvider>. */
155
+ declare function useTour(): TourControls;
156
+ declare function TourProvider(props: TourProviderProps): react.JSX.Element;
157
+
158
+ /**
159
+ * The zero-config default card. Every visual decision is a CSS variable with a
160
+ * neutral fallback, so it can be re-themed without touching a line of code:
161
+ *
162
+ * --tour-bg, --tour-fg, --tour-muted, --tour-accent, --tour-accent-fg,
163
+ * --tour-radius, --tour-shadow, --tour-border, --tour-font,
164
+ * --tour-max-width, --tour-padding, --tour-arrow-size
165
+ *
166
+ * For full control, replace it entirely via <TourProvider components={{ Card }}>.
167
+ */
168
+ declare function DefaultCard(props: TourCardProps & {
169
+ labels?: TourProviderProps["labels"];
170
+ classNames?: TourClassNames;
171
+ }): react.JSX.Element;
172
+
173
+ export { DefaultCard, type TargetRect, type TourArrowProps, type TourCardProps, type TourClassNames, type TourComponents, type TourControls, TourProvider, type TourProviderProps, type TourStep, type TourStopReason, useTour };