{"version":3,"file":"ViewportImage.CgB3wpbF.mjs","names":["React.useRef","React.useCallback","React.useSyncExternalStore","React.useMemo"],"sources":["https:/framerusercontent.com/modules/rL97FYGGGt1Z1MtwZ9hu/OWTiOYFaO8gkIvlD09WS/ViewportImage.js"],"sourcesContent":["import{jsx as _jsx}from\"react/jsx-runtime\";import*as React from\"react\";import{addPropertyControls,ControlType,useIsStaticRenderer}from\"framer\";// IMPORTANT: Viewport Image and Viewport Distortion are shipped as two\n// independent Framer modules. Symbol.for() makes both modules resolve the same\n// registry in the browser realm, regardless of which component is loaded first.\nconst STORE_KEY=Symbol.for(\"bestlooker.viewport-distortion.store.v1\");function getSharedStore(){const scope=globalThis;if(!scope[STORE_KEY]){scope[STORE_KEY]={elements:new Map,listeners:new Set,canvasReady:false,appearEnabled:false,effectEnabled:true,owner:null,sequence:0};}// Framer hot reload can preserve the Symbol store created by an older\n// module version. Backfill the responsive-effect flag when needed.\nif(typeof scope[STORE_KEY].effectEnabled!==\"boolean\"){scope[STORE_KEY].effectEnabled=true;}return scope[STORE_KEY];}const store=getSharedStore();function emitStoreChange(){store.listeners.forEach(listener=>listener());}function subscribeStore(listener){store.listeners.add(listener);return()=>store.listeners.delete(listener);}function registerElement(id,node,options){node.style.setProperty(\"--bestlooker-vd-force-fallback\",store.effectEnabled===false?\"1\":\"0\");const current=store.elements.get(id);if(current){const sourceChanged=current.options.sourceType!==options.sourceType||current.options.src!==options.src;current.node=node;current.options=options;if(sourceChanged){current.ready=options.sourceType===\"color\";}}else{store.elements.set(id,{id,node,options,sequence:store.sequence++,ready:options.sourceType===\"color\"});}emitStoreChange();}function unregisterElement(id){if(store.elements.delete(id))emitStoreChange();}function canHideDomFallback(id){const record=store.elements.get(id);if(!record||!record.options.enabled)return false;// Responsive OFF must always mean normal DOM content is visible,\n// regardless of stale canvasReady/appear state from a previous breakpoint.\nif(store.effectEnabled===false)return false;if(store.appearEnabled&&record.options.appear)return true;return Boolean(store.canvasReady&&record.ready);}function clamp(value,min,max){return Math.min(max,Math.max(min,value));}function makeId(){return`viewport-warp-${Math.random().toString(36).slice(2)}-${Date.now().toString(36)}`;}/**\n * @framerDisableUnlink\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n * @framerIntrinsicWidth 400\n * @framerIntrinsicHeight 300\n */export function ViewportImage(props){const isStaticRenderer=useIsStaticRenderer();const rootRef=React.useRef(null);const idRef=React.useRef(makeId());// Read WebGL/fallback visibility directly from the shared external store.\n// useSyncExternalStore avoids synchronously calling setState from an effect,\n// which newer React/Framer linting flags as a warning.\nconst getFallbackSnapshot=React.useCallback(()=>canHideDomFallback(idRef.current),[]);const hideFallback=React.useSyncExternalStore(subscribeStore,getFallbackSnapshot,()=>false);const src=props.sourceType===\"video\"?props.videoFile||\"\":props.image?.src||\"\";const options=React.useMemo(()=>({enabled:props.enabled,sourceType:props.sourceType,src,color:props.color,fit:props.fit,positionX:props.positionX,positionY:props.positionY,radius:props.radius,opacity:props.opacity,distortion:props.distortion,renderOrder:props.renderOrder,appear:props.appear,hoverZoom:props.hoverZoom}),[props.enabled,props.sourceType,src,props.color,props.fit,props.positionX,props.positionY,props.radius,props.opacity,props.distortion,props.renderOrder,props.appear,props.hoverZoom]);React.useLayoutEffect(()=>{if(isStaticRenderer)return;const node=rootRef.current;if(!node)return;const id=idRef.current;registerElement(id,node,options);return()=>unregisterElement(id);},[isStaticRenderer]);React.useLayoutEffect(()=>{if(isStaticRenderer)return;const node=rootRef.current;if(!node)return;registerElement(idRef.current,node,options);},[isStaticRenderer,options]);const objectPosition=`${clamp(props.positionX,0,1)*100}% ${clamp(props.positionY,0,1)*100}%`;// An item opted into Appear must NEVER expose its raw DOM fallback while\n// the WebGL effect is enabled. Waiting for store.appearEnabled creates a\n// one-frame race between the two independent Framer code modules: the DOM\n// image can paint first and then disappear behind the WebGL reveal.\n//\n// Responsive Effect OFF is still handled safely: effectEnabled=false plus\n// --bestlooker-vd-force-fallback=1 forces the normal DOM image/video/color\n// visible even though props.appear is true.\nconst forceHideAppearFallback=!isStaticRenderer&&props.appear&&store.effectEnabled!==false;const fallbackOpacity=forceHideAppearFallback||hideFallback?0:clamp(props.opacity,0,1);const normalOpacity=clamp(props.opacity,0,1);const fallbackCssOpacity=`calc(\n        var(--bestlooker-vd-force-fallback, 0) * ${normalOpacity} +\n        (1 - var(--bestlooker-vd-force-fallback, 0)) * ${fallbackOpacity}\n    )`;const fallbackTransition=props.appear?\"none\":\"opacity 80ms linear\";const effectiveAlt=props.alt??props.image?.alt??\"\";return /*#__PURE__*/_jsx(\"div\",{ref:rootRef,style:{...props.style,width:\"100%\",height:\"100%\",position:\"relative\",overflow:\"hidden\",borderRadius:props.radius,background:\"transparent\"},children:props.sourceType===\"image\"&&src?/*#__PURE__*/_jsx(\"img\",{src:src,srcSet:props.image?.srcSet,alt:effectiveAlt,draggable:false,style:{display:\"block\",width:\"100%\",height:\"100%\",objectFit:props.fit,objectPosition,opacity:fallbackCssOpacity,transition:fallbackTransition,userSelect:\"none\"}}):props.sourceType===\"video\"&&src?/*#__PURE__*/_jsx(\"video\",{src:src,autoPlay:true,muted:true,loop:true,playsInline:true,preload:\"auto\",\"aria-hidden\":\"true\",style:{display:\"block\",width:\"100%\",height:\"100%\",objectFit:props.fit,objectPosition,opacity:fallbackCssOpacity,transition:fallbackTransition,userSelect:\"none\",pointerEvents:\"none\"}}):/*#__PURE__*/_jsx(\"div\",{\"aria-hidden\":\"true\",style:{position:\"absolute\",inset:0,background:props.color,opacity:fallbackCssOpacity,transition:fallbackTransition}})});}ViewportImage.displayName=\"Viewport Image\";const viewportImageDefaultProps={sourceType:\"image\",videoFile:\"\",color:\"#E60023\",fit:\"cover\",positionX:.5,positionY:.5,radius:8,opacity:1,distortion:1,renderOrder:0,enabled:true,appear:false,hoverZoom:false,creatorLink:\"https://framer.link/CxdtHWB\"};ViewportImage.defaultProps=viewportImageDefaultProps;addPropertyControls(ViewportImage,{enabled:{type:ControlType.Boolean,title:\"Enabled\",defaultValue:true},appear:{type:ControlType.Boolean,title:\"Appear\",defaultValue:false,enabledTitle:\"Include\",disabledTitle:\"Ignore\",description:\"Include this item in the global Viewport Distortion Appear animation.\"},hoverZoom:{type:ControlType.Boolean,title:\"Hover Zoom\",defaultValue:false,enabledTitle:\"Include\",disabledTitle:\"Ignore\",hidden:props=>props.sourceType===\"color\",description:\"Include this item in the global Viewport Distortion hover zoom effect.\"},sourceType:{type:ControlType.Enum,title:\"Source\",options:[\"image\",\"video\",\"color\"],optionTitles:[\"Image\",\"Video\",\"Color\"],defaultValue:\"image\"},image:{type:ControlType.ResponsiveImage,title:\"Image\",hidden:props=>props.sourceType!==\"image\"},videoFile:{type:ControlType.File,title:\"Video File\",allowedFileTypes:[\"mp4\",\"mov\",\"webm\"],description:\"Used when Source is set to Video.\"},color:{type:ControlType.Color,title:\"Color\",defaultValue:\"#E60023\",hidden:props=>props.sourceType!==\"color\"},fit:{type:ControlType.Enum,title:\"Fit\",options:[\"cover\",\"contain\",\"fill\"],optionTitles:[\"Cover\",\"Contain\",\"Fill\"],defaultValue:\"cover\",displaySegmentedControl:true,hidden:props=>props.sourceType===\"color\"},positionX:{type:ControlType.Number,title:\"Position X\",defaultValue:.5,min:0,max:1,step:.01,hidden:props=>props.sourceType===\"color\"||props.fit===\"fill\"},positionY:{type:ControlType.Number,title:\"Position Y\",defaultValue:.5,min:0,max:1,step:.01,hidden:props=>props.sourceType===\"color\"||props.fit===\"fill\"},radius:{type:ControlType.Number,title:\"Radius\",defaultValue:8,min:0,max:200,step:1,unit:\"px\"},opacity:{type:ControlType.Number,title:\"Opacity\",defaultValue:1,min:0,max:1,step:.01},distortion:{type:ControlType.Number,title:\"Warp Mult.\",defaultValue:1,min:0,max:2,step:.05},renderOrder:{type:ControlType.Number,title:\"Draw Order\",defaultValue:0,min:-100,max:100,step:1,displayStepper:true},alt:{type:ControlType.String,title:\"Alt\",defaultValue:\"\",hidden:props=>props.sourceType!==\"image\"},creatorLink:{type:ControlType.Link,title:\"Creator\",defaultValue:\"https://framer.link/CxdtHWB\",description:\"Made by [Bestlooker](https://framer.link/CxdtHWB)\"}});\nexport const __FramerMetadata__ = {\"exports\":{\"ViewportImage\":{\"type\":\"reactComponent\",\"name\":\"ViewportImage\",\"slots\":[],\"annotations\":{\"framerIntrinsicWidth\":\"400\",\"framerContractVersion\":\"1\",\"framerIntrinsicHeight\":\"300\",\"framerDisableUnlink\":\"* @framerSupportedLayoutWidth any-prefer-fixed\",\"framerSupportedLayoutHeight\":\"any-prefer-fixed\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./ViewportImage.map"],"mappings":"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"}