{"version":3,"file":"Audio.CKTDGrWD.mjs","names":["useRef","useState","useCallback"],"sources":["https:/framerusercontent.com/modules/R6a3qodYuS7EqinPUpax/NOKhzf0Lt5NF6skdXB4S/Audio.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{addPropertyControls,ControlType}from\"framer\";import{useEffect,useState,useCallback,useRef}from\"react\";export default function SiteAudioToggle(props){const{mutedButton,unmutedButton,defaultMuted=false,storageKey=\"framer-site-audio-muted\",onMuteChange,style,showDebugInfo=false}=props;// Remember if the last stored preference was \"unmuted\".\n// We start muted for autoplay, then unmute on first user gesture.\nconst wantsUnmutedRef=useRef(false);const[isMuted,setIsMuted]=useState(()=>{if(typeof window!==\"undefined\"){const stored=localStorage.getItem(storageKey);if(stored!==null){if(stored===\"false\"){// User previously wanted unmuted; start muted to satisfy autoplay.\nwantsUnmutedRef.current=true;return true;}// User previously wanted muted; honor it.\nreturn stored===\"true\";}}// No stored preference; keep original default behavior.\nreturn defaultMuted;});const[mediaCount,setMediaCount]=useState({audio:0,video:0});// Store all AudioContext instances and their gain nodes\nconst audioContextsRef=useRef(new Set);// Create a global registry for audio control\nuseEffect(()=>{if(typeof window===\"undefined\")return;// Create global audio mute control\nif(!window.__framerAudioMuteControl){window.__framerAudioMuteControl={isMuted:isMuted,gainNodes:new Set,register:function(gainNode){this.gainNodes.add(gainNode);gainNode.gain.value=this.isMuted?0:1;},unregister:function(gainNode){this.gainNodes.delete(gainNode);},setMuted:function(muted){this.isMuted=muted;this.gainNodes.forEach(node=>{node.gain.setValueAtTime(muted?0:1,0);});}};}window.__framerAudioMuteControl.isMuted=isMuted;},[isMuted]);// Function to mute/unmute all media elements\nconst updateAllMedia=useCallback(mute=>{if(typeof window===\"undefined\")return;let audioCount=0;let videoCount=0;// Handle all audio elements\nconst audioElements=document.querySelectorAll(\"audio\");audioElements.forEach(audio=>{audio.muted=mute;audioCount++;});// Handle all video elements\nconst videoElements=document.querySelectorAll(\"video\");videoElements.forEach(video=>{video.muted=mute;videoCount++;});// Handle Web Audio API contexts via gain nodes\naudioContextsRef.current.forEach(({gainNode})=>{// Use gain of 0 for mute, 1 for unmute\ngainNode.gain.setValueAtTime(mute?0:1,0);});// Use global audio control if available\nif(window.__framerAudioMuteControl){window.__framerAudioMuteControl.setMuted(mute);}setMediaCount({audio:audioCount,video:videoCount});},[]);// Intercept AudioContext creation to add gain control\nuseEffect(()=>{if(typeof window===\"undefined\")return;// Store original constructors\nconst OriginalAudioContext=window.AudioContext||window.webkitAudioContext;if(!OriginalAudioContext)return;// Try to find and patch existing AudioContext instances\n// This is a workaround for contexts created before this component mounted\ntry{// Look for existing audio contexts in the window object\nObject.keys(window).forEach(key=>{const value=window[key];if(value&&value.constructor&&(value instanceof OriginalAudioContext||value.constructor.name===\"AudioContext\"||value.constructor.name===\"webkitAudioContext\")){// Found an existing context, try to wrap it\nconst context=value;// Check if we haven't already wrapped this context\nconst alreadyWrapped=Array.from(audioContextsRef.current).some(item=>item.context===context);if(!alreadyWrapped&&context.destination){try{const gainNode=context.createGain();gainNode.gain.value=isMuted?0:1;gainNode.connect(context.destination);audioContextsRef.current.add({context,originalDestination:context.destination,gainNode});}catch(e){console.warn(\"Could not wrap existing AudioContext:\",e);}}}});}catch(e){console.warn(\"Error finding existing AudioContexts:\",e);}// Override AudioContext constructor\nconst AudioContextProxy=new Proxy(OriginalAudioContext,{construct(target,args){const context=new target(...args);// Create a master gain node for this context\nconst gainNode=context.createGain();gainNode.gain.value=isMuted?0:1;// Store the original destination\nconst originalDestination=context.destination;// Store context info\naudioContextsRef.current.add({context,originalDestination,gainNode});// Override the destination property to route through gain\nObject.defineProperty(context,\"destination\",{get(){// Connect gain node to actual destination if not connected\ntry{gainNode.disconnect();gainNode.connect(originalDestination);}catch(e){// Already connected or error\n}return gainNode;},configurable:true});return context;}});// Replace global AudioContext\nwindow.AudioContext=AudioContextProxy;if(window.webkitAudioContext){window.webkitAudioContext=AudioContextProxy;}// Cleanup function\nreturn()=>{window.AudioContext=OriginalAudioContext;if(window.webkitAudioContext){window.webkitAudioContext=OriginalAudioContext;}};},[isMuted]);// Toggle mute state\nconst toggleMute=useCallback(()=>{setIsMuted(prevMuted=>{const newMuted=!prevMuted;// Update all media immediately\nupdateAllMedia(newMuted);// Save to localStorage\nlocalStorage.setItem(storageKey,String(newMuted));// Call callback\nif(onMuteChange){onMuteChange(newMuted);}// Log for debugging\nif(showDebugInfo){console.log(`[Framer Audio Toggle] ${newMuted?\"MUTED\":\"UNMUTED\"}`,{audioElements:document.querySelectorAll(\"audio\").length,videoElements:document.querySelectorAll(\"video\").length,audioContexts:audioContextsRef.current.size,globalGainNodes:window.__framerAudioMuteControl?.gainNodes.size||0});}return newMuted;});},[storageKey,onMuteChange,updateAllMedia,showDebugInfo]);// Apply mute state to all existing media on mount and when state changes\nuseEffect(()=>{updateAllMedia(isMuted);},[isMuted,updateAllMedia]);// Watch for dynamically added media elements\nuseEffect(()=>{if(typeof window===\"undefined\")return;const observer=new MutationObserver(mutations=>{mutations.forEach(mutation=>{mutation.addedNodes.forEach(node=>{if(node instanceof HTMLElement){// Check if the added node is audio/video\nif(node.tagName===\"AUDIO\"||node.tagName===\"VIDEO\"){node.muted=isMuted;}// Check if any children are audio/video\nconst mediaElements=node.querySelectorAll(\"audio, video\");mediaElements.forEach(media=>{media.muted=isMuted;});}});});// Update count after mutation\nupdateAllMedia(isMuted);});observer.observe(document.body,{childList:true,subtree:true});return()=>{observer.disconnect();};},[isMuted,updateAllMedia]);// Scan for media elements periodically (backup for edge cases)\nuseEffect(()=>{const interval=setInterval(()=>{updateAllMedia(isMuted);},2e3)// Check every 2 seconds\n;return()=>clearInterval(interval);},[isMuted,updateAllMedia]);// Minimal tweak: if user previously chose \"unmuted\",\n// wait for the first user gesture, then unmute and try to play.\nuseEffect(()=>{if(!wantsUnmutedRef.current)return;const unmuteAndPlay=()=>{wantsUnmutedRef.current=false;setIsMuted(false);updateAllMedia(false);// Attempt to start any paused media under a valid user gesture\nconst mediaEls=document.querySelectorAll(\"video, audio\");mediaEls.forEach(m=>{const el=m;el.muted=false;if(el.paused){el.play().catch(()=>{// Ignore play errors; some media might still require interaction\n});}});};const opts={once:true};window.addEventListener(\"pointerdown\",unmuteAndPlay,opts);window.addEventListener(\"keydown\",unmuteAndPlay,opts);window.addEventListener(\"touchstart\",unmuteAndPlay,opts);return()=>{window.removeEventListener(\"pointerdown\",unmuteAndPlay);window.removeEventListener(\"keydown\",unmuteAndPlay);window.removeEventListener(\"touchstart\",unmuteAndPlay);};},[updateAllMedia]);return /*#__PURE__*/_jsxs(\"div\",{onClick:toggleMute,style:{...style,cursor:\"pointer\",position:\"relative\",userSelect:\"none\"},\"data-muted\":isMuted,role:\"button\",\"aria-label\":isMuted?\"Unmute site audio\":\"Mute site audio\",\"aria-pressed\":isMuted,children:[isMuted?mutedButton:unmutedButton,showDebugInfo&&/*#__PURE__*/_jsxs(\"div\",{style:{position:\"absolute\",top:0,right:0,background:\"rgba(0, 0, 0, 0.8)\",color:\"white\",padding:\"4px 8px\",fontSize:\"10px\",borderRadius:\"4px\",pointerEvents:\"none\",zIndex:1e3,fontFamily:\"monospace\"},children:[isMuted?\"🔇 MUTED\":\"🔊 UNMUTED\",/*#__PURE__*/_jsx(\"br\",{}),\"Audio: \",mediaCount.audio,\" | Video: \",mediaCount.video]})]});}SiteAudioToggle.defaultProps={defaultMuted:false,storageKey:\"framer-site-audio-muted\",showDebugInfo:false};addPropertyControls(SiteAudioToggle,{unmutedButton:{type:ControlType.ComponentInstance,title:\"Unmuted Button\",description:\"Button to show when audio is playing (speaker icon)\"},mutedButton:{type:ControlType.ComponentInstance,title:\"Muted Button\",description:\"Button to show when audio is muted (muted speaker icon)\"},defaultMuted:{type:ControlType.Boolean,title:\"Default Muted\",description:\"Start with audio muted by default\",defaultValue:false},storageKey:{type:ControlType.String,title:\"Storage Key\",description:\"localStorage key for persisting mute state\",defaultValue:\"framer-site-audio-muted\",placeholder:\"framer-site-audio-muted\"},showDebugInfo:{type:ControlType.Boolean,title:\"Show Debug Info\",description:\"Show mute state and media count overlay\",defaultValue:false,hidden:props=>false}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"SiteAudioToggle\",\"slots\":[\"mutedButton\",\"unmutedButton\"],\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./Audio.map"],"mappings":"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"}