{"version":3,"file":"action_manipulators.1fe819fa.js","sources":["../../../node_modules/@headlessui/vue/dist/utils/micro-task.js","../../../node_modules/@headlessui/vue/dist/components/focus-trap/focus-trap.js","../../../node_modules/@headlessui/vue/dist/hooks/use-inert-others.js","../../../node_modules/@headlessui/vue/dist/internal/portal-force-root.js","../../../node_modules/@headlessui/vue/dist/components/portal/portal.js","../../../node_modules/@headlessui/vue/dist/internal/stack-context.js","../../../node_modules/@headlessui/vue/dist/components/description/description.js","../../../node_modules/@headlessui/vue/dist/utils/disposables.js","../../../node_modules/@headlessui/vue/dist/utils/platform.js","../../../node_modules/@headlessui/vue/dist/components/dialog/dialog.js","../../../node_modules/@headlessui/vue/dist/utils/once.js","../../../node_modules/@headlessui/vue/dist/components/transitions/utils/transition.js","../../../node_modules/@headlessui/vue/dist/components/transitions/transition.js","../../../app/javascript/modules/runtime.ts","../../../app/javascript/modules/keyboard_helpers.ts","../../../app/javascript/modules/extractor.ts","../../../app/javascript/components/Modal.vue","../../../app/javascript/components/Subtitle.vue","../../../node_modules/lodash/isObjectLike.js","../../../node_modules/lodash/_freeGlobal.js","../../../node_modules/lodash/_root.js","../../../node_modules/lodash/_Symbol.js","../../../node_modules/lodash/_getRawTag.js","../../../node_modules/lodash/_objectToString.js","../../../node_modules/lodash/_baseGetTag.js","../../../node_modules/lodash/_overArg.js","../../../node_modules/lodash/_getPrototype.js","../../../node_modules/lodash/isPlainObject.js","../../../node_modules/lodash/isElement.js","../../../app/javascript/modules/get_nested_bounding_client_rect.ts","../../../app/javascript/modules/move_mouse.ts","../../../app/assets/sounds/silence.mp3","../../../app/javascript/modules/trigger_silent_audio_playback.ts","../../../app/javascript/components/Player.vue","../../../app/javascript/modules/player_controls.ts","../../../app/javascript/components/SubtitleIcon.vue","../../../app/javascript/modules/provide_elapsed_time.ts","../../../app/javascript/modules/action_manipulators.ts"],"sourcesContent":["function t(e){typeof queueMicrotask==\"function\"?queueMicrotask(e):Promise.resolve().then(e).catch(o=>setTimeout(()=>{throw o}))}export{t as microTask};\n","import{computed as F,defineComponent as N,h as R,onMounted as w,onUnmounted as y,ref as E,watch as g,Fragment as A}from\"vue\";import{render as O}from'../../utils/render.js';import{Hidden as h,Features as k}from'../../internal/hidden.js';import{dom as H}from'../../utils/dom.js';import{focusIn as M,Focus as T,focusElement as v,FocusResult as I}from'../../utils/focus-management.js';import{match as D}from'../../utils/match.js';import{useTabDirection as j,Direction as b}from'../../hooks/use-tab-direction.js';import{getOwnerDocument as K}from'../../utils/owner.js';import{useEventListener as C}from'../../hooks/use-event-listener.js';import{microTask as x}from'../../utils/micro-task.js';var P=(e=>(e[e.None=1]=\"None\",e[e.InitialFocus=2]=\"InitialFocus\",e[e.TabLock=4]=\"TabLock\",e[e.FocusLock=8]=\"FocusLock\",e[e.RestoreFocus=16]=\"RestoreFocus\",e[e.All=30]=\"All\",e))(P||{});let le=Object.assign(N({name:\"FocusTrap\",props:{as:{type:[Object,String],default:\"div\"},initialFocus:{type:Object,default:null},features:{type:Number,default:30},containers:{type:Object,default:E(new Set)}},inheritAttrs:!1,setup(l,{attrs:i,slots:n,expose:r}){let t=E(null);r({el:t,$el:t});let o=F(()=>K(t));U({ownerDocument:o},F(()=>Boolean(l.features&16)));let e=_({ownerDocument:o,container:t,initialFocus:F(()=>l.initialFocus)},F(()=>Boolean(l.features&2)));q({ownerDocument:o,container:t,containers:l.containers,previousActiveElement:e},F(()=>Boolean(l.features&8)));let s=j();function c(a){let m=H(t);if(!m)return;(p=>p())(()=>{D(s.value,{[b.Forwards]:()=>M(m,T.First,{skipElements:[a.relatedTarget]}),[b.Backwards]:()=>M(m,T.Last,{skipElements:[a.relatedTarget]})})})}let u=E(!1);function f(a){a.key===\"Tab\"&&(u.value=!0,requestAnimationFrame(()=>{u.value=!1}))}function L(a){var p;let m=new Set((p=l.containers)==null?void 0:p.value);m.add(t);let d=a.relatedTarget;!d||d.dataset.headlessuiFocusGuard!==\"true\"&&(B(m,d)||(u.value?M(H(t),D(s.value,{[b.Forwards]:()=>T.Next,[b.Backwards]:()=>T.Previous})|T.WrapAround,{relativeTo:a.target}):a.target instanceof HTMLElement&&v(a.target)))}return()=>{let a={},m={ref:t,onKeydown:f,onFocusout:L},{features:d,initialFocus:p,containers:G,...S}=l;return R(A,[Boolean(d&4)&&R(h,{as:\"button\",type:\"button\",\"data-headlessui-focus-guard\":!0,onFocus:c,features:k.Focusable}),O({ourProps:m,theirProps:{...i,...S},slot:a,attrs:i,slots:n,name:\"FocusTrap\"}),Boolean(d&4)&&R(h,{as:\"button\",type:\"button\",\"data-headlessui-focus-guard\":!0,onFocus:c,features:k.Focusable})])}}}),{features:P});function U({ownerDocument:l},i){let n=E(null);function r(){var o;n.value||(n.value=(o=l.value)==null?void 0:o.activeElement)}function t(){!n.value||(v(n.value),n.value=null)}w(()=>{g(i,(o,e)=>{o!==e&&(o?r():t())},{immediate:!0})}),y(t)}function _({ownerDocument:l,container:i,initialFocus:n},r){let t=E(null),o=E(!1);return w(()=>o.value=!0),y(()=>o.value=!1),w(()=>{g([i,n,r],(e,s)=>{if(e.every((u,f)=>(s==null?void 0:s[f])===u)||!r.value)return;let c=H(i);!c||x(()=>{var L,a;if(!o.value)return;let u=H(n),f=(L=l.value)==null?void 0:L.activeElement;if(u){if(u===f){t.value=f;return}}else if(c.contains(f)){t.value=f;return}u?v(u):M(c,T.First|T.NoScroll)===I.Error&&console.warn(\"There are no focusable elements inside the \"),t.value=(a=l.value)==null?void 0:a.activeElement})},{immediate:!0,flush:\"post\"})}),t}function q({ownerDocument:l,container:i,containers:n,previousActiveElement:r},t){var o;C((o=l.value)==null?void 0:o.defaultView,\"focus\",e=>{if(!t.value)return;let s=new Set(n==null?void 0:n.value);s.add(i);let c=r.value;if(!c)return;let u=e.target;u&&u instanceof HTMLElement?B(s,u)?(r.value=u,v(u)):(e.preventDefault(),e.stopPropagation(),v(c)):v(r.value)},!0)}function B(l,i){var n;for(let r of l)if((n=r.value)!=null&&n.contains(i))return!0;return!1}export{le as FocusTrap};\n","import{ref as E,watchEffect as m}from\"vue\";import{getOwnerDocument as b}from'../utils/owner.js';let l=\"body > *\",i=new Set,r=new Map;function u(t){t.setAttribute(\"aria-hidden\",\"true\"),t.inert=!0}function s(t){let n=r.get(t);!n||(n[\"aria-hidden\"]===null?t.removeAttribute(\"aria-hidden\"):t.setAttribute(\"aria-hidden\",n[\"aria-hidden\"]),t.inert=n.inert)}function g(t,n=E(!0)){m(d=>{if(!n.value||!t.value)return;let a=t.value,o=b(a);if(!!o){i.add(a);for(let e of r.keys())e.contains(a)&&(s(e),r.delete(e));o.querySelectorAll(l).forEach(e=>{if(e instanceof HTMLElement){for(let f of i)if(e.contains(f))return;i.size===1&&(r.set(e,{\"aria-hidden\":e.getAttribute(\"aria-hidden\"),inert:e.inert}),u(e))}}),d(()=>{if(i.delete(a),i.size>0)o.querySelectorAll(l).forEach(e=>{if(e instanceof HTMLElement&&!r.has(e)){for(let f of i)if(e.contains(f))return;r.set(e,{\"aria-hidden\":e.getAttribute(\"aria-hidden\"),inert:e.inert}),u(e)}});else for(let e of r.keys())s(e),r.delete(e)})}})}export{g as useInertOthers};\n","import{defineComponent as l,inject as a,provide as c}from\"vue\";import{render as p}from'../utils/render.js';let e=Symbol(\"ForcePortalRootContext\");function u(){return a(e,!1)}let P=l({name:\"ForcePortalRoot\",props:{as:{type:[Object,String],default:\"template\"},force:{type:Boolean,default:!1}},setup(o,{slots:t,attrs:r}){return c(e,o.force),()=>{let{force:f,...n}=o;return p({theirProps:n,ourProps:{},slot:{},slots:t,attrs:r,name:\"ForcePortalRoot\"})}}});export{P as ForcePortalRoot,u as usePortalRoot};\n","import{Teleport as P,defineComponent as s,h,inject as y,onUnmounted as T,provide as E,reactive as w,ref as d,watchEffect as C,computed as b}from\"vue\";import{render as f}from'../../utils/render.js';import{usePortalRoot as j}from'../../internal/portal-force-root.js';import{getOwnerDocument as v}from'../../utils/owner.js';function c(t){let r=v(t);if(!r){if(t===null)return null;throw new Error(`[Headless UI]: Cannot find ownerDocument for contextElement: ${t}`)}let o=r.getElementById(\"headlessui-portal-root\");if(o)return o;let e=r.createElement(\"div\");return e.setAttribute(\"id\",\"headlessui-portal-root\"),r.body.appendChild(e)}let R=s({name:\"Portal\",props:{as:{type:[Object,String],default:\"div\"}},setup(t,{slots:r,attrs:o}){let e=d(null),p=b(()=>v(e)),n=j(),u=y(g,null),l=d(n===!0||u==null?c(e.value):u.resolveTarget());return C(()=>{n||u!=null&&(l.value=u.resolveTarget())}),T(()=>{var i,m;let a=(i=p.value)==null?void 0:i.getElementById(\"headlessui-portal-root\");!a||l.value===a&&l.value.children.length<=0&&((m=l.value.parentElement)==null||m.removeChild(l.value))}),()=>{if(l.value===null)return null;let a={ref:e,\"data-headlessui-portal\":\"\"};return h(P,{to:l.value},f({ourProps:a,theirProps:t,slot:{},attrs:o,slots:r,name:\"Portal\"}))}}}),g=Symbol(\"PortalGroupContext\"),L=s({name:\"PortalGroup\",props:{as:{type:[Object,String],default:\"template\"},target:{type:Object,default:null}},setup(t,{attrs:r,slots:o}){let e=w({resolveTarget(){return t.target}});return E(g,e),()=>{let{target:p,...n}=t;return f({theirProps:n,ourProps:{},slot:{},attrs:r,slots:o,name:\"PortalGroup\"})}}});export{R as Portal,L as PortalGroup};\n","import{inject as f,provide as m,onMounted as l,onUnmounted as c,watch as s}from\"vue\";let u=Symbol(\"StackContext\");var p=(e=>(e[e.Add=0]=\"Add\",e[e.Remove=1]=\"Remove\",e))(p||{});function v(){return f(u,()=>{})}function S({type:o,enabled:r,element:e,onUpdate:i}){let a=v();function t(...n){i==null||i(...n),a(...n)}l(()=>{s(r,(n,d)=>{n?t(0,o,e):d===!0&&t(1,o,e)},{immediate:!0,flush:\"sync\"})}),c(()=>{r.value&&t(1,o,e)}),m(u,t)}export{p as StackMessage,v as useStackContext,S as useStackProvider};\n","import{computed as m,defineComponent as x,inject as R,onMounted as v,onUnmounted as D,provide as j,ref as u,unref as y}from\"vue\";import{useId as C}from'../../hooks/use-id.js';import{render as h}from'../../utils/render.js';let p=Symbol(\"DescriptionContext\");function b(){let t=R(p,null);if(t===null)throw new Error(\"Missing parent\");return t}function M({slot:t=u({}),name:i=\"Description\",props:o={}}={}){let e=u([]);function s(n){return e.value.push(n),()=>{let r=e.value.indexOf(n);r!==-1&&e.value.splice(r,1)}}return j(p,{register:s,slot:t,name:i,props:o}),m(()=>e.value.length>0?e.value.join(\" \"):void 0)}let E=x({name:\"Description\",props:{as:{type:[Object,String],default:\"p\"},id:{type:String,default:()=>`headlessui-description-${C()}`}},setup(t,{attrs:i,slots:o}){let e=b();return v(()=>D(e.register(t.id))),()=>{let{name:s=\"Description\",slot:n=u({}),props:r={}}=e,{id:d,...l}=t,c={...Object.entries(r).reduce((f,[a,g])=>Object.assign(f,{[a]:y(g)}),{}),id:d};return h({ourProps:c,theirProps:l,slot:n.value,attrs:i,slots:o,name:s})}}});export{E as Description,M as useDescriptions};\n","function s(){let a=[],i=[],t={enqueue(e){i.push(e)},addEventListener(e,n,o,r){return e.addEventListener(n,o,r),t.add(()=>e.removeEventListener(n,o,r))},requestAnimationFrame(...e){let n=requestAnimationFrame(...e);t.add(()=>cancelAnimationFrame(n))},nextFrame(...e){t.requestAnimationFrame(()=>{t.requestAnimationFrame(...e)})},setTimeout(...e){let n=setTimeout(...e);t.add(()=>clearTimeout(n))},add(e){a.push(e)},dispose(){for(let e of a.splice(0))e()},async workQueue(){for(let e of i.splice(0))await e()}};return t}export{s as disposables};\n","function o(){return/iPhone/gi.test(window.navigator.platform)||/Mac/gi.test(window.navigator.platform)&&window.navigator.maxTouchPoints>0}export{o as isIOS};\n","import{computed as g,defineComponent as T,h as S,inject as _,nextTick as oe,onMounted as j,onUnmounted as ae,provide as ne,ref as y,watchEffect as q}from\"vue\";import{render as P,Features as G}from'../../utils/render.js';import{Keys as re}from'../../keyboard.js';import{useId as E}from'../../hooks/use-id.js';import{FocusTrap as C}from'../../components/focus-trap/focus-trap.js';import{useInertOthers as ie}from'../../hooks/use-inert-others.js';import{Portal as z,PortalGroup as se}from'../portal/portal.js';import{StackMessage as J,useStackProvider as ue}from'../../internal/stack-context.js';import{match as A}from'../../utils/match.js';import{ForcePortalRoot as B}from'../../internal/portal-force-root.js';import{Description as de,useDescriptions as pe}from'../description/description.js';import{dom as Q}from'../../utils/dom.js';import{useOpenClosed as fe,State as X}from'../../internal/open-closed.js';import{useOutsideClick as ce}from'../../hooks/use-outside-click.js';import{getOwnerDocument as ge}from'../../utils/owner.js';import{useEventListener as me}from'../../hooks/use-event-listener.js';import{Hidden as ve,Features as De}from'../../internal/hidden.js';import{disposables as he}from'../../utils/disposables.js';import{isIOS as Se}from'../../utils/platform.js';var ye=(t=>(t[t.Open=0]=\"Open\",t[t.Closed=1]=\"Closed\",t))(ye||{});let W=Symbol(\"DialogContext\");function R(l){let i=_(W,null);if(i===null){let t=new Error(`<${l} /> is missing a parent component.`);throw Error.captureStackTrace&&Error.captureStackTrace(t,R),t}return i}let M=\"DC8F892D-2EBD-447C-A4C8-A03058436FF4\",Ue=T({name:\"Dialog\",inheritAttrs:!1,props:{as:{type:[Object,String],default:\"div\"},static:{type:Boolean,default:!1},unmount:{type:Boolean,default:!0},open:{type:[Boolean,String],default:M},initialFocus:{type:Object,default:null},id:{type:String,default:()=>`headlessui-dialog-${E()}`}},emits:{close:l=>!0},setup(l,{emit:i,attrs:t,slots:u,expose:s}){var K;let o=y(!1);j(()=>{o.value=!0});let d=y(0),D=fe(),h=g(()=>l.open===M&&D!==null?A(D.value,{[X.Open]:!0,[X.Closed]:!1}):l.open),H=y(new Set),m=y(null),V=y(null),x=g(()=>ge(m));if(s({el:m,$el:m}),!(l.open!==M||D!==null))throw new Error(\"You forgot to provide an `open` prop to the `Dialog`.\");if(typeof h.value!=\"boolean\")throw new Error(`You provided an \\`open\\` prop to the \\`Dialog\\`, but the value is not a boolean. Received: ${h.value===M?void 0:l.open}`);let c=g(()=>o.value&&h.value?0:1),Y=g(()=>c.value===0),k=g(()=>d.value>1),Z=_(W,null)!==null,ee=g(()=>k.value?\"parent\":\"leaf\");ie(m,g(()=>k.value?Y.value:!1)),ue({type:\"Dialog\",enabled:g(()=>c.value===0),element:m,onUpdate:(a,e,n)=>{if(e===\"Dialog\")return A(a,{[J.Add](){H.value.add(n),d.value+=1},[J.Remove](){H.value.delete(n),d.value-=1}})}});let te=pe({name:\"DialogDescription\",slot:g(()=>({open:h.value}))}),L=y(null),b={titleId:L,panelRef:y(null),dialogState:c,setTitleId(a){L.value!==a&&(L.value=a)},close(){i(\"close\",!1)}};ne(W,b);function I(){var e,n,v;return[...Array.from((n=(e=x.value)==null?void 0:e.querySelectorAll(\"body > *, [data-headlessui-portal]\"))!=null?n:[]).filter(r=>!(!(r instanceof HTMLElement)||r.contains(Q(V))||b.panelRef.value&&r.contains(b.panelRef.value))),(v=b.panelRef.value)!=null?v:m.value]}return ce(()=>I(),(a,e)=>{b.close(),oe(()=>e==null?void 0:e.focus())},g(()=>c.value===0&&!k.value)),me((K=x.value)==null?void 0:K.defaultView,\"keydown\",a=>{a.defaultPrevented||a.key===re.Escape&&c.value===0&&(k.value||(a.preventDefault(),a.stopPropagation(),b.close()))}),q(a=>{var U;if(c.value!==0||Z)return;let e=x.value;if(!e)return;let n=he(),v=window.pageYOffset;function r(f,p,w){let F=f.style.getPropertyValue(p);return Object.assign(f.style,{[p]:w}),n.add(()=>{Object.assign(f.style,{[p]:F})})}let O=e==null?void 0:e.documentElement,N=((U=e.defaultView)!=null?U:window).innerWidth-O.clientWidth;if(r(O,\"overflow\",\"hidden\"),N>0){let f=O.clientWidth-O.offsetWidth,p=N-f;r(O,\"paddingRight\",`${p}px`)}if(Se()){r(e.body,\"marginTop\",`-${v}px`),window.scrollTo(0,0);let f=null;n.addEventListener(e,\"click\",p=>{if(p.target instanceof HTMLElement)try{let w=p.target.closest(\"a\");if(!w)return;let{hash:F}=new URL(w.href),$=e.querySelector(F);$&&!I().some(le=>le.contains($))&&(f=$)}catch{}},!0),n.addEventListener(e,\"touchmove\",p=>{p.target instanceof HTMLElement&&!I().some(w=>w.contains(p.target))&&p.preventDefault()},{passive:!1}),n.add(()=>{window.scrollTo(0,window.pageYOffset+v),f&&f.isConnected&&(f.scrollIntoView({block:\"nearest\"}),f=null)})}a(n.dispose)}),q(a=>{if(c.value!==0)return;let e=Q(m);if(!e)return;let n=new IntersectionObserver(v=>{for(let r of v)r.boundingClientRect.x===0&&r.boundingClientRect.y===0&&r.boundingClientRect.width===0&&r.boundingClientRect.height===0&&b.close()});n.observe(e),a(()=>n.disconnect())}),()=>{let{id:a,open:e,initialFocus:n,...v}=l,r={...t,ref:m,id:a,role:\"dialog\",\"aria-modal\":c.value===0?!0:void 0,\"aria-labelledby\":L.value,\"aria-describedby\":te.value},O={open:c.value===0};return S(B,{force:!0},()=>[S(z,()=>S(se,{target:m.value},()=>S(B,{force:!1},()=>S(C,{initialFocus:n,containers:H,features:Y.value?A(ee.value,{parent:C.features.RestoreFocus,leaf:C.features.All&~C.features.FocusLock}):C.features.None},()=>P({ourProps:r,theirProps:v,slot:O,attrs:t,slots:u,visible:c.value===0,features:G.RenderStrategy|G.Static,name:\"Dialog\"}))))),S(ve,{features:De.Hidden,ref:V})])}}}),_e=T({name:\"DialogOverlay\",props:{as:{type:[Object,String],default:\"div\"},id:{type:String,default:()=>`headlessui-dialog-overlay-${E()}`}},setup(l,{attrs:i,slots:t}){let u=R(\"DialogOverlay\");function s(o){o.target===o.currentTarget&&(o.preventDefault(),o.stopPropagation(),u.close())}return()=>{let{id:o,...d}=l;return P({ourProps:{id:o,\"aria-hidden\":!0,onClick:s},theirProps:d,slot:{open:u.dialogState.value===0},attrs:i,slots:t,name:\"DialogOverlay\"})}}}),qe=T({name:\"DialogBackdrop\",props:{as:{type:[Object,String],default:\"div\"},id:{type:String,default:()=>`headlessui-dialog-backdrop-${E()}`}},inheritAttrs:!1,setup(l,{attrs:i,slots:t,expose:u}){let s=R(\"DialogBackdrop\"),o=y(null);return u({el:o,$el:o}),j(()=>{if(s.panelRef.value===null)throw new Error(\"A component is being used, but a component is missing.\")}),()=>{let{id:d,...D}=l,h={id:d,ref:o,\"aria-hidden\":!0};return S(B,{force:!0},()=>S(z,()=>P({ourProps:h,theirProps:{...i,...D},slot:{open:s.dialogState.value===0},attrs:i,slots:t,name:\"DialogBackdrop\"})))}}}),Ge=T({name:\"DialogPanel\",props:{as:{type:[Object,String],default:\"div\"},id:{type:String,default:()=>`headlessui-dialog-panel-${E()}`}},setup(l,{attrs:i,slots:t,expose:u}){let s=R(\"DialogPanel\");u({el:s.panelRef,$el:s.panelRef});function o(d){d.stopPropagation()}return()=>{let{id:d,...D}=l,h={id:d,ref:s.panelRef,onClick:o};return P({ourProps:h,theirProps:D,slot:{open:s.dialogState.value===0},attrs:i,slots:t,name:\"DialogPanel\"})}}}),ze=T({name:\"DialogTitle\",props:{as:{type:[Object,String],default:\"h2\"},id:{type:String,default:()=>`headlessui-dialog-title-${E()}`}},setup(l,{attrs:i,slots:t}){let u=R(\"DialogTitle\");return j(()=>{u.setTitleId(l.id),ae(()=>u.setTitleId(null))}),()=>{let{id:s,...o}=l;return P({ourProps:{id:s},theirProps:o,slot:{open:u.dialogState.value===0},attrs:i,slots:t,name:\"DialogTitle\"})}}}),Je=de;export{Ue as Dialog,qe as DialogBackdrop,Je as DialogDescription,_e as DialogOverlay,Ge as DialogPanel,ze as DialogTitle};\n","function l(r){let e={called:!1};return(...t)=>{if(!e.called)return e.called=!0,r(...t)}}export{l as once};\n","import{once as f}from'../../../utils/once.js';import{disposables as p}from'../../../utils/disposables.js';function m(e,...t){e&&t.length>0&&e.classList.add(...t)}function d(e,...t){e&&t.length>0&&e.classList.remove(...t)}var g=(i=>(i.Finished=\"finished\",i.Cancelled=\"cancelled\",i))(g||{});function F(e,t){let i=p();if(!e)return i.dispose;let{transitionDuration:n,transitionDelay:a}=getComputedStyle(e),[l,s]=[n,a].map(o=>{let[u=0]=o.split(\",\").filter(Boolean).map(r=>r.includes(\"ms\")?parseFloat(r):parseFloat(r)*1e3).sort((r,c)=>c-r);return u});return l!==0?i.setTimeout(()=>t(\"finished\"),l+s):t(\"finished\"),i.add(()=>t(\"cancelled\")),i.dispose}function L(e,t,i,n,a,l){let s=p(),o=l!==void 0?f(l):()=>{};return d(e,...a),m(e,...t,...i),s.nextFrame(()=>{d(e,...i),m(e,...n),s.add(F(e,u=>(d(e,...n,...t),m(e,...a),o(u))))}),s.add(()=>d(e,...t,...i,...n,...a)),s.add(()=>o(\"cancelled\")),s.dispose}export{g as Reason,L as transition};\n","import{computed as b,defineComponent as A,h as D,inject as L,onMounted as h,onUnmounted as I,provide as H,ref as T,watch as X,watchEffect as y}from\"vue\";import{useId as Y}from'../../hooks/use-id.js';import{match as E}from'../../utils/match.js';import{Features as Z,omit as ee,render as P,RenderStrategy as f}from'../../utils/render.js';import{Reason as j,transition as M}from'./utils/transition.js';import{dom as U}from'../../utils/dom.js';import{useOpenClosedProvider as te,State as V,useOpenClosed as ne,hasOpenClosed as re}from'../../internal/open-closed.js';function d(e=\"\"){return e.split(\" \").filter(t=>t.trim().length>1)}let B=Symbol(\"TransitionContext\");var ae=(a=>(a.Visible=\"visible\",a.Hidden=\"hidden\",a))(ae||{});function le(){return L(B,null)!==null}function ie(){let e=L(B,null);if(e===null)throw new Error(\"A is used but it is missing a parent .\");return e}function se(){let e=L(F,null);if(e===null)throw new Error(\"A is used but it is missing a parent .\");return e}let F=Symbol(\"NestingContext\");function w(e){return\"children\"in e?w(e.children):e.value.filter(({state:t})=>t===\"visible\").length>0}function K(e){let t=T([]),a=T(!1);h(()=>a.value=!0),I(()=>a.value=!1);function s(r,n=f.Hidden){let l=t.value.findIndex(({id:i})=>i===r);l!==-1&&(E(n,{[f.Unmount](){t.value.splice(l,1)},[f.Hidden](){t.value[l].state=\"hidden\"}}),!w(t)&&a.value&&(e==null||e()))}function v(r){let n=t.value.find(({id:l})=>l===r);return n?n.state!==\"visible\"&&(n.state=\"visible\"):t.value.push({id:r,state:\"visible\"}),()=>s(r,f.Unmount)}return{children:t,register:v,unregister:s}}let _=Z.RenderStrategy,oe=A({props:{as:{type:[Object,String],default:\"div\"},show:{type:[Boolean],default:null},unmount:{type:[Boolean],default:!0},appear:{type:[Boolean],default:!1},enter:{type:[String],default:\"\"},enterFrom:{type:[String],default:\"\"},enterTo:{type:[String],default:\"\"},entered:{type:[String],default:\"\"},leave:{type:[String],default:\"\"},leaveFrom:{type:[String],default:\"\"},leaveTo:{type:[String],default:\"\"}},emits:{beforeEnter:()=>!0,afterEnter:()=>!0,beforeLeave:()=>!0,afterLeave:()=>!0},setup(e,{emit:t,attrs:a,slots:s,expose:v}){if(!le()&&re())return()=>D(fe,{...e,onBeforeEnter:()=>t(\"beforeEnter\"),onAfterEnter:()=>t(\"afterEnter\"),onBeforeLeave:()=>t(\"beforeLeave\"),onAfterLeave:()=>t(\"afterLeave\")},s);let r=T(null),n=T(\"visible\"),l=b(()=>e.unmount?f.Unmount:f.Hidden);v({el:r,$el:r});let{show:i,appear:x}=ie(),{register:g,unregister:p}=se(),R={value:!0},m=Y(),S={value:!1},N=K(()=>{S.value||(n.value=\"hidden\",p(m),t(\"afterLeave\"))});h(()=>{let o=g(m);I(o)}),y(()=>{if(l.value===f.Hidden&&!!m){if(i&&n.value!==\"visible\"){n.value=\"visible\";return}E(n.value,{[\"hidden\"]:()=>p(m),[\"visible\"]:()=>g(m)})}});let k=d(e.enter),$=d(e.enterFrom),q=d(e.enterTo),O=d(e.entered),z=d(e.leave),G=d(e.leaveFrom),J=d(e.leaveTo);h(()=>{y(()=>{if(n.value===\"visible\"){let o=U(r);if(o instanceof Comment&&o.data===\"\")throw new Error(\"Did you forget to passthrough the `ref` to the actual DOM node?\")}})});function Q(o){let c=R.value&&!x.value,u=U(r);!u||!(u instanceof HTMLElement)||c||(S.value=!0,i.value&&t(\"beforeEnter\"),i.value||t(\"beforeLeave\"),o(i.value?M(u,k,$,q,O,C=>{S.value=!1,C===j.Finished&&t(\"afterEnter\")}):M(u,z,G,J,O,C=>{S.value=!1,C===j.Finished&&(w(N)||(n.value=\"hidden\",p(m),t(\"afterLeave\")))})))}return h(()=>{X([i],(o,c,u)=>{Q(u),R.value=!1},{immediate:!0})}),H(F,N),te(b(()=>E(n.value,{[\"visible\"]:V.Open,[\"hidden\"]:V.Closed}))),()=>{let{appear:o,show:c,enter:u,enterFrom:C,enterTo:de,entered:ve,leave:pe,leaveFrom:me,leaveTo:Te,...W}=e;return P({theirProps:W,ourProps:{ref:r},slot:{},slots:s,attrs:a,features:_,visible:n.value===\"visible\",name:\"TransitionChild\"})}}}),ue=oe,fe=A({inheritAttrs:!1,props:{as:{type:[Object,String],default:\"div\"},show:{type:[Boolean],default:null},unmount:{type:[Boolean],default:!0},appear:{type:[Boolean],default:!1},enter:{type:[String],default:\"\"},enterFrom:{type:[String],default:\"\"},enterTo:{type:[String],default:\"\"},entered:{type:[String],default:\"\"},leave:{type:[String],default:\"\"},leaveFrom:{type:[String],default:\"\"},leaveTo:{type:[String],default:\"\"}},emits:{beforeEnter:()=>!0,afterEnter:()=>!0,beforeLeave:()=>!0,afterLeave:()=>!0},setup(e,{emit:t,attrs:a,slots:s}){let v=ne(),r=b(()=>e.show===null&&v!==null?E(v.value,{[V.Open]:!0,[V.Closed]:!1}):e.show);y(()=>{if(![!0,!1].includes(r.value))throw new Error('A is used but it is missing a `:show=\"true | false\"` prop.')});let n=T(r.value?\"visible\":\"hidden\"),l=K(()=>{n.value=\"hidden\"}),i=T(!0),x={show:r,appear:b(()=>e.appear||!i.value)};return h(()=>{y(()=>{i.value=!1,r.value?n.value=\"visible\":w(l)||(n.value=\"hidden\")})}),H(F,l),H(B,x),()=>{let g=ee(e,[\"show\",\"appear\",\"unmount\",\"onBeforeEnter\",\"onBeforeLeave\",\"onAfterEnter\",\"onAfterLeave\"]),p={unmount:e.unmount};return P({ourProps:{...p,as:\"template\"},theirProps:{},slot:{},slots:{...s,default:()=>[D(ue,{onBeforeEnter:()=>t(\"beforeEnter\"),onAfterEnter:()=>t(\"afterEnter\"),onBeforeLeave:()=>t(\"beforeLeave\"),onAfterLeave:()=>t(\"afterLeave\"),...a,...p,...g},s.default)]},attrs:{},features:_,visible:n.value===\"visible\",name:\"Transition\"})}}});export{oe as TransitionChild,fe as TransitionRoot};\n","import { Action } from \"@models/ActionHierarchy\";\nimport VoiceOver from \"@models/VoiceOver\";\nimport { formatSecondsAsString } from \"@modules/helpers\";\nimport { sum, groupBy } from \"lodash\";\nimport { type Ref, unref } from \"vue\";\n\n/**\n * Calculates the total duration of a list of actions and their voice overs\n * @param actions\n * @param voiceOvers\n */\nexport function calculateRuntime(actions: Action[], voiceOvers?: VoiceOver[]): number {\n if (!voiceOvers) return sum(actions.map((action) => action.timings.total));\n\n const actionsGroupedByVoiceOverId: Record = groupBy(\n actions,\n (action) => action.voiceOverId,\n );\n let totalRuntime = 0;\n const voiceOverIds = Object.keys(actionsGroupedByVoiceOverId);\n voiceOverIds.forEach((voiceOverId) => {\n const actionsInVoiceOver = actionsGroupedByVoiceOverId[voiceOverId];\n if (!actionsInVoiceOver || actionsInVoiceOver.length === 0) return;\n\n const actionRuntime = calculateRuntime(actionsInVoiceOver);\n\n const voiceOver = voiceOvers.find((v) => v.id === voiceOverId);\n\n if (voiceOver) {\n totalRuntime += Math.max(voiceOver.duration, actionRuntime);\n } else {\n // actions without voiceover, just count all actions\n totalRuntime += actionRuntime;\n }\n });\n return totalRuntime;\n}\n\n/**\n * Formats the runtime\n * @param actions\n * @param voiceOvers\n */\nexport function calculateFormattedRuntime(actions: Action[], voiceOvers: VoiceOver[]): string {\n const runtime = calculateRuntime(actions, voiceOvers);\n return formatSecondsAsString(runtime);\n}\n\n/**\n * Calculates total runtime of a list of actions and their voice overs before a given action\n * @param currentAction\n * @param actions\n * @param voiceOvers\n */\nexport function calculatePrecedingRuntime(\n currentAction: Action | string | null,\n actions: Action[],\n voiceOvers?: VoiceOver[],\n): number {\n if (!currentAction) return 0;\n\n const orderedVoiceOvers =\n voiceOvers?.sort(\n (a, b) =>\n actions.findIndex((action) => action.voiceOverId === a.id) -\n actions.findIndex((action) => action.voiceOverId === b.id),\n ) || [];\n\n const currentActionIndex =\n typeof currentAction === \"object\"\n ? actions.indexOf(currentAction)\n : actions.findIndex((action) => action.id === currentAction);\n\n if (currentActionIndex === -1) return 0; // hidden action\n\n let currentVoiceOverIndex = orderedVoiceOvers?.findIndex(\n (voiceOver) => voiceOver.id === actions[currentActionIndex]?.voiceOverId,\n );\n\n if (currentActionIndex <= 0) return 0;\n if (currentVoiceOverIndex === -1) currentVoiceOverIndex = orderedVoiceOvers.length;\n\n return calculateRuntime(\n actions.slice(0, currentActionIndex),\n orderedVoiceOvers.slice(0, currentVoiceOverIndex),\n );\n}\n\nexport function calculateActionRuntime(\n currentActionId: string | null | Ref,\n actions: Action[] | Ref,\n voiceOvers: VoiceOver[] | Ref,\n): number {\n const currentId = unref(currentActionId);\n if (!currentId) return 0;\n\n const visibleActions = Action.getVisibleActions(unref(actions));\n const currentAction = visibleActions.find((action) => action.id === currentId);\n if (!currentAction) return 0;\n\n const currentRuntime = currentAction.timings.total || 0;\n if (!currentAction.voiceOverId) return currentRuntime;\n\n const actionsInVoiceOver = visibleActions.filter(\n (action) => action.voiceOverId === currentAction.voiceOverId,\n );\n\n // if it isn't the last action, just return the current runtime\n if (actionsInVoiceOver[actionsInVoiceOver.length - 1] !== currentAction) return currentRuntime;\n\n // it is the last action, calculate total length, including any padding due to longer voice over\n const voiceOver = unref(voiceOvers).find((v) => v.id === currentAction.voiceOverId);\n\n if (!voiceOver) return currentRuntime;\n\n const totalRuntimeOfActionsInVoiceOver = actionsInVoiceOver.reduce(\n (total, action) => total + (action.timings.total || 0),\n 0,\n );\n const runtimeOfOtherActions = totalRuntimeOfActionsInVoiceOver - currentRuntime;\n\n return Math.max(currentRuntime, voiceOver.duration - runtimeOfOtherActions);\n}\n","export function blur(): void {\n if (document.activeElement instanceof HTMLElement) document.activeElement.blur();\n}\n\nexport function isBody(e: KeyboardEvent): boolean {\n return (e.target as HTMLBodyElement).tagName === \"BODY\";\n}\n\nexport function isButton(e: KeyboardEvent): boolean {\n return (e.target as HTMLBodyElement).tagName === \"BUTTON\";\n}\n\nexport function isBodyOrButton(e: KeyboardEvent): boolean {\n return isBody(e) || isButton(e);\n}\n\nexport function hasModifier(e: KeyboardEvent): boolean {\n // This check can be used to prevent hijacking the default behavior of the keypress, such as using\n // commands to back/forward in the browser.\n return e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n","import type { eventWithTime } from \"@rrweb/types\";\nimport { findLastIndex } from \"lodash\";\nimport {\n registerActionStreaming as extractActionFromStreamedEvent, // version 3.0.0\n registerActions,\n resetReplayer,\n} from \"./event_processor\";\n\nimport { BrowserActionTypes } from \"../models/ActionHierarchy\";\nimport type { ActionType } from \"./event_processor/types\";\n\nexport async function resetExtractor(): Promise {\n await resetReplayer();\n}\n\nexport async function updateActionsWithStreamedEvent(\n event: eventWithTime,\n actions: ActionType[],\n allEvents: eventWithTime[],\n): Promise {\n await extractActionFromStreamedEvent(event, actions, allEvents);\n}\n\nexport async function extractActionsFromEvents(events: eventWithTime[]): Promise {\n const actions: ActionType[] = [];\n await registerActions(events, actions);\n return actions;\n}\n\nconst isBrowserAction = (\n action: { id: string; name: string } | { id: string; type: string },\n): boolean => {\n if (\"type\" in action) {\n return BrowserActionTypes().includes(action.type);\n }\n return BrowserActionTypes().includes(action.name);\n};\n\n/**\n * finds closest action to existing actions and\n * returns the position before or after it (depending on timestamp)\n * @param action - new action\n * @param actions - array of existing actions (not sorted by timestamp)\n */\nexport function findPositionFor(\n action: { id: string; name: string } | { id: string; type: string },\n actions: Array<{ id: string; name: string } | { id: string; type: string }>,\n): number {\n const timestamp = Number(action.id.split(\"-\")[0]);\n let closestActionIndex = 0;\n let closestDiff = Number.MAX_SAFE_INTEGER;\n let before = true;\n\n for (let i = 0; i < actions.length; i += 1) {\n const existingAction = actions[i];\n if (existingAction && isBrowserAction(existingAction)) {\n const existingTimestamp = Number(existingAction.id.split(\"-\")[0]);\n const currentDiff = Math.abs(existingTimestamp - timestamp);\n if (currentDiff < closestDiff) {\n before = existingTimestamp > timestamp;\n closestDiff = currentDiff;\n closestActionIndex = i;\n }\n }\n }\n\n return before ? closestActionIndex : closestActionIndex + 1;\n}\n\n// export async function reParseEvents(\n// events: eventWithTime[],\n// existingActions: ActionType[],\n// alertAboutWarnings = false,\n// ): Promise<{\n// actions: ActionType[];\n// newActions: ActionType[];\n// updatedActions: ActionType[];\n// staleActions: ActionType[];\n// }> {\n// const actions = await parseEvents(events);\n// console.log(\"reParseEvents(): actions\", actions, \"existingActions\", existingActions);\n// const newActions = actions.filter(\n// // Check whether this action has a corresponding existing action, when it does not, this\n// // must be a new action:\n// (updatedAction) =>\n// !existingActions.some((existingAction) => updatedAction.id === existingAction.id),\n// );\n\n// const staleActions = existingActions.filter(\n// // find the actions marked to be deleted\n// (existingAction) => {\n// if (!isBrowserAction(existingAction)) return false;\n// return !actions.some((updatedAction) => updatedAction.id === existingAction.id);\n// },\n// );\n\n// // copy over parameters from re-extracted actions into their corresponding existing actions.\n// const updatedActions = existingActions.map((existingAction) => {\n// if (!isBrowserAction(existingAction)) return { ...existingAction };\n\n// const reExtractedAction = actions.find((action) => existingAction.id === action.id);\n// return { ...existingAction, ...reExtractedAction };\n// });\n\n// newActions.forEach((newAction) => {\n// const timestamp = Number(newAction.id.split(\"-\")[0]);\n// const position = findPositionFor(newAction, updatedActions);\n// updatedActions.splice(position, 0, newAction);\n// });\n\n// if (newActions.length > 0) {\n// if (alertAboutWarnings) {\n// alert(\n// `There are ${newActions.length} actions that were added by the re-extraction (they have no corresponding existing action. Will dump them to console).`,\n// );\n// }\n// console.log(\"reParseEvents(): Orphan newActions\", newActions);\n// }\n\n// if (staleActions.length > 0) {\n// if (alertAboutWarnings) {\n// alert(\n// `There are ${staleActions.length} actions that were removed by the re-extraction (they have no corresponding updated action. Will dump them to console).`,\n// );\n// }\n// console.warn(\"reParseEvents(): Orphan staleActions\", staleActions);\n// }\n// console.log(\n// \"reParseEvents(): actions, newActions, updatedActions, staleActions\",\n// actions,\n// newActions,\n// updatedActions,\n// staleActions,\n// );\n\n// // console.log(\"actions\", actions, \"updatedActions\", updatedActions);\n// return { actions, newActions, updatedActions, staleActions };\n// }\n","\n\n\n \n \n \n\n","\n\n\n
\n
\n {{ text }}\n
\n
\n\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nmodule.exports = isObjectLike;\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nmodule.exports = freeGlobal;\n","var freeGlobal = require('./_freeGlobal');\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nmodule.exports = root;\n","var root = require('./_root');\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nmodule.exports = Symbol;\n","var Symbol = require('./_Symbol');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nmodule.exports = getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nmodule.exports = objectToString;\n","var Symbol = require('./_Symbol'),\n getRawTag = require('./_getRawTag'),\n objectToString = require('./_objectToString');\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nmodule.exports = baseGetTag;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nmodule.exports = overArg;\n","var overArg = require('./_overArg');\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nmodule.exports = getPrototype;\n","var baseGetTag = require('./_baseGetTag'),\n getPrototype = require('./_getPrototype'),\n isObjectLike = require('./isObjectLike');\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n}\n\nmodule.exports = isPlainObject;\n","var isObjectLike = require('./isObjectLike'),\n isPlainObject = require('./isPlainObject');\n\n/**\n * Checks if `value` is likely a DOM element.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('');\n * // => false\n */\nfunction isElement(value) {\n return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n}\n\nmodule.exports = isElement;\n","import { Mirror } from \"rrweb-snapshot\";\nimport isElement from \"lodash/isElement\";\n\n// TODO: extract all of this into its own npm package that can be shared between desktop and web\n\nfunction getElementById(id: number, mirror: Mirror): HTMLElement | null {\n const node = mirror.getNode(id);\n\n if (!node || !isElement(node)) return null;\n return node as HTMLElement;\n}\n\nfunction multiplyIfPossible(num: number, multiplier: number): number {\n if (!num || !multiplier) {\n return 0;\n }\n return num * multiplier;\n}\n\nfunction getScale(iframeElement: HTMLElement): {\n scaleX: number;\n scaleY: number;\n} {\n const calculatedStyle = iframeElement.ownerDocument.defaultView?.getComputedStyle(iframeElement);\n\n if (!calculatedStyle) return { scaleX: 1, scaleY: 1 };\n\n const { transform } = calculatedStyle;\n if (transform === \"none\") {\n return { scaleX: 1, scaleY: 1 };\n }\n const matches = transform.match(/matrix(3d)?\\(([^)]+)\\)/);\n if (!matches || !matches[2]) {\n return { scaleX: 1, scaleY: 1 };\n }\n\n const scale = matches[2].split(\", \").map((val) => parseFloat(val)) as [\n number,\n number,\n number,\n number,\n number,\n number,\n ];\n if (scale.length !== 6) return { scaleX: 1, scaleY: 1 }; // something went wrong\n\n return {\n scaleX: scale[0],\n scaleY: scale[3],\n };\n}\n\nfunction getScaleFromElementAndAncestors(iframeElement: HTMLElement): {\n scaleX: number;\n scaleY: number;\n} {\n const scale = getScale(iframeElement);\n\n let parent = iframeElement.parentElement;\n while (parent) {\n const parentScale = getScale(parent);\n scale.scaleX *= parentScale.scaleX;\n scale.scaleY *= parentScale.scaleY;\n parent = parent.parentElement;\n }\n return scale;\n}\n\n// adapted from https://github.com/suchipi/get-nested-bounding-client-rect/blob/master/src/index.js\n\nexport type Rect = {\n top: number;\n left: number;\n width: number;\n height: number;\n bottom: number;\n right: number;\n x: number;\n y: number;\n};\n\ntype Scale = {\n scaleX: number;\n scaleY: number;\n};\n\nfunction getElementDimensions(element: HTMLElement): {\n borderLeft: number;\n borderRight: number;\n borderTop: number;\n borderBottom: number;\n marginLeft: number;\n marginRight: number;\n marginTop: number;\n marginBottom: number;\n paddingLeft: number;\n paddingRight: number;\n paddingTop: number;\n paddingBottom: number;\n} {\n const calculatedStyle = element.ownerDocument.defaultView?.getComputedStyle(element);\n\n if (!calculatedStyle)\n return {\n borderLeft: 0,\n borderRight: 0,\n borderTop: 0,\n borderBottom: 0,\n marginLeft: 0,\n marginRight: 0,\n marginTop: 0,\n marginBottom: 0,\n paddingLeft: 0,\n paddingRight: 0,\n paddingTop: 0,\n paddingBottom: 0,\n };\n\n return {\n borderLeft: parseFloat(calculatedStyle.borderLeftWidth),\n borderRight: parseFloat(calculatedStyle.borderRightWidth),\n borderTop: parseFloat(calculatedStyle.borderTopWidth),\n borderBottom: parseFloat(calculatedStyle.borderBottomWidth),\n marginLeft: parseFloat(calculatedStyle.marginLeft),\n marginRight: parseFloat(calculatedStyle.marginRight),\n marginTop: parseFloat(calculatedStyle.marginTop),\n marginBottom: parseFloat(calculatedStyle.marginBottom),\n paddingLeft: parseFloat(calculatedStyle.paddingLeft),\n paddingRight: parseFloat(calculatedStyle.paddingRight),\n paddingTop: parseFloat(calculatedStyle.paddingTop),\n paddingBottom: parseFloat(calculatedStyle.paddingBottom),\n };\n}\n\n// Get the window object for the document that a node belongs to,\n// or return null if it cannot be found (node not attached to DOM,\n// etc).\nfunction getOwnerWindow(node: HTMLElement): Window | null {\n if (!node.ownerDocument) {\n return null;\n }\n return node.ownerDocument.defaultView;\n}\n\n// Get the iframe containing a node, or return null if it cannot\n// be found (node not within iframe, etc).\nfunction getOwnerIframe(node: HTMLElement): HTMLElement | null {\n const nodeWindow = getOwnerWindow(node);\n if (nodeWindow) {\n return nodeWindow.frameElement as HTMLElement | null;\n }\n return null;\n}\n\n// Add together the top, left, bottom, and right properties of\n// each Rect, but keep the width and height of the first one.\nexport function mergeRectOffsets(rects: Array): Rect {\n let result: Rect | null = null;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const rect of rects) {\n if (result === null) {\n if (\"top\" in rect) result = rect;\n // eslint-disable-next-line no-continue\n continue;\n }\n\n if (\"scaleX\" in rect) {\n result = {\n top: multiplyIfPossible(result.top, rect.scaleY),\n left: multiplyIfPossible(result.left, rect.scaleX),\n width: multiplyIfPossible(result.width, rect.scaleX),\n height: multiplyIfPossible(result.height, rect.scaleY),\n bottom: multiplyIfPossible(result.bottom, rect.scaleY),\n right: multiplyIfPossible(result.right, rect.scaleX),\n x: multiplyIfPossible(result.x, rect.scaleX),\n y: multiplyIfPossible(result.y, rect.scaleY),\n };\n } else {\n const nextTop = result.top + rect.top;\n const nextLeft = result.left + rect.left;\n\n result = {\n top: nextTop,\n left: nextLeft,\n width: result.width,\n height: result.height,\n bottom: nextTop + result.height,\n right: nextLeft + result.width,\n x: nextLeft,\n y: nextTop,\n };\n }\n }\n\n if (result === null) throw new Error(\"No rects provided\");\n return result;\n}\n\n// Get a bounding client rect for a node, with an\n// offset added to compensate for its border.\nfunction getBoundingClientRectWithBorderOffset(\n node: HTMLElement,\n scale: { scaleX?: number; scaleY?: number } = {},\n): Rect {\n const dimensions = getElementDimensions(node);\n return mergeRectOffsets([\n node.getBoundingClientRect(),\n {\n top: dimensions.borderTop,\n left: dimensions.borderLeft,\n bottom: dimensions.borderBottom,\n right: dimensions.borderRight,\n // This width and height won't get used by mergeRectOffsets (since this\n // is not the first rect in the array), but we set them so that this\n // object typechecks as a Rect.\n width: 0,\n height: 0,\n x: dimensions.borderLeft,\n y: dimensions.borderTop,\n },\n { scaleX: 1, scaleY: 1, ...scale },\n ]);\n}\n\n// Calculate a boundingClientRect for a node relative to boundaryWindow,\n// taking into account any offsets caused by intermediate iframes.\nexport function getNestedBoundingClientRect(\n node: HTMLElement,\n boundaryWindow: Window = window,\n): Rect {\n const ownerIframe = getOwnerIframe(node);\n if (\n !ownerIframe ||\n (\"contentWindow\" in ownerIframe &&\n (ownerIframe as HTMLIFrameElement).contentWindow === boundaryWindow)\n ) {\n return node.getBoundingClientRect().toJSON() as Rect;\n }\n\n const rects: Array = [node.getBoundingClientRect().toJSON() as Rect];\n\n let currentIframe: HTMLElement | null = ownerIframe;\n while (currentIframe) {\n const scale = getScaleFromElementAndAncestors(currentIframe);\n const rect = getBoundingClientRectWithBorderOffset(currentIframe, scale);\n rects.push(scale, rect);\n\n currentIframe = getOwnerIframe(currentIframe);\n if (currentIframe && currentIframe === boundaryWindow.frameElement) {\n // We don't want to calculate iframe offsets upwards beyond\n // the iframe containing the boundaryWindow\n break;\n }\n }\n\n return mergeRectOffsets(rects);\n}\n\nexport function getClientRectForId(\n id: number,\n mirror: Mirror,\n boundaryWindow: Window = window,\n): Rect | null {\n const element = getElementById(id, mirror);\n if (!element) return null;\n\n return getNestedBoundingClientRect(element, boundaryWindow);\n}\n","import type { eventWithTime, mouseInteractionData } from \"@rrweb/types\";\nimport type { Mirror } from \"rrweb-snapshot\";\nimport { first } from \"lodash\";\nimport { BrowserAction } from \"../models/ActionHierarchy\";\nimport { Rect, getClientRectForId } from \"./get_nested_bounding_client_rect\";\n\ntype DocumentDimension = {\n x: number;\n y: number;\n // scale value relative to its parent iframe\n relativeScale: number;\n // scale value relative to the root iframe\n absoluteScale: number;\n};\n\n// taken from https://github.com/rrweb-io/rrweb/blob/e3f9a4d205afe081cfb4c86f4a5c3d2f32fe10cb/src/utils.ts#L553-L580\nfunction getBaseDimension(node: Node, rootIframe: Node): DocumentDimension {\n const frameElement = node.ownerDocument?.defaultView?.frameElement;\n if (!frameElement || frameElement === rootIframe) {\n return {\n x: 0,\n y: 0,\n relativeScale: 1,\n absoluteScale: 1,\n };\n }\n\n const frameDimension = frameElement.getBoundingClientRect();\n const frameBaseDimension = getBaseDimension(frameElement, rootIframe);\n // the iframe element may have a scale transform\n const relativeScale = frameDimension.height / frameElement.clientHeight;\n return {\n x: frameDimension.x * frameBaseDimension.relativeScale + frameBaseDimension.x,\n y: frameDimension.y * frameBaseDimension.relativeScale + frameBaseDimension.y,\n relativeScale,\n absoluteScale: frameBaseDimension.absoluteScale * relativeScale,\n };\n}\n\nfunction keepCorrectionInBounds(\n target: number,\n max: number,\n correctionCalculation: () => number,\n): number {\n const correction = correctionCalculation();\n if (target + correction >= max || target + correction <= 0) {\n return 0;\n }\n return correction;\n}\n\nfunction isPositionInsideBounds(x: number, y: number, bounds: Rect): boolean {\n return bounds && bounds.left <= x && bounds.right >= x && bounds.top <= y && bounds.bottom >= y;\n}\n\nfunction calculateCorrectionToBounds({\n x,\n y,\n bounds,\n padding,\n maxWidth,\n maxHeight,\n}: {\n x: number;\n y: number;\n bounds: Rect;\n padding: number;\n maxWidth: number;\n maxHeight: number;\n}): [number, number] {\n const isMousePositionInsideBounds = isPositionInsideBounds(x, y, bounds);\n\n if (isMousePositionInsideBounds) return [0, 0];\n const maxHorizontalPadding = Math.min(padding, bounds.width / 2);\n const maxVerticalPadding = Math.min(padding, bounds.height / 2);\n const targetBounds = {\n left: Math.min(Math.min(bounds.left + maxHorizontalPadding, bounds.right), maxWidth),\n right: Math.max(Math.max(bounds.right - maxHorizontalPadding, bounds.left), 0),\n top: Math.min(Math.min(bounds.top + maxVerticalPadding, bounds.bottom), maxHeight),\n bottom: Math.max(Math.max(bounds.bottom - maxVerticalPadding, bounds.top), 0),\n };\n\n let correctionX = 0;\n let correctionY = 0;\n\n if (x < targetBounds.left) {\n correctionX = keepCorrectionInBounds(x, maxWidth, () => targetBounds.left - x);\n } else if (x > targetBounds.right) {\n correctionX = keepCorrectionInBounds(x, maxWidth, () => targetBounds.right - x);\n }\n\n if (y < targetBounds.top) {\n correctionY = keepCorrectionInBounds(y, maxHeight, () => targetBounds.top - y);\n } else if (y > targetBounds.bottom) {\n correctionY = keepCorrectionInBounds(y, maxHeight, () => targetBounds.bottom - y);\n }\n\n return [correctionX, correctionY];\n}\n\nfunction calculateCorrectionToSnap({\n x,\n y,\n correctionX,\n correctionY,\n bounds,\n maxWidth,\n maxHeight,\n snapping,\n debug,\n}: {\n x: number;\n y: number;\n correctionX: number;\n correctionY: number;\n bounds: Rect;\n maxWidth: number;\n maxHeight: number;\n snapping: boolean;\n debug: boolean;\n}): [number, number] {\n const mousePositionIsInsideBounds = isPositionInsideBounds(x, y, bounds);\n\n let newCorrectionX = correctionX;\n let newCorrectionY = correctionY;\n\n if (!snapping || !mousePositionIsInsideBounds) return [newCorrectionX, newCorrectionY];\n\n const snapTriggerArea = 20; // area around the snap position that will trigger the snap\n const snapPositions = [1 / 4, 3 / 4, 1 / 2];\n snapPositions.forEach((position) => {\n const potentialCorrectionX = bounds.left + position * bounds.width - x;\n const potentialX = x + potentialCorrectionX;\n if (\n Math.abs(potentialCorrectionX) < snapTriggerArea &&\n potentialX > 0 &&\n potentialX < maxWidth\n ) {\n // eslint-disable-next-line no-console\n if (debug) console.log(`snap to ${position}`);\n newCorrectionX = potentialCorrectionX;\n }\n\n const potentialCorrectionY = bounds.top + position * bounds.height - y;\n const potentialY = y + potentialCorrectionY;\n if (\n Math.abs(potentialCorrectionY) < snapTriggerArea &&\n potentialY > 0 &&\n potentialY < maxHeight\n ) {\n // eslint-disable-next-line no-console\n if (debug) console.log(`snap to ${position}y`);\n newCorrectionY = potentialCorrectionY;\n }\n });\n\n return [newCorrectionX, newCorrectionY];\n}\n\nfunction calculateCorrection({\n x,\n y,\n bounds,\n padding,\n maxWidth,\n maxHeight,\n snapping,\n debugTarget,\n}: {\n x: number;\n y: number;\n bounds: Rect | null;\n padding: number;\n maxWidth: number;\n maxHeight: number;\n snapping: boolean;\n debugTarget: false | HTMLElement;\n}): [number, number] {\n if (!bounds || bounds.width <= 0 || bounds.height <= 0) return [0, 0];\n\n let correctionX = 0;\n let correctionY = 0;\n [correctionX, correctionY] = calculateCorrectionToBounds({\n x,\n y,\n padding,\n bounds,\n maxWidth,\n maxHeight,\n });\n\n [correctionX, correctionY] = calculateCorrectionToSnap({\n x,\n y,\n correctionX,\n correctionY,\n bounds,\n maxWidth,\n maxHeight,\n snapping,\n debug: Boolean(debugTarget),\n });\n\n // paint bounds if needed\n if (debugTarget) {\n let boundsPaintEl: HTMLElement | null = document.querySelector(\".bounds-paint\");\n if (!boundsPaintEl) {\n boundsPaintEl = document.createElement(\"div\");\n boundsPaintEl.classList.add(\"bounds-paint\");\n boundsPaintEl.style.position = \"absolute\";\n boundsPaintEl.style.outline = \"1px solid red\";\n debugTarget.appendChild(boundsPaintEl);\n }\n boundsPaintEl.style.top = `${bounds.top}px`;\n boundsPaintEl.style.left = `${bounds.left}px`;\n boundsPaintEl.style.width = `${bounds.width}px`;\n boundsPaintEl.style.height = `${bounds.height}px`;\n }\n\n return [correctionX, correctionY];\n}\n\n// most of this taken from https://github.com/rrweb-io/rrweb/blob/e3f9a4d205afe081cfb4c86f4a5c3d2f32fe10cb/src/replay/index.ts#L1419-L1433\nexport default function moveMouseTo({\n action,\n mirror,\n iframe,\n mousePosition,\n mouseAnimation,\n snapping = true,\n}: {\n action: BrowserAction;\n mirror: Mirror;\n iframe: HTMLIFrameElement;\n mousePosition: HTMLDivElement;\n mouseAnimation: HTMLDivElement;\n /**\n * TODO: move snapping to the action. eg. `action.snapping`\n */\n snapping?: boolean;\n}): void {\n const debug = false;\n const event = first(action.events);\n if (!event) return;\n\n const { x = -1, y = -1, id } = event.data as mouseInteractionData;\n\n const target = mirror.getNode(id);\n if (!target || x === -1 || y === -1) return;\n\n const base = getBaseDimension(target, iframe);\n /* eslint-disable no-underscore-dangle */\n const _x = x * base.absoluteScale + base.x;\n const _y = y * base.absoluteScale + base.y;\n /* eslint-enable no-underscore-dangle */\n\n if (!iframe.contentWindow) return;\n const bounds = getClientRectForId(id, mirror, iframe.contentWindow);\n\n const iframeWidth = Number(iframe.getAttribute(\"width\"));\n const iframeHeight = Number(iframe.getAttribute(\"height\"));\n\n const [correctionX, correctionY] = calculateCorrection({\n x: _x,\n y: _y,\n bounds,\n padding: 5,\n maxWidth: iframeWidth,\n maxHeight: iframeHeight,\n snapping,\n debugTarget: debug && mousePosition.parentElement,\n });\n\n if (mouseAnimation) {\n // eslint-disable-next-line no-param-reassign\n mouseAnimation.style.left = `${correctionX}px`;\n // eslint-disable-next-line no-param-reassign\n mouseAnimation.style.top = `${correctionY}px`;\n }\n\n if (!mousePosition) return;\n\n // eslint-disable-next-line no-param-reassign\n mousePosition.style.left = `${_x}px`;\n // eslint-disable-next-line no-param-reassign\n mousePosition.style.top = `${_y}px`;\n\n // eslint-disable-next-line no-unused-expressions\n mousePosition.offsetWidth;\n // todo; move the rrweb mouse... to startX and startY coords.\n}\n","export default \"data:audio/mpeg;base64,SUQzBAAAAAAAP1REUkMAAAASAAADMjAxOS0wNC0xMSAxNToxMABUU1NFAAAADwAAA0xhdmY1OS4yNy4xMDAAAAAAAAAAAAAAAP/7QMAAAAAAAAAAAAAAAAAAAAAAAEluZm8AAAAPAAAABQAABMoAUVFRUVFRUVFRUVFRUVFRUVFRUX19fX19fX19fX19fX19fX19fX19qKioqKioqKioqKioqKioqKioqKjU1NTU1NTU1NTU1NTU1NTU1NTU1P//////////////////////////AAAAAExhdmM1OS4zNwAAAAAAAAAAAAAAACQDBgAAAAAAAATKVemqTgAAAAAA//tQxAAACa1k8QCIdsE8r9+UEI65D1IoAFABDnUxjeDgUx3RyWM//8hCCzv/5GQhDv/RPiIiP+iJ6IieiIfdET//+E7u/Chdrv/u7v+W7hwMDAxf7uff3dwMDAxZ8Th/3n0ikRlZngVQGKyYNHNsshvNyAbONmyJvIi53GWDK/P/HEVlOpZvsbJyQ1By+xFJQGMsqJwzbMisJwWzlnu0lxsQ447EVP+dF3w+wsR4+S6OlQ223G3VKAgMY4iJUSZEnwq1pzyrsiIhyQiRDs8naf/7UsQPAAvg4xOAhGApfBuiGIKN6Q3ZERzjzOEVqO9Mld1PcyI5oiJrkZW12sdK4sY2RSCSO8PVx1PwAYqMWIkYGM+czMCTMOdTnrnl6zx7K/GxHGt6CAtKqgRcRDmblW0hdE10VpfachmzyIcjKd8hjwuO4oqJZnMs6qP5V6IhIdPszF6lyeidxxA7CyYyxpiDYg/Qiv1Q+3Qo7OB4fXA2oZg90wB9CFt7yLAApcAM4AAd/+RMAZVDysarqL3Syyiy/r5qp/ml/2YRWj+kgOIb//tSxA4DDBmjDCWYVQFIleGAkJl50UXzezGBrZGXTvY6Eew379+zZrgWgfjAQOAcEMP0PVi32q1LWaktjVe3zk8/Wj1dU73V/WNg/goP4IfgoMePBcDBAgQIMB4yZ07vyG2dDikiq+Qoz/v/ih1baby0y1ffETqanvKxDY//A0K295fb/zX0YLOxW+mlpFD573YLHRoDsK/yoGxIJebK/Acz+p9by/dfzvZOhghhuYmUOJupBwoRo4V7NY3qd6apj8SF7oLK/VjjcqM8lr1fXyn/+1LEEoPKoU0KBYSlSYYz4QDzFFD3lZ/9WnhihquG60aoYwJMW8L0M1Cmo0s0KCnVKL1hW2p8Cf21bgxbj/oLmK1gn/siaEVgfL7bm91YNLv925G6yQpEOZoUWjlqZ+plkRzBRnVC0Db+qKd8KdAtlkKeFhNzKE1CivdXRrmcFOCgkKucgXlUqAlF/U7pWu2RruddVKTR7eYIFhiJfOqahgMECndgygBEABILhRcVVTGUnQzl+NU+eFE+h6r1TIwwrcBLa6wCCleqrNSwwqzDHP/7UsQVAwyFmwykpGBBIIJeyMSYANv//2rNgTZkfrlRKlQxzVV6Kgr2CxoPLJUwxmTl+f+eFQr3wqefmTpVZapUMf5GsZuOVUln2SjA0nQEpABMZjoqEwuSgSBQGSITMx7mGQkaChoexyWgUV6B7eExUyLekXYnxbWRdCTTQFFA8PIjCIS930CiAKwBCqRiGcCiQ0KmQmZqTEFNRTMuMTAwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\"","import silentAudioURL from \"@assets/sounds/silence.mp3\";\nimport { type SendToAppsignal } from \"@modules/appsignal\";\n\nexport function triggerSilentAudioPlayback(sendToAppsignal: SendToAppsignal): void {\n const silentAudio = new Audio();\n silentAudio.preload = \"auto\";\n silentAudio.src = silentAudioURL;\n try {\n const promise = silentAudio.play();\n if (promise !== undefined) {\n promise.catch((error) => {\n console.error(\"triggerSilentAudioPlayback -> silentaudio play was prevented: \", error);\n sendToAppsignal({\n error,\n action: \"triggerSilentAudioPlayback\",\n tags: { triggerSilentAudioPlaybackErrorInfo: \"silentaudio play was prevented\" },\n });\n });\n }\n } catch (error) {\n console.error(\"triggerSilentAudioPlayback -> error playing silentaudio: \", error);\n sendToAppsignal({\n error,\n action: \"triggerSilentAudioPlayback\",\n tags: { triggerSilentAudioPlaybackErrorInfo: \"error playing silentaudio\" },\n });\n }\n}\n\nexport default triggerSilentAudioPlayback;\n","\n\n\n
\n \n
\n \n
\n\n
\n \n \n \n \n
\n
\n
Still processing this action…
\n
\n This step isn’t fully processed yet. Please be patient; it will be playable soon enough.\n Feel free to record more actions or view other actions that have finished\n processing.\n Feel free to view other steps that have finished processing.\n