{"version":3,"file":"LoopMedia.BcsTv3QJ.mjs","names":["useRef"],"sources":["https:/framerusercontent.com/modules/9q5bAdK50eeygq84m3pZ/uD2ELpzsYiQDHgw0UwfQ/LoopMedia.js"],"sourcesContent":["import{jsx as _jsx}from\"react/jsx-runtime\";import{addPropertyControls,ControlType,useIsStaticRenderer}from\"framer\";import{useEffect,useRef}from\"react\";/**\n * A looping, silent video that starts itself.\n *\n * The browser's own autoplay is not enough here: with preload=\"metadata\" it\n * fetches a few seconds, stops, and never reaches the \"enough data\" point it\n * waits for before autoplaying — so the video sits on frame one. Calling\n * play() ourselves does not wait for that. It plays while on screen and\n * pauses off screen; if the browser blocks it (iOS Low Power Mode does), the\n * first touch or click starts it.\n */function LoopVideo({src,style,lazy}){const ref=useRef(null);const isStatic=useIsStaticRenderer();useEffect(()=>{const v=ref.current;if(!v||isStatic||typeof window===\"undefined\")return;v.muted=true;let visible=false;// Hidden copies exist on purpose (the filter's data lists keep one of\n// every cover, at opacity 0, as a source of rows). They must not play\n// or download — only a video the visitor could actually see should.\nconst shown=()=>{for(let e=v;e&&e!==document.body;e=e.parentElement){const cs=getComputedStyle(e);if(cs.display===\"none\"||cs.visibility===\"hidden\"||cs.opacity===\"0\")return false;}return true;};const play=()=>{if(!visible||!v.paused||document.hidden||!shown())return;if(lazy&&v.preload!==\"metadata\")v.preload=\"metadata\";const p=v.play();if(p&&typeof p.catch===\"function\")p.catch(()=>{});};const io=new IntersectionObserver(entries=>{visible=entries[entries.length-1].isIntersecting;if(visible)play();else v.pause();},{rootMargin:\"120px\"});io.observe(v);const kick=()=>play();// A reveal animation can still hold the video at opacity 0 when it\n// first scrolls into range, so keep asking while it is due to play.\nconst retry=window.setInterval(()=>{if(visible&&v.paused)play();},500);v.addEventListener(\"loadedmetadata\",kick);v.addEventListener(\"canplay\",kick);v.addEventListener(\"loadeddata\",kick);document.addEventListener(\"visibilitychange\",kick);window.addEventListener(\"touchstart\",kick,{passive:true});window.addEventListener(\"pointerdown\",kick,{passive:true});return()=>{io.disconnect();window.clearInterval(retry);v.removeEventListener(\"loadedmetadata\",kick);v.removeEventListener(\"canplay\",kick);v.removeEventListener(\"loadeddata\",kick);document.removeEventListener(\"visibilitychange\",kick);window.removeEventListener(\"touchstart\",kick);window.removeEventListener(\"pointerdown\",kick);};},[src,isStatic,lazy]);return /*#__PURE__*/_jsx(\"video\",{ref:ref,src:src,style:style,// muted + playsInline are what let iOS play inline at all.\nmuted:true,playsInline:true,loop:true,// No autoplay attribute: a browser honours it for a video the\n// visitor can never see too, and buffers the whole file. Playing\n// is done by the effect above, only while the video is on screen.\n// A frame with a fixed size can wait: nothing is fetched until the\n// effect above finds the video on screen, so the hidden copies\n// (the filter's data lists keep one of every cover) cost no\n// bandwidth. A \"natural\" frame takes its height from the file, so\n// it needs the metadata up front.\npreload:lazy?\"none\":\"metadata\",controls:false,disablePictureInPicture:true,tabIndex:-1,\"aria-hidden\":true});}/**\n * Image or silently looping video, filling whatever frame it is placed in.\n * No controls, no scrub bar, no poster flash — a video here reads as a moving\n * still. A Video Link wins over an uploaded Video, which wins over Image; leaving\n * all empty renders nothing, so\n * the parent frame's own fill shows through untouched.\n *\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight any\n * @framerIntrinsicWidth 240\n * @framerIntrinsicHeight 145\n */export default function LoopMedia(props){const{video,videoLink,image,fit,radius,urlOnly,style}=props;const isStatic=useIsStaticRenderer();// \"natural\" lets the file set the height, so an uploaded cover keeps its\n// own shape instead of being cropped into a fixed box.\nconst natural=fit===\"natural\";const box={position:\"relative\",width:\"100%\",height:natural?\"auto\":\"100%\",overflow:\"hidden\",borderRadius:radius?`${radius}px`:undefined,...style};const media={width:\"100%\",height:natural?\"auto\":\"100%\",objectFit:natural?undefined:fit,display:\"block\"};// A link wins over an upload, so a video can be hosted anywhere.\nconst link=typeof videoLink===\"string\"?videoLink.trim():\"\";const src=link||(typeof video===\"string\"?video:video?.src);const imgSrc=typeof image===\"string\"?image:image?.src;// A data row, not a picture: the page only reads the address from it\n// (the Next project link, the filter's lists). Nothing is fetched, so a\n// hidden copy costs no bandwidth at all.\nif(urlOnly){if(src)return /*#__PURE__*/_jsx(\"video\",{\"data-src\":src,hidden:true,preload:\"none\",muted:true,playsInline:true,\"aria-hidden\":true});if(imgSrc)return /*#__PURE__*/_jsx(\"img\",{\"data-src\":imgSrc,alt:\"\",hidden:true,\"aria-hidden\":true});return /*#__PURE__*/_jsx(\"div\",{style:box});}if(src){return /*#__PURE__*/_jsx(\"div\",{style:box,children:/*#__PURE__*/_jsx(LoopVideo,{src:src,style:media,lazy:!natural})});}if(imgSrc){return /*#__PURE__*/_jsx(\"div\",{style:box,children:/*#__PURE__*/_jsx(\"img\",{src:imgSrc,alt:image?.alt??\"\",style:media})});}return /*#__PURE__*/_jsx(\"div\",{style:box});}// Control keys are derived from the title, so each title matches its prop name.\naddPropertyControls(LoopMedia,{video:{type:ControlType.File,title:\"Video\",allowedFileTypes:[\"mp4\",\"webm\",\"mov\",\"m4v\"]},urlOnly:{type:ControlType.Boolean,title:\"URL only\",description:\"Hidden data row: expose the address, load nothing\",defaultValue:false},videoLink:{type:ControlType.String,title:\"Video Link\",placeholder:\"https://… .mp4\",description:\"Direct link to a video file hosted elsewhere (.mp4, .webm, .mov). Used instead of Video when filled.\"},image:{type:ControlType.ResponsiveImage,title:\"Image\"},fit:{type:ControlType.Enum,title:\"Fit\",options:[\"cover\",\"contain\",\"natural\"],optionTitles:[\"Cover\",\"Contain\",\"Natural\"],defaultValue:\"cover\",displaySegmentedControl:true},radius:{type:ControlType.Number,title:\"Radius\",min:0,max:64,step:1,defaultValue:0,displayStepper:true}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"LoopMedia\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerIntrinsicHeight\":\"145\",\"framerIntrinsicWidth\":\"240\",\"framerSupportedLayoutWidth\":\"any\",\"framerSupportedLayoutHeight\":\"any\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./LoopMedia.map"],"mappings":"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"}