@comitor/ui 3.0.0 → 3.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.
- package/README.md +5 -1
- package/dist/components/composite/confirm-dialog.js +56 -35
- package/dist/components/composite/confirm-dialog.js.map +1 -1
- package/dist/components/composite/search-filter-bar-constants.d.ts +3 -0
- package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
- package/dist/components/composite/table-pagination-constants.d.ts +3 -1
- package/dist/components/composite/table-pagination-constants.js.map +1 -1
- package/dist/components/composite/table-pagination.js +10 -2
- package/dist/components/composite/table-pagination.js.map +1 -1
- package/dist/components/composite/text-utils.d.ts +4 -23
- package/dist/components/composite/text-utils.js +1 -11
- package/dist/components/composite/text-utils.js.map +1 -1
- package/dist/components/composite/toast.d.ts +2 -1
- package/dist/components/composite/toast.js +3 -9
- package/dist/components/composite/toast.js.map +1 -1
- package/dist/components/ui/action-bar.js +45 -1
- package/dist/components/ui/action-bar.js.map +1 -1
- package/dist/components/ui/banner.d.ts +8 -0
- package/dist/components/ui/banner.js +149 -35
- package/dist/components/ui/banner.js.map +1 -1
- package/dist/components/ui/circular-progress.js +10 -2
- package/dist/components/ui/circular-progress.js.map +1 -1
- package/dist/components/ui/kanban.js +9 -3
- package/dist/components/ui/kanban.js.map +1 -1
- package/dist/components/ui/key-value.js +70 -76
- package/dist/components/ui/key-value.js.map +1 -1
- package/dist/components/ui/mask-input-constants.d.ts +34 -2
- package/dist/components/ui/mask-input-constants.js +87 -76
- package/dist/components/ui/mask-input-constants.js.map +1 -1
- package/dist/components/ui/mask-input.d.ts +6 -5
- package/dist/components/ui/mask-input.js +23 -21
- package/dist/components/ui/mask-input.js.map +1 -1
- package/dist/components/ui/mention.d.ts +14 -2
- package/dist/components/ui/mention.js +33 -6
- package/dist/components/ui/mention.js.map +1 -1
- package/dist/components/ui/phone-input.d.ts +18 -8
- package/dist/components/ui/phone-input.js +125 -35
- package/dist/components/ui/phone-input.js.map +1 -1
- package/dist/components/ui/rating.js +4 -2
- package/dist/components/ui/rating.js.map +1 -1
- package/dist/components/ui/scroll-spy.js +46 -31
- package/dist/components/ui/scroll-spy.js.map +1 -1
- package/dist/components/ui/slider.d.ts +1 -1
- package/dist/components/ui/slider.js +15 -1
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/sonner.js +2 -0
- package/dist/components/ui/sonner.js.map +1 -1
- package/dist/components/ui/stepper.js +26 -3
- package/dist/components/ui/stepper.js.map +1 -1
- package/dist/components/ui/time-picker.d.ts +24 -4
- package/dist/components/ui/time-picker.js +425 -162
- package/dist/components/ui/time-picker.js.map +1 -1
- package/dist/components/ui/timeline.js +45 -9
- package/dist/components/ui/timeline.js.map +1 -1
- package/dist/components/ui/toggle-group.js +12 -1
- package/dist/components/ui/toggle-group.js.map +1 -1
- package/dist/components/ui/tour.js +3 -2
- package/dist/components/ui/tour.js.map +1 -1
- package/dist/data-grid/data-grid-cell-variants.js +4 -4
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.d.ts +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js +6 -0
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
- package/dist/data-grid/data-grid-row.js +1 -1
- package/dist/data-grid/data-grid-row.js.map +1 -1
- package/dist/data-grid/data-grid-select-column.js +6 -2
- package/dist/data-grid/data-grid-select-column.js.map +1 -1
- package/dist/data-grid/data-grid-skeleton.d.ts +5 -0
- package/dist/data-grid/data-grid-skeleton.js +1 -4
- package/dist/data-grid/data-grid-skeleton.js.map +1 -1
- package/dist/data-grid/data-grid.d.ts +1 -1
- package/dist/data-grid/data-grid.js +3 -2
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/filters.js +3 -2
- package/dist/data-grid/filters.js.map +1 -1
- package/dist/data-grid/types.d.ts +7 -0
- package/dist/data-grid/use-data-grid.d.ts +1 -0
- package/dist/data-grid/use-data-grid.js +70 -24
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/data-grid/utils.d.ts +7 -0
- package/dist/data-grid/utils.js +3 -1
- package/dist/data-grid/utils.js.map +1 -1
- package/dist/i18n/locale-provider.d.ts +18 -0
- package/dist/i18n/locale-provider.js.map +1 -1
- package/dist/i18n/namespaces/rating.js +2 -1
- package/dist/i18n/namespaces/rating.js.map +1 -1
- package/dist/i18n/namespaces/search-filter-bar.js +8 -6
- package/dist/i18n/namespaces/search-filter-bar.js.map +1 -1
- package/dist/i18n/namespaces/shell.d.ts +4 -0
- package/dist/i18n/namespaces/shell.js +1 -1
- package/dist/i18n/namespaces/shell.js.map +1 -1
- package/dist/i18n/namespaces/table-pagination.js +6 -4
- package/dist/i18n/namespaces/table-pagination.js.map +1 -1
- package/dist/i18n/namespaces/toast.d.ts +3 -2
- package/dist/i18n/namespaces/toast.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/lib/collect-item-elements.d.ts +47 -0
- package/dist/lib/collect-item-elements.js +22 -0
- package/dist/lib/collect-item-elements.js.map +1 -0
- package/dist/lib/text-search.d.ts +32 -0
- package/dist/lib/text-search.js +17 -0
- package/dist/lib/text-search.js.map +1 -0
- package/dist/lib/toast-language.d.ts +8 -0
- package/dist/lib/toast-language.js +19 -0
- package/dist/lib/toast-language.js.map +1 -0
- package/dist/shell/app-shell.d.ts +1 -0
- package/dist/shell/index.d.ts +2 -1
- package/dist/shell/shell-context.d.ts +1 -0
- package/dist/shell/utils.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/tour.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/tour) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport {\n autoUpdate,\n flip,\n hide,\n limitShift,\n type Middleware,\n offset,\n arrow as onArrow,\n type Placement,\n shift,\n useFloating\n} from \"@floating-ui/react-dom\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { useComitorLabels } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { Button } from \"./button.js\";\nimport type { TourLabels } from \"./tour-constants.js\";\n\nconst ROOT_NAME = \"Tour\";\nconst PORTAL_NAME = \"TourPortal\";\nconst STEP_NAME = \"TourStep\";\nconst ARROW_NAME = \"TourArrow\";\nconst HEADER_NAME = \"TourHeader\";\nconst TITLE_NAME = \"TourTitle\";\nconst DESCRIPTION_NAME = \"TourDescription\";\nconst CLOSE_NAME = \"TourClose\";\nconst PREV_NAME = \"TourPrev\";\nconst NEXT_NAME = \"TourNext\";\nconst SKIP_NAME = \"TourSkip\";\nconst STEP_COUNTER_NAME = \"TourStepCounter\";\nconst FOOTER_NAME = \"TourFooter\";\n\nconst POINTER_DOWN_OUTSIDE = \"tour.pointerDownOutside\";\nconst INTERACT_OUTSIDE = \"tour.interactOutside\";\nconst OPEN_AUTO_FOCUS = \"tour.openAutoFocus\";\nconst CLOSE_AUTO_FOCUS = \"tour.closeAutoFocus\";\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\nconst SIDE_OPTIONS = [\"top\", \"right\", \"bottom\", \"left\"] as const;\nconst ALIGN_OPTIONS = [\"start\", \"center\", \"end\"] as const;\n\nconst DEFAULT_ALIGN_OFFSET = 0;\nconst DEFAULT_SIDE_OFFSET = 16;\nconst DEFAULT_SPOTLIGHT_PADDING = 4;\n\ntype Side = (typeof SIDE_OPTIONS)[number];\ntype Align = (typeof ALIGN_OPTIONS)[number];\ntype Direction = \"ltr\" | \"rtl\";\n\ninterface ScrollOffset {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\ntype Boundary = Element | null;\n\n/*\n * ⚠ Khác thượng nguồn: mặc định `collisionBoundary` là MỘT mảng rỗng dùng chung thay vì `[]`\n * viết tại chỗ — mảng mới mỗi lần render sẽ làm dữ liệu bước \"đổi\" liên tục (xem `ownStepData`).\n */\nconst EMPTY_BOUNDARY: Boundary[] = [];\n\n/*\n * ⚠ Khác thượng nguồn: `RefObject<HTMLElement | null>` thay vì `RefObject<HTMLElement>`. Với\n * React 19, `useRef<HTMLDivElement>(null)` có kiểu `RefObject<HTMLDivElement | null>` — kiểu gốc\n * từ chối đúng cái ref mà app nào cũng tạo ra.\n */\ntype StepTarget = string | React.RefObject<HTMLElement | null> | HTMLElement;\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype StepElement = React.ComponentRef<typeof TourStep>;\ntype CloseElement = React.ComponentRef<typeof TourClose>;\ntype PrevElement = React.ComponentRef<typeof TourPrev>;\ntype NextElement = React.ComponentRef<typeof TourNext>;\ntype SkipElement = React.ComponentRef<typeof TourSkip>;\ntype FooterElement = React.ComponentRef<typeof TourFooter>;\n\nconst OPPOSITE_SIDE: Record<Side, Side> = {\n top: \"bottom\",\n right: \"left\",\n bottom: \"top\",\n left: \"right\"\n};\n\n/**\n * @see https://github.com/radix-ui/primitives/blob/main/packages/react/focus-guards/src/focus-guards.tsx\n */\nlet focusGuardCount = 0;\n\nfunction createFocusGuard() {\n const element = document.createElement(\"span\");\n element.setAttribute(\"data-tour-focus-guard\", \"\");\n element.tabIndex = 0;\n element.style.outline = \"none\";\n element.style.opacity = \"0\";\n element.style.position = \"fixed\";\n element.style.pointerEvents = \"none\";\n return element;\n}\n\n/*\n * ⚠ Khác thượng nguồn: nhận `enabled`. Bản gốc gọi hook này vô điều kiện ở MỌI `TourStep`, nên\n * chỉ cần `Tour` nằm sẵn trong layout (đúng cách dùng onboarding: gắn sẵn, đóng mặc định) là trang\n * có thêm HAI điểm dừng Tab VÔ HÌNH ở đầu và cuối `<body>` suốt vòng đời app — người dùng bàn phím\n * Tab vào một thứ không nhìn thấy. Radix chỉ cắm lính gác khi lớp modal đang MỞ.\n */\nfunction useFocusGuards(enabled: boolean) {\n React.useEffect(() => {\n if (!enabled) return;\n\n const edgeGuards = document.querySelectorAll(\"[data-tour-focus-guard]\");\n document.body.insertAdjacentElement(\"afterbegin\", edgeGuards[0] ?? createFocusGuard());\n document.body.insertAdjacentElement(\"beforeend\", edgeGuards[1] ?? createFocusGuard());\n focusGuardCount++;\n\n return () => {\n if (focusGuardCount === 1) {\n const guards = document.querySelectorAll(\"[data-tour-focus-guard]\");\n for (const node of guards) {\n node.remove();\n }\n }\n focusGuardCount--;\n };\n }, [enabled]);\n}\n\nfunction useFocusTrap(\n containerRef: React.RefObject<HTMLElement | null>,\n enabled: boolean,\n tourOpen: boolean,\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void,\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void\n) {\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const onOpenAutoFocusRef = useAsRef(onOpenAutoFocus);\n const onCloseAutoFocusRef = useAsRef(onCloseAutoFocus);\n const tourOpenRef = useAsRef(tourOpen);\n\n React.useEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n\n function getTabbableCandidates() {\n if (!container) return [];\n\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: Element) => {\n const element = node as HTMLElement;\n const isHiddenInput = element.tagName === \"INPUT\" && (element as HTMLInputElement).type === \"hidden\";\n /*\n * ⚠ Khác thượng nguồn: bỏ qua phần tử `disabled`. `TourPrev` bị khoá ở bước đầu mà\n * `tabIndex` vẫn là 0; nếu nó là ứng viên đầu tiên thì `focus()` thất bại IM LẶNG,\n * focus ở lại ngoài bước, và phím Tab kế tiếp bị tính là \"tương tác bên ngoài\" — tour\n * ĐÓNG trong tay người dùng bàn phím.\n */\n const isDisabled = (element as HTMLButtonElement).disabled === true;\n if (element.hidden || isHiddenInput || isDisabled) return NodeFilter.FILTER_SKIP;\n return element.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n }\n });\n while (walker.nextNode()) {\n nodes.push(walker.currentNode as HTMLElement);\n }\n return nodes;\n }\n\n function getTabbableEdges() {\n const candidates = getTabbableCandidates();\n const first = candidates[0];\n const last = candidates[candidates.length - 1];\n return [first, last] as const;\n }\n\n function onFocusIn(event: FocusEvent) {\n if (!container) return;\n\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n const elementToFocus = lastFocusedElementRef.current ?? getTabbableCandidates()[0];\n elementToFocus?.focus({ preventScroll: true });\n }\n }\n\n function onKeyDown(event: KeyboardEvent) {\n if (event.key !== \"Tab\" || event.altKey || event.ctrlKey || event.metaKey) return;\n\n const [first, last] = getTabbableEdges();\n const hasTabbableElements = first && last;\n\n if (!hasTabbableElements) {\n if (document.activeElement === container) event.preventDefault();\n return;\n }\n\n if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first?.focus({ preventScroll: true });\n } else if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last?.focus({ preventScroll: true });\n }\n }\n\n const openAutoFocusEvent = new CustomEvent(OPEN_AUTO_FOCUS, EVENT_OPTIONS);\n if (onOpenAutoFocusRef.current) {\n container.addEventListener(OPEN_AUTO_FOCUS, onOpenAutoFocusRef.current as EventListener, { once: true });\n }\n container.dispatchEvent(openAutoFocusEvent);\n\n if (!openAutoFocusEvent.defaultPrevented) {\n const tabbableCandidates = getTabbableCandidates();\n if (tabbableCandidates.length > 0) {\n tabbableCandidates[0]?.focus({ preventScroll: true });\n } else {\n container.focus({ preventScroll: true });\n }\n }\n\n document.addEventListener(\"focusin\", onFocusIn);\n container.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.removeEventListener(\"focusin\", onFocusIn);\n container.removeEventListener(\"keydown\", onKeyDown);\n\n if (!tourOpenRef.current) {\n setTimeout(() => {\n const closeAutoFocusEvent = new CustomEvent(CLOSE_AUTO_FOCUS, EVENT_OPTIONS);\n if (onCloseAutoFocusRef.current) {\n container.addEventListener(CLOSE_AUTO_FOCUS, onCloseAutoFocusRef.current as EventListener, {\n once: true\n });\n }\n container.dispatchEvent(closeAutoFocusEvent);\n\n if (!closeAutoFocusEvent.defaultPrevented) {\n if (previouslyFocusedElement && document.body.contains(previouslyFocusedElement)) {\n previouslyFocusedElement.focus({ preventScroll: true });\n }\n }\n\n if (onCloseAutoFocusRef.current) {\n container.removeEventListener(CLOSE_AUTO_FOCUS, onCloseAutoFocusRef.current as EventListener);\n }\n }, 0);\n }\n };\n }, [containerRef, enabled, onOpenAutoFocusRef, onCloseAutoFocusRef, tourOpenRef]);\n}\n\nfunction getDataState(open: boolean) {\n return open ? \"open\" : \"closed\";\n}\n\ninterface StepData {\n target: StepTarget;\n align?: Align;\n alignOffset?: number;\n side?: Side;\n sideOffset?: number;\n collisionBoundary?: Boundary | Boundary[];\n collisionPadding?: number | Partial<Record<Side, number>>;\n arrowPadding?: number;\n sticky?: \"partial\" | \"always\";\n hideWhenDetached?: boolean;\n avoidCollisions?: boolean;\n onStepEnter?: () => void;\n onStepLeave?: () => void;\n required?: boolean;\n}\n\ninterface StoreState {\n open: boolean;\n value: number;\n steps: StepData[];\n maskPath: string;\n spotlightRect: { x: number; y: number; width: number; height: number } | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K], opts?: unknown) => void;\n notify: () => void;\n addStep: (stepData: StepData) => { id: string; index: number };\n removeStep: (id: string) => void;\n /** ⚠ Thêm so với thượng nguồn — xem chú thích ở `TourStep`. */\n updateStep: (id: string, stepData: StepData) => void;\n /** ⚠ Thêm so với thượng nguồn — vị trí HIỆN TẠI của một bước, `-1` nếu chưa đăng ký. */\n getStepIndex: (id: string) => number;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\nfunction getTargetElement(target: StepTarget): HTMLElement | null {\n if (typeof target === \"string\") {\n return document.querySelector(target);\n }\n if (target && \"current\" in target) {\n return target.current;\n }\n if (target instanceof HTMLElement) {\n return target;\n }\n return null;\n}\n\nfunction getDefaultScrollBehavior(): ScrollBehavior {\n if (typeof window === \"undefined\") return \"smooth\";\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\";\n}\n\n/*\n * ⚠ Khác thượng nguồn: tìm vùng cuộn gần nhất. Bản gốc chỉ `window.scrollTo`, nhưng khung\n * `AppShell` của Comitor là `h-dvh overflow-hidden` và nội dung cuộn trong `<main\n * overflow-y-auto>` — cửa sổ KHÔNG BAO GIỜ cuộn, nên `autoScroll` im lặng bỏ qua mọi đích nằm\n * dưới mép màn hình.\n */\nfunction getScrollParent(element: HTMLElement): HTMLElement | null {\n let parent = element.parentElement;\n while (parent && parent !== document.body && parent !== document.documentElement) {\n const { overflowY } = window.getComputedStyle(parent);\n const isScrollable = overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\";\n if (isScrollable && parent.scrollHeight > parent.clientHeight) return parent;\n parent = parent.parentElement;\n }\n return null;\n}\n\nfunction onScrollToElement(\n element: HTMLElement,\n scrollBehavior: ScrollBehavior = getDefaultScrollBehavior(),\n scrollOffset?: ScrollOffset\n) {\n const offset: Required<ScrollOffset> = {\n top: 100,\n bottom: 100,\n left: 0,\n right: 0,\n ...scrollOffset\n };\n const rect = element.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n\n const isInViewport =\n rect.top >= offset.top &&\n rect.bottom <= viewportHeight - offset.bottom &&\n rect.left >= offset.left &&\n rect.right <= viewportWidth - offset.right;\n\n if (!isInViewport) {\n const scrollParent = getScrollParent(element);\n if (scrollParent) {\n // Cuộn vùng chứa đúng bấy nhiêu để đích dừng cách mép trên khung nhìn `offset.top` — cùng\n // điểm đến với nhánh `window` bên dưới.\n scrollParent.scrollBy({ top: rect.top - offset.top, behavior: scrollBehavior });\n return;\n }\n\n const elementTop = rect.top + window.scrollY;\n const scrollTop = elementTop - offset.top;\n\n window.scrollTo({\n top: Math.max(0, scrollTop),\n behavior: scrollBehavior\n });\n }\n}\n\nfunction getSideAndAlignFromPlacement(placement: Placement): [Side, Align] {\n const [side, align = \"center\"] = placement.split(\"-\") as [Side, Align?];\n return [side, align];\n}\n\nfunction getPlacement(side: Side, align: Align): Placement {\n if (align === \"center\") {\n return side as Placement;\n }\n return `${side}-${align}` as Placement;\n}\n\nfunction updateMask(store: Store, targetElement: HTMLElement, padding: number = DEFAULT_SPOTLIGHT_PADDING) {\n const clientRect = targetElement.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n const x = Math.max(0, clientRect.left - padding);\n const y = Math.max(0, clientRect.top - padding);\n const width = Math.min(viewportWidth - x, clientRect.width + padding * 2);\n const height = Math.min(viewportHeight - y, clientRect.height + padding * 2);\n\n const path = `polygon(0% 0%, 0% 100%, ${x}px 100%, ${x}px ${y}px, ${x + width}px ${y}px, ${x + width}px ${y + height}px, ${x}px ${y + height}px, ${x}px 100%, 100% 100%, 100% 0%)`;\n store.setState(\"maskPath\", path);\n store.setState(\"spotlightRect\", { x, y, width, height });\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface TourContextValue {\n dir: Direction;\n alignOffset: number;\n sideOffset: number;\n spotlightPadding: number;\n dismissible: boolean;\n modal: boolean;\n stepFooter?: React.ReactElement;\n labels: TourLabels;\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;\n onInteractOutside?: (event: InteractOutsideEvent) => void;\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void;\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void;\n}\n\nconst TourContext = React.createContext<TourContextValue | null>(null);\n\nfunction useTourContext(consumerName: string) {\n const context = React.useContext(TourContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface StepContextValue {\n arrowX?: number;\n arrowY?: number;\n placedAlign: Align;\n placedSide: Side;\n shouldHideArrow: boolean;\n /** ⚠ Thêm so với thượng nguồn — id cho `aria-labelledby`/`aria-describedby` của bước. */\n titleId: string;\n descriptionId: string;\n onArrowChange: (arrow: HTMLSpanElement | null) => void;\n onFooterChange: (footer: FooterElement | null) => void;\n}\n\nconst StepContext = React.createContext<StepContextValue | null>(null);\n\nfunction useStepContext(consumerName: string) {\n const context = React.useContext(StepContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${STEP_NAME}\\``);\n }\n return context;\n}\n\nconst DefaultFooterContext = React.createContext(false);\n\ninterface PortalContextValue {\n portal: HTMLElement | null;\n onPortalChange: (node: HTMLElement | null) => void;\n}\n\nconst PortalContext = React.createContext<PortalContextValue | null>(null);\n\nfunction usePortalContext(consumerName: string) {\n const context = React.useContext(PortalContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useScrollLock(enabled: boolean) {\n React.useEffect(() => {\n if (!enabled) return;\n\n const originalStyle = window.getComputedStyle(document.body).overflow;\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n document.body.style.overflow = \"hidden\";\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n\n return () => {\n document.body.style.overflow = originalStyle;\n document.body.style.paddingRight = \"\";\n };\n }, [enabled]);\n}\n\ntype PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;\ntype InteractOutsideEvent = CustomEvent<{\n originalEvent: PointerEvent | FocusEvent;\n}>;\ntype OpenAutoFocusEvent = CustomEvent<Record<string, never>>;\ntype CloseAutoFocusEvent = CustomEvent<Record<string, never>>;\n\ninterface TourProps extends DivProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n value?: number;\n defaultValue?: number;\n onValueChange?: (step: number) => void;\n onComplete?: () => void;\n onSkip?: () => void;\n onEscapeKeyDown?: (event: KeyboardEvent) => void;\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;\n onInteractOutside?: (event: InteractOutsideEvent) => void;\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void;\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void;\n dir?: Direction;\n alignOffset?: number;\n sideOffset?: number;\n spotlightPadding?: number;\n autoScroll?: boolean;\n /** Mặc định `\"smooth\"`, hoặc `\"auto\"` khi người dùng bật `prefers-reduced-motion`. */\n scrollBehavior?: ScrollBehavior;\n scrollOffset?: ScrollOffset;\n dismissible?: boolean;\n modal?: boolean;\n stepFooter?: React.ReactElement;\n /**\n * Ghi đè chuỗi hiển thị/a11y — xem `TourLabels`. Không truyền thì theo namespace `tour` của\n * `ComitorLocaleProvider` (mặc định tiếng Anh).\n * ⚠ Thêm so với thượng nguồn: bản gốc chôn cứng chuỗi tiếng Anh trong từng nút.\n */\n labels?: Partial<TourLabels>;\n}\n\nfunction Tour(props: TourProps) {\n const {\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n value: valueProp,\n defaultValue = 0,\n onValueChange,\n onComplete,\n onSkip,\n autoScroll = true,\n /*\n * ⚠ Khác thượng nguồn: KHÔNG có giá trị mặc định ở đây. Bản gốc viết\n * `scrollBehavior = getDefaultScrollBehavior()`, tức đọc `window.matchMedia` NGAY TRONG\n * render. Để `undefined` thì tham số mặc định của `onScrollToElement` tính đúng giá trị đó\n * vào lúc CUỘN — ngoài render, và theo cài đặt reduced-motion ở thời điểm ấy.\n */\n scrollBehavior,\n scrollOffset,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus,\n dir: dirProp,\n alignOffset = DEFAULT_ALIGN_OFFSET,\n sideOffset = DEFAULT_SIDE_OFFSET,\n spotlightPadding = DEFAULT_SPOTLIGHT_PADDING,\n dismissible = true,\n modal = true,\n stepFooter,\n labels: labelsProp,\n asChild,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const [portal, setPortal] = React.useState<HTMLElement | null>(null);\n const prevOpenRef = React.useRef<boolean | undefined>(undefined);\n const previouslyFocusedElementRef = React.useRef<HTMLElement | null>(null);\n\n const stateRef = useLazyRef<StoreState>(() => ({\n open: openProp ?? defaultOpen,\n value: valueProp ?? defaultValue,\n steps: [],\n maskPath: \"\",\n spotlightRect: null\n }));\n const listenersRef = useLazyRef<Set<() => void>>(() => new Set());\n const stepIdsMapRef = useLazyRef<Map<string, number>>(() => new Map());\n const stepIdCounterRef = useLazyRef(() => ({ current: 0 }));\n const propsRef = useAsRef({\n valueProp,\n onOpenChange,\n onValueChange,\n onComplete,\n onSkip,\n onEscapeKeyDown,\n onCloseAutoFocus,\n autoScroll,\n scrollBehavior,\n scrollOffset\n });\n\n const store: Store = React.useMemo(\n () => ({\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => {\n return stateRef.current;\n },\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n stateRef.current[key] = value;\n\n if (key === \"open\" && typeof value === \"boolean\") {\n propsRef.current.onOpenChange?.(value);\n\n if (value) {\n if (stateRef.current.steps.length > 0) {\n if (stateRef.current.value >= stateRef.current.steps.length) {\n store.setState(\"value\", 0);\n }\n }\n } else {\n if (stateRef.current.value < (stateRef.current.steps.length || 0) - 1) {\n propsRef.current.onSkip?.();\n }\n }\n } else if (key === \"value\" && typeof value === \"number\") {\n const prevStep = stateRef.current.steps[stateRef.current.value];\n const nextStep = stateRef.current.steps[value];\n\n prevStep?.onStepLeave?.();\n nextStep?.onStepEnter?.();\n\n if (value >= stateRef.current.steps.length) {\n propsRef.current.onComplete?.();\n\n if (propsRef.current.valueProp !== undefined) {\n propsRef.current.onValueChange?.(value);\n }\n\n store.setState(\"open\", false);\n return;\n }\n\n if (propsRef.current.valueProp !== undefined) {\n propsRef.current.onValueChange?.(value);\n return;\n }\n\n propsRef.current.onValueChange?.(value);\n\n if (nextStep && propsRef.current.autoScroll) {\n const targetElement = getTargetElement(nextStep.target);\n if (targetElement) {\n onScrollToElement(targetElement, propsRef.current.scrollBehavior, propsRef.current.scrollOffset);\n }\n }\n }\n\n store.notify();\n },\n notify: () => {\n for (const listener of listenersRef.current) {\n listener();\n }\n },\n addStep: (stepData) => {\n const id = `step-${stepIdCounterRef.current.current++}`;\n const index = stateRef.current.steps.length;\n stepIdsMapRef.current.set(id, index);\n stateRef.current.steps = [...stateRef.current.steps, stepData];\n store.notify();\n return { id, index };\n },\n removeStep: (id) => {\n const index = stepIdsMapRef.current.get(id);\n if (index === undefined) return;\n\n stateRef.current.steps = stateRef.current.steps.filter((_, i) => i !== index);\n\n stepIdsMapRef.current.delete(id);\n\n for (const [stepId, stepIndex] of stepIdsMapRef.current.entries()) {\n if (stepIndex > index) {\n stepIdsMapRef.current.set(stepId, stepIndex - 1);\n }\n }\n\n store.notify();\n },\n updateStep: (id, stepData) => {\n const index = stepIdsMapRef.current.get(id);\n if (index === undefined) return;\n if (stateRef.current.steps[index] === stepData) return;\n\n const steps = [...stateRef.current.steps];\n steps[index] = stepData;\n stateRef.current.steps = steps;\n store.notify();\n },\n getStepIndex: (id) => stepIdsMapRef.current.get(id) ?? -1\n }),\n [stateRef, listenersRef, stepIdsMapRef, stepIdCounterRef, propsRef]\n );\n\n const open = useStore((state) => state.open, store);\n\n /*\n * ⚠ Khác thượng nguồn: Escape mà tour đã DÙNG thì phải đánh dấu là đã dùng, và phải nghe ở pha\n * CAPTURE. Bản gốc nghe ở pha nổi bọt và không gọi `preventDefault()`, nên đo được: MỘT lần\n * Escape vừa đóng tour vừa đóng luôn `ActionBar` đang mở — tức xoá mất lựa chọn dòng của người\n * dùng. Chỉ `preventDefault()` thôi là chưa đủ: listener của `ActionBar` cũng nằm ở `document`,\n * đăng ký TRƯỚC (thanh mở trước tour), nên nó chạy trước và chưa thấy cờ. Pha capture của\n * `document` chạy trước mọi listener nổi bọt — đúng chỗ Radix `DismissableLayer` nghe Escape,\n * nên tour cư xử như một Dialog của gói. Đang gõ dở bằng bộ gõ (Telex/VNI, `isComposing`) hoặc\n * Escape đã có lớp khác dùng thì bỏ qua, cùng luật với `ActionBar`.\n */\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if (!open || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n\n if (propsRef.current.onEscapeKeyDown) {\n propsRef.current.onEscapeKeyDown(event);\n if (event.defaultPrevented) return;\n }\n event.preventDefault();\n store.setState(\"open\", false);\n }\n\n document.addEventListener(\"keydown\", onKeyDown, { capture: true });\n return () => document.removeEventListener(\"keydown\", onKeyDown, { capture: true });\n }, [store, open, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n const wasOpen = prevOpenRef.current;\n\n if (open && !wasOpen) {\n previouslyFocusedElementRef.current = document.activeElement as HTMLElement | null;\n } else if (!open && wasOpen) {\n setTimeout(() => {\n const container = portal ?? document.body;\n const closeAutoFocusEvent = new CustomEvent(CLOSE_AUTO_FOCUS, EVENT_OPTIONS);\n\n if (propsRef.current.onCloseAutoFocus) {\n container.addEventListener(CLOSE_AUTO_FOCUS, propsRef.current.onCloseAutoFocus as EventListener, {\n once: true\n });\n }\n container.dispatchEvent(closeAutoFocusEvent);\n\n if (!closeAutoFocusEvent.defaultPrevented) {\n const elementToFocus = previouslyFocusedElementRef.current;\n if (elementToFocus && document.body.contains(elementToFocus)) {\n elementToFocus.focus({ preventScroll: true });\n }\n }\n\n previouslyFocusedElementRef.current = null;\n }, 0);\n }\n\n prevOpenRef.current = open;\n }, [open, portal, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n if (openProp !== undefined) {\n store.setState(\"open\", openProp);\n }\n }, [openProp, store]);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp, store]);\n\n const labels = useComitorLabels(\"tour\", labelsProp);\n\n const contextValue = React.useMemo<TourContextValue>(\n () => ({\n dir,\n alignOffset,\n sideOffset,\n spotlightPadding,\n dismissible,\n modal,\n stepFooter,\n labels,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus\n }),\n [\n dir,\n alignOffset,\n sideOffset,\n spotlightPadding,\n dismissible,\n modal,\n stepFooter,\n labels,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus\n ]\n );\n\n const portalContextValue = React.useMemo<PortalContextValue>(\n () => ({\n portal,\n onPortalChange: setPortal\n }),\n [portal]\n );\n\n useScrollLock(open && modal);\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <TourContext.Provider value={contextValue}>\n <PortalContext.Provider value={portalContextValue}>\n <RootPrimitive data-slot=\"tour\" dir={dir} {...rootProps} />\n </PortalContext.Provider>\n </TourContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface TourStepProps extends DivProps {\n target: StepTarget;\n side?: Side;\n sideOffset?: number;\n align?: Align;\n alignOffset?: number;\n collisionBoundary?: Boundary | Boundary[];\n collisionPadding?: number | Partial<Record<Side, number>>;\n arrowPadding?: number;\n sticky?: \"partial\" | \"always\";\n hideWhenDetached?: boolean;\n avoidCollisions?: boolean;\n required?: boolean;\n forceMount?: boolean;\n onStepEnter?: () => void;\n onStepLeave?: () => void;\n}\n\nfunction TourStep(props: TourStepProps) {\n const {\n target,\n side = \"bottom\",\n sideOffset,\n align = \"center\",\n alignOffset,\n collisionBoundary = EMPTY_BOUNDARY,\n collisionPadding = 0,\n arrowPadding = 0,\n sticky = \"partial\",\n hideWhenDetached = false,\n avoidCollisions = true,\n required = false,\n forceMount = false,\n onStepEnter,\n onStepLeave,\n onPointerDownCapture: onPointerDownCaptureProp,\n onFocusCapture: onFocusCaptureProp,\n onBlurCapture: onBlurCaptureProp,\n children,\n className,\n style,\n asChild,\n ...stepProps\n } = props;\n\n const store = useStoreContext(STEP_NAME);\n\n const [arrow, setArrow] = React.useState<HTMLSpanElement | null>(null);\n const [footer, setFooter] = React.useState<FooterElement | null>(null);\n const [targetElement, setTargetElement] = React.useState<HTMLElement | null>(null);\n\n const stepRef = React.useRef<StepElement | null>(null);\n const stepIdRef = React.useRef<string>(\"\");\n const isPointerInsideReactTreeRef = React.useRef(false);\n const isFocusInsideReactTreeRef = React.useRef(false);\n\n const titleId = React.useId();\n const descriptionId = React.useId();\n\n const open = useStore((state) => state.open);\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n const context = useTourContext(STEP_NAME);\n\n const resolvedSideOffset = sideOffset ?? context.sideOffset;\n const resolvedAlignOffset = alignOffset ?? context.alignOffset;\n\n /*\n * ⚠ Khác thượng nguồn: đăng ký bước MỘT lần khi mount, sau đó cập nhật TẠI CHỖ.\n *\n * Bản gốc gỡ rồi thêm lại bước mỗi khi một prop đổi (kể cả `onStepEnter={() => …}` viết tại\n * chỗ — tức MỖI lần render). Thêm lại là nối vào CUỐI danh sách, còn thứ tự các bước khác giữ\n * trong ref riêng không ai cập nhật: bước bị đẩy xuống cuối, và ở `value` cũ không bước nào\n * nhận mình là bước hiện tại — tour trống trơn. Chỉ cần `side={isMobile ? … : …}` là dính.\n *\n * Hai callback đi qua ref để luôn gọi bản mới nhất mà không làm dữ liệu bước \"đổi\".\n */\n const callbacksRef = useAsRef({ onStepEnter, onStepLeave });\n\n const ownStepData = React.useMemo<StepData>(\n () => ({\n target,\n align,\n alignOffset: resolvedAlignOffset,\n side,\n sideOffset: resolvedSideOffset,\n collisionBoundary,\n collisionPadding,\n arrowPadding,\n sticky,\n hideWhenDetached,\n avoidCollisions,\n onStepEnter: () => callbacksRef.current.onStepEnter?.(),\n onStepLeave: () => callbacksRef.current.onStepLeave?.(),\n required\n }),\n [\n target,\n align,\n resolvedAlignOffset,\n side,\n resolvedSideOffset,\n collisionBoundary,\n collisionPadding,\n arrowPadding,\n sticky,\n hideWhenDetached,\n avoidCollisions,\n required,\n callbacksRef\n ]\n );\n const ownStepDataRef = useAsRef(ownStepData);\n\n useIsomorphicLayoutEffect(() => {\n const { id } = store.addStep(ownStepDataRef.current);\n stepIdRef.current = id;\n\n return () => {\n store.removeStep(id);\n };\n }, [store, ownStepDataRef]);\n\n useIsomorphicLayoutEffect(() => {\n store.updateStep(stepIdRef.current, ownStepData);\n }, [store, ownStepData]);\n\n const stepData = steps[value];\n\n // ⚠ Khác thượng nguồn: vị trí đọc từ store theo id (được dồn lại khi một bước khác bị gỡ),\n // không từ một ref chụp lúc đăng ký.\n const isCurrentStep = store.getStepIndex(stepIdRef.current) === value;\n\n /*\n * ⚠ Khác thượng nguồn: bản gốc gọi `getTargetElement` — tức `document.querySelector` — NGAY\n * TRONG render. Ở đây phân giải trong layout effect: chạy sau MỖI lần render như nhịp của bản\n * gốc (đích xuất hiện muộn vẫn bắt được), vẫn trước lượt sơn, và chỉ cho bước đang hiện.\n * `setState` cùng giá trị thì React bỏ qua, nên không có vòng lặp.\n */\n useIsomorphicLayoutEffect(() => {\n setTargetElement(open && isCurrentStep && stepData ? getTargetElement(stepData.target) : null);\n });\n\n /*\n * ⚠ Khác thượng nguồn: gom điều kiện \"bước này đang HIỆN\" về một chỗ. Bản gốc bật bẫy focus\n * và bộ nghe bấm-ra-ngoài theo `open && isCurrentStep`; nếu lượt render đó chưa có đích (và\n * không `forceMount`) thì bước chưa có DOM, hiệu ứng thoát sớm và KHÔNG chạy lại khi đích xuất\n * hiện — focus không bao giờ vào được bước.\n */\n const isStepRendered = open && isCurrentStep && !!stepData && (!!targetElement || forceMount);\n\n const middleware = React.useMemo(() => {\n if (!stepData) return [];\n\n const mainAxisOffset = stepData.sideOffset ?? resolvedSideOffset;\n const crossAxisOffset = stepData.alignOffset ?? resolvedAlignOffset;\n\n const padding =\n typeof stepData.collisionPadding === \"number\"\n ? stepData.collisionPadding\n : {\n top: stepData.collisionPadding?.top ?? 0,\n right: stepData.collisionPadding?.right ?? 0,\n bottom: stepData.collisionPadding?.bottom ?? 0,\n left: stepData.collisionPadding?.left ?? 0\n };\n\n const boundary = Array.isArray(stepData.collisionBoundary)\n ? stepData.collisionBoundary\n : stepData.collisionBoundary\n ? [stepData.collisionBoundary]\n : [];\n const hasExplicitBoundaries = boundary.length > 0;\n\n const detectOverflowOptions = {\n padding,\n boundary: boundary.filter((b): b is Element => b !== null),\n altBoundary: hasExplicitBoundaries\n };\n\n return [\n offset({\n mainAxis: mainAxisOffset,\n alignmentAxis: crossAxisOffset\n }),\n stepData.avoidCollisions &&\n shift({\n mainAxis: true,\n crossAxis: false,\n limiter: stepData.sticky === \"partial\" ? limitShift() : undefined,\n ...detectOverflowOptions\n }),\n stepData.avoidCollisions && flip({ ...detectOverflowOptions }),\n arrow && onArrow({ element: arrow, padding: stepData.arrowPadding }),\n stepData.hideWhenDetached &&\n hide({\n strategy: \"referenceHidden\",\n ...detectOverflowOptions\n })\n ].filter(Boolean) as Middleware[];\n }, [stepData, resolvedSideOffset, resolvedAlignOffset, arrow]);\n\n const placement = getPlacement(stepData?.side ?? side, stepData?.align ?? align);\n\n const {\n refs,\n floatingStyles,\n placement: finalPlacement,\n middlewareData\n } = useFloating({\n placement,\n middleware,\n strategy: \"fixed\",\n whileElementsMounted: autoUpdate,\n elements: {\n reference: targetElement\n }\n });\n\n const composedRef = useComposedRefs(refs.setFloating, stepRef);\n\n const [placedSide, placedAlign] = getSideAndAlignFromPlacement(finalPlacement);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;\n const isHidden = hideWhenDetached && middlewareData.hide?.referenceHidden;\n\n const stepContextValue = React.useMemo<StepContextValue>(\n () => ({\n arrowX,\n arrowY,\n placedAlign,\n placedSide,\n shouldHideArrow: cannotCenterArrow,\n titleId,\n descriptionId,\n onArrowChange: setArrow,\n onFooterChange: setFooter\n }),\n [arrowX, arrowY, placedSide, placedAlign, cannotCenterArrow, titleId, descriptionId]\n );\n\n React.useEffect(() => {\n if (open && targetElement && isCurrentStep) {\n updateMask(store, targetElement, context.spotlightPadding);\n\n let rafId: number | null = null;\n\n function onResize() {\n if (targetElement) {\n updateMask(store, targetElement, context.spotlightPadding);\n }\n }\n\n function onScroll() {\n if (rafId !== null) return;\n rafId = requestAnimationFrame(() => {\n if (targetElement) {\n updateMask(store, targetElement, context.spotlightPadding);\n }\n rafId = null;\n });\n }\n\n window.addEventListener(\"resize\", onResize);\n /*\n * ⚠ Khác thượng nguồn: nghe ở pha CAPTURE. Sự kiện `scroll` của một phần tử không nổi bọt\n * lên `window`; bản gốc chỉ bắt được khi CỬA SỔ cuộn. Trong `AppShell` chỉ `<main>` cuộn,\n * nên lỗ sáng đứng yên trong khi đích trôi đi.\n */\n window.addEventListener(\"scroll\", onScroll, { capture: true, passive: true });\n return () => {\n window.removeEventListener(\"resize\", onResize);\n window.removeEventListener(\"scroll\", onScroll, { capture: true });\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n }\n };\n }\n }, [open, targetElement, isCurrentStep, store, context.spotlightPadding]);\n\n React.useEffect(() => {\n if (!isStepRendered) return;\n\n const stepElement = stepRef.current;\n if (!stepElement) return;\n\n const ownerDocument = stepElement.ownerDocument;\n\n function onPointerDown(event: PointerEvent) {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const pointerDownOutsideEvent = new CustomEvent(POINTER_DOWN_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n\n context.onPointerDownOutside?.(pointerDownOutsideEvent);\n\n const interactOutsideEvent = new CustomEvent(INTERACT_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n context.onInteractOutside?.(interactOutsideEvent);\n\n if (\n !pointerDownOutsideEvent.defaultPrevented &&\n !interactOutsideEvent.defaultPrevented &&\n context.dismissible\n ) {\n store.setState(\"open\", false);\n }\n }\n\n isPointerInsideReactTreeRef.current = false;\n }\n\n const timerId = window.setTimeout(() => {\n ownerDocument.addEventListener(\"pointerdown\", onPointerDown);\n }, 0);\n\n return () => {\n window.clearTimeout(timerId);\n ownerDocument.removeEventListener(\"pointerdown\", onPointerDown);\n };\n }, [isStepRendered, store, context]);\n\n React.useEffect(() => {\n if (!isStepRendered) return;\n\n const stepElement = stepRef.current;\n if (!stepElement) return;\n\n const ownerDocument = stepElement.ownerDocument;\n\n function onFocusIn(event: FocusEvent) {\n const target = event.target as HTMLElement;\n\n const isFocusInStep = stepElement?.contains(target);\n const isFocusInTarget = targetElement?.contains(target);\n\n if (event.target && !isFocusInsideReactTreeRef.current && !isFocusInStep && !isFocusInTarget) {\n const interactOutsideEvent = new CustomEvent(INTERACT_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n\n context.onInteractOutside?.(interactOutsideEvent);\n\n if (!interactOutsideEvent.defaultPrevented && context.dismissible) {\n store.setState(\"open\", false);\n }\n }\n }\n\n ownerDocument.addEventListener(\"focusin\", onFocusIn);\n\n return () => {\n ownerDocument.removeEventListener(\"focusin\", onFocusIn);\n };\n }, [isStepRendered, store, context, targetElement]);\n\n const onPointerDownCapture = React.useCallback(\n (event: React.PointerEvent<StepElement>) => {\n onPointerDownCaptureProp?.(event);\n isPointerInsideReactTreeRef.current = true;\n },\n [onPointerDownCaptureProp]\n );\n\n const onFocusCapture = React.useCallback(\n (event: React.FocusEvent<StepElement>) => {\n onFocusCaptureProp?.(event);\n isFocusInsideReactTreeRef.current = true;\n },\n [onFocusCaptureProp]\n );\n\n const onBlurCapture = React.useCallback(\n (event: React.FocusEvent<StepElement>) => {\n onBlurCaptureProp?.(event);\n isFocusInsideReactTreeRef.current = false;\n },\n [onBlurCaptureProp]\n );\n\n React.useEffect(() => {\n if (!open || !isCurrentStep || !targetElement) return;\n\n function onTargetPointerDownCapture() {\n isPointerInsideReactTreeRef.current = true;\n }\n\n function onTargetFocusCapture() {\n isFocusInsideReactTreeRef.current = true;\n }\n\n function onTargetBlurCapture() {\n isFocusInsideReactTreeRef.current = false;\n }\n\n targetElement.addEventListener(\"pointerdown\", onTargetPointerDownCapture, true);\n targetElement.addEventListener(\"focus\", onTargetFocusCapture, true);\n targetElement.addEventListener(\"blur\", onTargetBlurCapture, true);\n\n return () => {\n targetElement.removeEventListener(\"pointerdown\", onTargetPointerDownCapture, true);\n targetElement.removeEventListener(\"focus\", onTargetFocusCapture, true);\n targetElement.removeEventListener(\"blur\", onTargetBlurCapture, true);\n };\n }, [open, isCurrentStep, targetElement]);\n\n useFocusGuards(isStepRendered);\n useFocusTrap(stepRef, isStepRendered, open, context.onOpenAutoFocus, context.onCloseAutoFocus);\n\n if (!isStepRendered) {\n return null;\n }\n\n const StepPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StepContext.Provider value={stepContextValue}>\n <StepPrimitive\n ref={composedRef}\n /*\n * ⚠ Khác thượng nguồn: bản gốc là `<div>` TRẦN, không vai trò, không tên. Bẫy focus kéo\n * người dùng vào đó và trình đọc màn hình chỉ đọc \"nút Đóng hướng dẫn\" — không nói\n * đang ở đâu, bước này nói gì. `role=\"dialog\"` + tiêu đề/mô tả làm tên và lời mô tả, như\n * `PopoverContent` của Radix. Không `aria-modal`: đích đang được soi nằm NGOÀI bước và\n * người dùng vẫn cần đọc được nó.\n */\n role=\"dialog\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n data-slot=\"tour-step\"\n data-side={placedSide}\n data-align={placedAlign}\n dir={context.dir}\n tabIndex={-1}\n {...stepProps}\n onPointerDownCapture={onPointerDownCapture}\n onFocusCapture={onFocusCapture}\n onBlurCapture={onBlurCapture}\n className={cn(\n // Bề mặt cùng khuôn với `PopoverContent`: nền/chữ popover, viền token, bóng tầng nổi.\n \"fixed z-50 flex w-80 flex-col gap-4 rounded-lg border bg-popover p-4 text-popover-foreground shadow-overlay outline-none\",\n className\n )}\n style={{\n ...style,\n ...floatingStyles,\n visibility: isHidden ? \"hidden\" : undefined,\n pointerEvents: isHidden ? \"none\" : undefined\n }}\n >\n {children}\n {!footer && <DefaultFooterContext.Provider value={true}>{context.stepFooter}</DefaultFooterContext.Provider>}\n </StepPrimitive>\n </StepContext.Provider>\n );\n}\n\ninterface TourSpotlightProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TourSpotlight(props: TourSpotlightProps) {\n const { asChild, className, style, forceMount = false, ...backdropProps } = props;\n\n const open = useStore((state) => state.open);\n const maskPath = useStore((state) => state.maskPath);\n\n if (!open && !forceMount) return null;\n\n const SpotlightPrimitive = asChild ? Slot : \"div\";\n\n return (\n <SpotlightPrimitive\n data-slot=\"tour-spotlight\"\n data-state={getDataState(open)}\n {...backdropProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: `bg-black/80` (bảng màu mặc định Tailwind) → đúng màu lớp phủ của\n * `DialogOverlay`, để lớp tối của tour và của hộp thoại là MỘT thứ trong mắt người dùng.\n * Không lấy `backdrop-blur-sm` của nó: tour cần người dùng còn đọc được ngữ cảnh quanh đích.\n */\n \"fixed inset-0 z-50 bg-ink/60 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 dark:bg-ink/80\",\n className\n )}\n style={{\n clipPath: maskPath,\n ...style\n }}\n />\n );\n}\n\ninterface TourSpotlightRingProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TourSpotlightRing(props: TourSpotlightRingProps) {\n const { asChild, className, style, forceMount = false, ...ringProps } = props;\n\n const open = useStore((state) => state.open);\n const spotlightRect = useStore((state) => state.spotlightRect);\n\n if (!open && !forceMount) return null;\n if (!spotlightRect) return null;\n\n const RingPrimitive = asChild ? Slot : \"div\";\n\n return (\n <RingPrimitive\n data-slot=\"tour-spotlight-ring\"\n data-state={getDataState(open)}\n {...ringProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: bỏ `border-ring`. Không có độ dày viền đi kèm nên nó không vẽ gì —\n * chỉ là một màu viền treo sẵn. App muốn viền thì truyền đủ cả độ dày lẫn màu\n * (`border-2 border-primary-ink`), như chính các ví dụ của thượng nguồn vẫn làm.\n */\n \"pointer-events-none fixed z-50 ring-[3px] ring-ring/50\",\n className\n )}\n style={{\n left: spotlightRect.x,\n top: spotlightRect.y,\n width: spotlightRect.width,\n height: spotlightRect.height,\n ...style\n }}\n />\n );\n}\n\ninterface TourPortalProps {\n children?: React.ReactNode;\n container?: HTMLElement | null;\n}\n\nfunction TourPortal(props: TourPortalProps) {\n const { children, container } = props;\n\n const portalContext = usePortalContext(PORTAL_NAME);\n\n /*\n * ⚠ Khác thượng nguồn: giữ NÚT gắn trong state thay cho cờ `mounted`, để lượt render không\n * phải đọc `document.body` — mọi chỗ chạm DOM đều nằm trong effect.\n */\n const [mountNode, setMountNode] = React.useState<HTMLElement | null>(null);\n\n useIsomorphicLayoutEffect(() => {\n const node = container ?? document.body;\n setMountNode(node);\n\n portalContext?.onPortalChange(node);\n return () => {\n portalContext?.onPortalChange(null);\n };\n }, [container, portalContext]);\n\n if (!mountNode) return null;\n\n const portalContainer = container ?? portalContext?.portal ?? mountNode;\n\n return ReactDOM.createPortal(children, portalContainer);\n}\n\ninterface TourArrowProps extends React.ComponentProps<\"svg\"> {\n width?: number;\n height?: number;\n asChild?: boolean;\n}\n\nfunction TourArrow(props: TourArrowProps) {\n const { width = 10, height = 5, className, children, asChild, ...arrowProps } = props;\n\n const stepContext = useStepContext(ARROW_NAME);\n const baseSide = OPPOSITE_SIDE[stepContext.placedSide];\n\n return (\n <span\n ref={stepContext.onArrowChange}\n data-slot=\"tour-arrow\"\n style={{\n position: \"absolute\",\n left: stepContext.arrowX != null ? `${stepContext.arrowX}px` : undefined,\n top: stepContext.arrowY != null ? `${stepContext.arrowY}px` : undefined,\n [baseSide]: 0,\n transformOrigin: {\n top: \"\",\n right: \"0 0\",\n bottom: \"center 0\",\n left: \"100% 0\"\n }[stepContext.placedSide],\n transform: {\n top: \"translateY(100%)\",\n right: \"translateY(50%) rotate(90deg) translateX(-50%)\",\n bottom: \"rotate(180deg)\",\n left: \"translateY(50%) rotate(-90deg) translateX(50%)\"\n }[stepContext.placedSide],\n visibility: stepContext.shouldHideArrow ? \"hidden\" : undefined\n }}\n >\n {/* ⚠ Khác thượng nguồn: `aria-hidden` — mũi tên thuần trang trí, không có gì để đọc. */}\n <svg\n viewBox=\"0 0 30 10\"\n preserveAspectRatio=\"none\"\n width={width}\n height={height}\n aria-hidden=\"true\"\n {...arrowProps}\n className={cn(\"block fill-popover stroke-border\", className)}\n >\n {asChild ? children : <polygon points=\"0,0 30,0 15,10\" />}\n </svg>\n </span>\n );\n}\n\ntype TourHeaderProps = DivProps;\n\nfunction TourHeader(props: TourHeaderProps) {\n const { asChild, className, ...headerProps } = props;\n\n const context = useTourContext(HEADER_NAME);\n\n const HeaderPrimitive = asChild ? Slot : \"div\";\n\n return (\n <HeaderPrimitive\n data-slot=\"tour-header\"\n dir={context.dir}\n {...headerProps}\n className={cn(\"flex flex-col gap-1.5 text-center sm:text-left\", className)}\n />\n );\n}\n\ntype TourTitleProps = DivProps;\n\nfunction TourTitle(props: TourTitleProps) {\n const { asChild, className, ...titleProps } = props;\n\n const context = useTourContext(TITLE_NAME);\n // ⚠ Khác thượng nguồn: nhận id từ bước chứa nó để bước trỏ `aria-labelledby` vào đây.\n const stepContext = React.useContext(StepContext);\n\n const TitlePrimitive = asChild ? Slot : \"div\";\n\n return (\n <TitlePrimitive\n id={stepContext?.titleId}\n data-slot=\"tour-title\"\n dir={context.dir}\n {...titleProps}\n className={cn(\"text-lg leading-none font-semibold tracking-tight\", className)}\n />\n );\n}\n\ntype TourDescriptionProps = DivProps;\n\nfunction TourDescription(props: TourDescriptionProps) {\n const { asChild, className, ...descriptionProps } = props;\n\n const context = useTourContext(DESCRIPTION_NAME);\n // ⚠ Khác thượng nguồn: nhận id từ bước chứa nó để bước trỏ `aria-describedby` vào đây.\n const stepContext = React.useContext(StepContext);\n\n const DescriptionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DescriptionPrimitive\n id={stepContext?.descriptionId}\n data-slot=\"tour-description\"\n dir={context.dir}\n {...descriptionProps}\n className={cn(\"text-sm text-muted-foreground\", className)}\n />\n );\n}\n\ninterface TourCloseProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nfunction TourClose(props: TourCloseProps) {\n const { asChild, className, children, onClick: onClickProp, ...closeButtonProps } = props;\n\n const store = useStoreContext(CLOSE_NAME);\n const context = useTourContext(CLOSE_NAME);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<CloseElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"open\", false);\n },\n [store, onClickProp]\n );\n\n const ClosePrimitive = asChild ? Slot : \"button\";\n\n return (\n <ClosePrimitive\n type=\"button\"\n aria-label={context.labels.close}\n data-slot=\"tour-close\"\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: khuôn nút đóng của `DialogContent` (màu chữ muted, hover nền muted,\n * vòng focus của gói) thay cho `opacity-70` — `opacity` không miễn ngưỡng tương phản cho\n * thứ còn bấm được (docs/hop-dong-mau.md). `top-3 right-3 p-1` đặt icon đúng chỗ\n * `top-4 right-4` cũ nhưng vùng bấm lên ~24px thay vì 16px (WCAG 2.5.8).\n */\n \"absolute top-3 right-3 rounded-md p-1 text-muted-foreground transition-colors duration-150 ease-out hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n onClick={onClick}\n {...closeButtonProps}\n >\n {/*\n * ⚠ Khác thượng nguồn: bản gốc luôn render icon X làm con, đè mất `children` của app — và\n * với `asChild` thì Slot nhận chính cái `<svg>` làm phần tử được \"bọc\".\n */}\n {children ?? <X aria-hidden=\"true\" />}\n </ClosePrimitive>\n );\n}\n\ntype TourPrevProps = React.ComponentProps<typeof Button>;\n\n/*\n * ⚠ Khác thượng nguồn (áp cho cả `TourPrev`, `TourNext`, `TourSkip`): bỏ `aria-label` mặc định.\n * Nút đã có chữ hiện; `aria-label` cứng ĐÈ lên chữ đó — ở bước cuối `TourNext` HIỆN \"Finish\"\n * nhưng ĐỌC \"Next step\", và app truyền `children` riêng vẫn bị đọc bằng nhãn cũ. Lệch WCAG 2.5.3\n * (Label in Name): người dùng điều khiển bằng giọng nói gọi đúng chữ trên nút mà không bấm được.\n * App dùng nút chỉ-có-icon thì tự truyền `aria-label`.\n */\nfunction TourPrev(props: TourPrevProps) {\n const { children, onClick: onClickProp, ...prevButtonProps } = props;\n\n const store = useStoreContext(PREV_NAME);\n const context = useTourContext(PREV_NAME);\n const value = useStore((state) => state.value);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<PrevElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n if (value > 0) {\n store.setState(\"value\", value - 1);\n }\n },\n [value, store, onClickProp]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"tour-prev\"\n variant=\"outline\"\n {...prevButtonProps}\n onClick={onClick}\n disabled={value === 0}\n >\n {children ?? (\n <>\n {/* `Button` của gói không tự đặt cỡ icon (khác shadcn) → ghi `size-4` tường minh. */}\n <ChevronLeft aria-hidden=\"true\" className=\"size-4\" />\n {context.labels.prev}\n </>\n )}\n </Button>\n );\n}\n\ntype TourNextProps = React.ComponentProps<typeof Button>;\n\nfunction TourNext(props: TourNextProps) {\n const { children, onClick: onClickProp, ...nextButtonProps } = props;\n const store = useStoreContext(NEXT_NAME);\n const context = useTourContext(NEXT_NAME);\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n\n const isLastStep = value === steps.length - 1;\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<NextElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"value\", value + 1);\n },\n [value, store, onClickProp]\n );\n\n return (\n <Button type=\"button\" data-slot=\"tour-next\" {...nextButtonProps} onClick={onClick}>\n {children ?? (\n <>\n {isLastStep ? context.labels.finish : context.labels.next}\n {!isLastStep && <ChevronRight aria-hidden=\"true\" className=\"size-4\" />}\n </>\n )}\n </Button>\n );\n}\n\ntype TourSkipProps = React.ComponentProps<typeof Button>;\n\nfunction TourSkip(props: TourSkipProps) {\n const { children, onClick: onClickProp, ...skipButtonProps } = props;\n\n const store = useStoreContext(SKIP_NAME);\n const context = useTourContext(SKIP_NAME);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<SkipElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"open\", false);\n },\n [store, onClickProp]\n );\n\n return (\n <Button type=\"button\" data-slot=\"tour-skip\" variant=\"outline\" {...skipButtonProps} onClick={onClick}>\n {children ?? context.labels.skip}\n </Button>\n );\n}\n\ninterface TourStepCounterProps extends DivProps {\n /** Mặc định `labels.stepCounter` của `Tour` — \"Step 2 of 5\". */\n format?: (current: number, total: number) => string;\n}\n\nfunction TourStepCounter(props: TourStepCounterProps) {\n const { format: formatProp, asChild, className, children, ...stepCounterProps } = props;\n\n const context = useTourContext(STEP_COUNTER_NAME);\n const format = formatProp ?? context.labels.stepCounter;\n\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n\n const StepCounterPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StepCounterPrimitive\n data-slot=\"tour-step-counter\"\n {...stepCounterProps}\n // ⚠ Khác thượng nguồn: `whitespace-nowrap` — \"Bước 1/3\" đặt cạnh \"Quay lại\"/\"Tiếp theo\" trong\n // thẻ `w-80` bị bẻ làm hai dòng (đo trên trình duyệt); con số đếm bước không nên vỡ dòng.\n className={cn(\"whitespace-nowrap text-sm text-muted-foreground\", className)}\n >\n {children ?? format(value + 1, steps.length)}\n </StepCounterPrimitive>\n );\n}\n\ntype TourFooterProps = DivProps;\n\nfunction TourFooter(props: TourFooterProps) {\n const { asChild, className, ref, ...footerProps } = props;\n\n const stepContext = useStepContext(FOOTER_NAME);\n const hasDefaultFooter = React.useContext(DefaultFooterContext);\n const context = useTourContext(FOOTER_NAME);\n\n const composedRef = useComposedRefs(ref, hasDefaultFooter ? undefined : stepContext.onFooterChange);\n\n const FooterPrimitive = asChild ? Slot : \"div\";\n\n return (\n <FooterPrimitive\n data-slot=\"tour-footer\"\n dir={context.dir}\n {...footerProps}\n ref={composedRef}\n className={cn(\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\", className)}\n />\n );\n}\n\nexport {\n Tour,\n TourArrow,\n type TourArrowProps,\n TourClose,\n type TourCloseProps,\n TourDescription,\n type TourDescriptionProps,\n TourFooter,\n type TourFooterProps,\n TourHeader,\n type TourHeaderProps,\n TourNext,\n type TourNextProps,\n TourPortal,\n type TourPortalProps,\n TourPrev,\n type TourPrevProps,\n type TourProps,\n TourSkip,\n type TourSkipProps,\n TourSpotlight,\n type TourSpotlightProps,\n TourSpotlightRing,\n type TourSpotlightRingProps,\n TourStep,\n TourStepCounter,\n type TourStepCounterProps,\n type TourStepProps,\n TourTitle,\n type TourTitleProps\n};\n"],"mappings":"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","names":["offset","onResize","onScroll","target"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/tour.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/tour) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport {\n autoUpdate,\n flip,\n hide,\n limitShift,\n type Middleware,\n offset,\n arrow as onArrow,\n type Placement,\n shift,\n useFloating\n} from \"@floating-ui/react-dom\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { useComitorLabels } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { Button } from \"./button.js\";\nimport type { TourLabels } from \"./tour-constants.js\";\n\nconst ROOT_NAME = \"Tour\";\nconst PORTAL_NAME = \"TourPortal\";\nconst STEP_NAME = \"TourStep\";\nconst ARROW_NAME = \"TourArrow\";\nconst HEADER_NAME = \"TourHeader\";\nconst TITLE_NAME = \"TourTitle\";\nconst DESCRIPTION_NAME = \"TourDescription\";\nconst CLOSE_NAME = \"TourClose\";\nconst PREV_NAME = \"TourPrev\";\nconst NEXT_NAME = \"TourNext\";\nconst SKIP_NAME = \"TourSkip\";\nconst STEP_COUNTER_NAME = \"TourStepCounter\";\nconst FOOTER_NAME = \"TourFooter\";\n\nconst POINTER_DOWN_OUTSIDE = \"tour.pointerDownOutside\";\nconst INTERACT_OUTSIDE = \"tour.interactOutside\";\nconst OPEN_AUTO_FOCUS = \"tour.openAutoFocus\";\nconst CLOSE_AUTO_FOCUS = \"tour.closeAutoFocus\";\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\nconst SIDE_OPTIONS = [\"top\", \"right\", \"bottom\", \"left\"] as const;\nconst ALIGN_OPTIONS = [\"start\", \"center\", \"end\"] as const;\n\nconst DEFAULT_ALIGN_OFFSET = 0;\nconst DEFAULT_SIDE_OFFSET = 16;\nconst DEFAULT_SPOTLIGHT_PADDING = 4;\n\ntype Side = (typeof SIDE_OPTIONS)[number];\ntype Align = (typeof ALIGN_OPTIONS)[number];\ntype Direction = \"ltr\" | \"rtl\";\n\ninterface ScrollOffset {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\ntype Boundary = Element | null;\n\n/*\n * ⚠ Khác thượng nguồn: mặc định `collisionBoundary` là MỘT mảng rỗng dùng chung thay vì `[]`\n * viết tại chỗ — mảng mới mỗi lần render sẽ làm dữ liệu bước \"đổi\" liên tục (xem `ownStepData`).\n */\nconst EMPTY_BOUNDARY: Boundary[] = [];\n\n/*\n * ⚠ Khác thượng nguồn: `RefObject<HTMLElement | null>` thay vì `RefObject<HTMLElement>`. Với\n * React 19, `useRef<HTMLDivElement>(null)` có kiểu `RefObject<HTMLDivElement | null>` — kiểu gốc\n * từ chối đúng cái ref mà app nào cũng tạo ra.\n */\ntype StepTarget = string | React.RefObject<HTMLElement | null> | HTMLElement;\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype StepElement = React.ComponentRef<typeof TourStep>;\ntype CloseElement = React.ComponentRef<typeof TourClose>;\ntype PrevElement = React.ComponentRef<typeof TourPrev>;\ntype NextElement = React.ComponentRef<typeof TourNext>;\ntype SkipElement = React.ComponentRef<typeof TourSkip>;\ntype FooterElement = React.ComponentRef<typeof TourFooter>;\n\nconst OPPOSITE_SIDE: Record<Side, Side> = {\n top: \"bottom\",\n right: \"left\",\n bottom: \"top\",\n left: \"right\"\n};\n\n/**\n * @see https://github.com/radix-ui/primitives/blob/main/packages/react/focus-guards/src/focus-guards.tsx\n */\nlet focusGuardCount = 0;\n\nfunction createFocusGuard() {\n const element = document.createElement(\"span\");\n element.setAttribute(\"data-tour-focus-guard\", \"\");\n element.tabIndex = 0;\n element.style.outline = \"none\";\n element.style.opacity = \"0\";\n element.style.position = \"fixed\";\n element.style.pointerEvents = \"none\";\n return element;\n}\n\n/*\n * ⚠ Khác thượng nguồn: nhận `enabled`. Bản gốc gọi hook này vô điều kiện ở MỌI `TourStep`, nên\n * chỉ cần `Tour` nằm sẵn trong layout (đúng cách dùng onboarding: gắn sẵn, đóng mặc định) là trang\n * có thêm HAI điểm dừng Tab VÔ HÌNH ở đầu và cuối `<body>` suốt vòng đời app — người dùng bàn phím\n * Tab vào một thứ không nhìn thấy. Radix chỉ cắm lính gác khi lớp modal đang MỞ.\n */\nfunction useFocusGuards(enabled: boolean) {\n React.useEffect(() => {\n if (!enabled) return;\n\n const edgeGuards = document.querySelectorAll(\"[data-tour-focus-guard]\");\n document.body.insertAdjacentElement(\"afterbegin\", edgeGuards[0] ?? createFocusGuard());\n document.body.insertAdjacentElement(\"beforeend\", edgeGuards[1] ?? createFocusGuard());\n focusGuardCount++;\n\n return () => {\n if (focusGuardCount === 1) {\n const guards = document.querySelectorAll(\"[data-tour-focus-guard]\");\n for (const node of guards) {\n node.remove();\n }\n }\n focusGuardCount--;\n };\n }, [enabled]);\n}\n\nfunction useFocusTrap(\n containerRef: React.RefObject<HTMLElement | null>,\n enabled: boolean,\n tourOpen: boolean,\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void,\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void\n) {\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const onOpenAutoFocusRef = useAsRef(onOpenAutoFocus);\n const onCloseAutoFocusRef = useAsRef(onCloseAutoFocus);\n const tourOpenRef = useAsRef(tourOpen);\n\n React.useEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n\n function getTabbableCandidates() {\n if (!container) return [];\n\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: Element) => {\n const element = node as HTMLElement;\n const isHiddenInput = element.tagName === \"INPUT\" && (element as HTMLInputElement).type === \"hidden\";\n /*\n * ⚠ Khác thượng nguồn: bỏ qua phần tử `disabled`. `TourPrev` bị khoá ở bước đầu mà\n * `tabIndex` vẫn là 0; nếu nó là ứng viên đầu tiên thì `focus()` thất bại IM LẶNG,\n * focus ở lại ngoài bước, và phím Tab kế tiếp bị tính là \"tương tác bên ngoài\" — tour\n * ĐÓNG trong tay người dùng bàn phím.\n */\n const isDisabled = (element as HTMLButtonElement).disabled === true;\n if (element.hidden || isHiddenInput || isDisabled) return NodeFilter.FILTER_SKIP;\n return element.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n }\n });\n while (walker.nextNode()) {\n nodes.push(walker.currentNode as HTMLElement);\n }\n return nodes;\n }\n\n function getTabbableEdges() {\n const candidates = getTabbableCandidates();\n const first = candidates[0];\n const last = candidates[candidates.length - 1];\n return [first, last] as const;\n }\n\n function onFocusIn(event: FocusEvent) {\n if (!container) return;\n\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n const elementToFocus = lastFocusedElementRef.current ?? getTabbableCandidates()[0];\n elementToFocus?.focus({ preventScroll: true });\n }\n }\n\n function onKeyDown(event: KeyboardEvent) {\n if (event.key !== \"Tab\" || event.altKey || event.ctrlKey || event.metaKey) return;\n\n const [first, last] = getTabbableEdges();\n const hasTabbableElements = first && last;\n\n if (!hasTabbableElements) {\n if (document.activeElement === container) event.preventDefault();\n return;\n }\n\n if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first?.focus({ preventScroll: true });\n } else if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last?.focus({ preventScroll: true });\n }\n }\n\n const openAutoFocusEvent = new CustomEvent(OPEN_AUTO_FOCUS, EVENT_OPTIONS);\n if (onOpenAutoFocusRef.current) {\n container.addEventListener(OPEN_AUTO_FOCUS, onOpenAutoFocusRef.current as EventListener, { once: true });\n }\n container.dispatchEvent(openAutoFocusEvent);\n\n if (!openAutoFocusEvent.defaultPrevented) {\n const tabbableCandidates = getTabbableCandidates();\n if (tabbableCandidates.length > 0) {\n tabbableCandidates[0]?.focus({ preventScroll: true });\n } else {\n container.focus({ preventScroll: true });\n }\n }\n\n document.addEventListener(\"focusin\", onFocusIn);\n container.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.removeEventListener(\"focusin\", onFocusIn);\n container.removeEventListener(\"keydown\", onKeyDown);\n\n if (!tourOpenRef.current) {\n setTimeout(() => {\n const closeAutoFocusEvent = new CustomEvent(CLOSE_AUTO_FOCUS, EVENT_OPTIONS);\n if (onCloseAutoFocusRef.current) {\n container.addEventListener(CLOSE_AUTO_FOCUS, onCloseAutoFocusRef.current as EventListener, {\n once: true\n });\n }\n container.dispatchEvent(closeAutoFocusEvent);\n\n if (!closeAutoFocusEvent.defaultPrevented) {\n if (previouslyFocusedElement && document.body.contains(previouslyFocusedElement)) {\n previouslyFocusedElement.focus({ preventScroll: true });\n }\n }\n\n if (onCloseAutoFocusRef.current) {\n container.removeEventListener(CLOSE_AUTO_FOCUS, onCloseAutoFocusRef.current as EventListener);\n }\n }, 0);\n }\n };\n }, [containerRef, enabled, onOpenAutoFocusRef, onCloseAutoFocusRef, tourOpenRef]);\n}\n\nfunction getDataState(open: boolean) {\n return open ? \"open\" : \"closed\";\n}\n\ninterface StepData {\n target: StepTarget;\n align?: Align;\n alignOffset?: number;\n side?: Side;\n sideOffset?: number;\n collisionBoundary?: Boundary | Boundary[];\n collisionPadding?: number | Partial<Record<Side, number>>;\n arrowPadding?: number;\n sticky?: \"partial\" | \"always\";\n hideWhenDetached?: boolean;\n avoidCollisions?: boolean;\n onStepEnter?: () => void;\n onStepLeave?: () => void;\n required?: boolean;\n}\n\ninterface StoreState {\n open: boolean;\n value: number;\n steps: StepData[];\n maskPath: string;\n spotlightRect: { x: number; y: number; width: number; height: number } | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K], opts?: unknown) => void;\n notify: () => void;\n addStep: (stepData: StepData) => { id: string; index: number };\n removeStep: (id: string) => void;\n /** ⚠ Thêm so với thượng nguồn — xem chú thích ở `TourStep`. */\n updateStep: (id: string, stepData: StepData) => void;\n /** ⚠ Thêm so với thượng nguồn — vị trí HIỆN TẠI của một bước, `-1` nếu chưa đăng ký. */\n getStepIndex: (id: string) => number;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\nfunction getTargetElement(target: StepTarget): HTMLElement | null {\n if (typeof target === \"string\") {\n return document.querySelector(target);\n }\n if (target && \"current\" in target) {\n return target.current;\n }\n if (target instanceof HTMLElement) {\n return target;\n }\n return null;\n}\n\nfunction getDefaultScrollBehavior(): ScrollBehavior {\n if (typeof window === \"undefined\") return \"smooth\";\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\";\n}\n\n/*\n * ⚠ Khác thượng nguồn: tìm vùng cuộn gần nhất. Bản gốc chỉ `window.scrollTo`, nhưng khung\n * `AppShell` của Comitor là `h-dvh overflow-hidden` và nội dung cuộn trong `<main\n * overflow-y-auto>` — cửa sổ KHÔNG BAO GIỜ cuộn, nên `autoScroll` im lặng bỏ qua mọi đích nằm\n * dưới mép màn hình.\n */\nfunction getScrollParent(element: HTMLElement): HTMLElement | null {\n let parent = element.parentElement;\n while (parent && parent !== document.body && parent !== document.documentElement) {\n const { overflowY } = window.getComputedStyle(parent);\n const isScrollable = overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\";\n if (isScrollable && parent.scrollHeight > parent.clientHeight) return parent;\n parent = parent.parentElement;\n }\n return null;\n}\n\nfunction onScrollToElement(\n element: HTMLElement,\n scrollBehavior: ScrollBehavior = getDefaultScrollBehavior(),\n scrollOffset?: ScrollOffset\n) {\n const offset: Required<ScrollOffset> = {\n top: 100,\n bottom: 100,\n left: 0,\n right: 0,\n ...scrollOffset\n };\n const rect = element.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n\n const isInViewport =\n rect.top >= offset.top &&\n rect.bottom <= viewportHeight - offset.bottom &&\n rect.left >= offset.left &&\n rect.right <= viewportWidth - offset.right;\n\n if (!isInViewport) {\n const scrollParent = getScrollParent(element);\n if (scrollParent) {\n // Cuộn vùng chứa đúng bấy nhiêu để đích dừng cách mép trên khung nhìn `offset.top` — cùng\n // điểm đến với nhánh `window` bên dưới.\n scrollParent.scrollBy({ top: rect.top - offset.top, behavior: scrollBehavior });\n return;\n }\n\n const elementTop = rect.top + window.scrollY;\n const scrollTop = elementTop - offset.top;\n\n window.scrollTo({\n top: Math.max(0, scrollTop),\n behavior: scrollBehavior\n });\n }\n}\n\nfunction getSideAndAlignFromPlacement(placement: Placement): [Side, Align] {\n const [side, align = \"center\"] = placement.split(\"-\") as [Side, Align?];\n return [side, align];\n}\n\nfunction getPlacement(side: Side, align: Align): Placement {\n if (align === \"center\") {\n return side as Placement;\n }\n return `${side}-${align}` as Placement;\n}\n\nfunction updateMask(store: Store, targetElement: HTMLElement, padding: number = DEFAULT_SPOTLIGHT_PADDING) {\n const clientRect = targetElement.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n const x = Math.max(0, clientRect.left - padding);\n const y = Math.max(0, clientRect.top - padding);\n const width = Math.min(viewportWidth - x, clientRect.width + padding * 2);\n const height = Math.min(viewportHeight - y, clientRect.height + padding * 2);\n\n const path = `polygon(0% 0%, 0% 100%, ${x}px 100%, ${x}px ${y}px, ${x + width}px ${y}px, ${x + width}px ${y + height}px, ${x}px ${y + height}px, ${x}px 100%, 100% 100%, 100% 0%)`;\n store.setState(\"maskPath\", path);\n store.setState(\"spotlightRect\", { x, y, width, height });\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface TourContextValue {\n dir: Direction;\n alignOffset: number;\n sideOffset: number;\n spotlightPadding: number;\n dismissible: boolean;\n modal: boolean;\n stepFooter?: React.ReactElement;\n labels: TourLabels;\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;\n onInteractOutside?: (event: InteractOutsideEvent) => void;\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void;\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void;\n}\n\nconst TourContext = React.createContext<TourContextValue | null>(null);\n\nfunction useTourContext(consumerName: string) {\n const context = React.useContext(TourContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface StepContextValue {\n arrowX?: number;\n arrowY?: number;\n placedAlign: Align;\n placedSide: Side;\n shouldHideArrow: boolean;\n /** ⚠ Thêm so với thượng nguồn — id cho `aria-labelledby`/`aria-describedby` của bước. */\n titleId: string;\n descriptionId: string;\n onArrowChange: (arrow: HTMLSpanElement | null) => void;\n onFooterChange: (footer: FooterElement | null) => void;\n}\n\nconst StepContext = React.createContext<StepContextValue | null>(null);\n\nfunction useStepContext(consumerName: string) {\n const context = React.useContext(StepContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${STEP_NAME}\\``);\n }\n return context;\n}\n\nconst DefaultFooterContext = React.createContext(false);\n\ninterface PortalContextValue {\n portal: HTMLElement | null;\n onPortalChange: (node: HTMLElement | null) => void;\n}\n\nconst PortalContext = React.createContext<PortalContextValue | null>(null);\n\nfunction usePortalContext(consumerName: string) {\n const context = React.useContext(PortalContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useScrollLock(enabled: boolean) {\n React.useEffect(() => {\n if (!enabled) return;\n\n const originalStyle = window.getComputedStyle(document.body).overflow;\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n document.body.style.overflow = \"hidden\";\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n\n return () => {\n document.body.style.overflow = originalStyle;\n document.body.style.paddingRight = \"\";\n };\n }, [enabled]);\n}\n\ntype PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;\ntype InteractOutsideEvent = CustomEvent<{\n originalEvent: PointerEvent | FocusEvent;\n}>;\ntype OpenAutoFocusEvent = CustomEvent<Record<string, never>>;\ntype CloseAutoFocusEvent = CustomEvent<Record<string, never>>;\n\ninterface TourProps extends DivProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n value?: number;\n defaultValue?: number;\n onValueChange?: (step: number) => void;\n onComplete?: () => void;\n onSkip?: () => void;\n onEscapeKeyDown?: (event: KeyboardEvent) => void;\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;\n onInteractOutside?: (event: InteractOutsideEvent) => void;\n onOpenAutoFocus?: (event: OpenAutoFocusEvent) => void;\n onCloseAutoFocus?: (event: CloseAutoFocusEvent) => void;\n dir?: Direction;\n alignOffset?: number;\n sideOffset?: number;\n spotlightPadding?: number;\n autoScroll?: boolean;\n /** Mặc định `\"smooth\"`, hoặc `\"auto\"` khi người dùng bật `prefers-reduced-motion`. */\n scrollBehavior?: ScrollBehavior;\n scrollOffset?: ScrollOffset;\n dismissible?: boolean;\n modal?: boolean;\n stepFooter?: React.ReactElement;\n /**\n * Ghi đè chuỗi hiển thị/a11y — xem `TourLabels`. Không truyền thì theo namespace `tour` của\n * `ComitorLocaleProvider` (mặc định tiếng Anh).\n * ⚠ Thêm so với thượng nguồn: bản gốc chôn cứng chuỗi tiếng Anh trong từng nút.\n */\n labels?: Partial<TourLabels>;\n}\n\nfunction Tour(props: TourProps) {\n const {\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n value: valueProp,\n defaultValue = 0,\n onValueChange,\n onComplete,\n onSkip,\n autoScroll = true,\n /*\n * ⚠ Khác thượng nguồn: KHÔNG có giá trị mặc định ở đây. Bản gốc viết\n * `scrollBehavior = getDefaultScrollBehavior()`, tức đọc `window.matchMedia` NGAY TRONG\n * render. Để `undefined` thì tham số mặc định của `onScrollToElement` tính đúng giá trị đó\n * vào lúc CUỘN — ngoài render, và theo cài đặt reduced-motion ở thời điểm ấy.\n */\n scrollBehavior,\n scrollOffset,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus,\n dir: dirProp,\n alignOffset = DEFAULT_ALIGN_OFFSET,\n sideOffset = DEFAULT_SIDE_OFFSET,\n spotlightPadding = DEFAULT_SPOTLIGHT_PADDING,\n dismissible = true,\n modal = true,\n stepFooter,\n labels: labelsProp,\n asChild,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const [portal, setPortal] = React.useState<HTMLElement | null>(null);\n const prevOpenRef = React.useRef<boolean | undefined>(undefined);\n const previouslyFocusedElementRef = React.useRef<HTMLElement | null>(null);\n\n const stateRef = useLazyRef<StoreState>(() => ({\n open: openProp ?? defaultOpen,\n value: valueProp ?? defaultValue,\n steps: [],\n maskPath: \"\",\n spotlightRect: null\n }));\n const listenersRef = useLazyRef<Set<() => void>>(() => new Set());\n const stepIdsMapRef = useLazyRef<Map<string, number>>(() => new Map());\n const stepIdCounterRef = useLazyRef(() => ({ current: 0 }));\n const propsRef = useAsRef({\n valueProp,\n onOpenChange,\n onValueChange,\n onComplete,\n onSkip,\n onEscapeKeyDown,\n onCloseAutoFocus,\n autoScroll,\n scrollBehavior,\n scrollOffset\n });\n\n const store: Store = React.useMemo(\n () => ({\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => {\n return stateRef.current;\n },\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n /*\n * ⚠ Khác thượng nguồn (3.0.1): giữ giá trị CŨ trước khi ghi. Bản gốc ghi trước rồi mới đọc\n * `steps[stateRef.current.value]` làm \"bước vừa rời\" — lúc đó nó đã là bước MỚI, nên\n * `onStepLeave` chạy trên bước đang bước vào (ngay trước `onStepEnter` của chính nó) và bước\n * vừa rời thì không bao giờ nhận được.\n */\n const previousValue = stateRef.current.value;\n stateRef.current[key] = value;\n\n if (key === \"open\" && typeof value === \"boolean\") {\n propsRef.current.onOpenChange?.(value);\n\n if (value) {\n if (stateRef.current.steps.length > 0) {\n if (stateRef.current.value >= stateRef.current.steps.length) {\n store.setState(\"value\", 0);\n }\n }\n } else {\n /*\n * ⚠ Khác thượng nguồn (3.0.1): đóng ở BƯỚC CUỐI (×, Escape, bấm ra ngoài) cũng là `onSkip`.\n * Bản gốc so `< steps.length - 1`, nên đóng tại bước cuối không gọi `onSkip` lẫn\n * `onComplete` — app ghi \"đã xem tour\" ở hai callback đó sẽ bật lại tour lần sau. Đi hết\n * bằng nút Tiếp ở bước cuối vẫn là `onComplete`: khi đó `value` đã bằng `steps.length`.\n */\n if (stateRef.current.value < (stateRef.current.steps.length || 0)) {\n propsRef.current.onSkip?.();\n }\n }\n } else if (key === \"value\" && typeof value === \"number\") {\n const prevStep = stateRef.current.steps[previousValue];\n const nextStep = stateRef.current.steps[value];\n\n prevStep?.onStepLeave?.();\n nextStep?.onStepEnter?.();\n\n if (value >= stateRef.current.steps.length) {\n propsRef.current.onComplete?.();\n\n if (propsRef.current.valueProp !== undefined) {\n propsRef.current.onValueChange?.(value);\n }\n\n store.setState(\"open\", false);\n return;\n }\n\n if (propsRef.current.valueProp !== undefined) {\n propsRef.current.onValueChange?.(value);\n return;\n }\n\n propsRef.current.onValueChange?.(value);\n\n if (nextStep && propsRef.current.autoScroll) {\n const targetElement = getTargetElement(nextStep.target);\n if (targetElement) {\n onScrollToElement(targetElement, propsRef.current.scrollBehavior, propsRef.current.scrollOffset);\n }\n }\n }\n\n store.notify();\n },\n notify: () => {\n for (const listener of listenersRef.current) {\n listener();\n }\n },\n addStep: (stepData) => {\n const id = `step-${stepIdCounterRef.current.current++}`;\n const index = stateRef.current.steps.length;\n stepIdsMapRef.current.set(id, index);\n stateRef.current.steps = [...stateRef.current.steps, stepData];\n store.notify();\n return { id, index };\n },\n removeStep: (id) => {\n const index = stepIdsMapRef.current.get(id);\n if (index === undefined) return;\n\n stateRef.current.steps = stateRef.current.steps.filter((_, i) => i !== index);\n\n stepIdsMapRef.current.delete(id);\n\n for (const [stepId, stepIndex] of stepIdsMapRef.current.entries()) {\n if (stepIndex > index) {\n stepIdsMapRef.current.set(stepId, stepIndex - 1);\n }\n }\n\n store.notify();\n },\n updateStep: (id, stepData) => {\n const index = stepIdsMapRef.current.get(id);\n if (index === undefined) return;\n if (stateRef.current.steps[index] === stepData) return;\n\n const steps = [...stateRef.current.steps];\n steps[index] = stepData;\n stateRef.current.steps = steps;\n store.notify();\n },\n getStepIndex: (id) => stepIdsMapRef.current.get(id) ?? -1\n }),\n [stateRef, listenersRef, stepIdsMapRef, stepIdCounterRef, propsRef]\n );\n\n const open = useStore((state) => state.open, store);\n\n /*\n * ⚠ Khác thượng nguồn: Escape mà tour đã DÙNG thì phải đánh dấu là đã dùng, và phải nghe ở pha\n * CAPTURE. Bản gốc nghe ở pha nổi bọt và không gọi `preventDefault()`, nên đo được: MỘT lần\n * Escape vừa đóng tour vừa đóng luôn `ActionBar` đang mở — tức xoá mất lựa chọn dòng của người\n * dùng. Chỉ `preventDefault()` thôi là chưa đủ: listener của `ActionBar` cũng nằm ở `document`,\n * đăng ký TRƯỚC (thanh mở trước tour), nên nó chạy trước và chưa thấy cờ. Pha capture của\n * `document` chạy trước mọi listener nổi bọt — đúng chỗ Radix `DismissableLayer` nghe Escape,\n * nên tour cư xử như một Dialog của gói. Đang gõ dở bằng bộ gõ (Telex/VNI, `isComposing`) hoặc\n * Escape đã có lớp khác dùng thì bỏ qua, cùng luật với `ActionBar`.\n */\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if (!open || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n\n if (propsRef.current.onEscapeKeyDown) {\n propsRef.current.onEscapeKeyDown(event);\n if (event.defaultPrevented) return;\n }\n event.preventDefault();\n store.setState(\"open\", false);\n }\n\n document.addEventListener(\"keydown\", onKeyDown, { capture: true });\n return () => document.removeEventListener(\"keydown\", onKeyDown, { capture: true });\n }, [store, open, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n const wasOpen = prevOpenRef.current;\n\n if (open && !wasOpen) {\n previouslyFocusedElementRef.current = document.activeElement as HTMLElement | null;\n } else if (!open && wasOpen) {\n setTimeout(() => {\n const container = portal ?? document.body;\n const closeAutoFocusEvent = new CustomEvent(CLOSE_AUTO_FOCUS, EVENT_OPTIONS);\n\n if (propsRef.current.onCloseAutoFocus) {\n container.addEventListener(CLOSE_AUTO_FOCUS, propsRef.current.onCloseAutoFocus as EventListener, {\n once: true\n });\n }\n container.dispatchEvent(closeAutoFocusEvent);\n\n if (!closeAutoFocusEvent.defaultPrevented) {\n const elementToFocus = previouslyFocusedElementRef.current;\n if (elementToFocus && document.body.contains(elementToFocus)) {\n elementToFocus.focus({ preventScroll: true });\n }\n }\n\n previouslyFocusedElementRef.current = null;\n }, 0);\n }\n\n prevOpenRef.current = open;\n }, [open, portal, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n if (openProp !== undefined) {\n store.setState(\"open\", openProp);\n }\n }, [openProp, store]);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp, store]);\n\n const labels = useComitorLabels(\"tour\", labelsProp);\n\n const contextValue = React.useMemo<TourContextValue>(\n () => ({\n dir,\n alignOffset,\n sideOffset,\n spotlightPadding,\n dismissible,\n modal,\n stepFooter,\n labels,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus\n }),\n [\n dir,\n alignOffset,\n sideOffset,\n spotlightPadding,\n dismissible,\n modal,\n stepFooter,\n labels,\n onPointerDownOutside,\n onInteractOutside,\n onOpenAutoFocus,\n onCloseAutoFocus\n ]\n );\n\n const portalContextValue = React.useMemo<PortalContextValue>(\n () => ({\n portal,\n onPortalChange: setPortal\n }),\n [portal]\n );\n\n useScrollLock(open && modal);\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <TourContext.Provider value={contextValue}>\n <PortalContext.Provider value={portalContextValue}>\n <RootPrimitive data-slot=\"tour\" dir={dir} {...rootProps} />\n </PortalContext.Provider>\n </TourContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface TourStepProps extends DivProps {\n target: StepTarget;\n side?: Side;\n sideOffset?: number;\n align?: Align;\n alignOffset?: number;\n collisionBoundary?: Boundary | Boundary[];\n collisionPadding?: number | Partial<Record<Side, number>>;\n arrowPadding?: number;\n sticky?: \"partial\" | \"always\";\n hideWhenDetached?: boolean;\n avoidCollisions?: boolean;\n required?: boolean;\n forceMount?: boolean;\n onStepEnter?: () => void;\n onStepLeave?: () => void;\n}\n\nfunction TourStep(props: TourStepProps) {\n const {\n target,\n side = \"bottom\",\n sideOffset,\n align = \"center\",\n alignOffset,\n collisionBoundary = EMPTY_BOUNDARY,\n collisionPadding = 0,\n arrowPadding = 0,\n sticky = \"partial\",\n hideWhenDetached = false,\n avoidCollisions = true,\n required = false,\n forceMount = false,\n onStepEnter,\n onStepLeave,\n onPointerDownCapture: onPointerDownCaptureProp,\n onFocusCapture: onFocusCaptureProp,\n onBlurCapture: onBlurCaptureProp,\n children,\n className,\n style,\n asChild,\n ...stepProps\n } = props;\n\n const store = useStoreContext(STEP_NAME);\n\n const [arrow, setArrow] = React.useState<HTMLSpanElement | null>(null);\n const [footer, setFooter] = React.useState<FooterElement | null>(null);\n const [targetElement, setTargetElement] = React.useState<HTMLElement | null>(null);\n\n const stepRef = React.useRef<StepElement | null>(null);\n const stepIdRef = React.useRef<string>(\"\");\n const isPointerInsideReactTreeRef = React.useRef(false);\n const isFocusInsideReactTreeRef = React.useRef(false);\n\n const titleId = React.useId();\n const descriptionId = React.useId();\n\n const open = useStore((state) => state.open);\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n const context = useTourContext(STEP_NAME);\n\n const resolvedSideOffset = sideOffset ?? context.sideOffset;\n const resolvedAlignOffset = alignOffset ?? context.alignOffset;\n\n /*\n * ⚠ Khác thượng nguồn: đăng ký bước MỘT lần khi mount, sau đó cập nhật TẠI CHỖ.\n *\n * Bản gốc gỡ rồi thêm lại bước mỗi khi một prop đổi (kể cả `onStepEnter={() => …}` viết tại\n * chỗ — tức MỖI lần render). Thêm lại là nối vào CUỐI danh sách, còn thứ tự các bước khác giữ\n * trong ref riêng không ai cập nhật: bước bị đẩy xuống cuối, và ở `value` cũ không bước nào\n * nhận mình là bước hiện tại — tour trống trơn. Chỉ cần `side={isMobile ? … : …}` là dính.\n *\n * Hai callback đi qua ref để luôn gọi bản mới nhất mà không làm dữ liệu bước \"đổi\".\n */\n const callbacksRef = useAsRef({ onStepEnter, onStepLeave });\n\n const ownStepData = React.useMemo<StepData>(\n () => ({\n target,\n align,\n alignOffset: resolvedAlignOffset,\n side,\n sideOffset: resolvedSideOffset,\n collisionBoundary,\n collisionPadding,\n arrowPadding,\n sticky,\n hideWhenDetached,\n avoidCollisions,\n onStepEnter: () => callbacksRef.current.onStepEnter?.(),\n onStepLeave: () => callbacksRef.current.onStepLeave?.(),\n required\n }),\n [\n target,\n align,\n resolvedAlignOffset,\n side,\n resolvedSideOffset,\n collisionBoundary,\n collisionPadding,\n arrowPadding,\n sticky,\n hideWhenDetached,\n avoidCollisions,\n required,\n callbacksRef\n ]\n );\n const ownStepDataRef = useAsRef(ownStepData);\n\n useIsomorphicLayoutEffect(() => {\n const { id } = store.addStep(ownStepDataRef.current);\n stepIdRef.current = id;\n\n return () => {\n store.removeStep(id);\n };\n }, [store, ownStepDataRef]);\n\n useIsomorphicLayoutEffect(() => {\n store.updateStep(stepIdRef.current, ownStepData);\n }, [store, ownStepData]);\n\n const stepData = steps[value];\n\n // ⚠ Khác thượng nguồn: vị trí đọc từ store theo id (được dồn lại khi một bước khác bị gỡ),\n // không từ một ref chụp lúc đăng ký.\n const isCurrentStep = store.getStepIndex(stepIdRef.current) === value;\n\n /*\n * ⚠ Khác thượng nguồn: bản gốc gọi `getTargetElement` — tức `document.querySelector` — NGAY\n * TRONG render. Ở đây phân giải trong layout effect: chạy sau MỖI lần render như nhịp của bản\n * gốc (đích xuất hiện muộn vẫn bắt được), vẫn trước lượt sơn, và chỉ cho bước đang hiện.\n * `setState` cùng giá trị thì React bỏ qua, nên không có vòng lặp.\n */\n useIsomorphicLayoutEffect(() => {\n setTargetElement(open && isCurrentStep && stepData ? getTargetElement(stepData.target) : null);\n });\n\n /*\n * ⚠ Khác thượng nguồn: gom điều kiện \"bước này đang HIỆN\" về một chỗ. Bản gốc bật bẫy focus\n * và bộ nghe bấm-ra-ngoài theo `open && isCurrentStep`; nếu lượt render đó chưa có đích (và\n * không `forceMount`) thì bước chưa có DOM, hiệu ứng thoát sớm và KHÔNG chạy lại khi đích xuất\n * hiện — focus không bao giờ vào được bước.\n */\n const isStepRendered = open && isCurrentStep && !!stepData && (!!targetElement || forceMount);\n\n const middleware = React.useMemo(() => {\n if (!stepData) return [];\n\n const mainAxisOffset = stepData.sideOffset ?? resolvedSideOffset;\n const crossAxisOffset = stepData.alignOffset ?? resolvedAlignOffset;\n\n const padding =\n typeof stepData.collisionPadding === \"number\"\n ? stepData.collisionPadding\n : {\n top: stepData.collisionPadding?.top ?? 0,\n right: stepData.collisionPadding?.right ?? 0,\n bottom: stepData.collisionPadding?.bottom ?? 0,\n left: stepData.collisionPadding?.left ?? 0\n };\n\n const boundary = Array.isArray(stepData.collisionBoundary)\n ? stepData.collisionBoundary\n : stepData.collisionBoundary\n ? [stepData.collisionBoundary]\n : [];\n const hasExplicitBoundaries = boundary.length > 0;\n\n const detectOverflowOptions = {\n padding,\n boundary: boundary.filter((b): b is Element => b !== null),\n altBoundary: hasExplicitBoundaries\n };\n\n return [\n offset({\n mainAxis: mainAxisOffset,\n alignmentAxis: crossAxisOffset\n }),\n stepData.avoidCollisions &&\n shift({\n mainAxis: true,\n crossAxis: false,\n limiter: stepData.sticky === \"partial\" ? limitShift() : undefined,\n ...detectOverflowOptions\n }),\n stepData.avoidCollisions && flip({ ...detectOverflowOptions }),\n arrow && onArrow({ element: arrow, padding: stepData.arrowPadding }),\n stepData.hideWhenDetached &&\n hide({\n strategy: \"referenceHidden\",\n ...detectOverflowOptions\n })\n ].filter(Boolean) as Middleware[];\n }, [stepData, resolvedSideOffset, resolvedAlignOffset, arrow]);\n\n const placement = getPlacement(stepData?.side ?? side, stepData?.align ?? align);\n\n const {\n refs,\n floatingStyles,\n placement: finalPlacement,\n middlewareData\n } = useFloating({\n placement,\n middleware,\n strategy: \"fixed\",\n whileElementsMounted: autoUpdate,\n elements: {\n reference: targetElement\n }\n });\n\n const composedRef = useComposedRefs(refs.setFloating, stepRef);\n\n const [placedSide, placedAlign] = getSideAndAlignFromPlacement(finalPlacement);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;\n const isHidden = hideWhenDetached && middlewareData.hide?.referenceHidden;\n\n const stepContextValue = React.useMemo<StepContextValue>(\n () => ({\n arrowX,\n arrowY,\n placedAlign,\n placedSide,\n shouldHideArrow: cannotCenterArrow,\n titleId,\n descriptionId,\n onArrowChange: setArrow,\n onFooterChange: setFooter\n }),\n [arrowX, arrowY, placedSide, placedAlign, cannotCenterArrow, titleId, descriptionId]\n );\n\n React.useEffect(() => {\n if (open && targetElement && isCurrentStep) {\n updateMask(store, targetElement, context.spotlightPadding);\n\n let rafId: number | null = null;\n\n function onResize() {\n if (targetElement) {\n updateMask(store, targetElement, context.spotlightPadding);\n }\n }\n\n function onScroll() {\n if (rafId !== null) return;\n rafId = requestAnimationFrame(() => {\n if (targetElement) {\n updateMask(store, targetElement, context.spotlightPadding);\n }\n rafId = null;\n });\n }\n\n window.addEventListener(\"resize\", onResize);\n /*\n * ⚠ Khác thượng nguồn: nghe ở pha CAPTURE. Sự kiện `scroll` của một phần tử không nổi bọt\n * lên `window`; bản gốc chỉ bắt được khi CỬA SỔ cuộn. Trong `AppShell` chỉ `<main>` cuộn,\n * nên lỗ sáng đứng yên trong khi đích trôi đi.\n */\n window.addEventListener(\"scroll\", onScroll, { capture: true, passive: true });\n return () => {\n window.removeEventListener(\"resize\", onResize);\n window.removeEventListener(\"scroll\", onScroll, { capture: true });\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n }\n };\n }\n }, [open, targetElement, isCurrentStep, store, context.spotlightPadding]);\n\n React.useEffect(() => {\n if (!isStepRendered) return;\n\n const stepElement = stepRef.current;\n if (!stepElement) return;\n\n const ownerDocument = stepElement.ownerDocument;\n\n function onPointerDown(event: PointerEvent) {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const pointerDownOutsideEvent = new CustomEvent(POINTER_DOWN_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n\n context.onPointerDownOutside?.(pointerDownOutsideEvent);\n\n const interactOutsideEvent = new CustomEvent(INTERACT_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n context.onInteractOutside?.(interactOutsideEvent);\n\n if (\n !pointerDownOutsideEvent.defaultPrevented &&\n !interactOutsideEvent.defaultPrevented &&\n context.dismissible\n ) {\n store.setState(\"open\", false);\n }\n }\n\n isPointerInsideReactTreeRef.current = false;\n }\n\n const timerId = window.setTimeout(() => {\n ownerDocument.addEventListener(\"pointerdown\", onPointerDown);\n }, 0);\n\n return () => {\n window.clearTimeout(timerId);\n ownerDocument.removeEventListener(\"pointerdown\", onPointerDown);\n };\n }, [isStepRendered, store, context]);\n\n React.useEffect(() => {\n if (!isStepRendered) return;\n\n const stepElement = stepRef.current;\n if (!stepElement) return;\n\n const ownerDocument = stepElement.ownerDocument;\n\n function onFocusIn(event: FocusEvent) {\n const target = event.target as HTMLElement;\n\n const isFocusInStep = stepElement?.contains(target);\n const isFocusInTarget = targetElement?.contains(target);\n\n if (event.target && !isFocusInsideReactTreeRef.current && !isFocusInStep && !isFocusInTarget) {\n const interactOutsideEvent = new CustomEvent(INTERACT_OUTSIDE, {\n ...EVENT_OPTIONS,\n detail: { originalEvent: event }\n });\n\n context.onInteractOutside?.(interactOutsideEvent);\n\n if (!interactOutsideEvent.defaultPrevented && context.dismissible) {\n store.setState(\"open\", false);\n }\n }\n }\n\n ownerDocument.addEventListener(\"focusin\", onFocusIn);\n\n return () => {\n ownerDocument.removeEventListener(\"focusin\", onFocusIn);\n };\n }, [isStepRendered, store, context, targetElement]);\n\n const onPointerDownCapture = React.useCallback(\n (event: React.PointerEvent<StepElement>) => {\n onPointerDownCaptureProp?.(event);\n isPointerInsideReactTreeRef.current = true;\n },\n [onPointerDownCaptureProp]\n );\n\n const onFocusCapture = React.useCallback(\n (event: React.FocusEvent<StepElement>) => {\n onFocusCaptureProp?.(event);\n isFocusInsideReactTreeRef.current = true;\n },\n [onFocusCaptureProp]\n );\n\n const onBlurCapture = React.useCallback(\n (event: React.FocusEvent<StepElement>) => {\n onBlurCaptureProp?.(event);\n isFocusInsideReactTreeRef.current = false;\n },\n [onBlurCaptureProp]\n );\n\n React.useEffect(() => {\n if (!open || !isCurrentStep || !targetElement) return;\n\n function onTargetPointerDownCapture() {\n isPointerInsideReactTreeRef.current = true;\n }\n\n function onTargetFocusCapture() {\n isFocusInsideReactTreeRef.current = true;\n }\n\n function onTargetBlurCapture() {\n isFocusInsideReactTreeRef.current = false;\n }\n\n targetElement.addEventListener(\"pointerdown\", onTargetPointerDownCapture, true);\n targetElement.addEventListener(\"focus\", onTargetFocusCapture, true);\n targetElement.addEventListener(\"blur\", onTargetBlurCapture, true);\n\n return () => {\n targetElement.removeEventListener(\"pointerdown\", onTargetPointerDownCapture, true);\n targetElement.removeEventListener(\"focus\", onTargetFocusCapture, true);\n targetElement.removeEventListener(\"blur\", onTargetBlurCapture, true);\n };\n }, [open, isCurrentStep, targetElement]);\n\n useFocusGuards(isStepRendered);\n useFocusTrap(stepRef, isStepRendered, open, context.onOpenAutoFocus, context.onCloseAutoFocus);\n\n if (!isStepRendered) {\n return null;\n }\n\n const StepPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StepContext.Provider value={stepContextValue}>\n <StepPrimitive\n ref={composedRef}\n /*\n * ⚠ Khác thượng nguồn: bản gốc là `<div>` TRẦN, không vai trò, không tên. Bẫy focus kéo\n * người dùng vào đó và trình đọc màn hình chỉ đọc \"nút Đóng hướng dẫn\" — không nói\n * đang ở đâu, bước này nói gì. `role=\"dialog\"` + tiêu đề/mô tả làm tên và lời mô tả, như\n * `PopoverContent` của Radix. Không `aria-modal`: đích đang được soi nằm NGOÀI bước và\n * người dùng vẫn cần đọc được nó.\n */\n role=\"dialog\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n data-slot=\"tour-step\"\n data-side={placedSide}\n data-align={placedAlign}\n dir={context.dir}\n tabIndex={-1}\n {...stepProps}\n onPointerDownCapture={onPointerDownCapture}\n onFocusCapture={onFocusCapture}\n onBlurCapture={onBlurCapture}\n className={cn(\n // Bề mặt cùng khuôn với `PopoverContent`: nền/chữ popover, viền token, bóng tầng nổi.\n \"fixed z-50 flex w-80 flex-col gap-4 rounded-lg border bg-popover p-4 text-popover-foreground shadow-overlay outline-none\",\n className\n )}\n style={{\n ...style,\n ...floatingStyles,\n visibility: isHidden ? \"hidden\" : undefined,\n pointerEvents: isHidden ? \"none\" : undefined\n }}\n >\n {children}\n {!footer && <DefaultFooterContext.Provider value={true}>{context.stepFooter}</DefaultFooterContext.Provider>}\n </StepPrimitive>\n </StepContext.Provider>\n );\n}\n\ninterface TourSpotlightProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TourSpotlight(props: TourSpotlightProps) {\n const { asChild, className, style, forceMount = false, ...backdropProps } = props;\n\n const open = useStore((state) => state.open);\n const maskPath = useStore((state) => state.maskPath);\n\n if (!open && !forceMount) return null;\n\n const SpotlightPrimitive = asChild ? Slot : \"div\";\n\n return (\n <SpotlightPrimitive\n data-slot=\"tour-spotlight\"\n data-state={getDataState(open)}\n {...backdropProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: `bg-black/80` (bảng màu mặc định Tailwind) → đúng màu lớp phủ của\n * `DialogOverlay`, để lớp tối của tour và của hộp thoại là MỘT thứ trong mắt người dùng.\n * Không lấy `backdrop-blur-sm` của nó: tour cần người dùng còn đọc được ngữ cảnh quanh đích.\n */\n \"fixed inset-0 z-50 bg-ink/60 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 dark:bg-ink/80\",\n className\n )}\n style={{\n clipPath: maskPath,\n ...style\n }}\n />\n );\n}\n\ninterface TourSpotlightRingProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TourSpotlightRing(props: TourSpotlightRingProps) {\n const { asChild, className, style, forceMount = false, ...ringProps } = props;\n\n const open = useStore((state) => state.open);\n const spotlightRect = useStore((state) => state.spotlightRect);\n\n if (!open && !forceMount) return null;\n if (!spotlightRect) return null;\n\n const RingPrimitive = asChild ? Slot : \"div\";\n\n return (\n <RingPrimitive\n data-slot=\"tour-spotlight-ring\"\n data-state={getDataState(open)}\n {...ringProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: bỏ `border-ring`. Không có độ dày viền đi kèm nên nó không vẽ gì —\n * chỉ là một màu viền treo sẵn. App muốn viền thì truyền đủ cả độ dày lẫn màu\n * (`border-2 border-primary-ink`), như chính các ví dụ của thượng nguồn vẫn làm.\n */\n \"pointer-events-none fixed z-50 ring-[3px] ring-ring/50\",\n className\n )}\n style={{\n left: spotlightRect.x,\n top: spotlightRect.y,\n width: spotlightRect.width,\n height: spotlightRect.height,\n ...style\n }}\n />\n );\n}\n\ninterface TourPortalProps {\n children?: React.ReactNode;\n container?: HTMLElement | null;\n}\n\nfunction TourPortal(props: TourPortalProps) {\n const { children, container } = props;\n\n const portalContext = usePortalContext(PORTAL_NAME);\n\n /*\n * ⚠ Khác thượng nguồn: giữ NÚT gắn trong state thay cho cờ `mounted`, để lượt render không\n * phải đọc `document.body` — mọi chỗ chạm DOM đều nằm trong effect.\n */\n const [mountNode, setMountNode] = React.useState<HTMLElement | null>(null);\n\n useIsomorphicLayoutEffect(() => {\n const node = container ?? document.body;\n setMountNode(node);\n\n portalContext?.onPortalChange(node);\n return () => {\n portalContext?.onPortalChange(null);\n };\n }, [container, portalContext]);\n\n if (!mountNode) return null;\n\n const portalContainer = container ?? portalContext?.portal ?? mountNode;\n\n return ReactDOM.createPortal(children, portalContainer);\n}\n\ninterface TourArrowProps extends React.ComponentProps<\"svg\"> {\n width?: number;\n height?: number;\n asChild?: boolean;\n}\n\nfunction TourArrow(props: TourArrowProps) {\n const { width = 10, height = 5, className, children, asChild, ...arrowProps } = props;\n\n const stepContext = useStepContext(ARROW_NAME);\n const baseSide = OPPOSITE_SIDE[stepContext.placedSide];\n\n return (\n <span\n ref={stepContext.onArrowChange}\n data-slot=\"tour-arrow\"\n style={{\n position: \"absolute\",\n left: stepContext.arrowX != null ? `${stepContext.arrowX}px` : undefined,\n top: stepContext.arrowY != null ? `${stepContext.arrowY}px` : undefined,\n [baseSide]: 0,\n transformOrigin: {\n top: \"\",\n right: \"0 0\",\n bottom: \"center 0\",\n left: \"100% 0\"\n }[stepContext.placedSide],\n transform: {\n top: \"translateY(100%)\",\n right: \"translateY(50%) rotate(90deg) translateX(-50%)\",\n bottom: \"rotate(180deg)\",\n left: \"translateY(50%) rotate(-90deg) translateX(50%)\"\n }[stepContext.placedSide],\n visibility: stepContext.shouldHideArrow ? \"hidden\" : undefined\n }}\n >\n {/* ⚠ Khác thượng nguồn: `aria-hidden` — mũi tên thuần trang trí, không có gì để đọc. */}\n <svg\n viewBox=\"0 0 30 10\"\n preserveAspectRatio=\"none\"\n width={width}\n height={height}\n aria-hidden=\"true\"\n {...arrowProps}\n className={cn(\"block fill-popover stroke-border\", className)}\n >\n {asChild ? children : <polygon points=\"0,0 30,0 15,10\" />}\n </svg>\n </span>\n );\n}\n\ntype TourHeaderProps = DivProps;\n\nfunction TourHeader(props: TourHeaderProps) {\n const { asChild, className, ...headerProps } = props;\n\n const context = useTourContext(HEADER_NAME);\n\n const HeaderPrimitive = asChild ? Slot : \"div\";\n\n return (\n <HeaderPrimitive\n data-slot=\"tour-header\"\n dir={context.dir}\n {...headerProps}\n className={cn(\"flex flex-col gap-1.5 text-center sm:text-left\", className)}\n />\n );\n}\n\ntype TourTitleProps = DivProps;\n\nfunction TourTitle(props: TourTitleProps) {\n const { asChild, className, ...titleProps } = props;\n\n const context = useTourContext(TITLE_NAME);\n // ⚠ Khác thượng nguồn: nhận id từ bước chứa nó để bước trỏ `aria-labelledby` vào đây.\n const stepContext = React.useContext(StepContext);\n\n const TitlePrimitive = asChild ? Slot : \"div\";\n\n return (\n <TitlePrimitive\n id={stepContext?.titleId}\n data-slot=\"tour-title\"\n dir={context.dir}\n {...titleProps}\n className={cn(\"text-lg leading-none font-semibold tracking-tight\", className)}\n />\n );\n}\n\ntype TourDescriptionProps = DivProps;\n\nfunction TourDescription(props: TourDescriptionProps) {\n const { asChild, className, ...descriptionProps } = props;\n\n const context = useTourContext(DESCRIPTION_NAME);\n // ⚠ Khác thượng nguồn: nhận id từ bước chứa nó để bước trỏ `aria-describedby` vào đây.\n const stepContext = React.useContext(StepContext);\n\n const DescriptionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DescriptionPrimitive\n id={stepContext?.descriptionId}\n data-slot=\"tour-description\"\n dir={context.dir}\n {...descriptionProps}\n className={cn(\"text-sm text-muted-foreground\", className)}\n />\n );\n}\n\ninterface TourCloseProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nfunction TourClose(props: TourCloseProps) {\n const { asChild, className, children, onClick: onClickProp, ...closeButtonProps } = props;\n\n const store = useStoreContext(CLOSE_NAME);\n const context = useTourContext(CLOSE_NAME);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<CloseElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"open\", false);\n },\n [store, onClickProp]\n );\n\n const ClosePrimitive = asChild ? Slot : \"button\";\n\n return (\n <ClosePrimitive\n type=\"button\"\n aria-label={context.labels.close}\n data-slot=\"tour-close\"\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: khuôn nút đóng của `DialogContent` (màu chữ muted, hover nền muted,\n * vòng focus của gói) thay cho `opacity-70` — `opacity` không miễn ngưỡng tương phản cho\n * thứ còn bấm được (docs/hop-dong-mau.md). `top-3 right-3 p-1` đặt icon đúng chỗ\n * `top-4 right-4` cũ nhưng vùng bấm lên ~24px thay vì 16px (WCAG 2.5.8).\n */\n \"absolute top-3 right-3 rounded-md p-1 text-muted-foreground transition-colors duration-150 ease-out hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n onClick={onClick}\n {...closeButtonProps}\n >\n {/*\n * ⚠ Khác thượng nguồn: bản gốc luôn render icon X làm con, đè mất `children` của app — và\n * với `asChild` thì Slot nhận chính cái `<svg>` làm phần tử được \"bọc\".\n */}\n {children ?? <X aria-hidden=\"true\" />}\n </ClosePrimitive>\n );\n}\n\ntype TourPrevProps = React.ComponentProps<typeof Button>;\n\n/*\n * ⚠ Khác thượng nguồn (áp cho cả `TourPrev`, `TourNext`, `TourSkip`): bỏ `aria-label` mặc định.\n * Nút đã có chữ hiện; `aria-label` cứng ĐÈ lên chữ đó — ở bước cuối `TourNext` HIỆN \"Finish\"\n * nhưng ĐỌC \"Next step\", và app truyền `children` riêng vẫn bị đọc bằng nhãn cũ. Lệch WCAG 2.5.3\n * (Label in Name): người dùng điều khiển bằng giọng nói gọi đúng chữ trên nút mà không bấm được.\n * App dùng nút chỉ-có-icon thì tự truyền `aria-label`.\n */\nfunction TourPrev(props: TourPrevProps) {\n const { children, onClick: onClickProp, ...prevButtonProps } = props;\n\n const store = useStoreContext(PREV_NAME);\n const context = useTourContext(PREV_NAME);\n const value = useStore((state) => state.value);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<PrevElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n if (value > 0) {\n store.setState(\"value\", value - 1);\n }\n },\n [value, store, onClickProp]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"tour-prev\"\n variant=\"outline\"\n {...prevButtonProps}\n onClick={onClick}\n disabled={value === 0}\n >\n {children ?? (\n <>\n {/* `Button` của gói không tự đặt cỡ icon (khác shadcn) → ghi `size-4` tường minh. */}\n <ChevronLeft aria-hidden=\"true\" className=\"size-4\" />\n {context.labels.prev}\n </>\n )}\n </Button>\n );\n}\n\ntype TourNextProps = React.ComponentProps<typeof Button>;\n\nfunction TourNext(props: TourNextProps) {\n const { children, onClick: onClickProp, ...nextButtonProps } = props;\n const store = useStoreContext(NEXT_NAME);\n const context = useTourContext(NEXT_NAME);\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n\n const isLastStep = value === steps.length - 1;\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<NextElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"value\", value + 1);\n },\n [value, store, onClickProp]\n );\n\n return (\n <Button type=\"button\" data-slot=\"tour-next\" {...nextButtonProps} onClick={onClick}>\n {children ?? (\n <>\n {isLastStep ? context.labels.finish : context.labels.next}\n {!isLastStep && <ChevronRight aria-hidden=\"true\" className=\"size-4\" />}\n </>\n )}\n </Button>\n );\n}\n\ntype TourSkipProps = React.ComponentProps<typeof Button>;\n\nfunction TourSkip(props: TourSkipProps) {\n const { children, onClick: onClickProp, ...skipButtonProps } = props;\n\n const store = useStoreContext(SKIP_NAME);\n const context = useTourContext(SKIP_NAME);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<SkipElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n\n store.setState(\"open\", false);\n },\n [store, onClickProp]\n );\n\n return (\n <Button type=\"button\" data-slot=\"tour-skip\" variant=\"outline\" {...skipButtonProps} onClick={onClick}>\n {children ?? context.labels.skip}\n </Button>\n );\n}\n\ninterface TourStepCounterProps extends DivProps {\n /** Mặc định `labels.stepCounter` của `Tour` — \"Step 2 of 5\". */\n format?: (current: number, total: number) => string;\n}\n\nfunction TourStepCounter(props: TourStepCounterProps) {\n const { format: formatProp, asChild, className, children, ...stepCounterProps } = props;\n\n const context = useTourContext(STEP_COUNTER_NAME);\n const format = formatProp ?? context.labels.stepCounter;\n\n const value = useStore((state) => state.value);\n const steps = useStore((state) => state.steps);\n\n const StepCounterPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StepCounterPrimitive\n data-slot=\"tour-step-counter\"\n {...stepCounterProps}\n // ⚠ Khác thượng nguồn: `whitespace-nowrap` — \"Bước 1/3\" đặt cạnh \"Quay lại\"/\"Tiếp theo\" trong\n // thẻ `w-80` bị bẻ làm hai dòng (đo trên trình duyệt); con số đếm bước không nên vỡ dòng.\n className={cn(\"whitespace-nowrap text-sm text-muted-foreground\", className)}\n >\n {children ?? format(value + 1, steps.length)}\n </StepCounterPrimitive>\n );\n}\n\ntype TourFooterProps = DivProps;\n\nfunction TourFooter(props: TourFooterProps) {\n const { asChild, className, ref, ...footerProps } = props;\n\n const stepContext = useStepContext(FOOTER_NAME);\n const hasDefaultFooter = React.useContext(DefaultFooterContext);\n const context = useTourContext(FOOTER_NAME);\n\n const composedRef = useComposedRefs(ref, hasDefaultFooter ? undefined : stepContext.onFooterChange);\n\n const FooterPrimitive = asChild ? Slot : \"div\";\n\n return (\n <FooterPrimitive\n data-slot=\"tour-footer\"\n dir={context.dir}\n {...footerProps}\n ref={composedRef}\n className={cn(\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\", className)}\n />\n );\n}\n\nexport {\n Tour,\n TourArrow,\n type TourArrowProps,\n TourClose,\n type TourCloseProps,\n TourDescription,\n type TourDescriptionProps,\n TourFooter,\n type TourFooterProps,\n TourHeader,\n type TourHeaderProps,\n TourNext,\n type TourNextProps,\n TourPortal,\n type TourPortalProps,\n TourPrev,\n type TourPrevProps,\n type TourProps,\n TourSkip,\n type TourSkipProps,\n TourSpotlight,\n type TourSpotlightProps,\n TourSpotlightRing,\n type TourSpotlightRingProps,\n TourStep,\n TourStepCounter,\n type TourStepCounterProps,\n type TourStepProps,\n TourTitle,\n type TourTitleProps\n};\n"],"mappings":"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","names":["offset","onResize","onScroll","target"]}
|
|
@@ -105,7 +105,7 @@ function ShortTextCell({
|
|
|
105
105
|
setValue(initialValue);
|
|
106
106
|
cellRef.current?.blur();
|
|
107
107
|
}
|
|
108
|
-
} else if (isFocused && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
|
108
|
+
} else if (isFocused && !readOnly && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
|
109
109
|
setValue(event.key);
|
|
110
110
|
queueMicrotask(() => {
|
|
111
111
|
if (cellRef.current && cellRef.current.contentEditable === "true") {
|
|
@@ -120,7 +120,7 @@ function ShortTextCell({
|
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
|
-
[isEditing, isFocused, initialValue, tableMeta, rowIndex, columnId]
|
|
123
|
+
[isEditing, isFocused, readOnly, initialValue, tableMeta, rowIndex, columnId]
|
|
124
124
|
);
|
|
125
125
|
React.useEffect(() => {
|
|
126
126
|
const wasEditing = prevIsEditingRef.current;
|
|
@@ -405,7 +405,7 @@ function NumberCell({
|
|
|
405
405
|
setValue(String(initialValue ?? ""));
|
|
406
406
|
inputRef.current?.blur();
|
|
407
407
|
}
|
|
408
|
-
} else if (isFocused) {
|
|
408
|
+
} else if (isFocused && !readOnly) {
|
|
409
409
|
if (event.key === "Backspace") {
|
|
410
410
|
setValue("");
|
|
411
411
|
} else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
|
@@ -413,7 +413,7 @@ function NumberCell({
|
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
415
|
},
|
|
416
|
-
[isEditing, isFocused, initialValue, tableMeta, rowIndex, columnId, value]
|
|
416
|
+
[isEditing, isFocused, readOnly, initialValue, tableMeta, rowIndex, columnId, value]
|
|
417
417
|
);
|
|
418
418
|
React.useEffect(() => {
|
|
419
419
|
const wasEditing = prevIsEditingRef.current;
|