js-cloudimage-360-view 4.3.5 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/js-cloudimage-360-view.min.js +7 -7
- package/dist/react/{ci360-xUK7dmd6.mjs → ci360--3KbDLtq.mjs} +718 -678
- package/dist/react/ci360--3KbDLtq.mjs.map +1 -0
- package/dist/react/ci360-FVoLTUpQ.js +65 -0
- package/dist/react/ci360-FVoLTUpQ.js.map +1 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +15 -0
- package/dist/react/index.js +62 -58
- package/dist/react/index.js.map +1 -1
- package/dist/react/style.css +1 -1
- package/package.json +11 -11
- package/src/react/types.d.ts +15 -0
- package/dist/react/ci360-Bv2kRtqP.js +0 -65
- package/dist/react/ci360-Bv2kRtqP.js.map +0 -1
- package/dist/react/ci360-xUK7dmd6.mjs.map +0 -1
package/dist/react/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const we=require("react/jsx-runtime"),n=require("react");let I=null;function C(p,t){const[w,f]=n.useState(!1),a=n.useRef(null),l=n.useRef(null),m=n.useId();n.useEffect(()=>{if(typeof window>"u"||!p.current||t.autoInit===!1)return;let u=!0;const s=p.current;return(async()=>{try{if(I||(I=(await Promise.resolve().then(()=>require("./ci360-FVoLTUpQ.js"))).default),!s||!u)return;s.id||(s.id=`ci360-${m.replace(/:/g,"")}`);const i={...t,onReady:c=>{var d;u&&(f(!0),(d=t.onReady)==null||d.call(t,c))}};l.current=new I,a.current=l.current.init(s,i)}catch(i){console.error("Failed to initialize CI360 viewer:",i)}})(),()=>{if(u=!1,a.current){try{a.current.destroy()}catch{}a.current=null}l.current=null,f(!1)}},[t.folder,t.filenameX,t.filenameY,t.imageListX,t.imageListY,t.amountX,t.amountY,t.hotspots,t.theme,m]);const y=n.useCallback(()=>a.current,[]);return{viewer:a.current,isReady:w,getViewer:y}}const ve=(p,t)=>{const{id:w,className:f,style:a,folder:l,apiVersion:m,filenameX:y,filenameY:u,imageListX:s,imageListY:v,indexZeroBase:i,amountX:c,amountY:d,draggable:h,swipeable:g,keys:V,keysReverse:S,autoplay:T,autoplayBehavior:L,playOnce:b,speed:O,autoplayReverse:Z,dragSpeed:F,dragReverse:X,stopAtEdges:Y,inertia:k,fullscreen:q,magnifier:z,pointerZoom:A,pinchZoom:B,bottomCircle:D,bottomCircleOffset:E,initialIconShown:j,hide360Logo:x,logoSrc:M,imageInfo:P,hints:N,theme:H,ciToken:$,ciFilters:G,ciTransformation:J,lazyload:K,hotspots:Q,hotspotTrigger:U,hotspotTimelineOnClick:W,aspectRatio:_,onReady:ee,onLoad:te,onSpin:oe,onAutoplayStart:re,onAutoplayStop:ne,onFullscreenOpen:ae,onFullscreenClose:se,onZoomIn:ie,onZoomOut:le,onDragStart:ue,onDragEnd:me,onError:ce,...fe}=p,de=n.useRef(null),ye=n.useMemo(()=>({folder:l,apiVersion:m,filenameX:y,filenameY:u,imageListX:s,imageListY:v,indexZeroBase:i,amountX:c,amountY:d,draggable:h,swipeable:g,keys:V,keysReverse:S,autoplay:T,autoplayBehavior:L,playOnce:b,speed:O,autoplayReverse:Z,dragSpeed:F,dragReverse:X,stopAtEdges:Y,inertia:k,fullscreen:q,magnifier:z,pointerZoom:A,pinchZoom:B,bottomCircle:D,bottomCircleOffset:E,initialIconShown:j,hide360Logo:x,logoSrc:M,imageInfo:P,hints:N,theme:H,ciToken:$,ciFilters:G,ciTransformation:J,lazyload:K,hotspots:Q,hotspotTrigger:U,hotspotTimelineOnClick:W,aspectRatio:_,onReady:ee,onLoad:te,onSpin:oe,onAutoplayStart:re,onAutoplayStop:ne,onFullscreenOpen:ae,onFullscreenClose:se,onZoomIn:ie,onZoomOut:le,onDragStart:ue,onDragEnd:me,onError:ce}),[l,m,y,u,s,v,i,c,d,h,g,V,S,T,L,b,O,Z,F,X,Y,k,q,z,A,B,D,E,j,x,M,P,N,H,$,G,J,K,Q,U,W,_,ee,te,oe,re,ne,ae,se,ie,le,ue,me,ce]),{getViewer:r}=C(de,ye);return n.useImperativeHandle(t,()=>({moveLeft:(e=1)=>{var o;return(o=r())==null?void 0:o.moveLeft(!1,e)},moveRight:(e=1)=>{var o;return(o=r())==null?void 0:o.moveRight(!1,e)},moveTop:(e=1)=>{var o;return(o=r())==null?void 0:o.moveTop(!1,e)},moveBottom:(e=1)=>{var o;return(o=r())==null?void 0:o.moveBottom(!1,e)},play:()=>{var e;return(e=r())==null?void 0:e.play()},stop:()=>{var e;return(e=r())==null?void 0:e.stopAutoplay()},zoomIn:()=>{var e;return(e=r())==null?void 0:e.toggleZoom()},zoomOut:()=>{var e;return(e=r())==null?void 0:e.removeZoom()},goToFrame:(e,o)=>{var pe;return(pe=r())==null?void 0:pe.animateToFrame(e,o)},getViewer:()=>r()}),[r]),we.jsx("div",{ref:de,id:w,className:f,style:a,...fe})},R=n.forwardRef(ve);R.displayName="CI360Viewer";exports.CI360Viewer=R;exports.CI360ViewerDefault=R;exports.useCI360=C;exports.useCI360Default=C;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/react/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/react/useCI360.ts","../../src/react/CI360Viewer.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useId, useCallback, type RefObject } from 'react';\nimport type {\n CI360Config,\n CI360ViewerInstance,\n UseCI360Return,\n UseCI360Options,\n} from './types';\n\n// Import CI360 class dynamically to avoid SSR issues\nlet CI360Class: any = null;\n\n/**\n * Custom hook for integrating CI360 viewer with React\n *\n * @param containerRef - React ref to the container element\n * @param config - CI360 configuration options\n * @returns Object containing viewer instance and ready state\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const containerRef = useRef<HTMLDivElement>(null);\n * const { viewer, isReady } = useCI360(containerRef, {\n * folder: 'https://example.com/images/',\n * filenameX: 'image-{index}.jpg',\n * amountX: 36,\n * });\n *\n * return <div ref={containerRef} />;\n * }\n * ```\n */\nexport function useCI360(\n containerRef: RefObject<HTMLDivElement | null>,\n config: UseCI360Options\n): UseCI360Return {\n const [isReady, setIsReady] = useState(false);\n const viewerRef = useRef<CI360ViewerInstance | null>(null);\n const ci360Ref = useRef<any>(null);\n const uniqueId = useId();\n\n // Initialize viewer\n useEffect(() => {\n // SSR guard\n if (typeof window === 'undefined') return;\n if (!containerRef.current) return;\n if (config.autoInit === false) return;\n\n let isMounted = true;\n const container = containerRef.current;\n\n const initViewer = async () => {\n try {\n // Dynamically import CI360 to avoid SSR issues\n if (!CI360Class) {\n const module = await import('../ci360');\n CI360Class = module.default;\n }\n\n if (!container || !isMounted) return;\n\n // Set a unique ID on the container if not present\n if (!container.id) {\n container.id = `ci360-${uniqueId.replace(/:/g, '')}`;\n }\n\n // Wrap user callbacks to update React state\n const wrappedConfig: CI360Config = {\n ...config,\n onReady: (data) => {\n if (isMounted) {\n setIsReady(true);\n config.onReady?.(data);\n }\n },\n };\n\n // Create CI360 instance and initialize viewer\n ci360Ref.current = new CI360Class();\n viewerRef.current = ci360Ref.current.init(container, wrappedConfig);\n } catch (error) {\n console.error('Failed to initialize CI360 viewer:', error);\n }\n };\n\n initViewer();\n\n // Cleanup on unmount or when dependencies change\n return () => {\n isMounted = false;\n if (viewerRef.current) {\n try {\n viewerRef.current.destroy();\n } catch (e) {\n // Ignore errors during cleanup - element may already be detached\n }\n viewerRef.current = null;\n }\n ci360Ref.current = null;\n setIsReady(false);\n };\n }, [\n config.folder,\n config.filenameX,\n config.filenameY,\n config.imageListX,\n config.imageListY,\n config.amountX,\n config.amountY,\n config.theme,\n uniqueId,\n ]);\n\n // Stable getter to always return current viewer (avoids stale closures)\n const getViewer = useCallback(() => viewerRef.current, []);\n\n return {\n viewer: viewerRef.current,\n isReady,\n getViewer,\n };\n}\n\nexport default useCI360;\n","import {\n useRef,\n useImperativeHandle,\n forwardRef,\n useMemo,\n type ForwardRefRenderFunction,\n} from 'react';\nimport { useCI360 } from './useCI360';\nimport type {\n CI360ViewerProps,\n CI360ViewerRef,\n CI360Config,\n} from './types';\n\n/**\n * CI360Viewer React Component\n *\n * A declarative React wrapper for the CI360 360-degree image viewer.\n *\n * @example\n * ```tsx\n * import { CI360Viewer } from 'js-cloudimage-360-view/react';\n * import 'js-cloudimage-360-view/css';\n *\n * function ProductView() {\n * return (\n * <CI360Viewer\n * folder=\"https://example.com/images/\"\n * filenameX=\"product-{index}.jpg\"\n * amountX={36}\n * autoplay\n * fullscreen\n * />\n * );\n * }\n * ```\n *\n * @example With ref for imperative control\n * ```tsx\n * import { useRef } from 'react';\n * import { CI360Viewer, CI360ViewerRef } from 'js-cloudimage-360-view/react';\n *\n * function ProductView() {\n * const viewerRef = useRef<CI360ViewerRef>(null);\n *\n * return (\n * <>\n * <CI360Viewer\n * ref={viewerRef}\n * folder=\"https://example.com/images/\"\n * filenameX=\"{index}.jpg\"\n * amountX={36}\n * onSpin={(e) => console.log(`Frame: ${e.activeImageX}`)}\n * />\n * <button onClick={() => viewerRef.current?.play()}>Play</button>\n * <button onClick={() => viewerRef.current?.stop()}>Stop</button>\n * </>\n * );\n * }\n * ```\n */\nconst CI360ViewerComponent: ForwardRefRenderFunction<\n CI360ViewerRef,\n CI360ViewerProps\n> = (props, ref) => {\n const {\n // Container props\n id,\n className,\n style,\n\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n\n ...restProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Memoize config to prevent unnecessary re-initializations\n const config = useMemo<CI360Config>(\n () => ({\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n }),\n [\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n ]\n );\n\n const { getViewer } = useCI360(containerRef, config);\n\n // Expose imperative methods via ref\n // Use getViewer() inside methods to always get the current viewer instance,\n // avoiding stale closure issues when the viewer initializes after first render\n useImperativeHandle(\n ref,\n () => ({\n moveLeft: (steps = 1) => getViewer()?.moveLeft(false, steps),\n moveRight: (steps = 1) => getViewer()?.moveRight(false, steps),\n moveTop: (steps = 1) => getViewer()?.moveTop(false, steps),\n moveBottom: (steps = 1) => getViewer()?.moveBottom(false, steps),\n play: () => getViewer()?.play(),\n stop: () => getViewer()?.stopAutoplay(),\n zoomIn: () => getViewer()?.toggleZoom(),\n zoomOut: () => getViewer()?.removeZoom(),\n goToFrame: (frame: number, hotspotId?: string) =>\n getViewer()?.animateToFrame(frame, hotspotId),\n getViewer: () => getViewer(),\n }),\n [getViewer]\n );\n\n return (\n <div\n ref={containerRef}\n id={id}\n className={className}\n style={style}\n {...restProps}\n />\n );\n};\n\nexport const CI360Viewer = forwardRef(CI360ViewerComponent);\nCI360Viewer.displayName = 'CI360Viewer';\n\nexport default CI360Viewer;\n"],"names":["CI360Class","useCI360","containerRef","config","isReady","setIsReady","useState","viewerRef","useRef","ci360Ref","uniqueId","useId","useEffect","isMounted","container","wrappedConfig","data","_a","error","getViewer","useCallback","CI360ViewerComponent","props","ref","id","className","style","folder","apiVersion","filenameX","filenameY","imageListX","imageListY","indexZeroBase","amountX","amountY","draggable","swipeable","keys","keysReverse","autoplay","autoplayBehavior","playOnce","speed","autoplayReverse","dragSpeed","dragReverse","stopAtEdges","inertia","fullscreen","magnifier","pointerZoom","pinchZoom","bottomCircle","bottomCircleOffset","initialIconShown","hide360Logo","logoSrc","imageInfo","hints","theme","ciToken","ciFilters","ciTransformation","lazyload","hotspots","hotspotTimelineOnClick","aspectRatio","onReady","onLoad","onSpin","onAutoplayStart","onAutoplayStop","onFullscreenOpen","onFullscreenClose","onZoomIn","onZoomOut","onDragStart","onDragEnd","onError","restProps","useMemo","useImperativeHandle","steps","frame","hotspotId","jsx","CI360Viewer","forwardRef"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/react/useCI360.ts","../../src/react/CI360Viewer.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useId, useCallback, type RefObject } from 'react';\nimport type {\n CI360Config,\n CI360ViewerInstance,\n UseCI360Return,\n UseCI360Options,\n} from './types';\n\n// Import CI360 class dynamically to avoid SSR issues\nlet CI360Class: any = null;\n\n/**\n * Custom hook for integrating CI360 viewer with React\n *\n * @param containerRef - React ref to the container element\n * @param config - CI360 configuration options\n * @returns Object containing viewer instance and ready state\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const containerRef = useRef<HTMLDivElement>(null);\n * const { viewer, isReady } = useCI360(containerRef, {\n * folder: 'https://example.com/images/',\n * filenameX: 'image-{index}.jpg',\n * amountX: 36,\n * });\n *\n * return <div ref={containerRef} />;\n * }\n * ```\n */\nexport function useCI360(\n containerRef: RefObject<HTMLDivElement | null>,\n config: UseCI360Options\n): UseCI360Return {\n const [isReady, setIsReady] = useState(false);\n const viewerRef = useRef<CI360ViewerInstance | null>(null);\n const ci360Ref = useRef<any>(null);\n const uniqueId = useId();\n\n // Initialize viewer\n useEffect(() => {\n // SSR guard\n if (typeof window === 'undefined') return;\n if (!containerRef.current) return;\n if (config.autoInit === false) return;\n\n let isMounted = true;\n const container = containerRef.current;\n\n const initViewer = async () => {\n try {\n // Dynamically import CI360 to avoid SSR issues\n if (!CI360Class) {\n const module = await import('../ci360');\n CI360Class = module.default;\n }\n\n if (!container || !isMounted) return;\n\n // Set a unique ID on the container if not present\n if (!container.id) {\n container.id = `ci360-${uniqueId.replace(/:/g, '')}`;\n }\n\n // Wrap user callbacks to update React state\n const wrappedConfig: CI360Config = {\n ...config,\n onReady: (data) => {\n if (isMounted) {\n setIsReady(true);\n config.onReady?.(data);\n }\n },\n };\n\n // Create CI360 instance and initialize viewer\n ci360Ref.current = new CI360Class();\n viewerRef.current = ci360Ref.current.init(container, wrappedConfig);\n } catch (error) {\n console.error('Failed to initialize CI360 viewer:', error);\n }\n };\n\n initViewer();\n\n // Cleanup on unmount or when dependencies change\n return () => {\n isMounted = false;\n if (viewerRef.current) {\n try {\n viewerRef.current.destroy();\n } catch (e) {\n // Ignore errors during cleanup - element may already be detached\n }\n viewerRef.current = null;\n }\n ci360Ref.current = null;\n setIsReady(false);\n };\n }, [\n config.folder,\n config.filenameX,\n config.filenameY,\n config.imageListX,\n config.imageListY,\n config.amountX,\n config.amountY,\n config.hotspots,\n config.theme,\n uniqueId,\n ]);\n\n // Stable getter to always return current viewer (avoids stale closures)\n const getViewer = useCallback(() => viewerRef.current, []);\n\n return {\n viewer: viewerRef.current,\n isReady,\n getViewer,\n };\n}\n\nexport default useCI360;\n","import {\n useRef,\n useImperativeHandle,\n forwardRef,\n useMemo,\n type ForwardRefRenderFunction,\n} from 'react';\nimport { useCI360 } from './useCI360';\nimport type {\n CI360ViewerProps,\n CI360ViewerRef,\n CI360Config,\n} from './types';\n\n/**\n * CI360Viewer React Component\n *\n * A declarative React wrapper for the CI360 360-degree image viewer.\n *\n * @example\n * ```tsx\n * import { CI360Viewer } from 'js-cloudimage-360-view/react';\n * import 'js-cloudimage-360-view/css';\n *\n * function ProductView() {\n * return (\n * <CI360Viewer\n * folder=\"https://example.com/images/\"\n * filenameX=\"product-{index}.jpg\"\n * amountX={36}\n * autoplay\n * fullscreen\n * />\n * );\n * }\n * ```\n *\n * @example With ref for imperative control\n * ```tsx\n * import { useRef } from 'react';\n * import { CI360Viewer, CI360ViewerRef } from 'js-cloudimage-360-view/react';\n *\n * function ProductView() {\n * const viewerRef = useRef<CI360ViewerRef>(null);\n *\n * return (\n * <>\n * <CI360Viewer\n * ref={viewerRef}\n * folder=\"https://example.com/images/\"\n * filenameX=\"{index}.jpg\"\n * amountX={36}\n * onSpin={(e) => console.log(`Frame: ${e.activeImageX}`)}\n * />\n * <button onClick={() => viewerRef.current?.play()}>Play</button>\n * <button onClick={() => viewerRef.current?.stop()}>Stop</button>\n * </>\n * );\n * }\n * ```\n */\nconst CI360ViewerComponent: ForwardRefRenderFunction<\n CI360ViewerRef,\n CI360ViewerProps\n> = (props, ref) => {\n const {\n // Container props\n id,\n className,\n style,\n\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n\n ...restProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Memoize config to prevent unnecessary re-initializations\n const config = useMemo<CI360Config>(\n () => ({\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n }),\n [\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n ]\n );\n\n const { getViewer } = useCI360(containerRef, config);\n\n // Expose imperative methods via ref\n // Use getViewer() inside methods to always get the current viewer instance,\n // avoiding stale closure issues when the viewer initializes after first render\n useImperativeHandle(\n ref,\n () => ({\n moveLeft: (steps = 1) => getViewer()?.moveLeft(false, steps),\n moveRight: (steps = 1) => getViewer()?.moveRight(false, steps),\n moveTop: (steps = 1) => getViewer()?.moveTop(false, steps),\n moveBottom: (steps = 1) => getViewer()?.moveBottom(false, steps),\n play: () => getViewer()?.play(),\n stop: () => getViewer()?.stopAutoplay(),\n zoomIn: () => getViewer()?.toggleZoom(),\n zoomOut: () => getViewer()?.removeZoom(),\n goToFrame: (frame: number, hotspotId?: string) =>\n getViewer()?.animateToFrame(frame, hotspotId),\n getViewer: () => getViewer(),\n }),\n [getViewer]\n );\n\n return (\n <div\n ref={containerRef}\n id={id}\n className={className}\n style={style}\n {...restProps}\n />\n );\n};\n\nexport const CI360Viewer = forwardRef(CI360ViewerComponent);\nCI360Viewer.displayName = 'CI360Viewer';\n\nexport default CI360Viewer;\n"],"names":["CI360Class","useCI360","containerRef","config","isReady","setIsReady","useState","viewerRef","useRef","ci360Ref","uniqueId","useId","useEffect","isMounted","container","wrappedConfig","data","_a","error","getViewer","useCallback","CI360ViewerComponent","props","ref","id","className","style","folder","apiVersion","filenameX","filenameY","imageListX","imageListY","indexZeroBase","amountX","amountY","draggable","swipeable","keys","keysReverse","autoplay","autoplayBehavior","playOnce","speed","autoplayReverse","dragSpeed","dragReverse","stopAtEdges","inertia","fullscreen","magnifier","pointerZoom","pinchZoom","bottomCircle","bottomCircleOffset","initialIconShown","hide360Logo","logoSrc","imageInfo","hints","theme","ciToken","ciFilters","ciTransformation","lazyload","hotspots","hotspotTrigger","hotspotTimelineOnClick","aspectRatio","onReady","onLoad","onSpin","onAutoplayStart","onAutoplayStop","onFullscreenOpen","onFullscreenClose","onZoomIn","onZoomOut","onDragStart","onDragEnd","onError","restProps","useMemo","useImperativeHandle","steps","frame","hotspotId","jsx","CI360Viewer","forwardRef"],"mappings":"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"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -28,6 +28,20 @@ export interface HotspotPosition {
|
|
|
28
28
|
y: number;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Structured popover data for the built-in product-card template.
|
|
33
|
+
* Priority: content (raw HTML) > data (built-in template) > nothing.
|
|
34
|
+
*/
|
|
35
|
+
export interface PopoverData {
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
price?: string;
|
|
39
|
+
originalPrice?: string;
|
|
40
|
+
image?: string;
|
|
41
|
+
url?: string;
|
|
42
|
+
ctaText?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
/**
|
|
32
46
|
* Hotspot configuration
|
|
33
47
|
*/
|
|
@@ -38,6 +52,7 @@ export interface Hotspot {
|
|
|
38
52
|
containerSize?: [number, number];
|
|
39
53
|
positions: Record<number, HotspotPosition>;
|
|
40
54
|
content?: string;
|
|
55
|
+
data?: PopoverData;
|
|
41
56
|
className?: string;
|
|
42
57
|
}
|
|
43
58
|
|
package/dist/react/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useState as
|
|
1
|
+
import { jsx as fe } from "react/jsx-runtime";
|
|
2
|
+
import { useState as ye, useRef as I, useId as we, useEffect as ve, useCallback as Ie, forwardRef as Ce, useMemo as he, useImperativeHandle as Re } from "react";
|
|
3
3
|
let v = null;
|
|
4
|
-
function
|
|
5
|
-
const [y, d] =
|
|
6
|
-
|
|
4
|
+
function ge(p, t) {
|
|
5
|
+
const [y, d] = ye(!1), n = I(null), s = I(null), u = we();
|
|
6
|
+
ve(() => {
|
|
7
7
|
if (typeof window > "u" || !p.current || t.autoInit === !1) return;
|
|
8
8
|
let l = !0;
|
|
9
9
|
const a = p.current;
|
|
10
10
|
return (async () => {
|
|
11
11
|
try {
|
|
12
|
-
if (v || (v = (await import("./ci360
|
|
12
|
+
if (v || (v = (await import("./ci360--3KbDLtq.mjs")).default), !a || !l) return;
|
|
13
13
|
a.id || (a.id = `ci360-${u.replace(/:/g, "")}`);
|
|
14
14
|
const i = {
|
|
15
15
|
...t,
|
|
@@ -40,17 +40,18 @@ function he(p, t) {
|
|
|
40
40
|
t.imageListY,
|
|
41
41
|
t.amountX,
|
|
42
42
|
t.amountY,
|
|
43
|
+
t.hotspots,
|
|
43
44
|
t.theme,
|
|
44
45
|
u
|
|
45
46
|
]);
|
|
46
|
-
const f =
|
|
47
|
+
const f = Ie(() => n.current, []);
|
|
47
48
|
return {
|
|
48
49
|
viewer: n.current,
|
|
49
50
|
isReady: y,
|
|
50
51
|
getViewer: f
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
|
-
const
|
|
54
|
+
const Ve = (p, t) => {
|
|
54
55
|
const {
|
|
55
56
|
// Container props
|
|
56
57
|
id: y,
|
|
@@ -68,8 +69,8 @@ const ge = (p, t) => {
|
|
|
68
69
|
amountY: c,
|
|
69
70
|
// Behavior
|
|
70
71
|
draggable: C,
|
|
71
|
-
swipeable:
|
|
72
|
-
keys:
|
|
72
|
+
swipeable: h,
|
|
73
|
+
keys: R,
|
|
73
74
|
keysReverse: g,
|
|
74
75
|
autoplay: V,
|
|
75
76
|
autoplayBehavior: L,
|
|
@@ -101,24 +102,25 @@ const ge = (p, t) => {
|
|
|
101
102
|
lazyload: G,
|
|
102
103
|
// Hotspots
|
|
103
104
|
hotspots: J,
|
|
104
|
-
|
|
105
|
+
hotspotTrigger: K,
|
|
106
|
+
hotspotTimelineOnClick: Q,
|
|
105
107
|
// Container
|
|
106
|
-
aspectRatio:
|
|
108
|
+
aspectRatio: U,
|
|
107
109
|
// Event callbacks
|
|
108
|
-
onReady:
|
|
109
|
-
onLoad:
|
|
110
|
-
onSpin:
|
|
111
|
-
onAutoplayStart:
|
|
112
|
-
onAutoplayStop:
|
|
113
|
-
onFullscreenOpen:
|
|
114
|
-
onFullscreenClose:
|
|
115
|
-
onZoomIn:
|
|
116
|
-
onZoomOut:
|
|
117
|
-
onDragStart:
|
|
118
|
-
onDragEnd:
|
|
119
|
-
onError:
|
|
120
|
-
...
|
|
121
|
-
} = p,
|
|
110
|
+
onReady: W,
|
|
111
|
+
onLoad: _,
|
|
112
|
+
onSpin: ee,
|
|
113
|
+
onAutoplayStart: te,
|
|
114
|
+
onAutoplayStop: oe,
|
|
115
|
+
onFullscreenOpen: re,
|
|
116
|
+
onFullscreenClose: ne,
|
|
117
|
+
onZoomIn: ae,
|
|
118
|
+
onZoomOut: ie,
|
|
119
|
+
onDragStart: se,
|
|
120
|
+
onDragEnd: le,
|
|
121
|
+
onError: ue,
|
|
122
|
+
...pe
|
|
123
|
+
} = p, me = I(null), de = he(
|
|
122
124
|
() => ({
|
|
123
125
|
// Image source
|
|
124
126
|
folder: s,
|
|
@@ -132,8 +134,8 @@ const ge = (p, t) => {
|
|
|
132
134
|
amountY: c,
|
|
133
135
|
// Behavior
|
|
134
136
|
draggable: C,
|
|
135
|
-
swipeable:
|
|
136
|
-
keys:
|
|
137
|
+
swipeable: h,
|
|
138
|
+
keys: R,
|
|
137
139
|
keysReverse: g,
|
|
138
140
|
autoplay: V,
|
|
139
141
|
autoplayBehavior: L,
|
|
@@ -165,22 +167,23 @@ const ge = (p, t) => {
|
|
|
165
167
|
lazyload: G,
|
|
166
168
|
// Hotspots
|
|
167
169
|
hotspots: J,
|
|
168
|
-
|
|
170
|
+
hotspotTrigger: K,
|
|
171
|
+
hotspotTimelineOnClick: Q,
|
|
169
172
|
// Container
|
|
170
|
-
aspectRatio:
|
|
173
|
+
aspectRatio: U,
|
|
171
174
|
// Event callbacks
|
|
172
|
-
onReady:
|
|
173
|
-
onLoad:
|
|
174
|
-
onSpin:
|
|
175
|
-
onAutoplayStart:
|
|
176
|
-
onAutoplayStop:
|
|
177
|
-
onFullscreenOpen:
|
|
178
|
-
onFullscreenClose:
|
|
179
|
-
onZoomIn:
|
|
180
|
-
onZoomOut:
|
|
181
|
-
onDragStart:
|
|
182
|
-
onDragEnd:
|
|
183
|
-
onError:
|
|
175
|
+
onReady: W,
|
|
176
|
+
onLoad: _,
|
|
177
|
+
onSpin: ee,
|
|
178
|
+
onAutoplayStart: te,
|
|
179
|
+
onAutoplayStop: oe,
|
|
180
|
+
onFullscreenOpen: re,
|
|
181
|
+
onFullscreenClose: ne,
|
|
182
|
+
onZoomIn: ae,
|
|
183
|
+
onZoomOut: ie,
|
|
184
|
+
onDragStart: se,
|
|
185
|
+
onDragEnd: le,
|
|
186
|
+
onError: ue
|
|
184
187
|
}),
|
|
185
188
|
[
|
|
186
189
|
// Image source
|
|
@@ -195,8 +198,8 @@ const ge = (p, t) => {
|
|
|
195
198
|
c,
|
|
196
199
|
// Behavior
|
|
197
200
|
C,
|
|
198
|
-
R,
|
|
199
201
|
h,
|
|
202
|
+
R,
|
|
200
203
|
g,
|
|
201
204
|
V,
|
|
202
205
|
L,
|
|
@@ -229,10 +232,10 @@ const ge = (p, t) => {
|
|
|
229
232
|
// Hotspots
|
|
230
233
|
J,
|
|
231
234
|
K,
|
|
232
|
-
// Container
|
|
233
235
|
Q,
|
|
234
|
-
//
|
|
236
|
+
// Container
|
|
235
237
|
U,
|
|
238
|
+
// Event callbacks
|
|
236
239
|
W,
|
|
237
240
|
_,
|
|
238
241
|
ee,
|
|
@@ -243,9 +246,10 @@ const ge = (p, t) => {
|
|
|
243
246
|
ae,
|
|
244
247
|
ie,
|
|
245
248
|
se,
|
|
246
|
-
le
|
|
249
|
+
le,
|
|
250
|
+
ue
|
|
247
251
|
]
|
|
248
|
-
), { getViewer: r } =
|
|
252
|
+
), { getViewer: r } = ge(me, de);
|
|
249
253
|
return Re(
|
|
250
254
|
t,
|
|
251
255
|
() => ({
|
|
@@ -282,28 +286,28 @@ const ge = (p, t) => {
|
|
|
282
286
|
return (e = r()) == null ? void 0 : e.removeZoom();
|
|
283
287
|
},
|
|
284
288
|
goToFrame: (e, o) => {
|
|
285
|
-
var
|
|
286
|
-
return (
|
|
289
|
+
var ce;
|
|
290
|
+
return (ce = r()) == null ? void 0 : ce.animateToFrame(e, o);
|
|
287
291
|
},
|
|
288
292
|
getViewer: () => r()
|
|
289
293
|
}),
|
|
290
294
|
[r]
|
|
291
|
-
), /* @__PURE__ */
|
|
295
|
+
), /* @__PURE__ */ fe(
|
|
292
296
|
"div",
|
|
293
297
|
{
|
|
294
|
-
ref:
|
|
298
|
+
ref: me,
|
|
295
299
|
id: y,
|
|
296
300
|
className: d,
|
|
297
301
|
style: n,
|
|
298
|
-
...
|
|
302
|
+
...pe
|
|
299
303
|
}
|
|
300
304
|
);
|
|
301
|
-
},
|
|
302
|
-
|
|
305
|
+
}, Le = Ce(Ve);
|
|
306
|
+
Le.displayName = "CI360Viewer";
|
|
303
307
|
export {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
+
Le as CI360Viewer,
|
|
309
|
+
Le as CI360ViewerDefault,
|
|
310
|
+
ge as useCI360,
|
|
311
|
+
ge as useCI360Default
|
|
308
312
|
};
|
|
309
313
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/react/useCI360.ts","../../src/react/CI360Viewer.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useId, useCallback, type RefObject } from 'react';\nimport type {\n CI360Config,\n CI360ViewerInstance,\n UseCI360Return,\n UseCI360Options,\n} from './types';\n\n// Import CI360 class dynamically to avoid SSR issues\nlet CI360Class: any = null;\n\n/**\n * Custom hook for integrating CI360 viewer with React\n *\n * @param containerRef - React ref to the container element\n * @param config - CI360 configuration options\n * @returns Object containing viewer instance and ready state\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const containerRef = useRef<HTMLDivElement>(null);\n * const { viewer, isReady } = useCI360(containerRef, {\n * folder: 'https://example.com/images/',\n * filenameX: 'image-{index}.jpg',\n * amountX: 36,\n * });\n *\n * return <div ref={containerRef} />;\n * }\n * ```\n */\nexport function useCI360(\n containerRef: RefObject<HTMLDivElement | null>,\n config: UseCI360Options\n): UseCI360Return {\n const [isReady, setIsReady] = useState(false);\n const viewerRef = useRef<CI360ViewerInstance | null>(null);\n const ci360Ref = useRef<any>(null);\n const uniqueId = useId();\n\n // Initialize viewer\n useEffect(() => {\n // SSR guard\n if (typeof window === 'undefined') return;\n if (!containerRef.current) return;\n if (config.autoInit === false) return;\n\n let isMounted = true;\n const container = containerRef.current;\n\n const initViewer = async () => {\n try {\n // Dynamically import CI360 to avoid SSR issues\n if (!CI360Class) {\n const module = await import('../ci360');\n CI360Class = module.default;\n }\n\n if (!container || !isMounted) return;\n\n // Set a unique ID on the container if not present\n if (!container.id) {\n container.id = `ci360-${uniqueId.replace(/:/g, '')}`;\n }\n\n // Wrap user callbacks to update React state\n const wrappedConfig: CI360Config = {\n ...config,\n onReady: (data) => {\n if (isMounted) {\n setIsReady(true);\n config.onReady?.(data);\n }\n },\n };\n\n // Create CI360 instance and initialize viewer\n ci360Ref.current = new CI360Class();\n viewerRef.current = ci360Ref.current.init(container, wrappedConfig);\n } catch (error) {\n console.error('Failed to initialize CI360 viewer:', error);\n }\n };\n\n initViewer();\n\n // Cleanup on unmount or when dependencies change\n return () => {\n isMounted = false;\n if (viewerRef.current) {\n try {\n viewerRef.current.destroy();\n } catch (e) {\n // Ignore errors during cleanup - element may already be detached\n }\n viewerRef.current = null;\n }\n ci360Ref.current = null;\n setIsReady(false);\n };\n }, [\n config.folder,\n config.filenameX,\n config.filenameY,\n config.imageListX,\n config.imageListY,\n config.amountX,\n config.amountY,\n config.theme,\n uniqueId,\n ]);\n\n // Stable getter to always return current viewer (avoids stale closures)\n const getViewer = useCallback(() => viewerRef.current, []);\n\n return {\n viewer: viewerRef.current,\n isReady,\n getViewer,\n };\n}\n\nexport default useCI360;\n","import {\n useRef,\n useImperativeHandle,\n forwardRef,\n useMemo,\n type ForwardRefRenderFunction,\n} from 'react';\nimport { useCI360 } from './useCI360';\nimport type {\n CI360ViewerProps,\n CI360ViewerRef,\n CI360Config,\n} from './types';\n\n/**\n * CI360Viewer React Component\n *\n * A declarative React wrapper for the CI360 360-degree image viewer.\n *\n * @example\n * ```tsx\n * import { CI360Viewer } from 'js-cloudimage-360-view/react';\n * import 'js-cloudimage-360-view/css';\n *\n * function ProductView() {\n * return (\n * <CI360Viewer\n * folder=\"https://example.com/images/\"\n * filenameX=\"product-{index}.jpg\"\n * amountX={36}\n * autoplay\n * fullscreen\n * />\n * );\n * }\n * ```\n *\n * @example With ref for imperative control\n * ```tsx\n * import { useRef } from 'react';\n * import { CI360Viewer, CI360ViewerRef } from 'js-cloudimage-360-view/react';\n *\n * function ProductView() {\n * const viewerRef = useRef<CI360ViewerRef>(null);\n *\n * return (\n * <>\n * <CI360Viewer\n * ref={viewerRef}\n * folder=\"https://example.com/images/\"\n * filenameX=\"{index}.jpg\"\n * amountX={36}\n * onSpin={(e) => console.log(`Frame: ${e.activeImageX}`)}\n * />\n * <button onClick={() => viewerRef.current?.play()}>Play</button>\n * <button onClick={() => viewerRef.current?.stop()}>Stop</button>\n * </>\n * );\n * }\n * ```\n */\nconst CI360ViewerComponent: ForwardRefRenderFunction<\n CI360ViewerRef,\n CI360ViewerProps\n> = (props, ref) => {\n const {\n // Container props\n id,\n className,\n style,\n\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n\n ...restProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Memoize config to prevent unnecessary re-initializations\n const config = useMemo<CI360Config>(\n () => ({\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n }),\n [\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n ]\n );\n\n const { getViewer } = useCI360(containerRef, config);\n\n // Expose imperative methods via ref\n // Use getViewer() inside methods to always get the current viewer instance,\n // avoiding stale closure issues when the viewer initializes after first render\n useImperativeHandle(\n ref,\n () => ({\n moveLeft: (steps = 1) => getViewer()?.moveLeft(false, steps),\n moveRight: (steps = 1) => getViewer()?.moveRight(false, steps),\n moveTop: (steps = 1) => getViewer()?.moveTop(false, steps),\n moveBottom: (steps = 1) => getViewer()?.moveBottom(false, steps),\n play: () => getViewer()?.play(),\n stop: () => getViewer()?.stopAutoplay(),\n zoomIn: () => getViewer()?.toggleZoom(),\n zoomOut: () => getViewer()?.removeZoom(),\n goToFrame: (frame: number, hotspotId?: string) =>\n getViewer()?.animateToFrame(frame, hotspotId),\n getViewer: () => getViewer(),\n }),\n [getViewer]\n );\n\n return (\n <div\n ref={containerRef}\n id={id}\n className={className}\n style={style}\n {...restProps}\n />\n );\n};\n\nexport const CI360Viewer = forwardRef(CI360ViewerComponent);\nCI360Viewer.displayName = 'CI360Viewer';\n\nexport default CI360Viewer;\n"],"names":["CI360Class","useCI360","containerRef","config","isReady","setIsReady","useState","viewerRef","useRef","ci360Ref","uniqueId","useId","useEffect","isMounted","container","wrappedConfig","data","_a","error","getViewer","useCallback","CI360ViewerComponent","props","ref","id","className","style","folder","apiVersion","filenameX","filenameY","imageListX","imageListY","indexZeroBase","amountX","amountY","draggable","swipeable","keys","keysReverse","autoplay","autoplayBehavior","playOnce","speed","autoplayReverse","dragSpeed","dragReverse","stopAtEdges","inertia","fullscreen","magnifier","pointerZoom","pinchZoom","bottomCircle","bottomCircleOffset","initialIconShown","hide360Logo","logoSrc","imageInfo","hints","theme","ciToken","ciFilters","ciTransformation","lazyload","hotspots","hotspotTimelineOnClick","aspectRatio","onReady","onLoad","onSpin","onAutoplayStart","onAutoplayStop","onFullscreenOpen","onFullscreenClose","onZoomIn","onZoomOut","onDragStart","onDragEnd","onError","restProps","useMemo","useImperativeHandle","steps","frame","hotspotId","jsx","CI360Viewer","forwardRef"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/react/useCI360.ts","../../src/react/CI360Viewer.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useId, useCallback, type RefObject } from 'react';\nimport type {\n CI360Config,\n CI360ViewerInstance,\n UseCI360Return,\n UseCI360Options,\n} from './types';\n\n// Import CI360 class dynamically to avoid SSR issues\nlet CI360Class: any = null;\n\n/**\n * Custom hook for integrating CI360 viewer with React\n *\n * @param containerRef - React ref to the container element\n * @param config - CI360 configuration options\n * @returns Object containing viewer instance and ready state\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const containerRef = useRef<HTMLDivElement>(null);\n * const { viewer, isReady } = useCI360(containerRef, {\n * folder: 'https://example.com/images/',\n * filenameX: 'image-{index}.jpg',\n * amountX: 36,\n * });\n *\n * return <div ref={containerRef} />;\n * }\n * ```\n */\nexport function useCI360(\n containerRef: RefObject<HTMLDivElement | null>,\n config: UseCI360Options\n): UseCI360Return {\n const [isReady, setIsReady] = useState(false);\n const viewerRef = useRef<CI360ViewerInstance | null>(null);\n const ci360Ref = useRef<any>(null);\n const uniqueId = useId();\n\n // Initialize viewer\n useEffect(() => {\n // SSR guard\n if (typeof window === 'undefined') return;\n if (!containerRef.current) return;\n if (config.autoInit === false) return;\n\n let isMounted = true;\n const container = containerRef.current;\n\n const initViewer = async () => {\n try {\n // Dynamically import CI360 to avoid SSR issues\n if (!CI360Class) {\n const module = await import('../ci360');\n CI360Class = module.default;\n }\n\n if (!container || !isMounted) return;\n\n // Set a unique ID on the container if not present\n if (!container.id) {\n container.id = `ci360-${uniqueId.replace(/:/g, '')}`;\n }\n\n // Wrap user callbacks to update React state\n const wrappedConfig: CI360Config = {\n ...config,\n onReady: (data) => {\n if (isMounted) {\n setIsReady(true);\n config.onReady?.(data);\n }\n },\n };\n\n // Create CI360 instance and initialize viewer\n ci360Ref.current = new CI360Class();\n viewerRef.current = ci360Ref.current.init(container, wrappedConfig);\n } catch (error) {\n console.error('Failed to initialize CI360 viewer:', error);\n }\n };\n\n initViewer();\n\n // Cleanup on unmount or when dependencies change\n return () => {\n isMounted = false;\n if (viewerRef.current) {\n try {\n viewerRef.current.destroy();\n } catch (e) {\n // Ignore errors during cleanup - element may already be detached\n }\n viewerRef.current = null;\n }\n ci360Ref.current = null;\n setIsReady(false);\n };\n }, [\n config.folder,\n config.filenameX,\n config.filenameY,\n config.imageListX,\n config.imageListY,\n config.amountX,\n config.amountY,\n config.hotspots,\n config.theme,\n uniqueId,\n ]);\n\n // Stable getter to always return current viewer (avoids stale closures)\n const getViewer = useCallback(() => viewerRef.current, []);\n\n return {\n viewer: viewerRef.current,\n isReady,\n getViewer,\n };\n}\n\nexport default useCI360;\n","import {\n useRef,\n useImperativeHandle,\n forwardRef,\n useMemo,\n type ForwardRefRenderFunction,\n} from 'react';\nimport { useCI360 } from './useCI360';\nimport type {\n CI360ViewerProps,\n CI360ViewerRef,\n CI360Config,\n} from './types';\n\n/**\n * CI360Viewer React Component\n *\n * A declarative React wrapper for the CI360 360-degree image viewer.\n *\n * @example\n * ```tsx\n * import { CI360Viewer } from 'js-cloudimage-360-view/react';\n * import 'js-cloudimage-360-view/css';\n *\n * function ProductView() {\n * return (\n * <CI360Viewer\n * folder=\"https://example.com/images/\"\n * filenameX=\"product-{index}.jpg\"\n * amountX={36}\n * autoplay\n * fullscreen\n * />\n * );\n * }\n * ```\n *\n * @example With ref for imperative control\n * ```tsx\n * import { useRef } from 'react';\n * import { CI360Viewer, CI360ViewerRef } from 'js-cloudimage-360-view/react';\n *\n * function ProductView() {\n * const viewerRef = useRef<CI360ViewerRef>(null);\n *\n * return (\n * <>\n * <CI360Viewer\n * ref={viewerRef}\n * folder=\"https://example.com/images/\"\n * filenameX=\"{index}.jpg\"\n * amountX={36}\n * onSpin={(e) => console.log(`Frame: ${e.activeImageX}`)}\n * />\n * <button onClick={() => viewerRef.current?.play()}>Play</button>\n * <button onClick={() => viewerRef.current?.stop()}>Stop</button>\n * </>\n * );\n * }\n * ```\n */\nconst CI360ViewerComponent: ForwardRefRenderFunction<\n CI360ViewerRef,\n CI360ViewerProps\n> = (props, ref) => {\n const {\n // Container props\n id,\n className,\n style,\n\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n\n ...restProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Memoize config to prevent unnecessary re-initializations\n const config = useMemo<CI360Config>(\n () => ({\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n }),\n [\n // Image source\n folder,\n apiVersion,\n filenameX,\n filenameY,\n imageListX,\n imageListY,\n indexZeroBase,\n amountX,\n amountY,\n\n // Behavior\n draggable,\n swipeable,\n keys,\n keysReverse,\n autoplay,\n autoplayBehavior,\n playOnce,\n speed,\n autoplayReverse,\n dragSpeed,\n dragReverse,\n stopAtEdges,\n inertia,\n\n // UI Features\n fullscreen,\n magnifier,\n pointerZoom,\n pinchZoom,\n bottomCircle,\n bottomCircleOffset,\n initialIconShown,\n hide360Logo,\n logoSrc,\n imageInfo,\n hints,\n theme,\n\n // Cloudimage CDN\n ciToken,\n ciFilters,\n ciTransformation,\n\n // Loading\n lazyload,\n\n // Hotspots\n hotspots,\n hotspotTrigger,\n hotspotTimelineOnClick,\n\n // Container\n aspectRatio,\n\n // Event callbacks\n onReady,\n onLoad,\n onSpin,\n onAutoplayStart,\n onAutoplayStop,\n onFullscreenOpen,\n onFullscreenClose,\n onZoomIn,\n onZoomOut,\n onDragStart,\n onDragEnd,\n onError,\n ]\n );\n\n const { getViewer } = useCI360(containerRef, config);\n\n // Expose imperative methods via ref\n // Use getViewer() inside methods to always get the current viewer instance,\n // avoiding stale closure issues when the viewer initializes after first render\n useImperativeHandle(\n ref,\n () => ({\n moveLeft: (steps = 1) => getViewer()?.moveLeft(false, steps),\n moveRight: (steps = 1) => getViewer()?.moveRight(false, steps),\n moveTop: (steps = 1) => getViewer()?.moveTop(false, steps),\n moveBottom: (steps = 1) => getViewer()?.moveBottom(false, steps),\n play: () => getViewer()?.play(),\n stop: () => getViewer()?.stopAutoplay(),\n zoomIn: () => getViewer()?.toggleZoom(),\n zoomOut: () => getViewer()?.removeZoom(),\n goToFrame: (frame: number, hotspotId?: string) =>\n getViewer()?.animateToFrame(frame, hotspotId),\n getViewer: () => getViewer(),\n }),\n [getViewer]\n );\n\n return (\n <div\n ref={containerRef}\n id={id}\n className={className}\n style={style}\n {...restProps}\n />\n );\n};\n\nexport const CI360Viewer = forwardRef(CI360ViewerComponent);\nCI360Viewer.displayName = 'CI360Viewer';\n\nexport default CI360Viewer;\n"],"names":["CI360Class","useCI360","containerRef","config","isReady","setIsReady","useState","viewerRef","useRef","ci360Ref","uniqueId","useId","useEffect","isMounted","container","wrappedConfig","data","_a","error","getViewer","useCallback","CI360ViewerComponent","props","ref","id","className","style","folder","apiVersion","filenameX","filenameY","imageListX","imageListY","indexZeroBase","amountX","amountY","draggable","swipeable","keys","keysReverse","autoplay","autoplayBehavior","playOnce","speed","autoplayReverse","dragSpeed","dragReverse","stopAtEdges","inertia","fullscreen","magnifier","pointerZoom","pinchZoom","bottomCircle","bottomCircleOffset","initialIconShown","hide360Logo","logoSrc","imageInfo","hints","theme","ciToken","ciFilters","ciTransformation","lazyload","hotspots","hotspotTrigger","hotspotTimelineOnClick","aspectRatio","onReady","onLoad","onSpin","onAutoplayStart","onAutoplayStop","onFullscreenOpen","onFullscreenClose","onZoomIn","onZoomOut","onDragStart","onDragEnd","onError","restProps","useMemo","useImperativeHandle","steps","frame","hotspotId","jsx","CI360Viewer","forwardRef"],"mappings":"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"}
|
package/dist/react/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--ci360-button-bg: rgba(255, 255, 255, .9);--ci360-button-bg-hover: rgba(255, 255, 255, 1);--ci360-button-size: 40px;--ci360-button-border-radius: 6px;--ci360-button-shadow: 0 2px 8px rgba(0, 0, 0, .15);--ci360-icon-color: #505050;--ci360-icon-color-hover: #333333;--ci360-icon-size: 20px;--ci360-initial-icon-bg: transparent;--ci360-initial-icon-color: #ffffff;--ci360-initial-icon-size: 100px;--ci360-initial-icon-shadow: none;--ci360-spinner-color: rgba(0, 0, 0, .2);--ci360-spinner-accent: #505050;--ci360-spinner-size: 30px;--ci360-fullscreen-bg: #ffffff;--ci360-magnifier-size: 250px;--ci360-magnifier-border: 2px solid rgba(0, 0, 0, .2);--ci360-magnifier-shadow: 0 8px 16px rgba(0, 0, 0, .3);--ci360-focus-color: #0066cc;--ci360-overlay-bg: rgba(255, 255, 255, 1);--ci360-hotspot-color: #00aaff;--ci360-hotspot-border: 2px solid #fff;--ci360-hotspot-size: 18px;--ci360-popper-bg: rgba(255, 255, 255, .95);--ci360-popper-color: #333;--ci360-popper-shadow: 0px 4px 16px rgba(0, 0, 0, .15);--ci360-popper-border-radius: 8px;--ci360-hints-bg: rgba(255, 255, 255, .9);--ci360-hints-color: #333333;--ci360-hints-font-size: 13px;--ci360-hints-border-radius: 20px;--ci360-hints-shadow: 0 2px 12px rgba(0, 0, 0, .1);--ci360-circle-color: #888888;--ci360-timeline-height: 6px;--ci360-timeline-track-bg: rgba(0, 0, 0, .12);--ci360-timeline-dot-size: 18px;--ci360-timeline-dot-color: var(--ci360-hotspot-color);--ci360-timeline-dot-border: 2px solid #fff;--ci360-timeline-indicator-size: 12px;--ci360-timeline-indicator-color: #333333;--ci360-timeline-tooltip-bg: rgba(255, 255, 255, .95);--ci360-timeline-tooltip-color: #333333}.ci360-theme-dark{--ci360-button-bg: rgba(40, 40, 45, .9);--ci360-button-bg-hover: rgba(55, 55, 60, .95);--ci360-button-shadow: 0 2px 8px rgba(0, 0, 0, .4);--ci360-icon-color: #e0e0e0;--ci360-icon-color-hover: #ffffff;--ci360-initial-icon-bg: transparent;--ci360-initial-icon-color: #ffffff;--ci360-initial-icon-shadow: none;--ci360-spinner-color: rgba(255, 255, 255, .2);--ci360-spinner-accent: #e0e0e0;--ci360-fullscreen-bg: #1a1a1f;--ci360-overlay-bg: rgba(26, 26, 31, 1);--ci360-magnifier-border: 2px solid rgba(255, 255, 255, .2);--ci360-magnifier-shadow: 0 8px 16px rgba(0, 0, 0, .5);--ci360-popper-bg: rgba(40, 40, 45, .95);--ci360-popper-color: #e0e0e0;--ci360-popper-shadow: 0px 4px 16px rgba(0, 0, 0, .4);--ci360-hints-bg: rgba(40, 40, 45, .9);--ci360-hints-color: #e0e0e0;--ci360-hints-shadow: 0 2px 12px rgba(0, 0, 0, .3);--ci360-circle-color: #b0b0b0;--ci360-timeline-track-bg: rgba(255, 255, 255, .15);--ci360-timeline-dot-border: 2px solid rgba(255, 255, 255, .9);--ci360-timeline-indicator-color: #e0e0e0;--ci360-timeline-tooltip-bg: rgba(40, 40, 45, .95);--ci360-timeline-tooltip-color: #e0e0e0;--ci360-loader-bg: rgba(40, 40, 45, .9);--ci360-loader-color: #e0e0e0;--ci360-loader-shadow: 0 4px 20px rgba(0, 0, 0, .4)}@keyframes rotation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.cloudimage-360{width:100%;position:relative}.cloudimage-360-inner-box{width:100%;height:100%;position:relative}.cloudimage-360-icons-container{position:absolute;display:flex;top:15px;right:10px;height:100%;flex-direction:column;align-items:center;z-index:100;gap:8px}.cloudimage-360-transition-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--ci360-overlay-bg);opacity:0;transition:all 1s ease-out;z-index:10}.cloudimage-360-button{width:var(--ci360-button-size);height:var(--ci360-button-size);cursor:pointer;transition:transform .15s ease-out,background-color .15s ease-out,box-shadow .15s ease-out;display:flex;align-items:center;justify-content:center;border-radius:var(--ci360-button-border-radius);border:none;background-color:var(--ci360-button-bg);box-shadow:var(--ci360-button-shadow);padding:6px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cloudimage-360-button:hover{transform:scale(1.05);background-color:var(--ci360-button-bg-hover)}.cloudimage-360-button:focus{outline:none}.cloudimage-360-button:focus-visible{outline:2px solid var(--ci360-focus-color);outline-offset:2px}.cloudimage-360-button svg{width:var(--ci360-icon-size);height:var(--ci360-icon-size);stroke:var(--ci360-icon-color);transition:stroke .15s ease-out}.cloudimage-360-button:hover svg{stroke:var(--ci360-icon-color-hover)}.cloudimage-initial-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--ci360-initial-icon-size);aspect-ratio:150 / 87;border-radius:var(--ci360-initial-icon-border-radius, 0);background-color:var(--ci360-initial-icon-bg);box-shadow:var(--ci360-initial-icon-shadow);transition:all .3s ease;color:var(--ci360-initial-icon-color);display:flex;align-items:center;justify-content:center;z-index:2;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cloudimage-initial-icon svg{width:100%;height:auto;color:var(--ci360-initial-icon-color);fill:var(--ci360-initial-icon-color);filter:drop-shadow(0 2px 4px rgba(0,0,0,.4))}.cloudimage-initial-icon:hover{transform:translate(-50%,-50%) scale(1.08)}.cloudimage-360-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--ci360-loader-size, 70px);height:var(--ci360-loader-size, 70px);border-radius:50%;background-color:var(--ci360-loader-bg, rgba(255, 255, 255, .9));box-shadow:var(--ci360-loader-shadow, 0 4px 20px rgba(0, 0, 0, .15));transition:all .3s ease;color:var(--ci360-loader-color, #505050);display:flex;align-items:center;justify-content:center;z-index:2;-webkit-user-select:none;-moz-user-select:none;user-select:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);font-family:system-ui,-apple-system,sans-serif;font-size:14px;font-weight:600}.cloudimage-loading-spinner{width:var(--ci360-spinner-size);height:var(--ci360-spinner-size);transform:translate(-50%,-50%);border:3px solid var(--ci360-spinner-color);position:absolute;top:15px;left:15px;border-bottom-color:var(--ci360-spinner-accent);border-radius:50%;display:inline-block;box-sizing:border-box;opacity:0;animation:rotation .7s linear infinite}.cloudimage-360-view-360-circle{position:absolute;left:0;bottom:0;width:100%;height:auto;margin:auto;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:.2s all;z-index:2;color:var(--ci360-circle-color)}.cloudimage-360-view-360-circle svg{display:block;width:100%;height:auto}.cloudimage-360-fullscreen-modal{position:fixed;top:0;bottom:0;left:0;right:0;width:100%;height:100%;z-index:999;background-color:var(--ci360-fullscreen-bg)}.cloudimage-360-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.cloudimage-360-hints-overlay{position:absolute;bottom:0;left:0;width:100%;display:flex;align-items:flex-end;justify-content:center;padding-bottom:16px;z-index:50;pointer-events:none;opacity:0;transition:opacity .3s ease}.cloudimage-360-hints-overlay.visible{opacity:1}.cloudimage-360-hints-overlay.hiding{opacity:0}.cloudimage-360-hints-container{display:flex;flex-direction:row;gap:20px;padding:10px 20px;background:var(--ci360-hints-bg);border-radius:var(--ci360-hints-border-radius);box-shadow:var(--ci360-hints-shadow);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cloudimage-360-hint-item{display:flex;align-items:center;gap:8px;color:var(--ci360-hints-color);font-size:var(--ci360-hints-font-size);font-family:system-ui,-apple-system,sans-serif;white-space:nowrap}.cloudimage-360-hint-item svg{width:16px;height:16px;flex-shrink:0;stroke:var(--ci360-hints-color)}.cloudimage-360-hint-item span{opacity:.9}@media (max-width: 480px){.cloudimage-360-hints-container{flex-direction:column;gap:8px;padding:12px 16px;border-radius:12px}.cloudimage-360-hint-item{font-size:12px}.cloudimage-360-hint-item svg{width:14px;height:14px}.cloudimage-360-initial-icon{width:calc(var(--ci360-initial-icon-size) * .8);height:calc(var(--ci360-initial-icon-size) * .8)}}.cloudimage-360-img-magnifier-glass{background-color:#fff;background-image:radial-gradient(circle at center,#fffc,#f0f0f0e6);background-repeat:no-repeat;position:absolute;border:var(--ci360-magnifier-border);border-radius:50%;line-height:200px;text-align:center;z-index:1000;width:var(--ci360-magnifier-size);height:var(--ci360-magnifier-size);top:-75px;right:-85px;box-shadow:var(--ci360-magnifier-shadow);transition:box-shadow .2s ease;overflow:hidden;pointer-events:none}.cloudimage-360-hotspot-timeline{width:100%;max-width:500px;margin:16px auto 8px;padding:12px 20px;opacity:0;transition:opacity .3s ease;pointer-events:none}.cloudimage-360-hotspot-timeline.visible{opacity:1;pointer-events:auto}.cloudimage-360-hotspot-timeline-track{position:relative;width:100%;height:var(--ci360-timeline-height);background:var(--ci360-timeline-track-bg);border-radius:calc(var(--ci360-timeline-height) / 2)}.cloudimage-360-hotspot-timeline-indicator{position:absolute;top:50%;left:0;width:var(--ci360-timeline-indicator-size);height:var(--ci360-timeline-indicator-size);background:var(--ci360-timeline-indicator-color);border-radius:50%;transform:translate(-50%,-50%);transition:left .1s ease-out;pointer-events:none;box-shadow:0 2px 4px #0003}.cloudimage-360-hotspot-timeline-dot{position:absolute;top:50%;width:var(--ci360-timeline-dot-size);height:var(--ci360-timeline-dot-size);background:var(--ci360-timeline-dot-color);border:var(--ci360-timeline-dot-border);border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:transform .15s ease,box-shadow .15s ease;box-shadow:0 2px 6px #00000040;padding:0;font:inherit;outline:none}.cloudimage-360-hotspot-timeline-dot:hover{transform:translate(-50%,-50%) scale(1.25);box-shadow:0 3px 10px #0000004d}.cloudimage-360-hotspot-timeline-dot:focus-visible{outline:2px solid var(--ci360-focus-color);outline-offset:2px}.cloudimage-360-hotspot-timeline-tooltip{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);background:var(--ci360-timeline-tooltip-bg);color:var(--ci360-timeline-tooltip-color);padding:6px 12px;border-radius:6px;font-size:13px;font-weight:500;white-space:nowrap;opacity:0;visibility:hidden;transition:opacity .2s ease,visibility .2s ease;pointer-events:none;box-shadow:0 2px 8px #00000026;z-index:10}.cloudimage-360-hotspot-timeline-tooltip:after{content:"";position:absolute;top:100%;left:50%;transform:translate(-50%);border:6px solid transparent;border-top-color:var(--ci360-timeline-tooltip-bg)}.cloudimage-360-hotspot-timeline-tooltip.visible{opacity:1;visibility:visible}@media (max-width: 480px){.cloudimage-360-hotspot-timeline{max-width:none;padding:10px 16px;margin:12px auto 6px}}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline{position:absolute;bottom:0;left:0;right:0;max-width:none;margin:0;padding:24px 40px 20px;background:linear-gradient(to top,rgba(0,0,0,.6) 0%,rgba(0,0,0,.3) 60%,transparent 100%);z-index:200}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-track{max-width:600px;margin:0 auto;background:#ffffff4d}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-indicator{background:#fff;box-shadow:0 2px 6px #0006}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-dot{border-color:#fff;box-shadow:0 2px 8px #0006}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-tooltip{bottom:calc(100% + 20px)}.cloudimage-360-fullscreen-modal .cloudimage-360-hints-overlay{padding-bottom:42px}.cloudimage-360-hotspot-container{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:20}.cloudimage-360-popper{opacity:1;transition:opacity .2s ease-in-out}.cloudimage-360-hotspot{display:inline-block;position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(-50%,-50%);background:var(--ci360-hotspot-color);border:var(--ci360-hotspot-border);border-radius:50%;height:var(--ci360-hotspot-size);width:var(--ci360-hotspot-size);box-shadow:0 0 #0af9,0 2px 6px #0003;opacity:0;animation:pulse 2s infinite;transition:transform .2s ease,box-shadow .2s ease;padding:0;cursor:pointer;font:inherit;outline:none}.cloudimage-360-hotspot:focus-visible{outline:2px solid var(--ci360-focus-color, #0066cc);outline-offset:2px;animation:none}.cloudimage-360-hotspot.visible{opacity:1}@keyframes pulse{0%{transform:scale(1);box-shadow:0 0 #0af9,0 0 0 10px #0af6,0 0 0 20px #0af3}50%{transform:scale(1.1);box-shadow:0 0 0 10px #0af0,0 0 0 20px #00aaff1a,0 0 0 30px #0af0}to{transform:scale(1);box-shadow:0 0 #0af0,0 0 0 10px #0af0,0 0 0 20px #0af0}}.cloudimage-360-hotspot:hover{transform:scale(1.2);box-shadow:0 0 0 5px #00aaff80,0 4px 12px #0000004d}.cloudimage-360-popper{background-color:var(--ci360-popper-bg);color:var(--ci360-popper-color);padding:10px 15px;border-radius:var(--ci360-popper-border-radius);box-shadow:var(--ci360-popper-shadow);font-size:14px;max-width:220px;z-index:9999;text-align:center;transition:opacity .2s ease,translate .2s ease;opacity:0;translate:0 -10px}.cloudimage-360-popper[data-show]{opacity:1;translate:0}
|
|
1
|
+
:root{--ci360-button-bg: rgba(255, 255, 255, .9);--ci360-button-bg-hover: rgba(255, 255, 255, 1);--ci360-button-size: 40px;--ci360-button-border-radius: 6px;--ci360-button-shadow: 0 2px 8px rgba(0, 0, 0, .15);--ci360-icon-color: #505050;--ci360-icon-color-hover: #333333;--ci360-icon-size: 20px;--ci360-initial-icon-bg: transparent;--ci360-initial-icon-color: #ffffff;--ci360-initial-icon-size: 100px;--ci360-initial-icon-shadow: none;--ci360-spinner-color: rgba(0, 0, 0, .2);--ci360-spinner-accent: #505050;--ci360-spinner-size: 30px;--ci360-fullscreen-bg: #ffffff;--ci360-magnifier-size: 250px;--ci360-magnifier-border: 2px solid rgba(0, 0, 0, .2);--ci360-magnifier-shadow: 0 8px 16px rgba(0, 0, 0, .3);--ci360-focus-color: #0066cc;--ci360-overlay-bg: rgba(255, 255, 255, 1);--ci360-hotspot-color: #00aaff;--ci360-hotspot-border: 2px solid #fff;--ci360-hotspot-size: 18px;--ci360-popper-bg: #ffffff;--ci360-popper-color: #1a1a1a;--ci360-popper-border: 1px solid rgba(0, 0, 0, .1);--ci360-popper-border-radius: 12px;--ci360-popper-shadow: 0 8px 32px rgba(0, 0, 0, .12);--ci360-popper-padding: 16px;--ci360-popper-max-width: 320px;--ci360-popper-font-size: 14px;--ci360-popper-line-height: 1.5;--ci360-popper-title-font-size: 16px;--ci360-popper-title-font-weight: 600;--ci360-popper-title-color: #1a1a1a;--ci360-popper-price-color: #2d8c3c;--ci360-popper-price-font-size: 18px;--ci360-popper-price-font-weight: 700;--ci360-popper-original-price-color: #999999;--ci360-popper-description-color: #666666;--ci360-popper-cta-bg: #0058a3;--ci360-popper-cta-color: #fff;--ci360-popper-cta-border-radius: 8px;--ci360-popper-cta-padding: 8px 16px;--ci360-hints-bg: rgba(255, 255, 255, .9);--ci360-hints-color: #333333;--ci360-hints-font-size: 13px;--ci360-hints-border-radius: 20px;--ci360-hints-shadow: 0 2px 12px rgba(0, 0, 0, .1);--ci360-circle-color: #888888;--ci360-timeline-height: 6px;--ci360-timeline-track-bg: rgba(255, 255, 255, .4);--ci360-timeline-dot-size: 18px;--ci360-timeline-dot-color: var(--ci360-hotspot-color);--ci360-timeline-dot-border: 2px solid #fff;--ci360-timeline-indicator-size: 12px;--ci360-timeline-indicator-color: #333333;--ci360-timeline-tooltip-bg: rgba(255, 255, 255, .95);--ci360-timeline-tooltip-color: #333333}.ci360-theme-dark{--ci360-button-bg: rgba(40, 40, 45, .9);--ci360-button-bg-hover: rgba(55, 55, 60, .95);--ci360-button-shadow: 0 2px 8px rgba(0, 0, 0, .4);--ci360-icon-color: #e0e0e0;--ci360-icon-color-hover: #ffffff;--ci360-initial-icon-bg: transparent;--ci360-initial-icon-color: #ffffff;--ci360-initial-icon-shadow: none;--ci360-spinner-color: rgba(255, 255, 255, .2);--ci360-spinner-accent: #e0e0e0;--ci360-fullscreen-bg: #1a1a1f;--ci360-overlay-bg: rgba(26, 26, 31, 1);--ci360-magnifier-border: 2px solid rgba(255, 255, 255, .2);--ci360-magnifier-shadow: 0 8px 16px rgba(0, 0, 0, .5);--ci360-popper-bg: #1a1a1a;--ci360-popper-color: #f0f0f0;--ci360-popper-border: 1px solid rgba(255, 255, 255, .1);--ci360-popper-shadow: 0 8px 32px rgba(0, 0, 0, .4);--ci360-popper-title-color: #f0f0f0;--ci360-popper-description-color: #aaaaaa;--ci360-popper-original-price-color: #777777;--ci360-hints-bg: rgba(40, 40, 45, .9);--ci360-hints-color: #e0e0e0;--ci360-hints-shadow: 0 2px 12px rgba(0, 0, 0, .3);--ci360-circle-color: #b0b0b0;--ci360-timeline-track-bg: rgba(255, 255, 255, .4);--ci360-timeline-dot-border: 2px solid rgba(255, 255, 255, .9);--ci360-timeline-indicator-color: #e0e0e0;--ci360-timeline-tooltip-bg: rgba(40, 40, 45, .95);--ci360-timeline-tooltip-color: #e0e0e0;--ci360-loader-bg: rgba(40, 40, 45, .9);--ci360-loader-color: #e0e0e0;--ci360-loader-shadow: 0 4px 20px rgba(0, 0, 0, .4)}@keyframes rotation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.cloudimage-360{width:100%;position:relative}.cloudimage-360-inner-box{width:100%;height:100%;position:relative}.cloudimage-360-icons-container{position:absolute;display:flex;top:15px;right:10px;height:100%;flex-direction:column;align-items:center;z-index:100;gap:8px}.cloudimage-360-transition-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--ci360-overlay-bg);opacity:0;transition:all 1s ease-out;z-index:10}.cloudimage-360-button{width:var(--ci360-button-size);height:var(--ci360-button-size);cursor:pointer;transition:transform .15s ease-out,background-color .15s ease-out,box-shadow .15s ease-out;display:flex;align-items:center;justify-content:center;border-radius:var(--ci360-button-border-radius);border:none;background-color:var(--ci360-button-bg);box-shadow:var(--ci360-button-shadow);padding:6px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cloudimage-360-button:hover{transform:scale(1.05);background-color:var(--ci360-button-bg-hover)}.cloudimage-360-button:focus{outline:none}.cloudimage-360-button:focus-visible{outline:2px solid var(--ci360-focus-color);outline-offset:2px}.cloudimage-360-button svg{width:var(--ci360-icon-size);height:var(--ci360-icon-size);stroke:var(--ci360-icon-color);transition:stroke .15s ease-out}.cloudimage-360-button:hover svg{stroke:var(--ci360-icon-color-hover)}.cloudimage-initial-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--ci360-initial-icon-size);aspect-ratio:150 / 87;border-radius:var(--ci360-initial-icon-border-radius, 0);background-color:var(--ci360-initial-icon-bg);box-shadow:var(--ci360-initial-icon-shadow);transition:all .3s ease;color:var(--ci360-initial-icon-color);display:flex;align-items:center;justify-content:center;z-index:2;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cloudimage-initial-icon svg{width:100%;height:auto;color:var(--ci360-initial-icon-color);fill:var(--ci360-initial-icon-color);filter:drop-shadow(0 2px 4px rgba(0,0,0,.4))}.cloudimage-initial-icon:hover{transform:translate(-50%,-50%) scale(1.08)}.cloudimage-360-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--ci360-loader-size, 70px);height:var(--ci360-loader-size, 70px);border-radius:50%;background-color:var(--ci360-loader-bg, rgba(255, 255, 255, .9));box-shadow:var(--ci360-loader-shadow, 0 4px 20px rgba(0, 0, 0, .15));transition:all .3s ease;color:var(--ci360-loader-color, #505050);display:flex;align-items:center;justify-content:center;z-index:2;-webkit-user-select:none;-moz-user-select:none;user-select:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);font-family:system-ui,-apple-system,sans-serif;font-size:14px;font-weight:600}.cloudimage-loading-spinner{width:var(--ci360-spinner-size);height:var(--ci360-spinner-size);transform:translate(-50%,-50%);border:3px solid var(--ci360-spinner-color);position:absolute;top:15px;left:15px;border-bottom-color:var(--ci360-spinner-accent);border-radius:50%;display:inline-block;box-sizing:border-box;opacity:0;animation:rotation .7s linear infinite}.cloudimage-360-view-360-circle{position:absolute;left:0;bottom:0;width:100%;height:auto;margin:auto;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:.2s all;z-index:2;color:var(--ci360-circle-color)}.cloudimage-360-view-360-circle svg{display:block;width:100%;height:auto}.cloudimage-360-fullscreen-modal{position:fixed;top:0;bottom:0;left:0;right:0;width:100%;height:100%;z-index:999;background-color:var(--ci360-fullscreen-bg)}.cloudimage-360-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.cloudimage-360-hints-overlay{position:absolute;bottom:0;left:0;width:100%;display:flex;align-items:flex-end;justify-content:center;padding-bottom:16px;z-index:50;pointer-events:none;opacity:0;transition:opacity .3s ease}.cloudimage-360-hints-overlay.visible{opacity:1}.cloudimage-360-hints-overlay.hiding{opacity:0}.cloudimage-360-hints-container{display:flex;flex-direction:row;gap:20px;padding:10px 20px;background:var(--ci360-hints-bg);border-radius:var(--ci360-hints-border-radius);box-shadow:var(--ci360-hints-shadow);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cloudimage-360-hint-item{display:flex;align-items:center;gap:8px;color:var(--ci360-hints-color);font-size:var(--ci360-hints-font-size);font-family:system-ui,-apple-system,sans-serif;white-space:nowrap}.cloudimage-360-hint-item svg{width:16px;height:16px;flex-shrink:0;stroke:var(--ci360-hints-color)}.cloudimage-360-hint-item span{opacity:.9}@media (max-width: 480px){.cloudimage-360-hints-container{flex-direction:column;gap:8px;padding:12px 16px;border-radius:12px}.cloudimage-360-hint-item{font-size:12px}.cloudimage-360-hint-item svg{width:14px;height:14px}.cloudimage-360-initial-icon{width:calc(var(--ci360-initial-icon-size) * .8);height:calc(var(--ci360-initial-icon-size) * .8)}}.cloudimage-360-inner-box.has-hotspot-timeline .cloudimage-360-hints-overlay{padding-bottom:56px}.cloudimage-360-img-magnifier-glass{background-color:#fff;background-image:radial-gradient(circle at center,#fffc,#f0f0f0e6);background-repeat:no-repeat;position:absolute;border:var(--ci360-magnifier-border);border-radius:50%;line-height:200px;text-align:center;z-index:1000;width:var(--ci360-magnifier-size);height:var(--ci360-magnifier-size);top:-75px;right:-85px;box-shadow:var(--ci360-magnifier-shadow);transition:box-shadow .2s ease;overflow:hidden;pointer-events:none}.cloudimage-360-hotspot-timeline{position:absolute;bottom:0;left:0;right:0;width:100%;padding:20px;opacity:0;transition:opacity .3s ease;pointer-events:none;z-index:30;background:linear-gradient(to top,rgba(0,0,0,.45) 0%,rgba(0,0,0,.2) 60%,transparent 100%)}.cloudimage-360-hotspot-timeline.visible{opacity:1;pointer-events:auto}.cloudimage-360-hotspot-timeline-track{position:relative;width:100%;max-width:500px;margin:0 auto;height:var(--ci360-timeline-height);background:var(--ci360-timeline-track-bg);border-radius:calc(var(--ci360-timeline-height) / 2)}.cloudimage-360-hotspot-timeline-indicator{position:absolute;top:50%;left:0;width:var(--ci360-timeline-indicator-size);height:var(--ci360-timeline-indicator-size);background:var(--ci360-timeline-indicator-color);border-radius:50%;transform:translate(-50%,-50%);transition:left .1s ease-out;pointer-events:none;box-shadow:0 2px 4px #0003}.cloudimage-360-hotspot-timeline-dot{position:absolute;top:50%;width:var(--ci360-timeline-dot-size);height:var(--ci360-timeline-dot-size);background:var(--ci360-timeline-dot-color);border:var(--ci360-timeline-dot-border);border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:transform .15s ease,box-shadow .15s ease;box-shadow:0 2px 6px #00000040;padding:0;font:inherit;outline:none}.cloudimage-360-hotspot-timeline-dot:hover{transform:translate(-50%,-50%) scale(1.25);box-shadow:0 3px 10px #0000004d}.cloudimage-360-hotspot-timeline-dot:focus-visible{outline:2px solid var(--ci360-focus-color);outline-offset:2px}.cloudimage-360-hotspot-timeline-tooltip{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);background:var(--ci360-timeline-tooltip-bg);color:var(--ci360-timeline-tooltip-color);padding:6px 12px;border-radius:6px;font-size:13px;font-weight:500;white-space:nowrap;opacity:0;visibility:hidden;transition:opacity .2s ease,visibility .2s ease;pointer-events:none;box-shadow:0 2px 8px #00000026;z-index:10}.cloudimage-360-hotspot-timeline-tooltip:after{content:"";position:absolute;top:100%;left:50%;transform:translate(-50%);border:6px solid transparent;border-top-color:var(--ci360-timeline-tooltip-bg)}.cloudimage-360-hotspot-timeline-tooltip.visible{opacity:1;visibility:visible}@media (max-width: 480px){.cloudimage-360-hotspot-timeline{padding:14px 16px}}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline{padding:24px 40px 20px;background:linear-gradient(to top,rgba(0,0,0,.6) 0%,rgba(0,0,0,.3) 60%,transparent 100%)}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-track{max-width:600px;background:#ffffff4d}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-indicator{background:#fff;box-shadow:0 2px 6px #0006}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-dot{border-color:#fff;box-shadow:0 2px 8px #0006}.cloudimage-360-fullscreen-modal .cloudimage-360-hotspot-timeline-tooltip{bottom:calc(100% + 20px)}.cloudimage-360-fullscreen-modal .cloudimage-360-inner-box.has-hotspot-timeline .cloudimage-360-hints-overlay{padding-bottom:64px}.cloudimage-360-hotspot-container{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:20}.cloudimage-360-popper{opacity:1;transition:opacity .2s ease-in-out}.cloudimage-360-hotspot{display:inline-block;position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(-50%,-50%);background:var(--ci360-hotspot-color);border:var(--ci360-hotspot-border);border-radius:50%;height:var(--ci360-hotspot-size);width:var(--ci360-hotspot-size);box-shadow:0 0 #0af9,0 2px 6px #0003;opacity:0;animation:pulse 2s infinite;transition:transform .2s ease,box-shadow .2s ease;padding:0;cursor:pointer;font:inherit;outline:none}.cloudimage-360-hotspot:focus-visible{outline:2px solid var(--ci360-focus-color, #0066cc);outline-offset:2px;animation:none}.cloudimage-360-hotspot.visible{opacity:1}@keyframes pulse{0%{transform:scale(1);box-shadow:0 0 #0af9,0 0 0 10px #0af6,0 0 0 20px #0af3}50%{transform:scale(1.1);box-shadow:0 0 0 10px #0af0,0 0 0 20px #00aaff1a,0 0 0 30px #0af0}to{transform:scale(1);box-shadow:0 0 #0af0,0 0 0 10px #0af0,0 0 0 20px #0af0}}.cloudimage-360-hotspot:hover{transform:scale(1.2);box-shadow:0 0 0 5px #00aaff80,0 4px 12px #0000004d}.cloudimage-360-popper{background:var(--ci360-popper-bg);color:var(--ci360-popper-color);border:var(--ci360-popper-border);padding:var(--ci360-popper-padding);border-radius:var(--ci360-popper-border-radius);box-shadow:var(--ci360-popper-shadow);font-family:system-ui,-apple-system,sans-serif;font-size:var(--ci360-popper-font-size);line-height:var(--ci360-popper-line-height);max-width:var(--ci360-popper-max-width);z-index:9999;text-align:left;transition:opacity .2s ease;opacity:0}.cloudimage-360-popper[data-show]{opacity:1}.ci360-popper-image-wrapper{aspect-ratio:16 / 9;overflow:hidden;border-radius:calc(var(--ci360-popper-border-radius) - 4px) calc(var(--ci360-popper-border-radius) - 4px) 0 0;margin:calc(var(--ci360-popper-padding) * -1);margin-bottom:12px;width:calc(100% + var(--ci360-popper-padding) * 2)}.ci360-popper-image{display:block;width:100%;height:100%;-o-object-fit:cover;object-fit:cover}.ci360-popper-body{line-height:1.5;text-align:left}.ci360-popper-title{margin:0 0 4px;font-size:var(--ci360-popper-title-font-size);font-weight:var(--ci360-popper-title-font-weight);color:var(--ci360-popper-title-color);line-height:1.3}.ci360-popper-price-row{display:inline-flex;align-items:baseline;gap:6px;margin-bottom:8px;flex-wrap:wrap}.ci360-popper-price{font-size:var(--ci360-popper-price-font-size);font-weight:var(--ci360-popper-price-font-weight);color:var(--ci360-popper-price-color)}.ci360-popper-price-row .ci360-popper-price{margin-bottom:0}.ci360-popper-original-price{font-size:calc(var(--ci360-popper-price-font-size) - 2px);font-weight:500;color:var(--ci360-popper-original-price-color);text-decoration:line-through}.ci360-popper-description{margin:0 0 12px;color:var(--ci360-popper-description-color)}.ci360-popper-cta{display:inline-block;padding:var(--ci360-popper-cta-padding);background:var(--ci360-popper-cta-bg);color:var(--ci360-popper-cta-color);border-radius:var(--ci360-popper-cta-border-radius);text-decoration:none;font-weight:600;font-size:14px;transition:opacity .2s ease}.ci360-popper-cta:hover{opacity:.9}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-cloudimage-360-view",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"main": "dist/js-cloudimage-360-view.min.js",
|
|
5
5
|
"types": "src/types/ci360.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -79,33 +79,33 @@
|
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@babel/cli": "^7.16.7",
|
|
82
|
-
"@types/react": "^18.2.0",
|
|
83
|
-
"@types/react-dom": "^18.2.0",
|
|
84
|
-
"@vitejs/plugin-react": "^4.2.0",
|
|
85
|
-
"react": "^18.2.0",
|
|
86
|
-
"react-dom": "^18.2.0",
|
|
87
|
-
"typescript": "^5.3.0",
|
|
88
82
|
"@babel/core": "^7.16.7",
|
|
89
83
|
"@babel/plugin-transform-runtime": "^7.16.5",
|
|
90
84
|
"@babel/preset-env": "^7.16.5",
|
|
91
85
|
"@eslint/js": "^9.12.0",
|
|
86
|
+
"@types/react": "^18.2.0",
|
|
87
|
+
"@types/react-dom": "^18.2.0",
|
|
88
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
92
89
|
"@vitest/coverage-v8": "^4.0.17",
|
|
93
90
|
"autoprefixer": "^10.4.23",
|
|
94
91
|
"babel-loader": "^8.2.3",
|
|
95
92
|
"babel-plugin-array-includes": "^2.0.3",
|
|
96
93
|
"babel-preset-minify": "^0.5.0",
|
|
97
|
-
"css-loader": "^
|
|
94
|
+
"css-loader": "^7.1.4",
|
|
98
95
|
"dotenv": "^16.0.3",
|
|
99
96
|
"eslint": "^9.12.0",
|
|
100
97
|
"form-data": "^4.0.0",
|
|
101
|
-
"gh-pages": "^
|
|
98
|
+
"gh-pages": "^5.0.0",
|
|
102
99
|
"highlight.js": "^10.4.1",
|
|
103
100
|
"isomorphic-fetch": "^3.0.0",
|
|
104
101
|
"jsdom": "^27.4.0",
|
|
105
|
-
"mini-css-extract-plugin": "^
|
|
102
|
+
"mini-css-extract-plugin": "^2.10.0",
|
|
106
103
|
"mobile-detect": "^1.4.3",
|
|
107
104
|
"prettier": "3.3.3",
|
|
105
|
+
"react": "^18.2.0",
|
|
106
|
+
"react-dom": "^18.2.0",
|
|
108
107
|
"style-loader": "^3.3.2",
|
|
108
|
+
"typescript": "^5.3.0",
|
|
109
109
|
"vite": "^5.4.10",
|
|
110
110
|
"vite-plugin-dts": "^4.3.0",
|
|
111
111
|
"vite-plugin-html": "^3.2.2",
|
|
@@ -113,6 +113,6 @@
|
|
|
113
113
|
"vitest": "^4.0.17",
|
|
114
114
|
"webpack": "^5.95.0",
|
|
115
115
|
"webpack-cli": "^5.0.1",
|
|
116
|
-
"webpack-dev-server": "^
|
|
116
|
+
"webpack-dev-server": "^5.2.3"
|
|
117
117
|
}
|
|
118
118
|
}
|
package/src/react/types.d.ts
CHANGED
|
@@ -28,6 +28,20 @@ export interface HotspotPosition {
|
|
|
28
28
|
y: number;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Structured popover data for the built-in product-card template.
|
|
33
|
+
* Priority: content (raw HTML) > data (built-in template) > nothing.
|
|
34
|
+
*/
|
|
35
|
+
export interface PopoverData {
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
price?: string;
|
|
39
|
+
originalPrice?: string;
|
|
40
|
+
image?: string;
|
|
41
|
+
url?: string;
|
|
42
|
+
ctaText?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
/**
|
|
32
46
|
* Hotspot configuration
|
|
33
47
|
*/
|
|
@@ -38,6 +52,7 @@ export interface Hotspot {
|
|
|
38
52
|
containerSize?: [number, number];
|
|
39
53
|
positions: Record<number, HotspotPosition>;
|
|
40
54
|
content?: string;
|
|
55
|
+
data?: PopoverData;
|
|
41
56
|
className?: string;
|
|
42
57
|
}
|
|
43
58
|
|