@mmmmzxe/react-360-viewer 0.1.11 → 0.1.13
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 +54 -656
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/inject-styles.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ui/Badge/index.tsx +1 -1
- package/src/components/ui/Button/index.tsx +5 -6
- package/src/styles.css +2 -0
package/dist/index.js
CHANGED
|
@@ -510,7 +510,7 @@ import { cva } from "class-variance-authority";
|
|
|
510
510
|
import { Slot } from "radix-ui";
|
|
511
511
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
512
512
|
var badgeVariants = cva(
|
|
513
|
-
"h-5 gap-1 rounded-
|
|
513
|
+
"h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
|
|
514
514
|
{
|
|
515
515
|
variants: {
|
|
516
516
|
variant: {
|
|
@@ -713,7 +713,7 @@ import { cva as cva3 } from "class-variance-authority";
|
|
|
713
713
|
import { Slot as Slot3 } from "radix-ui";
|
|
714
714
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
715
715
|
var buttonVariants = cva3(
|
|
716
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-
|
|
716
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
|
|
717
717
|
{
|
|
718
718
|
variants: {
|
|
719
719
|
variant: {
|
|
@@ -726,12 +726,12 @@ var buttonVariants = cva3(
|
|
|
726
726
|
},
|
|
727
727
|
size: {
|
|
728
728
|
default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2",
|
|
729
|
-
xs: "h-6 gap-1 rounded-
|
|
730
|
-
sm: "h-8 gap-1 rounded-
|
|
729
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5",
|
|
730
|
+
sm: "h-8 gap-1 rounded-md px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5",
|
|
731
731
|
lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3",
|
|
732
732
|
icon: "size-9",
|
|
733
|
-
"icon-xs": "size-6 rounded-
|
|
734
|
-
"icon-sm": "size-8 rounded-
|
|
733
|
+
"icon-xs": "size-6 rounded-md in-data-[slot=button-group]:rounded-md",
|
|
734
|
+
"icon-sm": "size-8 rounded-md in-data-[slot=button-group]:rounded-md",
|
|
735
735
|
"icon-lg": "size-10"
|
|
736
736
|
}
|
|
737
737
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feature/Viewer360.tsx","../src/constants/viewer360Labels.ts","../src/constants/viewer360ClassNames.ts","../src/components/utils/index.ts","../src/helpers/viewer360PropsHelpers.ts","../src/hooks/useViewer360.ts","../src/helpers/adjustViewerZoom.ts","../src/helpers/computeDragFrameIndex.ts","../src/helpers/computeViewerImageLayout.ts","../src/helpers/computeViewerPanOffset.ts","../src/helpers/viewerHelpers.ts","../src/components/ui/Card/index.tsx","../src/components/ui/Badge/index.tsx","../src/feature/Viewer360AddModeBanner.tsx","../src/feature/Viewer360FrameIndicator.tsx","../src/helpers/markerHelpers.ts","../src/components/ui/Item/index.tsx","../src/components/ui/Separator/index.tsx","../src/feature/Viewer360MarkerPin.tsx","../src/constants/viewer360MarkerLabels.ts","../src/components/ui/Button/index.tsx","../src/feature/Viewer360HotspotOverlay.tsx","../src/components/ui/Label/index.tsx","../src/components/ui/Spinner/index.tsx","../src/feature/Viewer360LoadingOverlay.tsx","../src/feature/Viewer360Toolbar.tsx","../src/constants/viewer360Config.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { buildViewer360ThemeStyle, mergeViewer360ClassNames, mergeViewer360Labels } from '../helpers/viewer360PropsHelpers';\nimport { useViewer360 } from '../hooks/useViewer360';\nimport type { Viewer360OverlayRenderProps, Viewer360Props, Viewer360ToolbarRenderProps } from '../types';\nimport { Card } from '@/components/ui/Card';\nimport { cn } from '@/components/utils';\n\nimport { Viewer360AddModeBanner } from './Viewer360AddModeBanner';\nimport { Viewer360FrameIndicator } from './Viewer360FrameIndicator';\nimport { Viewer360HotspotOverlay } from './Viewer360HotspotOverlay';\nimport { Viewer360LoadingOverlay } from './Viewer360LoadingOverlay';\nimport { Viewer360Toolbar } from './Viewer360Toolbar';\n\nexport function Viewer360<TData = unknown>({\n frames,\n currentFrameIndex: controlledFrameIndex,\n defaultFrameIndex = 0,\n onFrameChange,\n config,\n className,\n classNames,\n style,\n theme,\n labels,\n aspectRatio = '16 / 10',\n showZoomControls = true,\n showResetControl = true,\n showFrameIndicator = true,\n showDragHint = true,\n showHotspotModeControl = false,\n hotspotPin,\n hotspots = [],\n renderHotspot,\n renderLoading,\n renderFrameIndicator,\n renderHotspotModeBanner,\n renderToolbar,\n onHotspotClick,\n hotspotMode: controlledHotspotMode,\n defaultHotspotMode = false,\n onHotspotModeChange,\n onHotspotAdd,\n children,\n}: Viewer360Props<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: States & Constants\n // ----------------------------------------------------------------------------------------------------\n const mergedLabels = useMemo(() => mergeViewer360Labels(labels), [labels]);\n const mergedClassNames = useMemo(() => mergeViewer360ClassNames(classNames), [classNames]);\n const themeStyle = useMemo(() => buildViewer360ThemeStyle(theme), [theme]);\n\n const [internalFrameIndex, setInternalFrameIndex] = useState(defaultFrameIndex);\n const [internalHotspotMode, setInternalHotspotMode] = useState(defaultHotspotMode);\n\n const currentFrameIndex = controlledFrameIndex ?? internalFrameIndex;\n const hotspotMode = controlledHotspotMode ?? internalHotspotMode;\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Functions\n // ----------------------------------------------------------------------------------------------------\n function handleFrameChange(index: number): void {\n if (controlledFrameIndex === undefined) {\n setInternalFrameIndex(index);\n }\n\n onFrameChange?.(index);\n }\n\n function handleHotspotModeChange(active: boolean): void {\n if (controlledHotspotMode === undefined) {\n setInternalHotspotMode(active);\n }\n\n onHotspotModeChange?.(active);\n }\n\n const {\n canvasRef,\n containerRef,\n currentFrame,\n currentFrameHotspots,\n imagesLoaded,\n isHotspotMode,\n isResetDisabled,\n maxZoom,\n minZoom,\n viewerCursorClass,\n zoom,\n getHotspotScreenPosition,\n handleCanvasClick,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleWheel,\n handleResetView,\n handleZoomIn,\n handleZoomOut,\n } = useViewer360<TData>({\n frames,\n hotspots,\n currentFrameIndex,\n onFrameChange: handleFrameChange,\n config,\n hotspotMode,\n onHotspotAdd,\n });\n\n useEffect(() => {\n if (controlledHotspotMode === undefined) return;\n if (controlledHotspotMode !== internalHotspotMode) {\n setInternalHotspotMode(controlledHotspotMode);\n }\n }, [controlledHotspotMode, internalHotspotMode]);\n\n const frameLabel = currentFrame?.label ?? frames[currentFrameIndex]?.label;\n const overlayProps: Viewer360OverlayRenderProps = {\n currentFrameIndex,\n frameCount: frames.length,\n frameLabel,\n isHotspotMode,\n labels: mergedLabels,\n frameIndicatorClassName: mergedClassNames.frameIndicator,\n };\n const toolbarProps: Viewer360ToolbarRenderProps = {\n zoom,\n minZoom,\n maxZoom,\n isResetDisabled,\n isHotspotMode,\n showHotspotModeControl,\n showZoomControls,\n showResetControl,\n showDragHint,\n labels: mergedLabels,\n onZoomIn: handleZoomIn,\n onZoomOut: handleZoomOut,\n onResetView: handleResetView,\n onHotspotModeChange: handleHotspotModeChange,\n };\n const showDefaultToolbar = showZoomControls || showResetControl || showHotspotModeControl || showDragHint;\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Card\n data-viewer-360=\"\"\n className={cn(mergedClassNames.root, 'gap-0 py-0 shadow-none ring-0', className)}\n style={{ ...themeStyle, ...style }}\n >\n <div\n ref={containerRef}\n className={cn(mergedClassNames.viewport, viewerCursorClass)}\n style={{ aspectRatio }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerLeave={handlePointerUp}\n onWheel={handleWheel}\n onClick={handleCanvasClick}\n >\n <canvas ref={canvasRef} className={mergedClassNames.canvas} />\n\n <div className={mergedClassNames.overlay}>\n {currentFrameHotspots.map((hotspot) => {\n const position = getHotspotScreenPosition(hotspot);\n\n return (\n <Viewer360HotspotOverlay\n key={hotspot.id}\n hotspot={hotspot}\n leftPercent={position.leftPercent}\n topPercent={position.topPercent}\n hotspotPin={hotspotPin}\n renderHotspot={renderHotspot}\n onHotspotClick={onHotspotClick}\n />\n );\n })}\n {children}\n </div>\n\n {!imagesLoaded &&\n (renderLoading ? (\n renderLoading()\n ) : (\n <Viewer360LoadingOverlay\n className={mergedClassNames.loading}\n textClassName={mergedClassNames.loadingText}\n label={mergedLabels.loading}\n />\n ))}\n\n {showFrameIndicator &&\n frames.length > 0 &&\n (renderFrameIndicator ? (\n renderFrameIndicator(overlayProps)\n ) : (\n <Viewer360FrameIndicator\n className={mergedClassNames.frameIndicator}\n label={mergedLabels.frameIndicator({\n current: currentFrameIndex + 1,\n total: frames.length,\n label: frameLabel,\n })}\n />\n ))}\n\n {isHotspotMode &&\n onHotspotAdd &&\n (renderHotspotModeBanner ? (\n renderHotspotModeBanner({ labels: mergedLabels })\n ) : (\n <Viewer360AddModeBanner className={mergedClassNames.hotspotModeBanner} label={mergedLabels.hotspotModeActive} />\n ))}\n </div>\n\n {renderToolbar ? renderToolbar(toolbarProps) : showDefaultToolbar ? <Viewer360Toolbar {...toolbarProps} /> : null}\n </Card>\n );\n}\n","import type { Viewer360Labels } from '../types/Viewer360Props';\n\nexport const defaultViewer360Labels: Required<Viewer360Labels> = {\n loading: 'Loading images…',\n dragHint: 'Drag to rotate • Scroll to zoom',\n frameIndicator: ({ current, total, label }) => (label ? `${label} · ${current} / ${total}` : `${current} / ${total}`),\n zoom: (percent) => `${percent}%`,\n hotspotModeActive: 'Click on the image to place a hotspot',\n addHotspot: 'Add hotspot',\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n resetView: 'Reset view',\n deleteMarker: 'Remove marker',\n};\n","import type { Viewer360ClassNames } from '../types/Viewer360Props';\nimport type { Viewer360MarkerPinClassNames } from '../types/Viewer360Marker';\n\nexport const viewer360ClassNames: Required<Viewer360ClassNames> = {\n root: 'overflow-hidden rounded-lg border bg-card text-card-foreground',\n viewport: 'relative aspect-[16/10] w-full touch-none select-none bg-muted',\n canvas: 'absolute inset-0 size-full',\n overlay: 'pointer-events-none absolute inset-0 overflow-hidden',\n loading: 'absolute inset-0 flex items-center justify-center bg-muted/80',\n loadingText: 'text-sm text-muted-foreground',\n frameIndicator:\n 'pointer-events-none absolute bottom-4 start-1/2 z-20 -translate-x-1/2 rounded-full border bg-background px-4 py-1.5 text-xs font-medium shadow-sm whitespace-nowrap',\n hotspotModeBanner:\n 'pointer-events-none absolute top-4 start-1/2 z-20 -translate-x-1/2 rounded-full border border-amber-200 bg-amber-50 px-4 py-1.5 text-xs font-medium text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-400',\n toolbar: 'flex flex-wrap items-center justify-between gap-2 border-t px-4 py-3',\n dragHint: 'hidden text-xs text-muted-foreground sm:block',\n controls: 'ms-auto flex items-center gap-1.5',\n controlButton: '',\n controlButtonActive: '',\n controlButtonDisabled: '',\n zoomDisplay: 'flex min-w-[3rem] items-center justify-center gap-1 rounded-md border bg-background px-2 py-1 text-xs font-medium',\n divider: 'mx-1 h-6 w-px bg-border',\n};\n\nexport const viewer360MarkerPinClassNames: Required<Viewer360MarkerPinClassNames> = {\n root: 'pointer-events-auto absolute z-30 -translate-x-1/2 -translate-y-1/2',\n ping: 'pointer-events-none absolute inset-0 inline-flex animate-ping rounded-full bg-destructive opacity-75',\n dot: 'relative z-10 inline-flex size-4 min-h-4 min-w-4 shrink-0 rounded-full border-2 border-background bg-destructive p-0 shadow-md transition-transform duration-200 hover:scale-125 focus:outline-none',\n tooltip:\n 'absolute bottom-6 left-1/2 z-40 w-64 -translate-x-1/2 rounded-lg border bg-popover p-3 text-popover-foreground shadow-md',\n tooltipHeader: 'flex items-start justify-between gap-2',\n tooltipBody: 'flex min-w-0 flex-col gap-1',\n tooltipTitle: 'text-sm font-medium',\n tooltipDescription: 'mt-2 line-clamp-3 text-xs text-muted-foreground',\n deleteButton: '',\n};\n\n/** @deprecated Use `viewer360ClassNames` */\nexport const defaultViewer360ClassNames = viewer360ClassNames;\n\n/** @deprecated Use `viewer360MarkerPinClassNames` */\nexport const defaultViewer360MarkerPinClassNames = viewer360MarkerPinClassNames;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { CSSProperties } from 'react';\n\nimport { defaultViewer360Labels } from '../constants/viewer360Labels';\nimport { viewer360ClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360ClassNames, Viewer360Labels, Viewer360Theme } from '../types';\nimport { cn } from '@/components/utils';\n\nexport function mergeViewer360Labels(labels?: Viewer360Labels): Required<Viewer360Labels> {\n return {\n loading: labels?.loading ?? defaultViewer360Labels.loading,\n dragHint: labels?.dragHint ?? defaultViewer360Labels.dragHint,\n frameIndicator: labels?.frameIndicator ?? defaultViewer360Labels.frameIndicator,\n zoom: labels?.zoom ?? defaultViewer360Labels.zoom,\n hotspotModeActive: labels?.hotspotModeActive ?? defaultViewer360Labels.hotspotModeActive,\n addHotspot: labels?.addHotspot ?? defaultViewer360Labels.addHotspot,\n zoomIn: labels?.zoomIn ?? defaultViewer360Labels.zoomIn,\n zoomOut: labels?.zoomOut ?? defaultViewer360Labels.zoomOut,\n resetView: labels?.resetView ?? defaultViewer360Labels.resetView,\n deleteMarker: labels?.deleteMarker ?? defaultViewer360Labels.deleteMarker,\n };\n}\n\nexport function mergeViewer360ClassNames(classNames?: Viewer360ClassNames): Required<Viewer360ClassNames> {\n return {\n root: cn(viewer360ClassNames.root, classNames?.root),\n viewport: cn(viewer360ClassNames.viewport, classNames?.viewport),\n canvas: cn(viewer360ClassNames.canvas, classNames?.canvas),\n overlay: cn(viewer360ClassNames.overlay, classNames?.overlay),\n loading: cn(viewer360ClassNames.loading, classNames?.loading),\n loadingText: cn(viewer360ClassNames.loadingText, classNames?.loadingText),\n frameIndicator: cn(viewer360ClassNames.frameIndicator, classNames?.frameIndicator),\n hotspotModeBanner: cn(viewer360ClassNames.hotspotModeBanner, classNames?.hotspotModeBanner),\n toolbar: cn(viewer360ClassNames.toolbar, classNames?.toolbar),\n dragHint: cn(viewer360ClassNames.dragHint, classNames?.dragHint),\n controls: cn(viewer360ClassNames.controls, classNames?.controls),\n controlButton: cn(viewer360ClassNames.controlButton, classNames?.controlButton),\n controlButtonActive: cn(viewer360ClassNames.controlButtonActive, classNames?.controlButtonActive),\n controlButtonDisabled: cn(viewer360ClassNames.controlButtonDisabled, classNames?.controlButtonDisabled),\n zoomDisplay: cn(viewer360ClassNames.zoomDisplay, classNames?.zoomDisplay),\n divider: cn(viewer360ClassNames.divider, classNames?.divider),\n };\n}\n\nexport function buildViewer360ThemeStyle(theme?: Viewer360Theme): CSSProperties {\n return theme ? (theme as CSSProperties) : {};\n}\n","import type { PointerEvent as ReactPointerEvent, RefObject, WheelEvent as ReactWheelEvent } from 'react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n applyWheelZoom,\n getViewerCursorClass,\n isResetDisabled,\n resolveViewer360Config,\n stepZoomIn,\n stepZoomOut,\n} from '../helpers/adjustViewerZoom';\nimport { computeDragFrameIndex } from '../helpers/computeDragFrameIndex';\nimport {\n computeHotspotPositionFromClick,\n computeHotspotScreenPosition,\n computeViewerImageLayout,\n type ViewerImageLayout,\n} from '../helpers/computeViewerImageLayout';\nimport { computeViewerPanOffset } from '../helpers/computeViewerPanOffset';\nimport {\n drawFrameOnCanvas,\n filterHotspotsByFrame,\n getFramesSignature,\n hasLoadedViewerFrame,\n preloadViewerFrames,\n} from '../helpers/viewerHelpers';\nimport type {\n Viewer360Config,\n Viewer360Frame,\n Viewer360Hotspot,\n Viewer360HotspotPosition,\n Viewer360PanOffset,\n} from '../types';\n\ntype UseViewer360Params<TData> = {\n frames: Viewer360Frame[];\n currentFrameIndex: number;\n onFrameChange: (index: number) => void;\n hotspots?: Viewer360Hotspot<TData>[];\n config?: Viewer360Config;\n hotspotMode?: boolean;\n onHotspotAdd?: (position: Viewer360HotspotPosition) => void;\n};\n\ntype UseViewer360Return<TData> = {\n canvasRef: RefObject<HTMLCanvasElement | null>;\n containerRef: RefObject<HTMLDivElement | null>;\n currentFrame: Viewer360Frame | undefined;\n currentFrameHotspots: Viewer360Hotspot<TData>[];\n imagesLoaded: boolean;\n isHotspotMode: boolean;\n isResetDisabled: boolean;\n maxZoom: number;\n minZoom: number;\n viewerCursorClass: string;\n zoom: number;\n getCurrentImageLayout: () => ViewerImageLayout | null;\n getHotspotScreenPosition: (hotspot: Viewer360Hotspot<TData>) => { leftPercent: number; topPercent: number };\n handleCanvasClick: (event: React.MouseEvent<HTMLDivElement>) => void;\n handlePointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handlePointerMove: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handlePointerUp: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handleResetView: () => void;\n handleWheel: (event: ReactWheelEvent<HTMLDivElement>) => void;\n handleZoomIn: () => void;\n handleZoomOut: () => void;\n};\n\nexport function useViewer360<TData = unknown>({\n frames,\n hotspots = [],\n currentFrameIndex,\n onFrameChange,\n config,\n hotspotMode: hotspotModeProp = false,\n onHotspotAdd,\n}: UseViewer360Params<TData>): UseViewer360Return<TData> {\n const resolvedConfig = useMemo(() => resolveViewer360Config(config), [config]);\n const { minZoom, maxZoom } = resolvedConfig;\n\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const imagesRef = useRef<HTMLImageElement[]>([]);\n const dragStartRef = useRef<{ pointerX: number; frameIndex: number } | null>(null);\n const panStartRef = useRef<{ pointerX: number; pointerY: number; panX: number; panY: number } | null>(null);\n\n const framesSignature = getFramesSignature(frames);\n const [loadedSignature, setLoadedSignature] = useState<string | null>(null);\n const [zoom, setZoom] = useState<number>(minZoom);\n const [pan, setPan] = useState<Viewer360PanOffset>({ panX: 0, panY: 0 });\n const [isDragging, setIsDragging] = useState(false);\n\n const isHotspotMode = hotspotModeProp;\n const imagesLoaded = loadedSignature === framesSignature;\n const currentFrameHotspots = filterHotspotsByFrame(hotspots, currentFrameIndex) as Viewer360Hotspot<TData>[];\n const currentFrame = frames[currentFrameIndex];\n const viewerCursorClass = getViewerCursorClass(isHotspotMode, zoom, isDragging, minZoom);\n const resetDisabled = isResetDisabled(zoom, pan, resolvedConfig);\n\n useEffect(() => {\n let cancelled = false;\n imagesRef.current = [];\n\n async function loadFrames(): Promise<void> {\n const loadedImages = await preloadViewerFrames(frames);\n\n if (!cancelled && hasLoadedViewerFrame(loadedImages)) {\n imagesRef.current = loadedImages;\n setLoadedSignature(framesSignature);\n }\n }\n\n void loadFrames();\n\n return (): void => {\n cancelled = true;\n };\n }, [frames, framesSignature]);\n\n useEffect(() => {\n if (!imagesLoaded) return;\n\n function renderFrame(): void {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n const img = imagesRef.current[currentFrameIndex];\n\n if (!canvas || !container) return;\n\n drawFrameOnCanvas({ canvas, container, image: img, zoom, pan });\n }\n\n renderFrame();\n window.addEventListener('resize', renderFrame);\n\n return (): void => window.removeEventListener('resize', renderFrame);\n }, [imagesLoaded, currentFrameIndex, zoom, pan]);\n\n useEffect(() => {\n if (!resolvedConfig.autoRotate || frames.length <= 1 || isDragging || isHotspotMode || zoom > minZoom) {\n return;\n }\n\n const direction = resolvedConfig.autoRotateDirection === 'backward' ? -1 : 1;\n const interval = window.setInterval(() => {\n onFrameChange((currentFrameIndex + direction + frames.length) % frames.length);\n }, resolvedConfig.autoRotateIntervalMs);\n\n return (): void => window.clearInterval(interval);\n }, [\n resolvedConfig.autoRotate,\n resolvedConfig.autoRotateDirection,\n resolvedConfig.autoRotateIntervalMs,\n frames.length,\n currentFrameIndex,\n isDragging,\n isHotspotMode,\n zoom,\n minZoom,\n onFrameChange,\n ]);\n\n function getCurrentImageLayout(): ViewerImageLayout | null {\n const container = containerRef.current;\n const image = imagesRef.current[currentFrameIndex];\n\n if (!container || !image || !image.complete || !image.naturalWidth) return null;\n\n const rect = container.getBoundingClientRect();\n\n return computeViewerImageLayout({\n containerWidth: rect.width,\n containerHeight: rect.height,\n imageWidth: image.naturalWidth,\n imageHeight: image.naturalHeight,\n pan,\n });\n }\n\n function getHotspotScreenPosition(hotspot: Viewer360Hotspot<TData>): { leftPercent: number; topPercent: number } {\n const layout = getCurrentImageLayout();\n\n if (!layout) {\n return { leftPercent: hotspot.positionX, topPercent: hotspot.positionY };\n }\n\n return computeHotspotScreenPosition(hotspot.positionX, hotspot.positionY, layout, zoom);\n }\n\n function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>): void {\n if (isHotspotMode) return;\n\n event.currentTarget.setPointerCapture(event.pointerId);\n\n if (zoom > minZoom) {\n panStartRef.current = { pointerX: event.clientX, pointerY: event.clientY, panX: pan.panX, panY: pan.panY };\n } else {\n dragStartRef.current = { pointerX: event.clientX, frameIndex: currentFrameIndex };\n }\n\n setIsDragging(true);\n }\n\n function handlePointerMove(event: ReactPointerEvent<HTMLDivElement>): void {\n if (!isDragging) return;\n\n if (panStartRef.current && zoom > minZoom) {\n setPan(computeViewerPanOffset(panStartRef.current, event.clientX, event.clientY));\n return;\n }\n\n if (dragStartRef.current && zoom <= minZoom) {\n const nextFrameIndex = computeDragFrameIndex(\n dragStartRef.current,\n event.clientX,\n frames.length,\n resolvedConfig.dragSensitivity\n );\n\n if (nextFrameIndex !== null) {\n onFrameChange(nextFrameIndex);\n }\n }\n }\n\n function handlePointerUp(event: ReactPointerEvent<HTMLDivElement>): void {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n\n dragStartRef.current = null;\n panStartRef.current = null;\n setIsDragging(false);\n }\n\n function handleWheel(event: ReactWheelEvent<HTMLDivElement>): void {\n event.preventDefault();\n const { zoom: nextZoom, pan: nextPan } = applyWheelZoom(zoom, event.deltaY, pan, resolvedConfig);\n setZoom(nextZoom);\n setPan(nextPan);\n }\n\n function handleCanvasClick(event: React.MouseEvent<HTMLDivElement>): void {\n if (!isHotspotMode || isDragging || !onHotspotAdd) return;\n\n const frame = frames[currentFrameIndex];\n if (!frame) return;\n\n const layout = getCurrentImageLayout();\n if (!layout) return;\n\n const { positionX, positionY } = computeHotspotPositionFromClick(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect(),\n layout,\n zoom\n );\n\n onHotspotAdd({\n frameIndex: currentFrameIndex,\n frameId: frame.id,\n positionX,\n positionY,\n });\n }\n\n function handleResetView(): void {\n setZoom(minZoom);\n setPan({ panX: 0, panY: 0 });\n }\n\n function handleZoomIn(): void {\n setZoom(stepZoomIn(zoom, resolvedConfig));\n }\n\n function handleZoomOut(): void {\n const { zoom: nextZoom, pan: nextPan } = stepZoomOut(zoom, pan, resolvedConfig);\n setZoom(nextZoom);\n setPan(nextPan);\n }\n\n return {\n canvasRef,\n containerRef,\n currentFrame,\n currentFrameHotspots,\n imagesLoaded,\n isHotspotMode,\n isResetDisabled: resetDisabled,\n maxZoom,\n minZoom,\n viewerCursorClass,\n zoom,\n getCurrentImageLayout,\n getHotspotScreenPosition,\n handleCanvasClick,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleResetView,\n handleWheel,\n handleZoomIn,\n handleZoomOut,\n };\n}\n","import type { Viewer360Config } from '../types';\n\nimport type { PanOffset } from './computeViewerImageLayout';\n\ntype ResolvedViewer360Config = Required<Viewer360Config>;\n\nexport function resolveViewer360Config(config?: Viewer360Config): ResolvedViewer360Config {\n return {\n minZoom: config?.minZoom ?? 1,\n maxZoom: config?.maxZoom ?? 3,\n zoomStep: config?.zoomStep ?? 0.15,\n dragSensitivity: config?.dragSensitivity ?? 8,\n autoRotate: config?.autoRotate ?? false,\n autoRotateIntervalMs: config?.autoRotateIntervalMs ?? 100,\n autoRotateDirection: config?.autoRotateDirection ?? 'forward',\n };\n}\n\nexport function clampZoom(zoom: number, config: ResolvedViewer360Config): number {\n return Math.min(config.maxZoom, Math.max(config.minZoom, zoom));\n}\n\nexport function applyWheelZoom(\n currentZoom: number,\n deltaY: number,\n currentPan: PanOffset,\n config: ResolvedViewer360Config\n): { zoom: number; pan: PanOffset } {\n const delta = deltaY > 0 ? -config.zoomStep : config.zoomStep;\n const zoom = clampZoom(currentZoom + delta, config);\n\n return {\n zoom,\n pan: zoom === config.minZoom ? { panX: 0, panY: 0 } : currentPan,\n };\n}\n\nexport function stepZoomIn(currentZoom: number, config: ResolvedViewer360Config): number {\n return clampZoom(currentZoom + config.zoomStep, config);\n}\n\nexport function stepZoomOut(\n currentZoom: number,\n currentPan: PanOffset,\n config: ResolvedViewer360Config\n): { zoom: number; pan: PanOffset } {\n const zoom = clampZoom(currentZoom - config.zoomStep, config);\n\n return {\n zoom,\n pan: zoom === config.minZoom ? { panX: 0, panY: 0 } : currentPan,\n };\n}\n\nexport function isResetDisabled(zoom: number, pan: PanOffset, config: ResolvedViewer360Config): boolean {\n return zoom === config.minZoom && pan.panX === 0 && pan.panY === 0;\n}\n\nexport function getViewerCursorClass(isHotspotMode: boolean, zoom: number, isDragging: boolean, minZoom: number): string {\n if (isHotspotMode) return 'cursor-crosshair';\n if (isDragging) return 'cursor-grabbing';\n if (zoom > minZoom) return 'cursor-grab';\n return 'cursor-ew-resize';\n}\n","export function clampFrameIndex(index: number, frameCount: number): number {\n if (frameCount === 0) return 0;\n return ((index % frameCount) + frameCount) % frameCount;\n}\n\ntype DragStart = {\n pointerX: number;\n frameIndex: number;\n};\n\nexport function computeDragFrameIndex(\n dragStart: DragStart,\n clientX: number,\n frameCount: number,\n dragSensitivity: number\n): number | null {\n const deltaX = clientX - dragStart.pointerX;\n const frameDelta = Math.round(-deltaX / dragSensitivity);\n\n if (frameDelta === 0) return null;\n\n return clampFrameIndex(dragStart.frameIndex + frameDelta, frameCount);\n}\n","export type ViewerImageLayout = {\n width: number;\n height: number;\n centerX: number;\n centerY: number;\n drawWidth: number;\n drawHeight: number;\n offsetX: number;\n offsetY: number;\n};\n\nexport type PanOffset = {\n panX: number;\n panY: number;\n};\n\ntype ComputeViewerImageLayoutParams = {\n containerWidth: number;\n containerHeight: number;\n imageWidth: number;\n imageHeight: number;\n pan?: PanOffset;\n};\n\nexport function computeViewerImageLayout({\n containerWidth,\n containerHeight,\n imageWidth,\n imageHeight,\n pan = { panX: 0, panY: 0 },\n}: ComputeViewerImageLayoutParams): ViewerImageLayout {\n const imgAspect = imageWidth / imageHeight;\n const containerAspect = containerWidth / containerHeight;\n\n let drawWidth: number;\n let drawHeight: number;\n\n if (imgAspect > containerAspect) {\n drawWidth = containerWidth;\n drawHeight = containerWidth / imgAspect;\n } else {\n drawHeight = containerHeight;\n drawWidth = containerHeight * imgAspect;\n }\n\n const offsetX = (containerWidth - drawWidth) / 2 + pan.panX;\n const offsetY = (containerHeight - drawHeight) / 2 + pan.panY;\n\n return {\n width: containerWidth,\n height: containerHeight,\n centerX: containerWidth / 2,\n centerY: containerHeight / 2,\n drawWidth,\n drawHeight,\n offsetX,\n offsetY,\n };\n}\n\nexport function computeHotspotScreenPosition(\n hotspotX: number,\n hotspotY: number,\n layout: ViewerImageLayout,\n zoom: number\n): { leftPercent: number; topPercent: number } {\n const baseOffsetX = (layout.width - layout.drawWidth) / 2;\n const baseOffsetY = (layout.height - layout.drawHeight) / 2;\n\n const containerX = (hotspotX / 100) * layout.width;\n const containerY = (hotspotY / 100) * layout.height;\n\n const imageLocalX = (containerX - baseOffsetX) / layout.drawWidth;\n const imageLocalY = (containerY - baseOffsetY) / layout.drawHeight;\n\n const imagePointX = layout.offsetX + imageLocalX * layout.drawWidth;\n const imagePointY = layout.offsetY + imageLocalY * layout.drawHeight;\n\n const screenX = layout.centerX + zoom * (imagePointX - layout.centerX);\n const screenY = layout.centerY + zoom * (imagePointY - layout.centerY);\n\n return {\n leftPercent: (screenX / layout.width) * 100,\n topPercent: (screenY / layout.height) * 100,\n };\n}\n\nexport function computeHotspotPositionFromClick(\n clientX: number,\n clientY: number,\n containerRect: DOMRect,\n layout: ViewerImageLayout,\n zoom: number\n): { positionX: number; positionY: number } {\n const clickX = clientX - containerRect.left;\n const clickY = clientY - containerRect.top;\n\n const unzoomedX = layout.centerX + (clickX - layout.centerX) / zoom;\n const unzoomedY = layout.centerY + (clickY - layout.centerY) / zoom;\n\n const baseOffsetX = (layout.width - layout.drawWidth) / 2;\n const baseOffsetY = (layout.height - layout.drawHeight) / 2;\n\n const imageLocalX = Math.min(1, Math.max(0, (unzoomedX - layout.offsetX) / layout.drawWidth));\n const imageLocalY = Math.min(1, Math.max(0, (unzoomedY - layout.offsetY) / layout.drawHeight));\n\n const storedX = baseOffsetX + imageLocalX * layout.drawWidth;\n const storedY = baseOffsetY + imageLocalY * layout.drawHeight;\n\n return {\n positionX: Math.min(100, Math.max(0, (storedX / layout.width) * 100)),\n positionY: Math.min(100, Math.max(0, (storedY / layout.height) * 100)),\n };\n}\n","import type { PanOffset } from './computeViewerImageLayout';\n\ntype PanStart = {\n pointerX: number;\n pointerY: number;\n panX: number;\n panY: number;\n};\n\nexport function computeViewerPanOffset(panStart: PanStart, clientX: number, clientY: number): PanOffset {\n const deltaX = clientX - panStart.pointerX;\n const deltaY = clientY - panStart.pointerY;\n\n return {\n panX: panStart.panX + deltaX,\n panY: panStart.panY + deltaY,\n };\n}\n","import type { Viewer360Frame } from '../types';\n\nimport { computeViewerImageLayout, type PanOffset } from './computeViewerImageLayout';\n\ntype DrawFrameOnCanvasParams = {\n canvas: HTMLCanvasElement;\n container: HTMLDivElement;\n image: HTMLImageElement;\n zoom: number;\n pan: PanOffset;\n};\n\nexport function drawFrameOnCanvas({ canvas, container, image, zoom, pan }: DrawFrameOnCanvasParams): void {\n if (!image.complete || !image.naturalWidth) return;\n\n const rect = container.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n\n canvas.width = rect.width * dpr;\n canvas.height = rect.height * dpr;\n canvas.style.width = `${rect.width}px`;\n canvas.style.height = `${rect.height}px`;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, rect.width, rect.height);\n\n const layout = computeViewerImageLayout({\n containerWidth: rect.width,\n containerHeight: rect.height,\n imageWidth: image.naturalWidth,\n imageHeight: image.naturalHeight,\n pan,\n });\n\n ctx.save();\n ctx.translate(layout.centerX, layout.centerY);\n ctx.scale(zoom, zoom);\n ctx.translate(-layout.centerX, -layout.centerY);\n ctx.drawImage(image, layout.offsetX, layout.offsetY, layout.drawWidth, layout.drawHeight);\n ctx.restore();\n}\n\nexport function getFramesSignature(frames: Viewer360Frame[]): string {\n return frames.map((frame) => frame.id).join('-');\n}\n\nexport function preloadFrameImage(frame: Viewer360Frame): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = (): void => resolve(img);\n img.onerror = (): void => reject(new Error(`Failed to load frame: ${frame.src}`));\n img.src = frame.src;\n });\n}\n\nexport async function preloadViewerFrames(frames: Viewer360Frame[]): Promise<HTMLImageElement[]> {\n const results = await Promise.allSettled(frames.map(preloadFrameImage));\n\n return results.map((result) => (result.status === 'fulfilled' ? result.value : new Image()));\n}\n\nexport function hasLoadedViewerFrame(images: HTMLImageElement[]): boolean {\n return images.some((image) => image.complete && image.naturalWidth > 0);\n}\n\nexport function filterHotspotsByFrame<TData>(\n hotspots: Array<{ frameIndex: number; data?: TData }>,\n frameIndex: number\n): Array<{ frameIndex: number; data?: TData }> {\n return hotspots.filter((hotspot) => hotspot.frameIndex === frameIndex);\n}\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cn } from '@/components/utils';\n\nfunction Card({ className, size = 'default', ...props }: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }): JSX.Element {\n return (\n <div\n data-slot=\"card\"\n data-size={size}\n className={cn(\n 'ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-xl py-6 text-sm shadow-xs ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n 'gap-0.5 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-title\"\n className={cn('text-lg leading-normal font-semibold group-data-[size=sm]/card:text-sm', className)}\n {...props}\n />\n );\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"card-description\" className={cn('text-muted-foreground text-xs font-medium', className)} {...props} />;\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-action\"\n className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}\n {...props}\n />\n );\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"card-content\" className={cn('px-6 group-data-[size=sm]/card:px-4', className)} {...props} />;\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\n 'rounded-b-xl px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4 flex items-center',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nconst badgeVariants = cva(\n 'h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',\n secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',\n destructive:\n 'bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20',\n outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',\n ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',\n link: 'text-primary underline-offset-4 hover:underline',\n info: 'bg-blue-500 text-white hover:bg-blue-600',\n warning:\n 'rounded-full border-transparent bg-amber-500 px-2.5 text-white shadow-none [a]:hover:bg-amber-600 [&>svg]:text-white',\n success: 'bg-green-600 text-white hover:bg-green-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n }\n);\n\nfunction Badge({\n className,\n variant = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'span';\n\n return <Comp data-slot=\"badge\" data-variant={variant} className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n\nexport { Badge, badgeVariants };\n","import type { JSX } from 'react';\n\nimport { Badge } from '@/components/ui/Badge';\nimport { cn } from '@/components/utils';\n\ntype Viewer360AddModeBannerProps = {\n className?: string;\n label: string;\n};\n\nexport function Viewer360AddModeBanner({ className, label }: Viewer360AddModeBannerProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Badge variant=\"outline\" className={cn('pointer-events-none', className)}>\n {label}\n </Badge>\n );\n}\n","import type { JSX } from 'react';\n\nimport { Badge } from '@/components/ui/Badge';\nimport { cn } from '@/components/utils';\n\ntype Viewer360FrameIndicatorProps = {\n className?: string;\n label: string;\n};\n\nexport function Viewer360FrameIndicator({ className, label }: Viewer360FrameIndicatorProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Badge variant=\"outline\" className={cn('pointer-events-none shadow-sm', className)}>\n {label}\n </Badge>\n );\n}\n","import type { Viewer360Hotspot, Viewer360Marker } from '../types';\n\nexport function hotspotToViewer360Marker<TData>(hotspot: Viewer360Hotspot<TData>): Viewer360Marker {\n const data = hotspot.data;\n\n if (data && typeof data === 'object' && 'title' in data && typeof (data as { title?: unknown }).title === 'string') {\n const marker = data as unknown as Viewer360Marker;\n\n return {\n id: marker.id ?? hotspot.id,\n title: marker.title,\n description: marker.description,\n };\n }\n\n return {\n id: hotspot.id,\n title: hotspot.id,\n };\n}\n\nexport function toViewer360Hotspots<TData extends Viewer360Marker>(\n markers: Array<Viewer360Marker & { frameIndex: number; positionX: number; positionY: number }>,\n mapData?: (marker: Viewer360Marker & { frameIndex: number; positionX: number; positionY: number }) => TData\n): Viewer360Hotspot<TData>[] {\n return markers.map((marker) => ({\n id: marker.id,\n frameIndex: marker.frameIndex,\n positionX: marker.positionX,\n positionY: marker.positionY,\n data: mapData ? mapData(marker) : (marker as unknown as TData),\n }));\n}\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { Separator } from '@/components/ui/Separator';\nimport { cn } from '@/components/utils';\n\nfunction ItemGroup({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn('gap-4 has-[[data-size=sm]]:gap-2.5 has-[[data-size=xs]]:gap-2 group/item-group flex w-full flex-col', className)}\n {...props}\n />\n );\n}\n\nfunction ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>): JSX.Element {\n return <Separator data-slot=\"item-separator\" orientation=\"horizontal\" className={cn('my-2', className)} {...props} />;\n}\n\nconst itemVariants = cva(\n '[a]:hover:bg-muted rounded-md border text-sm w-full group/item focus-visible:border-ring focus-visible:ring-ring/50 flex items-center flex-wrap outline-none transition-colors duration-100 focus-visible:ring-[3px] [a]:transition-colors',\n {\n variants: {\n variant: {\n default: 'border-transparent',\n outline: 'border-border',\n muted: 'bg-muted/50 border-transparent',\n },\n size: {\n default: 'gap-3.5 px-4 py-3.5',\n sm: 'gap-2.5 px-3 py-2.5',\n xs: 'gap-2 px-2.5 py-2 [[data-slot=dropdown-menu-content]_&]:p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nfunction Item({\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof itemVariants> & { asChild?: boolean }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'div';\n return (\n <Comp\n data-slot=\"item\"\n data-variant={variant}\n data-size={size}\n className={cn(itemVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst itemMediaVariants = cva(\n 'gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none',\n {\n variants: {\n variant: {\n default: 'bg-transparent',\n icon: '[&_svg]:size-4',\n image: 'size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n }\n);\n\nfunction ItemMedia({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>): JSX.Element {\n return <div data-slot=\"item-media\" data-variant={variant} className={cn(itemMediaVariants({ variant, className }))} {...props} />;\n}\n\nfunction ItemContent({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"item-content\"\n className={cn('gap-1 group-data-[size=xs]/item:gap-0 flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none', className)}\n {...props}\n />\n );\n}\n\nfunction ItemTitle({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"item-title\"\n className={cn('gap-2 text-sm leading-snug font-medium underline-offset-4 line-clamp-1 flex w-fit items-center', className)}\n {...props}\n />\n );\n}\n\nfunction ItemDescription({ className, ...props }: React.ComponentProps<'p'>): JSX.Element {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(\n 'text-muted-foreground text-left text-sm leading-normal group-data-[size=xs]/item:text-xs [&>a:hover]:text-primary line-clamp-2 font-normal [&>a]:underline [&>a]:underline-offset-4',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemActions({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-actions\" className={cn('gap-2 flex items-center', className)} {...props} />;\n}\n\nfunction ItemHeader({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-header\" className={cn('gap-2 flex basis-full items-center justify-between', className)} {...props} />;\n}\n\nfunction ItemFooter({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-footer\" className={cn('gap-2 flex basis-full items-center justify-between', className)} {...props} />;\n}\n\nexport { Item, ItemMedia, ItemContent, ItemActions, ItemGroup, ItemSeparator, ItemTitle, ItemDescription, ItemHeader, ItemFooter };\n","'use client';\n\nimport * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { Separator as SeparatorPrimitive } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nfunction Separator({\n className,\n orientation = 'horizontal',\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>): JSX.Element {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Separator };\n","import type { JSX, MouseEvent } from 'react';\n\nimport { Trash2 } from 'lucide-react';\n\nimport { defaultViewer360MarkerPinLabels } from '../constants/viewer360MarkerLabels';\nimport { viewer360MarkerPinClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360MarkerPinProps } from '../types';\nimport { Button } from '@/components/ui/Button';\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemTitle,\n} from '@/components/ui/Item';\nimport { cn } from '@/components/utils';\n\nexport function Viewer360MarkerPin<TData = unknown>({\n marker,\n hotspot,\n leftPercent,\n topPercent,\n onDelete,\n isDeletePending = false,\n onClick,\n renderTag,\n classNames,\n labels,\n}: Viewer360MarkerPinProps<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: States & Constants\n // ----------------------------------------------------------------------------------------------------\n const deleteLabel = labels?.delete ?? defaultViewer360MarkerPinLabels.delete;\n const showTooltip = Boolean(marker.title || marker.description || onDelete || renderTag);\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <div\n className={cn(viewer360MarkerPinClassNames.root, classNames?.root, 'group/marker')}\n style={{ left: `${leftPercent}%`, top: `${topPercent}%` }}\n >\n <div className=\"relative size-4 shrink-0\">\n <span className={cn(viewer360MarkerPinClassNames.ping, classNames?.ping)} aria-hidden=\"true\" />\n\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"icon-xs\"\n className={cn(viewer360MarkerPinClassNames.dot, classNames?.dot, 'hover:bg-destructive')}\n aria-label={marker.title}\n onClick={onClick}\n />\n </div>\n\n {showTooltip && (\n <div\n className={cn(\n viewer360MarkerPinClassNames.tooltip,\n classNames?.tooltip,\n 'pointer-events-none opacity-0 transition-opacity duration-150 group-hover/marker:pointer-events-auto group-hover/marker:opacity-100 group-focus-within/marker:pointer-events-auto group-focus-within/marker:opacity-100'\n )}\n >\n <Item\n size=\"sm\"\n variant=\"default\"\n className={cn(viewer360MarkerPinClassNames.tooltipHeader, classNames?.tooltipHeader, 'w-full border-transparent')}\n >\n <ItemContent className={cn(viewer360MarkerPinClassNames.tooltipBody, classNames?.tooltipBody)}>\n <ItemTitle className={cn(viewer360MarkerPinClassNames.tooltipTitle, classNames?.tooltipTitle)}>\n {marker.title}\n </ItemTitle>\n {renderTag && (\n <div className=\"mt-1 flex w-fit items-center\">{renderTag({ marker, hotspot })}</div>\n )}\n {marker.description && (\n <ItemDescription className={cn(viewer360MarkerPinClassNames.tooltipDescription, classNames?.tooltipDescription)}>\n {marker.description}\n </ItemDescription>\n )}\n </ItemContent>\n {onDelete && (\n <ItemActions>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n className={classNames?.deleteButton}\n disabled={isDeletePending}\n aria-label={deleteLabel}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n onDelete(marker.id);\n }}\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </ItemActions>\n )}\n </Item>\n </div>\n )}\n </div>\n );\n}\n","export const defaultViewer360MarkerPinLabels = {\n delete: 'Remove marker',\n} as const;\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nconst buttonVariants = cva(\n 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/80',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground shadow-xs',\n secondary:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',\n ghost: 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n destructive:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default:\n 'h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2',\n xs: 'h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n sm: 'h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n lg: 'h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3',\n icon: 'size-9',\n 'icon-xs':\n 'size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md',\n 'icon-sm': 'size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md',\n 'icon-lg': 'size-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nfunction Button({\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n","import type { JSX, MouseEvent, ReactNode } from 'react';\n\nimport { hotspotToViewer360Marker } from '../helpers/markerHelpers';\nimport type { Viewer360Hotspot, Viewer360HotspotPinOptions, Viewer360HotspotRenderProps } from '../types';\nimport { Item } from '@/components/ui/Item';\n\nimport { Viewer360MarkerPin } from './Viewer360MarkerPin';\n\ntype Viewer360HotspotOverlayProps<TData = unknown> = {\n hotspot: Viewer360Hotspot<TData>;\n leftPercent: number;\n topPercent: number;\n hotspotPin?: Viewer360HotspotPinOptions<TData>;\n renderHotspot?: (props: Viewer360HotspotRenderProps<TData>) => ReactNode;\n onHotspotClick?: (hotspot: Viewer360Hotspot<TData>, event: MouseEvent<HTMLDivElement>) => void;\n};\n\nexport function Viewer360HotspotOverlay<TData = unknown>({\n hotspot,\n leftPercent,\n topPercent,\n hotspotPin,\n renderHotspot,\n onHotspotClick,\n}: Viewer360HotspotOverlayProps<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n if (renderHotspot) {\n return (\n <Item size=\"xs\" variant=\"default\" className=\"pointer-events-auto w-auto border-transparent p-0\">\n {renderHotspot({ hotspot, leftPercent, topPercent })}\n </Item>\n );\n }\n\n const marker = hotspotPin?.getMarker?.(hotspot) ?? hotspotToViewer360Marker(hotspot);\n\n return (\n <Viewer360MarkerPin\n marker={marker}\n hotspot={hotspot}\n leftPercent={leftPercent}\n topPercent={topPercent}\n onDelete={hotspotPin?.onDelete}\n isDeletePending={hotspotPin?.deletingMarkerId === hotspot.id}\n renderTag={hotspotPin?.renderTag}\n classNames={hotspotPin?.classNames}\n labels={hotspotPin?.labels}\n onClick={\n onHotspotClick\n ? (event) => onHotspotClick(hotspot, event as unknown as MouseEvent<HTMLDivElement>)\n : undefined\n }\n />\n );\n}\n","'use client';\n\nimport * as React from 'react';\n\nimport { cn } from '@/components/utils';\n\nfunction Label({ className, ...props }: React.ComponentProps<'label'>): React.ReactNode {\n return (\n <label\n data-slot=\"label\"\n className={cn(\n 'gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import type { JSX } from 'react';\n\nimport { Loader2Icon } from 'lucide-react';\n\nimport { cn } from '@/components/utils';\n\nfunction Spinner({ className, ...props }: React.ComponentProps<'svg'>): JSX.Element {\n return <Loader2Icon role=\"status\" aria-label=\"Loading\" className={cn('size-4 animate-spin', className)} {...props} />;\n}\n\nexport { Spinner };\n","import type { JSX } from 'react';\n\nimport { Item } from '@/components/ui/Item';\nimport { Label } from '@/components/ui/Label';\nimport { Spinner } from '@/components/ui/Spinner';\nimport { cn } from '@/components/utils';\n\ntype Viewer360LoadingOverlayProps = {\n className?: string;\n textClassName?: string;\n label: string;\n};\n\nexport function Viewer360LoadingOverlay({ className, textClassName, label }: Viewer360LoadingOverlayProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Item\n size=\"sm\"\n variant=\"muted\"\n className={cn('pointer-events-none w-auto justify-center border-transparent bg-muted/80', className)}\n >\n <Spinner className=\"size-5 text-muted-foreground\" />\n <Label className={cn('font-normal text-muted-foreground', textClassName)}>{label}</Label>\n </Item>\n );\n}\n","import type { JSX } from 'react';\n\nimport { Crosshair, Minus, Plus, RotateCcw, ZoomIn } from 'lucide-react';\n\nimport { viewer360ClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360ToolbarRenderProps } from '../types';\nimport { Badge } from '@/components/ui/Badge';\nimport { Button } from '@/components/ui/Button';\nimport { CardFooter } from '@/components/ui/Card';\nimport { Label } from '@/components/ui/Label';\nimport { Separator } from '@/components/ui/Separator';\nimport { cn } from '@/components/utils';\n\ntype Viewer360ToolbarProps = Viewer360ToolbarRenderProps;\n\nexport function Viewer360Toolbar({\n showDragHint,\n showHotspotModeControl,\n showZoomControls,\n showResetControl,\n labels,\n isHotspotMode,\n zoom,\n minZoom,\n maxZoom,\n isResetDisabled,\n onHotspotModeChange,\n onZoomIn,\n onZoomOut,\n onResetView,\n}: Viewer360ToolbarProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <CardFooter className={cn(viewer360ClassNames.toolbar, 'gap-2 border-t px-4 py-3 pt-3')}>\n {showDragHint && (\n <Label className={cn(viewer360ClassNames.dragHint, 'font-normal text-muted-foreground')}>{labels.dragHint}</Label>\n )}\n\n <div className={viewer360ClassNames.controls}>\n {showHotspotModeControl && (\n <>\n <Button variant={isHotspotMode ? 'default' : 'outline'} size=\"sm\" onClick={() => onHotspotModeChange(!isHotspotMode)}>\n <Crosshair className=\"me-1.5 size-4\" />\n {labels.addHotspot}\n </Button>\n <Separator orientation=\"vertical\" className={cn(viewer360ClassNames.divider, 'h-6')} />\n </>\n )}\n\n {showZoomControls && (\n <>\n <Button variant=\"outline\" size=\"icon-sm\" disabled={zoom <= minZoom} aria-label={labels.zoomOut} onClick={onZoomOut}>\n <Minus className=\"size-4\" />\n </Button>\n <Badge variant=\"outline\" className={cn(viewer360ClassNames.zoomDisplay, 'h-8 gap-1 px-2 py-1')}>\n <ZoomIn className=\"size-3 text-muted-foreground\" />\n {labels.zoom(Math.round(zoom * 100))}\n </Badge>\n <Button variant=\"outline\" size=\"icon-sm\" disabled={zoom >= maxZoom} aria-label={labels.zoomIn} onClick={onZoomIn}>\n <Plus className=\"size-4\" />\n </Button>\n </>\n )}\n\n {showResetControl && (\n <Button variant=\"outline\" size=\"icon-sm\" disabled={isResetDisabled} aria-label={labels.resetView} onClick={onResetView}>\n <RotateCcw className=\"size-4\" />\n </Button>\n )}\n </div>\n </CardFooter>\n );\n}\n","export const viewer360Config = {\n minZoom: 1,\n maxZoom: 3,\n zoomStep: 0.15,\n dragSensitivity: 8,\n autoRotate: false,\n autoRotateIntervalMs: 100,\n autoRotateDirection: 'forward' as const,\n};\n\nexport const defaultViewer360Config = viewer360Config;\n"],"mappings":"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","names":["useEffect","useMemo","useState","jsx","jsx","jsx","cva","Slot","jsx","jsx","cva","Slot","jsx","jsx","cva","Slot","jsx","cva","Slot","jsx","jsx","jsx","jsx","jsx","jsxs","jsx","jsxs","isResetDisabled","jsx","jsxs","useMemo","useState","isResetDisabled","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/feature/Viewer360.tsx","../src/constants/viewer360Labels.ts","../src/constants/viewer360ClassNames.ts","../src/components/utils/index.ts","../src/helpers/viewer360PropsHelpers.ts","../src/hooks/useViewer360.ts","../src/helpers/adjustViewerZoom.ts","../src/helpers/computeDragFrameIndex.ts","../src/helpers/computeViewerImageLayout.ts","../src/helpers/computeViewerPanOffset.ts","../src/helpers/viewerHelpers.ts","../src/components/ui/Card/index.tsx","../src/components/ui/Badge/index.tsx","../src/feature/Viewer360AddModeBanner.tsx","../src/feature/Viewer360FrameIndicator.tsx","../src/helpers/markerHelpers.ts","../src/components/ui/Item/index.tsx","../src/components/ui/Separator/index.tsx","../src/feature/Viewer360MarkerPin.tsx","../src/constants/viewer360MarkerLabels.ts","../src/components/ui/Button/index.tsx","../src/feature/Viewer360HotspotOverlay.tsx","../src/components/ui/Label/index.tsx","../src/components/ui/Spinner/index.tsx","../src/feature/Viewer360LoadingOverlay.tsx","../src/feature/Viewer360Toolbar.tsx","../src/constants/viewer360Config.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { buildViewer360ThemeStyle, mergeViewer360ClassNames, mergeViewer360Labels } from '../helpers/viewer360PropsHelpers';\nimport { useViewer360 } from '../hooks/useViewer360';\nimport type { Viewer360OverlayRenderProps, Viewer360Props, Viewer360ToolbarRenderProps } from '../types';\nimport { Card } from '@/components/ui/Card';\nimport { cn } from '@/components/utils';\n\nimport { Viewer360AddModeBanner } from './Viewer360AddModeBanner';\nimport { Viewer360FrameIndicator } from './Viewer360FrameIndicator';\nimport { Viewer360HotspotOverlay } from './Viewer360HotspotOverlay';\nimport { Viewer360LoadingOverlay } from './Viewer360LoadingOverlay';\nimport { Viewer360Toolbar } from './Viewer360Toolbar';\n\nexport function Viewer360<TData = unknown>({\n frames,\n currentFrameIndex: controlledFrameIndex,\n defaultFrameIndex = 0,\n onFrameChange,\n config,\n className,\n classNames,\n style,\n theme,\n labels,\n aspectRatio = '16 / 10',\n showZoomControls = true,\n showResetControl = true,\n showFrameIndicator = true,\n showDragHint = true,\n showHotspotModeControl = false,\n hotspotPin,\n hotspots = [],\n renderHotspot,\n renderLoading,\n renderFrameIndicator,\n renderHotspotModeBanner,\n renderToolbar,\n onHotspotClick,\n hotspotMode: controlledHotspotMode,\n defaultHotspotMode = false,\n onHotspotModeChange,\n onHotspotAdd,\n children,\n}: Viewer360Props<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: States & Constants\n // ----------------------------------------------------------------------------------------------------\n const mergedLabels = useMemo(() => mergeViewer360Labels(labels), [labels]);\n const mergedClassNames = useMemo(() => mergeViewer360ClassNames(classNames), [classNames]);\n const themeStyle = useMemo(() => buildViewer360ThemeStyle(theme), [theme]);\n\n const [internalFrameIndex, setInternalFrameIndex] = useState(defaultFrameIndex);\n const [internalHotspotMode, setInternalHotspotMode] = useState(defaultHotspotMode);\n\n const currentFrameIndex = controlledFrameIndex ?? internalFrameIndex;\n const hotspotMode = controlledHotspotMode ?? internalHotspotMode;\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Functions\n // ----------------------------------------------------------------------------------------------------\n function handleFrameChange(index: number): void {\n if (controlledFrameIndex === undefined) {\n setInternalFrameIndex(index);\n }\n\n onFrameChange?.(index);\n }\n\n function handleHotspotModeChange(active: boolean): void {\n if (controlledHotspotMode === undefined) {\n setInternalHotspotMode(active);\n }\n\n onHotspotModeChange?.(active);\n }\n\n const {\n canvasRef,\n containerRef,\n currentFrame,\n currentFrameHotspots,\n imagesLoaded,\n isHotspotMode,\n isResetDisabled,\n maxZoom,\n minZoom,\n viewerCursorClass,\n zoom,\n getHotspotScreenPosition,\n handleCanvasClick,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleWheel,\n handleResetView,\n handleZoomIn,\n handleZoomOut,\n } = useViewer360<TData>({\n frames,\n hotspots,\n currentFrameIndex,\n onFrameChange: handleFrameChange,\n config,\n hotspotMode,\n onHotspotAdd,\n });\n\n useEffect(() => {\n if (controlledHotspotMode === undefined) return;\n if (controlledHotspotMode !== internalHotspotMode) {\n setInternalHotspotMode(controlledHotspotMode);\n }\n }, [controlledHotspotMode, internalHotspotMode]);\n\n const frameLabel = currentFrame?.label ?? frames[currentFrameIndex]?.label;\n const overlayProps: Viewer360OverlayRenderProps = {\n currentFrameIndex,\n frameCount: frames.length,\n frameLabel,\n isHotspotMode,\n labels: mergedLabels,\n frameIndicatorClassName: mergedClassNames.frameIndicator,\n };\n const toolbarProps: Viewer360ToolbarRenderProps = {\n zoom,\n minZoom,\n maxZoom,\n isResetDisabled,\n isHotspotMode,\n showHotspotModeControl,\n showZoomControls,\n showResetControl,\n showDragHint,\n labels: mergedLabels,\n onZoomIn: handleZoomIn,\n onZoomOut: handleZoomOut,\n onResetView: handleResetView,\n onHotspotModeChange: handleHotspotModeChange,\n };\n const showDefaultToolbar = showZoomControls || showResetControl || showHotspotModeControl || showDragHint;\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Card\n data-viewer-360=\"\"\n className={cn(mergedClassNames.root, 'gap-0 py-0 shadow-none ring-0', className)}\n style={{ ...themeStyle, ...style }}\n >\n <div\n ref={containerRef}\n className={cn(mergedClassNames.viewport, viewerCursorClass)}\n style={{ aspectRatio }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerLeave={handlePointerUp}\n onWheel={handleWheel}\n onClick={handleCanvasClick}\n >\n <canvas ref={canvasRef} className={mergedClassNames.canvas} />\n\n <div className={mergedClassNames.overlay}>\n {currentFrameHotspots.map((hotspot) => {\n const position = getHotspotScreenPosition(hotspot);\n\n return (\n <Viewer360HotspotOverlay\n key={hotspot.id}\n hotspot={hotspot}\n leftPercent={position.leftPercent}\n topPercent={position.topPercent}\n hotspotPin={hotspotPin}\n renderHotspot={renderHotspot}\n onHotspotClick={onHotspotClick}\n />\n );\n })}\n {children}\n </div>\n\n {!imagesLoaded &&\n (renderLoading ? (\n renderLoading()\n ) : (\n <Viewer360LoadingOverlay\n className={mergedClassNames.loading}\n textClassName={mergedClassNames.loadingText}\n label={mergedLabels.loading}\n />\n ))}\n\n {showFrameIndicator &&\n frames.length > 0 &&\n (renderFrameIndicator ? (\n renderFrameIndicator(overlayProps)\n ) : (\n <Viewer360FrameIndicator\n className={mergedClassNames.frameIndicator}\n label={mergedLabels.frameIndicator({\n current: currentFrameIndex + 1,\n total: frames.length,\n label: frameLabel,\n })}\n />\n ))}\n\n {isHotspotMode &&\n onHotspotAdd &&\n (renderHotspotModeBanner ? (\n renderHotspotModeBanner({ labels: mergedLabels })\n ) : (\n <Viewer360AddModeBanner className={mergedClassNames.hotspotModeBanner} label={mergedLabels.hotspotModeActive} />\n ))}\n </div>\n\n {renderToolbar ? renderToolbar(toolbarProps) : showDefaultToolbar ? <Viewer360Toolbar {...toolbarProps} /> : null}\n </Card>\n );\n}\n","import type { Viewer360Labels } from '../types/Viewer360Props';\n\nexport const defaultViewer360Labels: Required<Viewer360Labels> = {\n loading: 'Loading images…',\n dragHint: 'Drag to rotate • Scroll to zoom',\n frameIndicator: ({ current, total, label }) => (label ? `${label} · ${current} / ${total}` : `${current} / ${total}`),\n zoom: (percent) => `${percent}%`,\n hotspotModeActive: 'Click on the image to place a hotspot',\n addHotspot: 'Add hotspot',\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n resetView: 'Reset view',\n deleteMarker: 'Remove marker',\n};\n","import type { Viewer360ClassNames } from '../types/Viewer360Props';\nimport type { Viewer360MarkerPinClassNames } from '../types/Viewer360Marker';\n\nexport const viewer360ClassNames: Required<Viewer360ClassNames> = {\n root: 'overflow-hidden rounded-lg border bg-card text-card-foreground',\n viewport: 'relative aspect-[16/10] w-full touch-none select-none bg-muted',\n canvas: 'absolute inset-0 size-full',\n overlay: 'pointer-events-none absolute inset-0 overflow-hidden',\n loading: 'absolute inset-0 flex items-center justify-center bg-muted/80',\n loadingText: 'text-sm text-muted-foreground',\n frameIndicator:\n 'pointer-events-none absolute bottom-4 start-1/2 z-20 -translate-x-1/2 rounded-full border bg-background px-4 py-1.5 text-xs font-medium shadow-sm whitespace-nowrap',\n hotspotModeBanner:\n 'pointer-events-none absolute top-4 start-1/2 z-20 -translate-x-1/2 rounded-full border border-amber-200 bg-amber-50 px-4 py-1.5 text-xs font-medium text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-400',\n toolbar: 'flex flex-wrap items-center justify-between gap-2 border-t px-4 py-3',\n dragHint: 'hidden text-xs text-muted-foreground sm:block',\n controls: 'ms-auto flex items-center gap-1.5',\n controlButton: '',\n controlButtonActive: '',\n controlButtonDisabled: '',\n zoomDisplay: 'flex min-w-[3rem] items-center justify-center gap-1 rounded-md border bg-background px-2 py-1 text-xs font-medium',\n divider: 'mx-1 h-6 w-px bg-border',\n};\n\nexport const viewer360MarkerPinClassNames: Required<Viewer360MarkerPinClassNames> = {\n root: 'pointer-events-auto absolute z-30 -translate-x-1/2 -translate-y-1/2',\n ping: 'pointer-events-none absolute inset-0 inline-flex animate-ping rounded-full bg-destructive opacity-75',\n dot: 'relative z-10 inline-flex size-4 min-h-4 min-w-4 shrink-0 rounded-full border-2 border-background bg-destructive p-0 shadow-md transition-transform duration-200 hover:scale-125 focus:outline-none',\n tooltip:\n 'absolute bottom-6 left-1/2 z-40 w-64 -translate-x-1/2 rounded-lg border bg-popover p-3 text-popover-foreground shadow-md',\n tooltipHeader: 'flex items-start justify-between gap-2',\n tooltipBody: 'flex min-w-0 flex-col gap-1',\n tooltipTitle: 'text-sm font-medium',\n tooltipDescription: 'mt-2 line-clamp-3 text-xs text-muted-foreground',\n deleteButton: '',\n};\n\n/** @deprecated Use `viewer360ClassNames` */\nexport const defaultViewer360ClassNames = viewer360ClassNames;\n\n/** @deprecated Use `viewer360MarkerPinClassNames` */\nexport const defaultViewer360MarkerPinClassNames = viewer360MarkerPinClassNames;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { CSSProperties } from 'react';\n\nimport { defaultViewer360Labels } from '../constants/viewer360Labels';\nimport { viewer360ClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360ClassNames, Viewer360Labels, Viewer360Theme } from '../types';\nimport { cn } from '@/components/utils';\n\nexport function mergeViewer360Labels(labels?: Viewer360Labels): Required<Viewer360Labels> {\n return {\n loading: labels?.loading ?? defaultViewer360Labels.loading,\n dragHint: labels?.dragHint ?? defaultViewer360Labels.dragHint,\n frameIndicator: labels?.frameIndicator ?? defaultViewer360Labels.frameIndicator,\n zoom: labels?.zoom ?? defaultViewer360Labels.zoom,\n hotspotModeActive: labels?.hotspotModeActive ?? defaultViewer360Labels.hotspotModeActive,\n addHotspot: labels?.addHotspot ?? defaultViewer360Labels.addHotspot,\n zoomIn: labels?.zoomIn ?? defaultViewer360Labels.zoomIn,\n zoomOut: labels?.zoomOut ?? defaultViewer360Labels.zoomOut,\n resetView: labels?.resetView ?? defaultViewer360Labels.resetView,\n deleteMarker: labels?.deleteMarker ?? defaultViewer360Labels.deleteMarker,\n };\n}\n\nexport function mergeViewer360ClassNames(classNames?: Viewer360ClassNames): Required<Viewer360ClassNames> {\n return {\n root: cn(viewer360ClassNames.root, classNames?.root),\n viewport: cn(viewer360ClassNames.viewport, classNames?.viewport),\n canvas: cn(viewer360ClassNames.canvas, classNames?.canvas),\n overlay: cn(viewer360ClassNames.overlay, classNames?.overlay),\n loading: cn(viewer360ClassNames.loading, classNames?.loading),\n loadingText: cn(viewer360ClassNames.loadingText, classNames?.loadingText),\n frameIndicator: cn(viewer360ClassNames.frameIndicator, classNames?.frameIndicator),\n hotspotModeBanner: cn(viewer360ClassNames.hotspotModeBanner, classNames?.hotspotModeBanner),\n toolbar: cn(viewer360ClassNames.toolbar, classNames?.toolbar),\n dragHint: cn(viewer360ClassNames.dragHint, classNames?.dragHint),\n controls: cn(viewer360ClassNames.controls, classNames?.controls),\n controlButton: cn(viewer360ClassNames.controlButton, classNames?.controlButton),\n controlButtonActive: cn(viewer360ClassNames.controlButtonActive, classNames?.controlButtonActive),\n controlButtonDisabled: cn(viewer360ClassNames.controlButtonDisabled, classNames?.controlButtonDisabled),\n zoomDisplay: cn(viewer360ClassNames.zoomDisplay, classNames?.zoomDisplay),\n divider: cn(viewer360ClassNames.divider, classNames?.divider),\n };\n}\n\nexport function buildViewer360ThemeStyle(theme?: Viewer360Theme): CSSProperties {\n return theme ? (theme as CSSProperties) : {};\n}\n","import type { PointerEvent as ReactPointerEvent, RefObject, WheelEvent as ReactWheelEvent } from 'react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n applyWheelZoom,\n getViewerCursorClass,\n isResetDisabled,\n resolveViewer360Config,\n stepZoomIn,\n stepZoomOut,\n} from '../helpers/adjustViewerZoom';\nimport { computeDragFrameIndex } from '../helpers/computeDragFrameIndex';\nimport {\n computeHotspotPositionFromClick,\n computeHotspotScreenPosition,\n computeViewerImageLayout,\n type ViewerImageLayout,\n} from '../helpers/computeViewerImageLayout';\nimport { computeViewerPanOffset } from '../helpers/computeViewerPanOffset';\nimport {\n drawFrameOnCanvas,\n filterHotspotsByFrame,\n getFramesSignature,\n hasLoadedViewerFrame,\n preloadViewerFrames,\n} from '../helpers/viewerHelpers';\nimport type {\n Viewer360Config,\n Viewer360Frame,\n Viewer360Hotspot,\n Viewer360HotspotPosition,\n Viewer360PanOffset,\n} from '../types';\n\ntype UseViewer360Params<TData> = {\n frames: Viewer360Frame[];\n currentFrameIndex: number;\n onFrameChange: (index: number) => void;\n hotspots?: Viewer360Hotspot<TData>[];\n config?: Viewer360Config;\n hotspotMode?: boolean;\n onHotspotAdd?: (position: Viewer360HotspotPosition) => void;\n};\n\ntype UseViewer360Return<TData> = {\n canvasRef: RefObject<HTMLCanvasElement | null>;\n containerRef: RefObject<HTMLDivElement | null>;\n currentFrame: Viewer360Frame | undefined;\n currentFrameHotspots: Viewer360Hotspot<TData>[];\n imagesLoaded: boolean;\n isHotspotMode: boolean;\n isResetDisabled: boolean;\n maxZoom: number;\n minZoom: number;\n viewerCursorClass: string;\n zoom: number;\n getCurrentImageLayout: () => ViewerImageLayout | null;\n getHotspotScreenPosition: (hotspot: Viewer360Hotspot<TData>) => { leftPercent: number; topPercent: number };\n handleCanvasClick: (event: React.MouseEvent<HTMLDivElement>) => void;\n handlePointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handlePointerMove: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handlePointerUp: (event: ReactPointerEvent<HTMLDivElement>) => void;\n handleResetView: () => void;\n handleWheel: (event: ReactWheelEvent<HTMLDivElement>) => void;\n handleZoomIn: () => void;\n handleZoomOut: () => void;\n};\n\nexport function useViewer360<TData = unknown>({\n frames,\n hotspots = [],\n currentFrameIndex,\n onFrameChange,\n config,\n hotspotMode: hotspotModeProp = false,\n onHotspotAdd,\n}: UseViewer360Params<TData>): UseViewer360Return<TData> {\n const resolvedConfig = useMemo(() => resolveViewer360Config(config), [config]);\n const { minZoom, maxZoom } = resolvedConfig;\n\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const imagesRef = useRef<HTMLImageElement[]>([]);\n const dragStartRef = useRef<{ pointerX: number; frameIndex: number } | null>(null);\n const panStartRef = useRef<{ pointerX: number; pointerY: number; panX: number; panY: number } | null>(null);\n\n const framesSignature = getFramesSignature(frames);\n const [loadedSignature, setLoadedSignature] = useState<string | null>(null);\n const [zoom, setZoom] = useState<number>(minZoom);\n const [pan, setPan] = useState<Viewer360PanOffset>({ panX: 0, panY: 0 });\n const [isDragging, setIsDragging] = useState(false);\n\n const isHotspotMode = hotspotModeProp;\n const imagesLoaded = loadedSignature === framesSignature;\n const currentFrameHotspots = filterHotspotsByFrame(hotspots, currentFrameIndex) as Viewer360Hotspot<TData>[];\n const currentFrame = frames[currentFrameIndex];\n const viewerCursorClass = getViewerCursorClass(isHotspotMode, zoom, isDragging, minZoom);\n const resetDisabled = isResetDisabled(zoom, pan, resolvedConfig);\n\n useEffect(() => {\n let cancelled = false;\n imagesRef.current = [];\n\n async function loadFrames(): Promise<void> {\n const loadedImages = await preloadViewerFrames(frames);\n\n if (!cancelled && hasLoadedViewerFrame(loadedImages)) {\n imagesRef.current = loadedImages;\n setLoadedSignature(framesSignature);\n }\n }\n\n void loadFrames();\n\n return (): void => {\n cancelled = true;\n };\n }, [frames, framesSignature]);\n\n useEffect(() => {\n if (!imagesLoaded) return;\n\n function renderFrame(): void {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n const img = imagesRef.current[currentFrameIndex];\n\n if (!canvas || !container) return;\n\n drawFrameOnCanvas({ canvas, container, image: img, zoom, pan });\n }\n\n renderFrame();\n window.addEventListener('resize', renderFrame);\n\n return (): void => window.removeEventListener('resize', renderFrame);\n }, [imagesLoaded, currentFrameIndex, zoom, pan]);\n\n useEffect(() => {\n if (!resolvedConfig.autoRotate || frames.length <= 1 || isDragging || isHotspotMode || zoom > minZoom) {\n return;\n }\n\n const direction = resolvedConfig.autoRotateDirection === 'backward' ? -1 : 1;\n const interval = window.setInterval(() => {\n onFrameChange((currentFrameIndex + direction + frames.length) % frames.length);\n }, resolvedConfig.autoRotateIntervalMs);\n\n return (): void => window.clearInterval(interval);\n }, [\n resolvedConfig.autoRotate,\n resolvedConfig.autoRotateDirection,\n resolvedConfig.autoRotateIntervalMs,\n frames.length,\n currentFrameIndex,\n isDragging,\n isHotspotMode,\n zoom,\n minZoom,\n onFrameChange,\n ]);\n\n function getCurrentImageLayout(): ViewerImageLayout | null {\n const container = containerRef.current;\n const image = imagesRef.current[currentFrameIndex];\n\n if (!container || !image || !image.complete || !image.naturalWidth) return null;\n\n const rect = container.getBoundingClientRect();\n\n return computeViewerImageLayout({\n containerWidth: rect.width,\n containerHeight: rect.height,\n imageWidth: image.naturalWidth,\n imageHeight: image.naturalHeight,\n pan,\n });\n }\n\n function getHotspotScreenPosition(hotspot: Viewer360Hotspot<TData>): { leftPercent: number; topPercent: number } {\n const layout = getCurrentImageLayout();\n\n if (!layout) {\n return { leftPercent: hotspot.positionX, topPercent: hotspot.positionY };\n }\n\n return computeHotspotScreenPosition(hotspot.positionX, hotspot.positionY, layout, zoom);\n }\n\n function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>): void {\n if (isHotspotMode) return;\n\n event.currentTarget.setPointerCapture(event.pointerId);\n\n if (zoom > minZoom) {\n panStartRef.current = { pointerX: event.clientX, pointerY: event.clientY, panX: pan.panX, panY: pan.panY };\n } else {\n dragStartRef.current = { pointerX: event.clientX, frameIndex: currentFrameIndex };\n }\n\n setIsDragging(true);\n }\n\n function handlePointerMove(event: ReactPointerEvent<HTMLDivElement>): void {\n if (!isDragging) return;\n\n if (panStartRef.current && zoom > minZoom) {\n setPan(computeViewerPanOffset(panStartRef.current, event.clientX, event.clientY));\n return;\n }\n\n if (dragStartRef.current && zoom <= minZoom) {\n const nextFrameIndex = computeDragFrameIndex(\n dragStartRef.current,\n event.clientX,\n frames.length,\n resolvedConfig.dragSensitivity\n );\n\n if (nextFrameIndex !== null) {\n onFrameChange(nextFrameIndex);\n }\n }\n }\n\n function handlePointerUp(event: ReactPointerEvent<HTMLDivElement>): void {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n\n dragStartRef.current = null;\n panStartRef.current = null;\n setIsDragging(false);\n }\n\n function handleWheel(event: ReactWheelEvent<HTMLDivElement>): void {\n event.preventDefault();\n const { zoom: nextZoom, pan: nextPan } = applyWheelZoom(zoom, event.deltaY, pan, resolvedConfig);\n setZoom(nextZoom);\n setPan(nextPan);\n }\n\n function handleCanvasClick(event: React.MouseEvent<HTMLDivElement>): void {\n if (!isHotspotMode || isDragging || !onHotspotAdd) return;\n\n const frame = frames[currentFrameIndex];\n if (!frame) return;\n\n const layout = getCurrentImageLayout();\n if (!layout) return;\n\n const { positionX, positionY } = computeHotspotPositionFromClick(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect(),\n layout,\n zoom\n );\n\n onHotspotAdd({\n frameIndex: currentFrameIndex,\n frameId: frame.id,\n positionX,\n positionY,\n });\n }\n\n function handleResetView(): void {\n setZoom(minZoom);\n setPan({ panX: 0, panY: 0 });\n }\n\n function handleZoomIn(): void {\n setZoom(stepZoomIn(zoom, resolvedConfig));\n }\n\n function handleZoomOut(): void {\n const { zoom: nextZoom, pan: nextPan } = stepZoomOut(zoom, pan, resolvedConfig);\n setZoom(nextZoom);\n setPan(nextPan);\n }\n\n return {\n canvasRef,\n containerRef,\n currentFrame,\n currentFrameHotspots,\n imagesLoaded,\n isHotspotMode,\n isResetDisabled: resetDisabled,\n maxZoom,\n minZoom,\n viewerCursorClass,\n zoom,\n getCurrentImageLayout,\n getHotspotScreenPosition,\n handleCanvasClick,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handleResetView,\n handleWheel,\n handleZoomIn,\n handleZoomOut,\n };\n}\n","import type { Viewer360Config } from '../types';\n\nimport type { PanOffset } from './computeViewerImageLayout';\n\ntype ResolvedViewer360Config = Required<Viewer360Config>;\n\nexport function resolveViewer360Config(config?: Viewer360Config): ResolvedViewer360Config {\n return {\n minZoom: config?.minZoom ?? 1,\n maxZoom: config?.maxZoom ?? 3,\n zoomStep: config?.zoomStep ?? 0.15,\n dragSensitivity: config?.dragSensitivity ?? 8,\n autoRotate: config?.autoRotate ?? false,\n autoRotateIntervalMs: config?.autoRotateIntervalMs ?? 100,\n autoRotateDirection: config?.autoRotateDirection ?? 'forward',\n };\n}\n\nexport function clampZoom(zoom: number, config: ResolvedViewer360Config): number {\n return Math.min(config.maxZoom, Math.max(config.minZoom, zoom));\n}\n\nexport function applyWheelZoom(\n currentZoom: number,\n deltaY: number,\n currentPan: PanOffset,\n config: ResolvedViewer360Config\n): { zoom: number; pan: PanOffset } {\n const delta = deltaY > 0 ? -config.zoomStep : config.zoomStep;\n const zoom = clampZoom(currentZoom + delta, config);\n\n return {\n zoom,\n pan: zoom === config.minZoom ? { panX: 0, panY: 0 } : currentPan,\n };\n}\n\nexport function stepZoomIn(currentZoom: number, config: ResolvedViewer360Config): number {\n return clampZoom(currentZoom + config.zoomStep, config);\n}\n\nexport function stepZoomOut(\n currentZoom: number,\n currentPan: PanOffset,\n config: ResolvedViewer360Config\n): { zoom: number; pan: PanOffset } {\n const zoom = clampZoom(currentZoom - config.zoomStep, config);\n\n return {\n zoom,\n pan: zoom === config.minZoom ? { panX: 0, panY: 0 } : currentPan,\n };\n}\n\nexport function isResetDisabled(zoom: number, pan: PanOffset, config: ResolvedViewer360Config): boolean {\n return zoom === config.minZoom && pan.panX === 0 && pan.panY === 0;\n}\n\nexport function getViewerCursorClass(isHotspotMode: boolean, zoom: number, isDragging: boolean, minZoom: number): string {\n if (isHotspotMode) return 'cursor-crosshair';\n if (isDragging) return 'cursor-grabbing';\n if (zoom > minZoom) return 'cursor-grab';\n return 'cursor-ew-resize';\n}\n","export function clampFrameIndex(index: number, frameCount: number): number {\n if (frameCount === 0) return 0;\n return ((index % frameCount) + frameCount) % frameCount;\n}\n\ntype DragStart = {\n pointerX: number;\n frameIndex: number;\n};\n\nexport function computeDragFrameIndex(\n dragStart: DragStart,\n clientX: number,\n frameCount: number,\n dragSensitivity: number\n): number | null {\n const deltaX = clientX - dragStart.pointerX;\n const frameDelta = Math.round(-deltaX / dragSensitivity);\n\n if (frameDelta === 0) return null;\n\n return clampFrameIndex(dragStart.frameIndex + frameDelta, frameCount);\n}\n","export type ViewerImageLayout = {\n width: number;\n height: number;\n centerX: number;\n centerY: number;\n drawWidth: number;\n drawHeight: number;\n offsetX: number;\n offsetY: number;\n};\n\nexport type PanOffset = {\n panX: number;\n panY: number;\n};\n\ntype ComputeViewerImageLayoutParams = {\n containerWidth: number;\n containerHeight: number;\n imageWidth: number;\n imageHeight: number;\n pan?: PanOffset;\n};\n\nexport function computeViewerImageLayout({\n containerWidth,\n containerHeight,\n imageWidth,\n imageHeight,\n pan = { panX: 0, panY: 0 },\n}: ComputeViewerImageLayoutParams): ViewerImageLayout {\n const imgAspect = imageWidth / imageHeight;\n const containerAspect = containerWidth / containerHeight;\n\n let drawWidth: number;\n let drawHeight: number;\n\n if (imgAspect > containerAspect) {\n drawWidth = containerWidth;\n drawHeight = containerWidth / imgAspect;\n } else {\n drawHeight = containerHeight;\n drawWidth = containerHeight * imgAspect;\n }\n\n const offsetX = (containerWidth - drawWidth) / 2 + pan.panX;\n const offsetY = (containerHeight - drawHeight) / 2 + pan.panY;\n\n return {\n width: containerWidth,\n height: containerHeight,\n centerX: containerWidth / 2,\n centerY: containerHeight / 2,\n drawWidth,\n drawHeight,\n offsetX,\n offsetY,\n };\n}\n\nexport function computeHotspotScreenPosition(\n hotspotX: number,\n hotspotY: number,\n layout: ViewerImageLayout,\n zoom: number\n): { leftPercent: number; topPercent: number } {\n const baseOffsetX = (layout.width - layout.drawWidth) / 2;\n const baseOffsetY = (layout.height - layout.drawHeight) / 2;\n\n const containerX = (hotspotX / 100) * layout.width;\n const containerY = (hotspotY / 100) * layout.height;\n\n const imageLocalX = (containerX - baseOffsetX) / layout.drawWidth;\n const imageLocalY = (containerY - baseOffsetY) / layout.drawHeight;\n\n const imagePointX = layout.offsetX + imageLocalX * layout.drawWidth;\n const imagePointY = layout.offsetY + imageLocalY * layout.drawHeight;\n\n const screenX = layout.centerX + zoom * (imagePointX - layout.centerX);\n const screenY = layout.centerY + zoom * (imagePointY - layout.centerY);\n\n return {\n leftPercent: (screenX / layout.width) * 100,\n topPercent: (screenY / layout.height) * 100,\n };\n}\n\nexport function computeHotspotPositionFromClick(\n clientX: number,\n clientY: number,\n containerRect: DOMRect,\n layout: ViewerImageLayout,\n zoom: number\n): { positionX: number; positionY: number } {\n const clickX = clientX - containerRect.left;\n const clickY = clientY - containerRect.top;\n\n const unzoomedX = layout.centerX + (clickX - layout.centerX) / zoom;\n const unzoomedY = layout.centerY + (clickY - layout.centerY) / zoom;\n\n const baseOffsetX = (layout.width - layout.drawWidth) / 2;\n const baseOffsetY = (layout.height - layout.drawHeight) / 2;\n\n const imageLocalX = Math.min(1, Math.max(0, (unzoomedX - layout.offsetX) / layout.drawWidth));\n const imageLocalY = Math.min(1, Math.max(0, (unzoomedY - layout.offsetY) / layout.drawHeight));\n\n const storedX = baseOffsetX + imageLocalX * layout.drawWidth;\n const storedY = baseOffsetY + imageLocalY * layout.drawHeight;\n\n return {\n positionX: Math.min(100, Math.max(0, (storedX / layout.width) * 100)),\n positionY: Math.min(100, Math.max(0, (storedY / layout.height) * 100)),\n };\n}\n","import type { PanOffset } from './computeViewerImageLayout';\n\ntype PanStart = {\n pointerX: number;\n pointerY: number;\n panX: number;\n panY: number;\n};\n\nexport function computeViewerPanOffset(panStart: PanStart, clientX: number, clientY: number): PanOffset {\n const deltaX = clientX - panStart.pointerX;\n const deltaY = clientY - panStart.pointerY;\n\n return {\n panX: panStart.panX + deltaX,\n panY: panStart.panY + deltaY,\n };\n}\n","import type { Viewer360Frame } from '../types';\n\nimport { computeViewerImageLayout, type PanOffset } from './computeViewerImageLayout';\n\ntype DrawFrameOnCanvasParams = {\n canvas: HTMLCanvasElement;\n container: HTMLDivElement;\n image: HTMLImageElement;\n zoom: number;\n pan: PanOffset;\n};\n\nexport function drawFrameOnCanvas({ canvas, container, image, zoom, pan }: DrawFrameOnCanvasParams): void {\n if (!image.complete || !image.naturalWidth) return;\n\n const rect = container.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n\n canvas.width = rect.width * dpr;\n canvas.height = rect.height * dpr;\n canvas.style.width = `${rect.width}px`;\n canvas.style.height = `${rect.height}px`;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, rect.width, rect.height);\n\n const layout = computeViewerImageLayout({\n containerWidth: rect.width,\n containerHeight: rect.height,\n imageWidth: image.naturalWidth,\n imageHeight: image.naturalHeight,\n pan,\n });\n\n ctx.save();\n ctx.translate(layout.centerX, layout.centerY);\n ctx.scale(zoom, zoom);\n ctx.translate(-layout.centerX, -layout.centerY);\n ctx.drawImage(image, layout.offsetX, layout.offsetY, layout.drawWidth, layout.drawHeight);\n ctx.restore();\n}\n\nexport function getFramesSignature(frames: Viewer360Frame[]): string {\n return frames.map((frame) => frame.id).join('-');\n}\n\nexport function preloadFrameImage(frame: Viewer360Frame): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = (): void => resolve(img);\n img.onerror = (): void => reject(new Error(`Failed to load frame: ${frame.src}`));\n img.src = frame.src;\n });\n}\n\nexport async function preloadViewerFrames(frames: Viewer360Frame[]): Promise<HTMLImageElement[]> {\n const results = await Promise.allSettled(frames.map(preloadFrameImage));\n\n return results.map((result) => (result.status === 'fulfilled' ? result.value : new Image()));\n}\n\nexport function hasLoadedViewerFrame(images: HTMLImageElement[]): boolean {\n return images.some((image) => image.complete && image.naturalWidth > 0);\n}\n\nexport function filterHotspotsByFrame<TData>(\n hotspots: Array<{ frameIndex: number; data?: TData }>,\n frameIndex: number\n): Array<{ frameIndex: number; data?: TData }> {\n return hotspots.filter((hotspot) => hotspot.frameIndex === frameIndex);\n}\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cn } from '@/components/utils';\n\nfunction Card({ className, size = 'default', ...props }: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }): JSX.Element {\n return (\n <div\n data-slot=\"card\"\n data-size={size}\n className={cn(\n 'ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-xl py-6 text-sm shadow-xs ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n 'gap-0.5 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-title\"\n className={cn('text-lg leading-normal font-semibold group-data-[size=sm]/card:text-sm', className)}\n {...props}\n />\n );\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"card-description\" className={cn('text-muted-foreground text-xs font-medium', className)} {...props} />;\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-action\"\n className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}\n {...props}\n />\n );\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"card-content\" className={cn('px-6 group-data-[size=sm]/card:px-4', className)} {...props} />;\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\n 'rounded-b-xl px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4 flex items-center',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nconst badgeVariants = cva(\n 'h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',\n secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',\n destructive:\n 'bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20',\n outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',\n ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',\n link: 'text-primary underline-offset-4 hover:underline',\n info: 'bg-blue-500 text-white hover:bg-blue-600',\n warning:\n 'rounded-full border-transparent bg-amber-500 px-2.5 text-white shadow-none [a]:hover:bg-amber-600 [&>svg]:text-white',\n success: 'bg-green-600 text-white hover:bg-green-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n }\n);\n\nfunction Badge({\n className,\n variant = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'span';\n\n return <Comp data-slot=\"badge\" data-variant={variant} className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n\nexport { Badge, badgeVariants };\n","import type { JSX } from 'react';\n\nimport { Badge } from '@/components/ui/Badge';\nimport { cn } from '@/components/utils';\n\ntype Viewer360AddModeBannerProps = {\n className?: string;\n label: string;\n};\n\nexport function Viewer360AddModeBanner({ className, label }: Viewer360AddModeBannerProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Badge variant=\"outline\" className={cn('pointer-events-none', className)}>\n {label}\n </Badge>\n );\n}\n","import type { JSX } from 'react';\n\nimport { Badge } from '@/components/ui/Badge';\nimport { cn } from '@/components/utils';\n\ntype Viewer360FrameIndicatorProps = {\n className?: string;\n label: string;\n};\n\nexport function Viewer360FrameIndicator({ className, label }: Viewer360FrameIndicatorProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Badge variant=\"outline\" className={cn('pointer-events-none shadow-sm', className)}>\n {label}\n </Badge>\n );\n}\n","import type { Viewer360Hotspot, Viewer360Marker } from '../types';\n\nexport function hotspotToViewer360Marker<TData>(hotspot: Viewer360Hotspot<TData>): Viewer360Marker {\n const data = hotspot.data;\n\n if (data && typeof data === 'object' && 'title' in data && typeof (data as { title?: unknown }).title === 'string') {\n const marker = data as unknown as Viewer360Marker;\n\n return {\n id: marker.id ?? hotspot.id,\n title: marker.title,\n description: marker.description,\n };\n }\n\n return {\n id: hotspot.id,\n title: hotspot.id,\n };\n}\n\nexport function toViewer360Hotspots<TData extends Viewer360Marker>(\n markers: Array<Viewer360Marker & { frameIndex: number; positionX: number; positionY: number }>,\n mapData?: (marker: Viewer360Marker & { frameIndex: number; positionX: number; positionY: number }) => TData\n): Viewer360Hotspot<TData>[] {\n return markers.map((marker) => ({\n id: marker.id,\n frameIndex: marker.frameIndex,\n positionX: marker.positionX,\n positionY: marker.positionY,\n data: mapData ? mapData(marker) : (marker as unknown as TData),\n }));\n}\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { Separator } from '@/components/ui/Separator';\nimport { cn } from '@/components/utils';\n\nfunction ItemGroup({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn('gap-4 has-[[data-size=sm]]:gap-2.5 has-[[data-size=xs]]:gap-2 group/item-group flex w-full flex-col', className)}\n {...props}\n />\n );\n}\n\nfunction ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>): JSX.Element {\n return <Separator data-slot=\"item-separator\" orientation=\"horizontal\" className={cn('my-2', className)} {...props} />;\n}\n\nconst itemVariants = cva(\n '[a]:hover:bg-muted rounded-md border text-sm w-full group/item focus-visible:border-ring focus-visible:ring-ring/50 flex items-center flex-wrap outline-none transition-colors duration-100 focus-visible:ring-[3px] [a]:transition-colors',\n {\n variants: {\n variant: {\n default: 'border-transparent',\n outline: 'border-border',\n muted: 'bg-muted/50 border-transparent',\n },\n size: {\n default: 'gap-3.5 px-4 py-3.5',\n sm: 'gap-2.5 px-3 py-2.5',\n xs: 'gap-2 px-2.5 py-2 [[data-slot=dropdown-menu-content]_&]:p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nfunction Item({\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof itemVariants> & { asChild?: boolean }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'div';\n return (\n <Comp\n data-slot=\"item\"\n data-variant={variant}\n data-size={size}\n className={cn(itemVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst itemMediaVariants = cva(\n 'gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none',\n {\n variants: {\n variant: {\n default: 'bg-transparent',\n icon: '[&_svg]:size-4',\n image: 'size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n }\n);\n\nfunction ItemMedia({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>): JSX.Element {\n return <div data-slot=\"item-media\" data-variant={variant} className={cn(itemMediaVariants({ variant, className }))} {...props} />;\n}\n\nfunction ItemContent({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"item-content\"\n className={cn('gap-1 group-data-[size=xs]/item:gap-0 flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none', className)}\n {...props}\n />\n );\n}\n\nfunction ItemTitle({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return (\n <div\n data-slot=\"item-title\"\n className={cn('gap-2 text-sm leading-snug font-medium underline-offset-4 line-clamp-1 flex w-fit items-center', className)}\n {...props}\n />\n );\n}\n\nfunction ItemDescription({ className, ...props }: React.ComponentProps<'p'>): JSX.Element {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(\n 'text-muted-foreground text-left text-sm leading-normal group-data-[size=xs]/item:text-xs [&>a:hover]:text-primary line-clamp-2 font-normal [&>a]:underline [&>a]:underline-offset-4',\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemActions({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-actions\" className={cn('gap-2 flex items-center', className)} {...props} />;\n}\n\nfunction ItemHeader({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-header\" className={cn('gap-2 flex basis-full items-center justify-between', className)} {...props} />;\n}\n\nfunction ItemFooter({ className, ...props }: React.ComponentProps<'div'>): JSX.Element {\n return <div data-slot=\"item-footer\" className={cn('gap-2 flex basis-full items-center justify-between', className)} {...props} />;\n}\n\nexport { Item, ItemMedia, ItemContent, ItemActions, ItemGroup, ItemSeparator, ItemTitle, ItemDescription, ItemHeader, ItemFooter };\n","'use client';\n\nimport * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { Separator as SeparatorPrimitive } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nfunction Separator({\n className,\n orientation = 'horizontal',\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>): JSX.Element {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Separator };\n","import type { JSX, MouseEvent } from 'react';\n\nimport { Trash2 } from 'lucide-react';\n\nimport { defaultViewer360MarkerPinLabels } from '../constants/viewer360MarkerLabels';\nimport { viewer360MarkerPinClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360MarkerPinProps } from '../types';\nimport { Button } from '@/components/ui/Button';\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemTitle,\n} from '@/components/ui/Item';\nimport { cn } from '@/components/utils';\n\nexport function Viewer360MarkerPin<TData = unknown>({\n marker,\n hotspot,\n leftPercent,\n topPercent,\n onDelete,\n isDeletePending = false,\n onClick,\n renderTag,\n classNames,\n labels,\n}: Viewer360MarkerPinProps<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: States & Constants\n // ----------------------------------------------------------------------------------------------------\n const deleteLabel = labels?.delete ?? defaultViewer360MarkerPinLabels.delete;\n const showTooltip = Boolean(marker.title || marker.description || onDelete || renderTag);\n\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <div\n className={cn(viewer360MarkerPinClassNames.root, classNames?.root, 'group/marker')}\n style={{ left: `${leftPercent}%`, top: `${topPercent}%` }}\n >\n <div className=\"relative size-4 shrink-0\">\n <span className={cn(viewer360MarkerPinClassNames.ping, classNames?.ping)} aria-hidden=\"true\" />\n\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"icon-xs\"\n className={cn(viewer360MarkerPinClassNames.dot, classNames?.dot, 'hover:bg-destructive')}\n aria-label={marker.title}\n onClick={onClick}\n />\n </div>\n\n {showTooltip && (\n <div\n className={cn(\n viewer360MarkerPinClassNames.tooltip,\n classNames?.tooltip,\n 'pointer-events-none opacity-0 transition-opacity duration-150 group-hover/marker:pointer-events-auto group-hover/marker:opacity-100 group-focus-within/marker:pointer-events-auto group-focus-within/marker:opacity-100'\n )}\n >\n <Item\n size=\"sm\"\n variant=\"default\"\n className={cn(viewer360MarkerPinClassNames.tooltipHeader, classNames?.tooltipHeader, 'w-full border-transparent')}\n >\n <ItemContent className={cn(viewer360MarkerPinClassNames.tooltipBody, classNames?.tooltipBody)}>\n <ItemTitle className={cn(viewer360MarkerPinClassNames.tooltipTitle, classNames?.tooltipTitle)}>\n {marker.title}\n </ItemTitle>\n {renderTag && (\n <div className=\"mt-1 flex w-fit items-center\">{renderTag({ marker, hotspot })}</div>\n )}\n {marker.description && (\n <ItemDescription className={cn(viewer360MarkerPinClassNames.tooltipDescription, classNames?.tooltipDescription)}>\n {marker.description}\n </ItemDescription>\n )}\n </ItemContent>\n {onDelete && (\n <ItemActions>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n className={classNames?.deleteButton}\n disabled={isDeletePending}\n aria-label={deleteLabel}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n onDelete(marker.id);\n }}\n >\n <Trash2 className=\"size-4\" />\n </Button>\n </ItemActions>\n )}\n </Item>\n </div>\n )}\n </div>\n );\n}\n","export const defaultViewer360MarkerPinLabels = {\n delete: 'Remove marker',\n} as const;\n","import * as React from 'react';\nimport type { JSX } from 'react';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/components/utils';\n\nconst buttonVariants = cva(\n 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/80',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground shadow-xs',\n secondary:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',\n ghost: 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n destructive:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default:\n 'h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2',\n xs: 'h-6 gap-1 rounded-md px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n sm: 'h-8 gap-1 rounded-md px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n lg: 'h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3',\n icon: 'size-9',\n 'icon-xs': 'size-6 rounded-md in-data-[slot=button-group]:rounded-md',\n 'icon-sm': 'size-8 rounded-md in-data-[slot=button-group]:rounded-md',\n 'icon-lg': 'size-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nfunction Button({\n className,\n variant = 'default',\n size = 'default',\n asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }): JSX.Element {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n","import type { JSX, MouseEvent, ReactNode } from 'react';\n\nimport { hotspotToViewer360Marker } from '../helpers/markerHelpers';\nimport type { Viewer360Hotspot, Viewer360HotspotPinOptions, Viewer360HotspotRenderProps } from '../types';\nimport { Item } from '@/components/ui/Item';\n\nimport { Viewer360MarkerPin } from './Viewer360MarkerPin';\n\ntype Viewer360HotspotOverlayProps<TData = unknown> = {\n hotspot: Viewer360Hotspot<TData>;\n leftPercent: number;\n topPercent: number;\n hotspotPin?: Viewer360HotspotPinOptions<TData>;\n renderHotspot?: (props: Viewer360HotspotRenderProps<TData>) => ReactNode;\n onHotspotClick?: (hotspot: Viewer360Hotspot<TData>, event: MouseEvent<HTMLDivElement>) => void;\n};\n\nexport function Viewer360HotspotOverlay<TData = unknown>({\n hotspot,\n leftPercent,\n topPercent,\n hotspotPin,\n renderHotspot,\n onHotspotClick,\n}: Viewer360HotspotOverlayProps<TData>): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n if (renderHotspot) {\n return (\n <Item size=\"xs\" variant=\"default\" className=\"pointer-events-auto w-auto border-transparent p-0\">\n {renderHotspot({ hotspot, leftPercent, topPercent })}\n </Item>\n );\n }\n\n const marker = hotspotPin?.getMarker?.(hotspot) ?? hotspotToViewer360Marker(hotspot);\n\n return (\n <Viewer360MarkerPin\n marker={marker}\n hotspot={hotspot}\n leftPercent={leftPercent}\n topPercent={topPercent}\n onDelete={hotspotPin?.onDelete}\n isDeletePending={hotspotPin?.deletingMarkerId === hotspot.id}\n renderTag={hotspotPin?.renderTag}\n classNames={hotspotPin?.classNames}\n labels={hotspotPin?.labels}\n onClick={\n onHotspotClick\n ? (event) => onHotspotClick(hotspot, event as unknown as MouseEvent<HTMLDivElement>)\n : undefined\n }\n />\n );\n}\n","'use client';\n\nimport * as React from 'react';\n\nimport { cn } from '@/components/utils';\n\nfunction Label({ className, ...props }: React.ComponentProps<'label'>): React.ReactNode {\n return (\n <label\n data-slot=\"label\"\n className={cn(\n 'gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import type { JSX } from 'react';\n\nimport { Loader2Icon } from 'lucide-react';\n\nimport { cn } from '@/components/utils';\n\nfunction Spinner({ className, ...props }: React.ComponentProps<'svg'>): JSX.Element {\n return <Loader2Icon role=\"status\" aria-label=\"Loading\" className={cn('size-4 animate-spin', className)} {...props} />;\n}\n\nexport { Spinner };\n","import type { JSX } from 'react';\n\nimport { Item } from '@/components/ui/Item';\nimport { Label } from '@/components/ui/Label';\nimport { Spinner } from '@/components/ui/Spinner';\nimport { cn } from '@/components/utils';\n\ntype Viewer360LoadingOverlayProps = {\n className?: string;\n textClassName?: string;\n label: string;\n};\n\nexport function Viewer360LoadingOverlay({ className, textClassName, label }: Viewer360LoadingOverlayProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <Item\n size=\"sm\"\n variant=\"muted\"\n className={cn('pointer-events-none w-auto justify-center border-transparent bg-muted/80', className)}\n >\n <Spinner className=\"size-5 text-muted-foreground\" />\n <Label className={cn('font-normal text-muted-foreground', textClassName)}>{label}</Label>\n </Item>\n );\n}\n","import type { JSX } from 'react';\n\nimport { Crosshair, Minus, Plus, RotateCcw, ZoomIn } from 'lucide-react';\n\nimport { viewer360ClassNames } from '../constants/viewer360ClassNames';\nimport type { Viewer360ToolbarRenderProps } from '../types';\nimport { Badge } from '@/components/ui/Badge';\nimport { Button } from '@/components/ui/Button';\nimport { CardFooter } from '@/components/ui/Card';\nimport { Label } from '@/components/ui/Label';\nimport { Separator } from '@/components/ui/Separator';\nimport { cn } from '@/components/utils';\n\ntype Viewer360ToolbarProps = Viewer360ToolbarRenderProps;\n\nexport function Viewer360Toolbar({\n showDragHint,\n showHotspotModeControl,\n showZoomControls,\n showResetControl,\n labels,\n isHotspotMode,\n zoom,\n minZoom,\n maxZoom,\n isResetDisabled,\n onHotspotModeChange,\n onZoomIn,\n onZoomOut,\n onResetView,\n}: Viewer360ToolbarProps): JSX.Element {\n // ----------------------------------------------------------------------------------------------------\n // MARK: Main Component UI\n // ----------------------------------------------------------------------------------------------------\n return (\n <CardFooter className={cn(viewer360ClassNames.toolbar, 'gap-2 border-t px-4 py-3 pt-3')}>\n {showDragHint && (\n <Label className={cn(viewer360ClassNames.dragHint, 'font-normal text-muted-foreground')}>{labels.dragHint}</Label>\n )}\n\n <div className={viewer360ClassNames.controls}>\n {showHotspotModeControl && (\n <>\n <Button variant={isHotspotMode ? 'default' : 'outline'} size=\"sm\" onClick={() => onHotspotModeChange(!isHotspotMode)}>\n <Crosshair className=\"me-1.5 size-4\" />\n {labels.addHotspot}\n </Button>\n <Separator orientation=\"vertical\" className={cn(viewer360ClassNames.divider, 'h-6')} />\n </>\n )}\n\n {showZoomControls && (\n <>\n <Button variant=\"outline\" size=\"icon-sm\" disabled={zoom <= minZoom} aria-label={labels.zoomOut} onClick={onZoomOut}>\n <Minus className=\"size-4\" />\n </Button>\n <Badge variant=\"outline\" className={cn(viewer360ClassNames.zoomDisplay, 'h-8 gap-1 px-2 py-1')}>\n <ZoomIn className=\"size-3 text-muted-foreground\" />\n {labels.zoom(Math.round(zoom * 100))}\n </Badge>\n <Button variant=\"outline\" size=\"icon-sm\" disabled={zoom >= maxZoom} aria-label={labels.zoomIn} onClick={onZoomIn}>\n <Plus className=\"size-4\" />\n </Button>\n </>\n )}\n\n {showResetControl && (\n <Button variant=\"outline\" size=\"icon-sm\" disabled={isResetDisabled} aria-label={labels.resetView} onClick={onResetView}>\n <RotateCcw className=\"size-4\" />\n </Button>\n )}\n </div>\n </CardFooter>\n );\n}\n","export const viewer360Config = {\n minZoom: 1,\n maxZoom: 3,\n zoomStep: 0.15,\n dragSensitivity: 8,\n autoRotate: false,\n autoRotateIntervalMs: 100,\n autoRotateDirection: 'forward' as const,\n};\n\nexport const defaultViewer360Config = viewer360Config;\n"],"mappings":"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","names":["useEffect","useMemo","useState","jsx","jsx","jsx","cva","Slot","jsx","jsx","cva","Slot","jsx","jsx","cva","Slot","jsx","cva","Slot","jsx","jsx","jsx","jsx","jsx","jsxs","jsx","jsxs","isResetDisabled","jsx","jsxs","useMemo","useState","isResetDisabled","useEffect"]}
|