gotcha-feedback 1.0.9 → 1.0.10
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/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom');var
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom');var Ee="https://gotcha.cx/api/v1";var se={ANONYMOUS_ID:"gotcha_anonymous_id"},I={POSITION:"top-right",SIZE:"md",THEME:"light",SHOW_ON_HOVER:true,TOUCH_BEHAVIOR:"always-visible",SUBMIT_TEXT:"Submit",THANK_YOU_MESSAGE:"Thanks for your feedback!"};var j={MAX_RETRIES:2,BASE_DELAY_MS:500,MAX_DELAY_MS:5e3};function ke(){if(typeof window>"u")return `anon_${crypto.randomUUID()}`;let e=localStorage.getItem(se.ANONYMOUS_ID);if(e)return e;let s=`anon_${crypto.randomUUID()}`;return localStorage.setItem(se.ANONYMOUS_ID,s),s}var Q={maxRetries:j.MAX_RETRIES,baseDelayMs:j.BASE_DELAY_MS,maxDelayMs:j.MAX_DELAY_MS};async function ae(e,s,a=Q,n=false){let u=null;for(let c=0;c<=a.maxRetries;c++){try{n&&c>0&&console.log(`[Gotcha] Retry attempt ${c}/${a.maxRetries}`);let t=await fetch(e,s);if(t.status>=400&&t.status<500&&t.status!==429||t.ok)return t;u=new Error(`HTTP ${t.status}`);}catch(t){u=t,n&&console.log(`[Gotcha] Network error: ${u.message}`);}if(c<a.maxRetries){let t=Math.min(a.baseDelayMs*Math.pow(2,c),a.maxDelayMs);await new Promise(p=>setTimeout(p,t));}}throw u}function Re(e){let{apiKey:s,baseUrl:a=Ee,debug:n=false}=e,u={"Content-Type":"application/json",Authorization:`Bearer ${s}`};async function c(t,p,r){let d=`${a}${p}`,l=crypto.randomUUID();n&&console.log(`[Gotcha] ${t} ${p}`,r);let m=await ae(d,{method:t,headers:{...u,"Idempotency-Key":l},body:r?JSON.stringify(r):void 0},Q,n),o=await m.json();if(!m.ok){let f=o.error;throw n&&console.error(`[Gotcha] Error: ${f.code} - ${f.message}`),f}return n&&console.log("[Gotcha] Response:",o),o}return {async submitResponse(t){let p=t.user||{};p.id||(p.id=ke());let r={...t,user:p,context:{url:typeof window<"u"?window.location.href:void 0,userAgent:typeof navigator<"u"?navigator.userAgent:void 0}};return c("POST","/responses",r)},async checkExistingResponse(t,p){let r=`${a}/responses/check?elementId=${encodeURIComponent(t)}&userId=${encodeURIComponent(p)}`;n&&console.log("[Gotcha] GET /responses/check");let d=await ae(r,{method:"GET",headers:u},Q,n),l=await d.json();if(!d.ok){let m=l.error;throw n&&console.error(`[Gotcha] Error: ${m.code} - ${m.message}`),m}return l.exists?(n&&console.log("[Gotcha] Found existing response:",l.response),l.response):null},async updateResponse(t,p,r){let d=`${a}/responses/${t}${r?`?userId=${encodeURIComponent(r)}`:""}`;n&&console.log(`[Gotcha] PATCH /responses/${t}`,p);let l=await ae(d,{method:"PATCH",headers:u,body:JSON.stringify(p)},Q,n),m=await l.json();if(!l.ok){let o=m.error;throw n&&console.error(`[Gotcha] Error: ${o.code} - ${o.message}`),o}return n&&console.log("[Gotcha] Response updated:",m),m},getBaseUrl(){return a}}}var Ce=react.createContext(null);function Ye({apiKey:e,children:s,baseUrl:a,debug:n=false,disabled:u=false,defaultUser:c={}}){let[t,p]=react.useState(null),r=react.useMemo(()=>Re({apiKey:e,baseUrl:a,debug:n}),[e,a,n]),d=react.useCallback(o=>{p(o);},[]),l=react.useCallback(()=>{p(null);},[]),m=react.useMemo(()=>({client:r,disabled:u,defaultUser:c,debug:n,activeModalId:t,openModal:d,closeModal:l}),[r,u,c,n,t,d,l]);return jsxRuntime.jsx(Ce.Provider,{value:m,children:s})}function _(){let e=react.useContext(Ce);if(!e)throw new Error("useGotchaContext must be used within a GotchaProvider");return e}function Ie(e){let{client:s,defaultUser:a}=_(),[n,u]=react.useState(false),[c,t]=react.useState(false),[p,r]=react.useState(null),[d,l]=react.useState(null);return react.useEffect(()=>{let o=e.user?.id||a?.id;if(!o){l(null);return}let f=false;return (async()=>{t(true);try{let g=await s.checkExistingResponse(e.elementId,o);f||l(g);}catch{f||l(null);}finally{f||t(false);}})(),()=>{f=true;}},[s,e.elementId,e.user?.id,a?.id]),{submit:react.useCallback(async o=>{u(true),r(null);try{let f=e.user?.id||a?.id,i;return d&&f?i=await s.updateResponse(d.id,{content:o.content,title:o.title,rating:o.rating,vote:o.vote,pollSelected:o.pollSelected},f):i=await s.submitResponse({elementId:e.elementId,mode:e.mode,content:o.content,title:o.title,rating:o.rating,vote:o.vote,pollOptions:e.pollOptions,pollSelected:o.pollSelected,experimentId:e.experimentId,variant:e.variant,user:{...a,...e.user}}),e.onSuccess?.(i),i}catch(f){let i=f instanceof Error?f.message:"Something went wrong";throw r(i),e.onError?.(f instanceof Error?f:new Error(i)),f}finally{u(false);}},[s,a,e,d]),isLoading:n,isCheckingExisting:c,error:p,existingResponse:d,isEditing:!!d,clearError:()=>r(null)}}function Z(...e){return e.filter(Boolean).join(" ")}var D=()=>typeof window>"u"?false:"ontouchstart"in window||navigator.maxTouchPoints>0,Me=(e,s)=>{let a={sm:{desktop:24,mobile:32},md:{desktop:32,mobile:36},lg:{desktop:40,mobile:40}};return s?a[e].mobile:a[e].desktop};function Ke(){return typeof window>"u"?"light":window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Pe({size:e,theme:s,customStyles:a,showOnHover:n,touchBehavior:u,onClick:c,isOpen:t,isParentHovered:p=false}){let[r,d]=react.useState(false),[l,m]=react.useState(false),[o,f]=react.useState(Ke);react.useEffect(()=>{d(D());let G=window.matchMedia("(prefers-color-scheme: dark)"),A=O=>f(O.matches?"dark":"light");return G.addEventListener("change",A),()=>G.removeEventListener("change",A)},[]);let i=t?true:!r&&n?p:r&&u==="tap-to-reveal"?l:true,g=()=>{if(r&&u==="tap-to-reveal"&&!l){m(true);return}c();},x=Me(e,r),h=(s==="auto"?o:s)==="dark",v={width:x,height:x,borderRadius:"50%",border:h?"1px solid rgba(255,255,255,0.15)":"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",background:h?"linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.04) 60%, rgba(0,0,0,0.05) 100%)":"linear-gradient(160deg, rgba(255,255,255,0.7) 0%, rgba(200,210,230,0.4) 40%, rgba(180,192,220,0.5) 100%)",backdropFilter:"blur(16px) saturate(170%)",WebkitBackdropFilter:"blur(16px) saturate(170%)",color:h?"rgba(255,255,255,0.88)":"rgba(0,0,0,0.75)",boxShadow:h?["0 4px 14px rgba(0,0,0,0.45)","0 1px 3px rgba(0,0,0,0.35)","inset 0 1px 2px rgba(255,255,255,0.1)","inset 0 -1px 2px rgba(0,0,0,0.08)"].join(", "):["0 3px 12px rgba(0,0,0,0.12)","0 0 1px rgba(0,0,0,0.2)","inset 0 4px 8px rgba(255,255,255,0.95)","inset 0 -4px 8px rgba(0,0,0,0.08)"].join(", "),transition:"all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",opacity:i?1:0,transform:i?"scale(1)":"scale(0.6)",pointerEvents:i?"auto":"none",...a?.button};return jsxRuntime.jsx("button",{type:"button",onClick:g,style:v,className:Z("gotcha-button",t&&"gotcha-button--open"),"aria-label":"Give feedback on this feature","aria-expanded":t,"aria-haspopup":"dialog",children:jsxRuntime.jsx(je,{size:x*.65})})}var Ge="gotcha-carter-one";function Xe(){react.useEffect(()=>{if(document.getElementById(Ge))return;let e=document.createElement("link");e.id=Ge,e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Carter+One&display=swap",document.head.appendChild(e);},[]);}function je({size:e}){return Xe(),jsxRuntime.jsx("span",{"aria-hidden":"true",style:{fontFamily:"'Carter One', cursive",fontSize:e,lineHeight:1,display:"flex",alignItems:"center",justifyContent:"center",marginTop:e*.05,marginRight:e*.05,userSelect:"none"},children:"G"})}function $({size:e=16,color:s="currentColor"}){return jsxRuntime.jsxs("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",style:{animation:"gotcha-spin 0.8s linear infinite"},children:[jsxRuntime.jsx("style",{children:`
|
|
2
2
|
@keyframes gotcha-spin {
|
|
3
3
|
from { transform: rotate(0deg); }
|
|
4
4
|
to { transform: rotate(360deg); }
|
|
5
5
|
}
|
|
6
|
-
`}),jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"10",stroke:s,strokeWidth:"3",strokeOpacity:"0.25"}),jsxRuntime.jsx("path",{d:"M12 2a10 10 0 0 1 10 10",stroke:s,strokeWidth:"3",strokeLinecap:"round"})]})}function _e({theme:e,placeholder:s,submitText:i,isLoading:n,onSubmit:p,customStyles:a,initialValues:t,isEditing:u=false}){let[r,c]=react.useState(t?.content||""),[l,f]=react.useState(t?.rating??null),[o,d]=react.useState(false);react.useEffect(()=>{d(O());},[]),react.useEffect(()=>{t?.content!==void 0&&c(t.content||""),t?.rating!==void 0&&f(t.rating??null);},[t?.content,t?.rating]);let m=e==="dark",h=R=>{R.preventDefault(),!(!r.trim()&&l===null)&&p({content:r.trim()||void 0,rating:l??void 0});},b={width:"100%",padding:o?"12px 14px":"10px 12px",border:`1px solid ${m?"#374151":"#d1d5db"}`,borderRadius:o?8:6,backgroundColor:m?"#374151":"#ffffff",color:m?"#f9fafb":"#111827",fontSize:o?16:14,resize:"vertical",minHeight:o?100:80,fontFamily:"inherit",...a?.input},S={width:"100%",padding:o?"14px 16px":"10px 16px",border:"none",borderRadius:o?8:6,backgroundColor:n?m?"#4b5563":"#9ca3af":"#6366f1",color:"#ffffff",fontSize:o?16:14,fontWeight:500,cursor:n?"not-allowed":"pointer",transition:"background-color 150ms ease",...a?.submitButton};return jsxRuntime.jsxs("form",{onSubmit:h,children:[jsxRuntime.jsx("div",{style:{marginBottom:o?16:12},children:jsxRuntime.jsx(Xe,{value:l,onChange:f,isDark:m,isTouch:o})}),jsxRuntime.jsx("textarea",{value:r,onChange:R=>c(R.target.value),placeholder:s||"Share your thoughts...",style:b,disabled:n,"aria-label":"Your feedback"}),jsxRuntime.jsxs("button",{type:"submit",disabled:n||!r.trim()&&l===null,style:{...S,marginTop:12,opacity:!r.trim()&&l===null?.5:1,display:"flex",alignItems:"center",justifyContent:"center",gap:8},children:[n&&jsxRuntime.jsx(B,{size:o?18:16,color:"#ffffff"}),n?u?"Updating...":"Submitting...":u?"Update":i]})]})}function Xe({value:e,onChange:s,isDark:i,isTouch:n}){let[p,a]=react.useState(null),t=n?32:20,u=n?6:2;return jsxRuntime.jsx("div",{style:{display:"flex",gap:n?8:4},role:"group","aria-label":"Rating",children:[1,2,3,4,5].map(r=>{let c=(p??e??0)>=r;return jsxRuntime.jsx("button",{type:"button",onClick:()=>s(r),onMouseEnter:()=>a(r),onMouseLeave:()=>a(null),"aria-label":`Rate ${r} out of 5`,"aria-pressed":e===r,style:{background:"none",border:"none",cursor:"pointer",padding:u,color:c?"#f59e0b":i?"#4b5563":"#d1d5db",transition:"color 150ms ease"},children:jsxRuntime.jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"currentColor",children:jsxRuntime.jsx("path",{d:"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"})})},r)})})}function Oe({theme:e,isLoading:s,onSubmit:i,initialVote:n,isEditing:p=false}){let[a,t]=react.useState(false),[u,r]=react.useState(n||null),[c,l]=react.useState(n||null);react.useEffect(()=>{t(O());},[]),react.useEffect(()=>{n!==void 0&&(l(n),r(n));},[n]),react.useEffect(()=>{!s&&!p&&r(null);},[s,p]);let f=h=>{r(h),i({vote:h});},o=e==="dark",d=h=>{let b=c===h;return {flex:1,padding:a?"16px 20px":"12px 16px",border:b?`2px solid ${h==="up"?"#22c55e":"#ef4444"}`:`1px solid ${o?"#374151":"#e5e7eb"}`,borderRadius:a?12:8,backgroundColor:b?h==="up"?o?"#14532d":"#dcfce7":o?"#450a0a":"#fee2e2":o?"#374151":"#f9fafb",color:o?"#f9fafb":"#111827",fontSize:a?28:24,cursor:s?"not-allowed":"pointer",transition:"all 150ms ease",display:"flex",alignItems:"center",justifyContent:"center",gap:a?10:8}},m=a?28:24;return jsxRuntime.jsxs("div",{style:{display:"flex",gap:a?16:12},role:"group","aria-label":"Vote",children:[jsxRuntime.jsx("button",{type:"button",onClick:()=>f("up"),disabled:s,style:d("up"),"aria-label":"Vote up - I like this","aria-pressed":c==="up",children:s&&u==="up"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(B,{size:m,color:o?"#f9fafb":"#111827"}),jsxRuntime.jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:p?"Updating...":"Sending..."})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(Qe,{size:m}),jsxRuntime.jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:c==="up"?"Liked":"Like"})]})}),jsxRuntime.jsx("button",{type:"button",onClick:()=>f("down"),disabled:s,style:d("down"),"aria-label":"Vote down - I don't like this","aria-pressed":c==="down",children:s&&u==="down"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(B,{size:m,color:o?"#f9fafb":"#111827"}),jsxRuntime.jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:p?"Updating...":"Sending..."})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(qe,{size:m}),jsxRuntime.jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:c==="down"?"Disliked":"Dislike"})]})})]})}function Qe({size:e=24}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsxRuntime.jsx("path",{d:"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"})})}function qe({size:e=24}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsxRuntime.jsx("path",{d:"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"})})}function fe({mode:e,theme:s,customStyles:i,promptText:n,placeholder:p,submitText:a,thankYouMessage:t,isLoading:u,isSubmitted:r,error:c,existingResponse:l,isEditing:f=false,onSubmit:o,onClose:d,anchorRect:m}){let h=react.useRef(null),b=react.useRef(null),[S,R]=react.useState(false),[g,I]=react.useState(false),[P,Y]=react.useState("light");react.useEffect(()=>{I(window.innerWidth<640);let E=window.matchMedia("(prefers-color-scheme: dark)");Y(E.matches?"dark":"light");let M=x=>Y(x.matches?"dark":"light");return E.addEventListener("change",M),()=>E.removeEventListener("change",M)},[]),react.useEffect(()=>{let E=requestAnimationFrame(()=>R(true));return ()=>cancelAnimationFrame(E)},[]);let D=s==="auto"?P:s,y=D==="dark",U=(m?window.innerHeight-m.bottom:window.innerHeight/2)<280+20;react.useEffect(()=>{let E=h.current;if(!E)return;b.current?.focus();let M=x=>{if(x.key==="Escape"){d();return}if(x.key==="Tab"){let N=E.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),C=N[0],A=N[N.length-1];x.shiftKey&&document.activeElement===C?(x.preventDefault(),A?.focus()):!x.shiftKey&&document.activeElement===A&&(x.preventDefault(),C?.focus());}};return document.addEventListener("keydown",M),()=>document.removeEventListener("keydown",M)},[d]);let L=e==="vote"?"What do you think?":"What do you think of this feature?",F=g?20:16,W=g?{position:"fixed",left:"50%",top:"50%",width:"calc(100vw - 32px)",maxWidth:320,padding:F,borderRadius:12,backgroundColor:y?"#1f2937":"#ffffff",color:y?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.2)",border:`1px solid ${y?"#374151":"#e5e7eb"}`,zIndex:9999,transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:S?1:0,transform:S?"translate(-50%, -50%) scale(1)":"translate(-50%, -50%) scale(0.95)",...i?.modal}:{position:"absolute",left:"50%",width:320,padding:F,borderRadius:8,backgroundColor:y?"#1f2937":"#ffffff",color:y?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.15)",border:`1px solid ${y?"#374151":"#e5e7eb"}`,zIndex:9999,...U?{bottom:"100%",marginBottom:8}:{top:"100%",marginTop:8},transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:S?1:0,transform:S?"translateX(-50%) scale(1) translateY(0)":`translateX(-50%) scale(0.95) translateY(${U?"10px":"-10px"})`,...i?.modal};return jsxRuntime.jsxs("div",{ref:h,role:"dialog","aria-modal":"true","aria-labelledby":"gotcha-modal-title",style:W,className:j("gotcha-modal",y&&"gotcha-modal--dark"),children:[jsxRuntime.jsx("button",{ref:b,type:"button",onClick:d,"aria-label":"Close feedback form",style:{position:"absolute",top:g?12:8,right:g?12:8,width:g?36:24,height:g?36:24,border:"none",background:"none",cursor:"pointer",color:y?"#9ca3af":"#6b7280",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:4},children:jsxRuntime.jsx("svg",{width:g?18:14,height:g?18:14,viewBox:"0 0 14 14",fill:"none",children:jsxRuntime.jsx("path",{d:"M1 1L13 13M1 13L13 1",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}),jsxRuntime.jsx("h2",{id:"gotcha-modal-title",style:{margin:"0 0 12px 0",fontSize:g?16:14,fontWeight:500,paddingRight:g?40:24},children:n||L}),r&&jsxRuntime.jsxs("div",{style:{textAlign:"center",padding:"20px 0",color:y?"#10b981":"#059669"},children:[jsxRuntime.jsx("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",style:{margin:"0 auto 8px"},children:jsxRuntime.jsx("path",{d:"M20 6L9 17L4 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})}),jsxRuntime.jsx("p",{style:{margin:0,fontSize:14},children:t})]}),c&&!r&&jsxRuntime.jsx("div",{style:{padding:8,marginBottom:12,borderRadius:4,backgroundColor:y?"#7f1d1d":"#fef2f2",color:y?"#fecaca":"#dc2626",fontSize:13},children:c}),!r&&jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[e==="feedback"&&jsxRuntime.jsx(_e,{theme:D,placeholder:p,submitText:a,isLoading:u,onSubmit:o,customStyles:i,initialValues:l?{content:l.content,rating:l.rating}:void 0,isEditing:f}),e==="vote"&&jsxRuntime.jsx(Oe,{theme:D,isLoading:u,onSubmit:o,initialVote:l?.vote||void 0,isEditing:f})]}),jsxRuntime.jsxs("div",{"aria-live":"polite",className:"sr-only",style:{position:"absolute",left:-9999},children:[r&&"Thank you! Your feedback has been submitted.",c&&`Error: ${c}`]})]})}function et({elementId:e,user:s,mode:i="feedback",experimentId:n,variant:p,options:a,allowMultiple:t=false,showResults:u=true,position:r=T.POSITION,size:c=T.SIZE,theme:l=T.THEME,customStyles:f,visible:o=true,showOnHover:d=T.SHOW_ON_HOVER,touchBehavior:m=T.TOUCH_BEHAVIOR,promptText:h,placeholder:b,submitText:S=T.SUBMIT_TEXT,thankYouMessage:R=T.THANK_YOU_MESSAGE,onSubmit:g,onOpen:I,onClose:P,onError:Y}){let{disabled:D,activeModalId:y,openModal:ne,closeModal:V}=_(),[U,L]=react.useState(false),[F,W]=react.useState(false),[E,M]=react.useState(null),[x,N]=react.useState(false),C=react.useRef(null);react.useEffect(()=>{N(window.innerWidth<640);},[]);let A=y===e;react.useEffect(()=>{if(!d)return;let k=C.current;if(!k)return;let z=k.parentElement;if(!z)return;let Se=()=>W(true),Ee=()=>W(false);return z.addEventListener("mouseenter",Se),z.addEventListener("mouseleave",Ee),()=>{z.removeEventListener("mouseenter",Se),z.removeEventListener("mouseleave",Ee);}},[d]);let{submit:he,isLoading:ge,error:be,existingResponse:ve,isEditing:K}=Ie({elementId:e,mode:i,experimentId:n,variant:p,pollOptions:a,user:s,onSuccess:k=>{L(true),g?.(k),setTimeout(()=>{V(),L(false);},2500);},onError:k=>{Y?.(k);}}),Le=react.useCallback(()=>{C.current&&M(C.current.getBoundingClientRect()),ne(e),I?.();},[e,ne,I]),re=react.useCallback(()=>{V(),L(false),P?.();},[V,P]),ye=react.useCallback(k=>{he(k);},[he]);return D||!o?null:jsxRuntime.jsxs("div",{ref:C,style:{...{"top-right":{position:"absolute",top:0,right:0,transform:"translate(50%, -50%)"},"top-left":{position:"absolute",top:0,left:0,transform:"translate(-50%, -50%)"},"bottom-right":{position:"absolute",bottom:0,right:0,transform:"translate(50%, 50%)"},"bottom-left":{position:"absolute",bottom:0,left:0,transform:"translate(-50%, 50%)"},inline:{position:"relative",display:"inline-flex"}}[r],zIndex:A?1e4:"auto"},className:"gotcha-container","data-gotcha-element":e,children:[jsxRuntime.jsx(Ce,{size:c,theme:l,customStyles:f,showOnHover:d,touchBehavior:m,onClick:Le,isOpen:A,isParentHovered:F}),A&&!x&&jsxRuntime.jsx(fe,{mode:i,theme:l,customStyles:f,promptText:h,placeholder:b,submitText:S,thankYouMessage:K?"Your feedback has been updated!":R,isLoading:ge,isSubmitted:U,error:be,existingResponse:ve,isEditing:K,onSubmit:ye,onClose:re,anchorRect:E||void 0}),A&&x&&reactDom.createPortal(jsxRuntime.jsx("div",{style:{position:"fixed",inset:0,zIndex:99999,backgroundColor:"rgba(0, 0, 0, 0.3)"},onClick:re,"aria-hidden":"true",children:jsxRuntime.jsx("div",{onClick:k=>k.stopPropagation(),children:jsxRuntime.jsx(fe,{mode:i,theme:l,customStyles:f,promptText:h,placeholder:b,submitText:S,thankYouMessage:K?"Your feedback has been updated!":R,isLoading:ge,isSubmitted:U,error:be,existingResponse:ve,isEditing:K,onSubmit:ye,onClose:re,anchorRect:E||void 0})})}),document.body)]})}function ot(){let{client:e,disabled:s,defaultUser:i,debug:n}=_();return {client:e,disabled:s,defaultUser:i,debug:n,submitFeedback:e.submitResponse.bind(e)}}exports.Gotcha=et;exports.GotchaProvider=He;exports.useGotcha=ot;//# sourceMappingURL=index.js.map
|
|
6
|
+
@keyframes gotcha-dash {
|
|
7
|
+
0% { stroke-dasharray: 1, 62; stroke-dashoffset: 0; }
|
|
8
|
+
50% { stroke-dasharray: 40, 62; stroke-dashoffset: -12; }
|
|
9
|
+
100% { stroke-dasharray: 1, 62; stroke-dashoffset: -62; }
|
|
10
|
+
}
|
|
11
|
+
`}),jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"10",stroke:s,strokeWidth:"2",strokeOpacity:"0.12"}),jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"10",stroke:s,strokeWidth:"2",strokeLinecap:"round",style:{animation:"gotcha-dash 1.2s ease-in-out infinite"}})]})}function De({theme:e,placeholder:s,submitText:a,isLoading:n,onSubmit:u,customStyles:c,initialValues:t,isEditing:p=false}){let[r,d]=react.useState(t?.content||""),[l,m]=react.useState(t?.rating??null),[o,f]=react.useState(false);react.useEffect(()=>{f(D());},[]),react.useEffect(()=>{t?.content!==void 0&&d(t.content||""),t?.rating!==void 0&&m(t.rating??null);},[t?.content,t?.rating]);let i=e==="dark",g=h=>{h.preventDefault(),!(!r.trim()&&l===null)&&u({content:r.trim()||void 0,rating:l??void 0});},x={width:"100%",padding:o?"12px 14px":"10px 12px",border:`1px solid ${i?"rgba(255,255,255,0.08)":"#e2e8f0"}`,borderRadius:8,backgroundColor:i?"rgba(55,65,81,0.5)":"#fafbfc",color:i?"#f9fafb":"#111827",fontSize:o?16:14,resize:"vertical",minHeight:o?100:80,fontFamily:"inherit",outline:"none",transition:"border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1)",lineHeight:1.5,...c?.input},E={width:"100%",padding:o?"14px 16px":"10px 16px",border:"none",borderRadius:8,backgroundColor:i?"#e2e8f0":"#1e293b",color:i?"#1e293b":"#ffffff",fontSize:o?16:14,fontWeight:500,cursor:n?"not-allowed":"pointer",transition:"all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",letterSpacing:"0.01em",...c?.submitButton};return jsxRuntime.jsxs("form",{onSubmit:g,children:[jsxRuntime.jsx("div",{style:{marginBottom:o?16:12},children:jsxRuntime.jsx(qe,{value:l,onChange:m,isDark:i,isTouch:o})}),jsxRuntime.jsx("textarea",{value:r,onChange:h=>d(h.target.value),placeholder:s||"Share your thoughts...",style:x,disabled:n,"aria-label":"Your feedback",onFocus:h=>{h.currentTarget.style.borderColor="#1e293b",h.currentTarget.style.boxShadow="0 0 0 2px rgba(30,41,59,0.15)",h.currentTarget.style.backgroundColor=i?"rgba(55,65,81,0.7)":"#ffffff";},onBlur:h=>{h.currentTarget.style.borderColor=i?"rgba(255,255,255,0.08)":"#e2e8f0",h.currentTarget.style.boxShadow="none",h.currentTarget.style.backgroundColor=i?"rgba(55,65,81,0.5)":"#fafbfc";}}),jsxRuntime.jsxs("button",{type:"submit",disabled:n||!r.trim()&&l===null,style:{...E,marginTop:12,opacity:n?.8:1,backgroundColor:!r.trim()&&l===null?i?"#374151":"#e2e8f0":i?"#e2e8f0":"#1e293b",color:!r.trim()&&l===null?i?"#6b7280":"#94a3b8":i?"#1e293b":"#ffffff",display:"flex",alignItems:"center",justifyContent:"center",gap:8},onMouseEnter:h=>{h.currentTarget.disabled||(h.currentTarget.style.backgroundColor=i?"#cbd5e1":"#334155");},onMouseLeave:h=>{h.currentTarget.disabled||(h.currentTarget.style.backgroundColor=i?"#e2e8f0":"#1e293b");},children:[n&&jsxRuntime.jsx($,{size:o?18:16,color:i?"#1e293b":"#ffffff"}),n?p?"Updating...":"Submitting...":p?"Update":a]})]})}function qe({value:e,onChange:s,isDark:a,isTouch:n}){let[u,c]=react.useState(null),t=n?28:18,p=n?6:3;return jsxRuntime.jsx("div",{style:{display:"flex",gap:n?6:2},role:"group","aria-label":"Rating",children:[1,2,3,4,5].map(r=>{let d=(u??e??0)>=r;return jsxRuntime.jsx("button",{type:"button",onClick:()=>s(r),onMouseEnter:()=>c(r),onMouseLeave:()=>c(null),"aria-label":`Rate ${r} out of 5`,"aria-pressed":e===r,style:{background:"none",border:"none",cursor:"pointer",padding:p,color:d?"#f59e0b":a?"rgba(255,255,255,0.12)":"#e2e8f0",transition:"color 0.15s cubic-bezier(0.4, 0, 0.2, 1), transform 0.15s cubic-bezier(0.4, 0, 0.2, 1)",transform:u!==null&&u>=r?"scale(1.1)":"scale(1)"},children:jsxRuntime.jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"currentColor",children:jsxRuntime.jsx("path",{d:"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"})})},r)})})}function Le({theme:e,isLoading:s,onSubmit:a,initialVote:n,isEditing:u=false}){let[c,t]=react.useState(false),[p,r]=react.useState(n||null),[d,l]=react.useState(n||null);react.useEffect(()=>{t(D());},[]),react.useEffect(()=>{n!==void 0&&(l(n),r(n));},[n]),react.useEffect(()=>{!s&&!u&&r(null);},[s,u]);let m=g=>{r(g),a({vote:g});},o=e==="dark",f=g=>{let x=d===g;return {flex:1,minWidth:0,overflow:"hidden",padding:c?"14px 18px":"10px 14px",border:`1px solid ${x?g==="up"?o?"rgba(16,185,129,0.3)":"rgba(16,185,129,0.25)":o?"rgba(239,68,68,0.3)":"rgba(239,68,68,0.25)":o?"rgba(255,255,255,0.08)":"#e2e8f0"}`,borderRadius:c?10:8,backgroundColor:x?g==="up"?o?"rgba(16,185,129,0.08)":"rgba(16,185,129,0.06)":o?"rgba(239,68,68,0.08)":"rgba(239,68,68,0.06)":o?"rgba(55,65,81,0.5)":"#fafbfc",color:x?g==="up"?"#10b981":"#ef4444":o?"#d1d5db":"#64748b",fontSize:c?28:24,cursor:s?"not-allowed":"pointer",transition:"background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s, box-shadow 0.2s",display:"flex",alignItems:"center",justifyContent:"center",gap:c?10:8}},i=c?24:20;return jsxRuntime.jsxs("div",{style:{display:"flex",gap:c?12:10},role:"group","aria-label":"Vote",children:[jsxRuntime.jsx("button",{type:"button",onClick:()=>m("up"),disabled:s,style:f("up"),"aria-label":"Vote up - I like this","aria-pressed":d==="up",onMouseEnter:g=>{s||(g.currentTarget.style.transform="translateY(-1px)",g.currentTarget.style.boxShadow="0 2px 8px rgba(0,0,0,0.06)");},onMouseLeave:g=>{g.currentTarget.style.transform="translateY(0)",g.currentTarget.style.boxShadow="none";},children:s&&p==="up"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx($,{size:i,color:o?"#f9fafb":"#111827"}),jsxRuntime.jsx("span",{style:{fontSize:c?15:13,fontWeight:500,letterSpacing:"0.01em"},children:u?"Updating...":"Sending..."})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(Ze,{size:i}),jsxRuntime.jsx("span",{style:{fontSize:c?15:13,fontWeight:500,letterSpacing:"0.01em"},children:d==="up"?"Liked":"Like"})]})}),jsxRuntime.jsx("button",{type:"button",onClick:()=>m("down"),disabled:s,style:f("down"),"aria-label":"Vote down - I don't like this","aria-pressed":d==="down",onMouseEnter:g=>{s||(g.currentTarget.style.transform="translateY(-1px)",g.currentTarget.style.boxShadow="0 2px 8px rgba(0,0,0,0.06)");},onMouseLeave:g=>{g.currentTarget.style.transform="translateY(0)",g.currentTarget.style.boxShadow="none";},children:s&&p==="down"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx($,{size:i,color:o?"#f9fafb":"#111827"}),jsxRuntime.jsx("span",{style:{fontSize:c?15:13,fontWeight:500,letterSpacing:"0.01em"},children:u?"Updating...":"Sending..."})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(Je,{size:i}),jsxRuntime.jsx("span",{style:{fontSize:c?15:13,fontWeight:500,letterSpacing:"0.01em"},children:d==="down"?"Disliked":"Dislike"})]})})]})}function Ze({size:e=24}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"})})}function Je({size:e=24}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"})})}function ge({mode:e,theme:s,customStyles:a,promptText:n,placeholder:u,submitText:c,thankYouMessage:t,isLoading:p,isSubmitted:r,error:d,existingResponse:l,isEditing:m=false,onSubmit:o,onClose:f,anchorRect:i}){let g=react.useRef(null),x=react.useRef(null),[E,h]=react.useState(false),[v,G]=react.useState(false),[A,O]=react.useState("light");react.useEffect(()=>{G(window.innerWidth<640);let y=window.matchMedia("(prefers-color-scheme: dark)");O(y.matches?"dark":"light");let w=R=>O(R.matches?"dark":"light");return y.addEventListener("change",w),()=>y.removeEventListener("change",w)},[]),react.useEffect(()=>{let y=requestAnimationFrame(()=>h(true));return ()=>cancelAnimationFrame(y)},[]);let L=s==="auto"?A:s,b=L==="dark",U=(i?window.innerHeight-i.bottom:window.innerHeight/2)<280+20;react.useEffect(()=>{let y=g.current;if(!y)return;x.current?.focus();let w=R=>{if(R.key==="Escape"){f();return}if(R.key==="Tab"){let C=y.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),P=C[0],B=C[C.length-1];R.shiftKey&&document.activeElement===P?(R.preventDefault(),B?.focus()):!R.shiftKey&&document.activeElement===B&&(R.preventDefault(),P?.focus());}};return document.addEventListener("keydown",w),()=>document.removeEventListener("keydown",w)},[f]);let z=e==="vote"?"What do you think?":"What do you think of this feature?",W=v?20:16,N=b?"0 1px 2px rgba(0,0,0,0.2), 0 4px 12px rgba(0,0,0,0.3), 0 12px 32px rgba(0,0,0,0.2)":"0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06), 0 12px 32px rgba(0,0,0,0.06)",K=v?{position:"fixed",left:"50%",top:"50%",width:"calc(100vw - 32px)",maxWidth:320,padding:W,borderRadius:12,backgroundColor:b?"#1f2937":"#ffffff",color:b?"#f9fafb":"#111827",boxShadow:N,border:`1px solid ${b?"rgba(255,255,255,0.06)":"rgba(0,0,0,0.06)"}`,zIndex:9999,transition:"opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)",opacity:E?1:0,transform:E?"translate(-50%, -50%) scale(1)":"translate(-50%, -50%) scale(0.96)",...a?.modal}:{position:"absolute",left:"50%",width:320,padding:W,borderRadius:10,backgroundColor:b?"#1f2937":"#ffffff",color:b?"#f9fafb":"#111827",boxShadow:N,border:`1px solid ${b?"rgba(255,255,255,0.06)":"rgba(0,0,0,0.06)"}`,zIndex:9999,...U?{bottom:"100%",marginBottom:8}:{top:"100%",marginTop:8},transition:"opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)",opacity:E?1:0,transform:E?"translateX(-50%) scale(1) translateY(0)":`translateX(-50%) scale(0.96) translateY(${U?"6px":"-6px"})`,...a?.modal};return jsxRuntime.jsxs("div",{ref:g,role:"dialog","aria-modal":"true","aria-labelledby":"gotcha-modal-title",style:K,className:Z("gotcha-modal",b&&"gotcha-modal--dark"),children:[jsxRuntime.jsx("button",{ref:x,type:"button",onClick:f,"aria-label":"Close feedback form",style:{position:"absolute",top:v?12:8,right:v?12:8,width:v?36:28,height:v?36:28,border:"none",background:"transparent",cursor:"pointer",color:b?"#6b7280":"#9ca3af",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:6,transition:"all 0.15s cubic-bezier(0.4, 0, 0.2, 1)"},onMouseEnter:y=>{y.currentTarget.style.backgroundColor=b?"rgba(255,255,255,0.06)":"rgba(0,0,0,0.04)",y.currentTarget.style.color=b?"#9ca3af":"#6b7280";},onMouseLeave:y=>{y.currentTarget.style.backgroundColor="transparent",y.currentTarget.style.color=b?"#6b7280":"#9ca3af";},children:jsxRuntime.jsx("svg",{width:v?16:12,height:v?16:12,viewBox:"0 0 14 14",fill:"none",children:jsxRuntime.jsx("path",{d:"M1 1L13 13M1 13L13 1",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})})}),jsxRuntime.jsx("h2",{id:"gotcha-modal-title",style:{margin:"0 0 16px 0",fontSize:v?16:14,fontWeight:600,paddingRight:v?40:32,letterSpacing:"-0.01em",lineHeight:1.4},children:n||z}),r&&jsxRuntime.jsxs("div",{style:{textAlign:"center",padding:"24px 0",color:b?"#10b981":"#059669"},children:[jsxRuntime.jsx("div",{style:{width:44,height:44,borderRadius:"50%",backgroundColor:b?"rgba(16,185,129,0.1)":"rgba(5,150,105,0.08)",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 12px"},children:jsxRuntime.jsx("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"none",children:jsxRuntime.jsx("path",{d:"M20 6L9 17L4 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsxRuntime.jsx("p",{style:{margin:0,fontSize:13,fontWeight:500,color:b?"#d1d5db":"#374151"},children:t})]}),d&&!r&&jsxRuntime.jsx("div",{style:{padding:"8px 10px",marginBottom:12,borderRadius:8,backgroundColor:b?"rgba(127,29,29,0.3)":"#fef2f2",border:`1px solid ${b?"rgba(254,202,202,0.1)":"rgba(220,38,38,0.1)"}`,color:b?"#fecaca":"#dc2626",fontSize:13,lineHeight:1.4},children:d}),!r&&jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[e==="feedback"&&jsxRuntime.jsx(De,{theme:L,placeholder:u,submitText:c,isLoading:p,onSubmit:o,customStyles:a,initialValues:l?{content:l.content,rating:l.rating}:void 0,isEditing:m}),e==="vote"&&jsxRuntime.jsx(Le,{theme:L,isLoading:p,onSubmit:o,initialVote:l?.vote||void 0,isEditing:m})]}),jsxRuntime.jsxs("div",{"aria-live":"polite",className:"sr-only",style:{position:"absolute",left:-9999},children:[r&&"Thank you! Your feedback has been submitted.",d&&`Error: ${d}`]})]})}function nt({elementId:e,user:s,mode:a="feedback",experimentId:n,variant:u,options:c,allowMultiple:t=false,showResults:p=true,position:r=I.POSITION,size:d=I.SIZE,theme:l=I.THEME,customStyles:m,visible:o=true,showOnHover:f=I.SHOW_ON_HOVER,touchBehavior:i=I.TOUCH_BEHAVIOR,promptText:g,placeholder:x,submitText:E=I.SUBMIT_TEXT,thankYouMessage:h=I.THANK_YOU_MESSAGE,onSubmit:v,onOpen:G,onClose:A,onError:O}){let{disabled:L,activeModalId:b,openModal:ne,closeModal:V}=_(),[U,z]=react.useState(false),[W,N]=react.useState(false),[K,y]=react.useState(null),[w,R]=react.useState(false),C=react.useRef(null);react.useEffect(()=>{R(window.innerWidth<640);},[]);let P=b===e;react.useEffect(()=>{if(!f)return;let T=C.current;if(!T)return;let H=T.parentElement;if(!H)return;let ve=()=>N(true),Se=()=>N(false);return H.addEventListener("mouseenter",ve),H.addEventListener("mouseleave",Se),()=>{H.removeEventListener("mouseenter",ve),H.removeEventListener("mouseleave",Se);}},[f]);let{submit:B,isLoading:he,error:be,existingResponse:ye,isEditing:X}=Ie({elementId:e,mode:a,experimentId:n,variant:u,pollOptions:c,user:s,onSuccess:T=>{z(true),v?.(T),setTimeout(()=>{V(),z(false);},2500);},onError:T=>{O?.(T);}}),Ne=react.useCallback(()=>{C.current&&y(C.current.getBoundingClientRect()),ne(e),G?.();},[e,ne,G]),re=react.useCallback(()=>{V(),z(false),A?.();},[V,A]),xe=react.useCallback(T=>{B(T);},[B]);return L||!o?null:jsxRuntime.jsxs("div",{ref:C,style:{...{"top-right":{position:"absolute",top:0,right:0,transform:"translate(50%, -50%)"},"top-left":{position:"absolute",top:0,left:0,transform:"translate(-50%, -50%)"},"bottom-right":{position:"absolute",bottom:0,right:0,transform:"translate(50%, 50%)"},"bottom-left":{position:"absolute",bottom:0,left:0,transform:"translate(-50%, 50%)"},inline:{position:"relative",display:"inline-flex"}}[r],zIndex:P?1e4:"auto"},className:"gotcha-container","data-gotcha-element":e,children:[jsxRuntime.jsx(Pe,{size:d,theme:l,customStyles:m,showOnHover:f,touchBehavior:i,onClick:Ne,isOpen:P,isParentHovered:W}),P&&!w&&jsxRuntime.jsx(ge,{mode:a,theme:l,customStyles:m,promptText:g,placeholder:x,submitText:E,thankYouMessage:X?"Your feedback has been updated!":h,isLoading:he,isSubmitted:U,error:be,existingResponse:ye,isEditing:X,onSubmit:xe,onClose:re,anchorRect:K||void 0}),P&&w&&reactDom.createPortal(jsxRuntime.jsx("div",{style:{position:"fixed",inset:0,zIndex:99999,backgroundColor:"rgba(0, 0, 0, 0.3)"},onClick:re,"aria-hidden":"true",children:jsxRuntime.jsx("div",{onClick:T=>T.stopPropagation(),children:jsxRuntime.jsx(ge,{mode:a,theme:l,customStyles:m,promptText:g,placeholder:x,submitText:E,thankYouMessage:X?"Your feedback has been updated!":h,isLoading:he,isSubmitted:U,error:be,existingResponse:ye,isEditing:X,onSubmit:xe,onClose:re,anchorRect:K||void 0})})}),document.body)]})}function st(){let{client:e,disabled:s,defaultUser:a,debug:n}=_();return {client:e,disabled:s,defaultUser:a,debug:n,submitFeedback:e.submitResponse.bind(e)}}exports.Gotcha=nt;exports.GotchaProvider=Ye;exports.useGotcha=st;//# sourceMappingURL=index.js.map
|
|
7
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/utils/anonymous.ts","../src/api/client.ts","../src/components/GotchaProvider.tsx","../src/hooks/useSubmit.ts","../src/utils/cn.ts","../src/utils/device.ts","../src/components/GotchaButton.tsx","../src/components/Spinner.tsx","../src/components/modes/FeedbackMode.tsx","../src/components/modes/VoteMode.tsx","../src/components/GotchaModal.tsx","../src/components/Gotcha.tsx","../src/hooks/useGotcha.ts"],"names":["API_BASE_URL","STORAGE_KEYS","DEFAULTS","RETRY_CONFIG","getAnonymousId","stored","id","DEFAULT_RETRY_CONFIG","fetchWithRetry","url","options","config","debug","lastError","attempt","response","error","delay","resolve","createApiClient","apiKey","baseUrl","headers","request","method","endpoint","body","idempotencyKey","data","payload","user","fullPayload","elementId","userId","GotchaContext","createContext","GotchaProvider","children","disabled","defaultUser","activeModalId","setActiveModalId","useState","client","useMemo","openModal","useCallback","closeModal","value","jsx","useGotchaContext","context","useContext","useSubmit","isLoading","setIsLoading","isCheckingExisting","setIsCheckingExisting","setError","existingResponse","setExistingResponse","useEffect","cancelled","existing","err","errorMessage","cn","classes","isTouchDevice","getResponsiveSize","size","isTouch","sizes","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","darkQuery","handler","e","shouldShow","handleClick","buttonSize","resolvedTheme","baseStyles","GotchaIcon","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","initialValues","isEditing","content","setContent","rating","setRating","isDark","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","initialVote","activeVote","setActiveVote","previousVote","setPreviousVote","handleVote","vote","getButtonStyles","voteType","isSelected","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","modalStyles","Gotcha","experimentId","variant","allowMultiple","showResults","position","visible","onOpen","onError","setIsSubmitted","setIsParentHovered","setAnchorRect","containerRef","container","parent","handleMouseEnter","handleMouseLeave","submit","handleOpen","handleClose","createPortal","useGotcha"],"mappings":"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","file":"index.js","sourcesContent":["// API URL\nexport const API_BASE_URL = 'https://gotcha.cx/api/v1';\n\n// Error codes\nexport const ERROR_CODES = {\n INVALID_API_KEY: 'INVALID_API_KEY',\n ORIGIN_NOT_ALLOWED: 'ORIGIN_NOT_ALLOWED',\n RATE_LIMITED: 'RATE_LIMITED',\n QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',\n INVALID_REQUEST: 'INVALID_REQUEST',\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n} as const;\n\n// Local storage keys\nexport const STORAGE_KEYS = {\n ANONYMOUS_ID: 'gotcha_anonymous_id',\n OFFLINE_QUEUE: 'gotcha_offline_queue',\n} as const;\n\n// Default values\nexport const DEFAULTS = {\n POSITION: 'top-right' as const,\n SIZE: 'md' as const,\n THEME: 'light' as const,\n SHOW_ON_HOVER: true,\n TOUCH_BEHAVIOR: 'always-visible' as const,\n SUBMIT_TEXT: 'Submit',\n THANK_YOU_MESSAGE: 'Thanks for your feedback!',\n} as const;\n\n// Size mappings (desktop/mobile in pixels)\nexport const SIZE_MAP = {\n sm: { desktop: 24, mobile: 44 },\n md: { desktop: 32, mobile: 44 },\n lg: { desktop: 40, mobile: 48 },\n} as const;\n\n// Retry config\nexport const RETRY_CONFIG = {\n MAX_RETRIES: 2,\n BASE_DELAY_MS: 500,\n MAX_DELAY_MS: 5000,\n} as const;\n","import { STORAGE_KEYS } from '../constants';\n\n/**\n * Get or create an anonymous user ID\n * Stored in localStorage for consistency across sessions\n */\nexport function getAnonymousId(): string {\n if (typeof window === 'undefined') {\n // SSR fallback - generate but don't persist\n return `anon_${crypto.randomUUID()}`;\n }\n\n const stored = localStorage.getItem(STORAGE_KEYS.ANONYMOUS_ID);\n if (stored) return stored;\n\n const id = `anon_${crypto.randomUUID()}`;\n localStorage.setItem(STORAGE_KEYS.ANONYMOUS_ID, id);\n return id;\n}\n\n/**\n * Clear the anonymous ID (useful for testing)\n */\nexport function clearAnonymousId(): void {\n if (typeof window !== 'undefined') {\n localStorage.removeItem(STORAGE_KEYS.ANONYMOUS_ID);\n }\n}\n","import { API_BASE_URL, RETRY_CONFIG } from '../constants';\nimport { SubmitResponsePayload, GotchaResponse, GotchaError, ExistingResponse, VoteType } from '../types';\nimport { getAnonymousId } from '../utils/anonymous';\n\ninterface ApiClientConfig {\n apiKey: string;\n baseUrl?: string;\n debug?: boolean;\n}\n\ninterface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: RETRY_CONFIG.MAX_RETRIES,\n baseDelayMs: RETRY_CONFIG.BASE_DELAY_MS,\n maxDelayMs: RETRY_CONFIG.MAX_DELAY_MS,\n};\n\n/**\n * Fetch with automatic retry and exponential backoff\n */\nasync function fetchWithRetry(\n url: string,\n options: RequestInit,\n config: RetryConfig = DEFAULT_RETRY_CONFIG,\n debug: boolean = false\n): Promise<Response> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n if (debug && attempt > 0) {\n console.log(`[Gotcha] Retry attempt ${attempt}/${config.maxRetries}`);\n }\n\n const response = await fetch(url, options);\n\n // Don't retry client errors (4xx) except 429 (rate limit)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return response;\n }\n\n // Success - return immediately\n if (response.ok) {\n return response;\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (error) {\n // Network error - retry\n lastError = error as Error;\n if (debug) {\n console.log(`[Gotcha] Network error: ${lastError.message}`);\n }\n }\n\n // Don't delay after last attempt\n if (attempt < config.maxRetries) {\n const delay = Math.min(\n config.baseDelayMs * Math.pow(2, attempt),\n config.maxDelayMs\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n\nexport function createApiClient(config: ApiClientConfig) {\n const { apiKey, baseUrl = API_BASE_URL, debug = false } = config;\n\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n };\n\n async function request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${baseUrl}${endpoint}`;\n const idempotencyKey = crypto.randomUUID();\n\n if (debug) {\n console.log(`[Gotcha] ${method} ${endpoint}`, body);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method,\n headers: {\n ...headers,\n 'Idempotency-Key': idempotencyKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response:`, data);\n }\n\n return data as T;\n }\n\n return {\n /**\n * Submit a response (feedback, vote, etc.)\n */\n async submitResponse(\n payload: Omit<SubmitResponsePayload, 'context'>\n ): Promise<GotchaResponse> {\n // Ensure user has an ID (anonymous if not provided)\n const user = payload.user || {};\n if (!user.id) {\n user.id = getAnonymousId();\n }\n\n const fullPayload: SubmitResponsePayload = {\n ...payload,\n user,\n context: {\n url: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n };\n\n return request<GotchaResponse>('POST', '/responses', fullPayload);\n },\n\n /**\n * Check if a user has an existing response for an element\n */\n async checkExistingResponse(\n elementId: string,\n userId: string\n ): Promise<ExistingResponse | null> {\n const url = `${baseUrl}/responses/check?elementId=${encodeURIComponent(elementId)}&userId=${encodeURIComponent(userId)}`;\n\n if (debug) {\n console.log(`[Gotcha] GET /responses/check`);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'GET',\n headers,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (data.exists) {\n if (debug) {\n console.log(`[Gotcha] Found existing response:`, data.response);\n }\n return data.response as ExistingResponse;\n }\n\n return null;\n },\n\n /**\n * Update an existing response\n */\n async updateResponse(\n id: string,\n payload: {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n },\n userId?: string\n ): Promise<GotchaResponse> {\n const url = `${baseUrl}/responses/${id}${userId ? `?userId=${encodeURIComponent(userId)}` : ''}`;\n\n if (debug) {\n console.log(`[Gotcha] PATCH /responses/${id}`, payload);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'PATCH',\n headers,\n body: JSON.stringify(payload),\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response updated:`, data);\n }\n\n return data as GotchaResponse;\n },\n\n /**\n * Get the base URL (for debugging)\n */\n getBaseUrl(): string {\n return baseUrl;\n },\n };\n}\n\nexport type ApiClient = ReturnType<typeof createApiClient>;\n","import React, { createContext, useContext, useMemo, useState, useCallback } from 'react';\nimport { createApiClient, ApiClient } from '../api/client';\nimport { GotchaUser } from '../types';\n\nexport interface GotchaProviderProps {\n /** Your Gotcha API key */\n apiKey: string;\n /** React children */\n children: React.ReactNode;\n /** Override the API base URL (for testing/staging) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /** Disable all Gotcha buttons globally */\n disabled?: boolean;\n /** Default user metadata applied to all submissions */\n defaultUser?: GotchaUser;\n}\n\nexport interface GotchaContextValue {\n client: ApiClient;\n disabled: boolean;\n defaultUser: GotchaUser;\n debug: boolean;\n // Modal management - only one open at a time\n activeModalId: string | null;\n openModal: (elementId: string) => void;\n closeModal: () => void;\n}\n\nconst GotchaContext = createContext<GotchaContextValue | null>(null);\n\nexport function GotchaProvider({\n apiKey,\n children,\n baseUrl,\n debug = false,\n disabled = false,\n defaultUser = {},\n}: GotchaProviderProps) {\n const [activeModalId, setActiveModalId] = useState<string | null>(null);\n\n const client = useMemo(\n () => createApiClient({ apiKey, baseUrl, debug }),\n [apiKey, baseUrl, debug]\n );\n\n const openModal = useCallback((elementId: string) => {\n setActiveModalId(elementId);\n }, []);\n\n const closeModal = useCallback(() => {\n setActiveModalId(null);\n }, []);\n\n const value: GotchaContextValue = useMemo(\n () => ({\n client,\n disabled,\n defaultUser,\n debug,\n activeModalId,\n openModal,\n closeModal,\n }),\n [client, disabled, defaultUser, debug, activeModalId, openModal, closeModal]\n );\n\n return (\n <GotchaContext.Provider value={value}>{children}</GotchaContext.Provider>\n );\n}\n\nexport function useGotchaContext(): GotchaContextValue {\n const context = useContext(GotchaContext);\n if (!context) {\n throw new Error('useGotchaContext must be used within a GotchaProvider');\n }\n return context;\n}\n","import { useState, useCallback, useEffect } from 'react';\nimport { useGotchaContext } from '../components/GotchaProvider';\nimport { ResponseMode, GotchaUser, GotchaResponse, VoteType, ExistingResponse } from '../types';\n\ninterface UseSubmitOptions {\n elementId: string;\n mode: ResponseMode;\n experimentId?: string;\n variant?: string;\n pollOptions?: string[];\n user?: GotchaUser;\n onSuccess?: (response: GotchaResponse) => void;\n onError?: (error: Error) => void;\n}\n\ninterface SubmitData {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n}\n\nexport function useSubmit(options: UseSubmitOptions) {\n const { client, defaultUser } = useGotchaContext();\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [existingResponse, setExistingResponse] = useState<ExistingResponse | null>(null);\n\n // Check for existing response when user ID is provided\n useEffect(() => {\n const userId = options.user?.id || defaultUser?.id;\n if (!userId) {\n setExistingResponse(null);\n return;\n }\n\n let cancelled = false;\n\n const checkExisting = async () => {\n setIsCheckingExisting(true);\n try {\n const existing = await client.checkExistingResponse(options.elementId, userId);\n if (!cancelled) {\n setExistingResponse(existing);\n }\n } catch {\n // Ignore errors - just means no existing response found\n if (!cancelled) {\n setExistingResponse(null);\n }\n } finally {\n if (!cancelled) {\n setIsCheckingExisting(false);\n }\n }\n };\n\n checkExisting();\n\n return () => {\n cancelled = true;\n };\n }, [client, options.elementId, options.user?.id, defaultUser?.id]);\n\n const submit = useCallback(\n async (data: SubmitData) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const userId = options.user?.id || defaultUser?.id;\n let response: GotchaResponse;\n\n // If we have an existing response and a user ID, update instead of create\n if (existingResponse && userId) {\n response = await client.updateResponse(\n existingResponse.id,\n {\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollSelected: data.pollSelected,\n },\n userId\n );\n } else {\n response = await client.submitResponse({\n elementId: options.elementId,\n mode: options.mode,\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollOptions: options.pollOptions,\n pollSelected: data.pollSelected,\n experimentId: options.experimentId,\n variant: options.variant,\n user: { ...defaultUser, ...options.user },\n });\n }\n\n options.onSuccess?.(response);\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Something went wrong';\n setError(errorMessage);\n options.onError?.(err instanceof Error ? err : new Error(errorMessage));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [client, defaultUser, options, existingResponse]\n );\n\n return {\n submit,\n isLoading,\n isCheckingExisting,\n error,\n existingResponse,\n isEditing: !!existingResponse,\n clearError: () => setError(null),\n };\n}\n","/**\n * Simple class name utility\n * Combines class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n","/**\n * Detect if the device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n if (typeof window === 'undefined') return false;\n return 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get the appropriate size based on device type\n */\nexport const getResponsiveSize = (\n size: 'sm' | 'md' | 'lg',\n isTouch: boolean\n): number => {\n const sizes = {\n sm: { desktop: 24, mobile: 32 },\n md: { desktop: 32, mobile: 36 },\n lg: { desktop: 40, mobile: 40 },\n };\n\n return isTouch ? sizes[size].mobile : sizes[size].desktop;\n};\n","import React, { useState, useEffect } from 'react';\nimport { Size, Theme, GotchaStyles } from '../types';\nimport { cn } from '../utils/cn';\nimport { isTouchDevice, getResponsiveSize } from '../utils/device';\n\nexport interface GotchaButtonProps {\n size: Size;\n theme: Theme;\n customStyles?: GotchaStyles;\n showOnHover: boolean;\n touchBehavior: 'always-visible' | 'tap-to-reveal';\n onClick: () => void;\n isOpen: boolean;\n isParentHovered?: boolean;\n}\n\nexport function GotchaButton({\n size,\n theme,\n customStyles,\n showOnHover,\n touchBehavior,\n onClick,\n isOpen,\n isParentHovered = false,\n}: GotchaButtonProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [tapRevealed, setTapRevealed] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>('light');\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n // Detect system theme preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setSystemTheme(darkQuery.matches ? 'dark' : 'light');\n\n // Listen for theme changes\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Determine visibility\n const shouldShow = (() => {\n // Always show if modal is open\n if (isOpen) return true;\n\n // Desktop with showOnHover: only show when parent is hovered\n if (!isTouch && showOnHover) {\n return isParentHovered;\n }\n\n // Touch device with tap-to-reveal: show only after first tap\n if (isTouch && touchBehavior === 'tap-to-reveal') {\n return tapRevealed;\n }\n\n // All other cases: always visible\n return true;\n })();\n\n const handleClick = () => {\n // For tap-to-reveal on touch: first tap reveals, second tap opens\n if (isTouch && touchBehavior === 'tap-to-reveal' && !tapRevealed) {\n setTapRevealed(true);\n return;\n }\n onClick();\n };\n\n const buttonSize = getResponsiveSize(size, isTouch);\n\n // Determine theme colors\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: resolvedTheme === 'dark' ? '#374151' : '#c7d2dc',\n color: resolvedTheme === 'dark' ? '#e5e7eb' : '#4b5563',\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)',\n // CSS transition for animations\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: shouldShow ? 1 : 0,\n transform: shouldShow ? 'scale(1)' : 'scale(0.6)',\n pointerEvents: shouldShow ? 'auto' : 'none',\n ...customStyles?.button,\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n style={baseStyles}\n className={cn('gotcha-button', isOpen && 'gotcha-button--open')}\n aria-label=\"Give feedback on this feature\"\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n >\n <GotchaIcon size={buttonSize * 0.75} />\n </button>\n );\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <text\n x=\"50%\"\n y=\"50%\"\n dominantBaseline=\"central\"\n textAnchor=\"middle\"\n fontSize=\"16\"\n fontWeight=\"bold\"\n fill=\"currentColor\"\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n G\n </text>\n </svg>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: number;\n color?: string;\n}\n\nexport function Spinner({ size = 16, color = 'currentColor' }: SpinnerProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n animation: 'gotcha-spin 1s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeOpacity=\"0.25\"\n />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { GotchaStyles } from '../../types';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface FeedbackModeProps {\n theme: 'light' | 'dark' | 'custom';\n placeholder?: string;\n submitText: string;\n isLoading: boolean;\n onSubmit: (data: { content?: string; rating?: number }) => void;\n customStyles?: GotchaStyles;\n initialValues?: {\n content?: string | null;\n rating?: number | null;\n };\n isEditing?: boolean;\n}\n\nexport function FeedbackMode({\n theme,\n placeholder,\n submitText,\n isLoading,\n onSubmit,\n customStyles,\n initialValues,\n isEditing = false,\n}: FeedbackModeProps) {\n const [content, setContent] = useState(initialValues?.content || '');\n const [rating, setRating] = useState<number | null>(initialValues?.rating ?? null);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update local state when initialValues change (e.g., after loading existing response)\n useEffect(() => {\n if (initialValues?.content !== undefined) {\n setContent(initialValues.content || '');\n }\n if (initialValues?.rating !== undefined) {\n setRating(initialValues.rating ?? null);\n }\n }, [initialValues?.content, initialValues?.rating]);\n\n const isDark = theme === 'dark';\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!content.trim() && rating === null) return;\n onSubmit({ content: content.trim() || undefined, rating: rating ?? undefined });\n };\n\n const inputStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '12px 14px' : '10px 12px',\n border: `1px solid ${isDark ? '#374151' : '#d1d5db'}`,\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isDark ? '#374151' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 16 : 14, // 16px prevents iOS zoom on focus\n resize: 'vertical',\n minHeight: isTouch ? 100 : 80,\n fontFamily: 'inherit',\n ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isLoading ? (isDark ? '#4b5563' : '#9ca3af') : '#6366f1',\n color: '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 150ms ease',\n ...customStyles?.submitButton,\n };\n\n return (\n <form onSubmit={handleSubmit}>\n {/* Rating (optional) */}\n <div style={{ marginBottom: isTouch ? 16 : 12 }}>\n <StarRating value={rating} onChange={setRating} isDark={isDark} isTouch={isTouch} />\n </div>\n\n {/* Text input */}\n <textarea\n value={content}\n onChange={(e) => setContent(e.target.value)}\n placeholder={placeholder || 'Share your thoughts...'}\n style={inputStyles}\n disabled={isLoading}\n aria-label=\"Your feedback\"\n />\n\n {/* Submit button */}\n <button\n type=\"submit\"\n disabled={isLoading || (!content.trim() && rating === null)}\n style={{\n ...buttonStyles,\n marginTop: 12,\n opacity: (!content.trim() && rating === null) ? 0.5 : 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color=\"#ffffff\" />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : submitText)}\n </button>\n </form>\n );\n}\n\ninterface StarRatingProps {\n value: number | null;\n onChange: (rating: number) => void;\n isDark: boolean;\n isTouch: boolean;\n}\n\nfunction StarRating({ value, onChange, isDark, isTouch }: StarRatingProps) {\n const [hovered, setHovered] = useState<number | null>(null);\n const starSize = isTouch ? 32 : 20;\n const buttonPadding = isTouch ? 6 : 2;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 8 : 4,\n }}\n role=\"group\"\n aria-label=\"Rating\"\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const isFilled = (hovered ?? value ?? 0) >= star;\n return (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHovered(star)}\n onMouseLeave={() => setHovered(null)}\n aria-label={`Rate ${star} out of 5`}\n aria-pressed={value === star}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: buttonPadding,\n color: isFilled ? '#f59e0b' : (isDark ? '#4b5563' : '#d1d5db'),\n transition: 'color 150ms ease',\n }}\n >\n <svg width={starSize} height={starSize} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n </button>\n );\n })}\n </div>\n );\n}\n","import React, { useEffect, useState } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface VoteModeProps {\n theme: 'light' | 'dark' | 'custom';\n isLoading: boolean;\n onSubmit: (data: { vote: 'up' | 'down' }) => void;\n initialVote?: 'up' | 'down' | null;\n isEditing?: boolean;\n}\n\nexport function VoteMode({ theme, isLoading, onSubmit, initialVote, isEditing = false }: VoteModeProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [activeVote, setActiveVote] = useState<'up' | 'down' | null>(initialVote || null);\n const [previousVote, setPreviousVote] = useState<'up' | 'down' | null>(initialVote || null);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update when initialVote changes (e.g., after loading existing response)\n useEffect(() => {\n if (initialVote !== undefined) {\n setPreviousVote(initialVote);\n setActiveVote(initialVote);\n }\n }, [initialVote]);\n\n // Reset active vote when loading completes (but keep previous vote for edit mode)\n useEffect(() => {\n if (!isLoading && !isEditing) {\n setActiveVote(null);\n }\n }, [isLoading, isEditing]);\n\n const handleVote = (vote: 'up' | 'down') => {\n setActiveVote(vote);\n onSubmit({ vote });\n };\n\n const isDark = theme === 'dark';\n\n const getButtonStyles = (voteType: 'up' | 'down'): React.CSSProperties => {\n const isSelected = previousVote === voteType;\n return {\n flex: 1,\n padding: isTouch ? '16px 20px' : '12px 16px',\n border: isSelected\n ? `2px solid ${voteType === 'up' ? '#22c55e' : '#ef4444'}`\n : `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n borderRadius: isTouch ? 12 : 8,\n backgroundColor: isSelected\n ? (voteType === 'up' ? (isDark ? '#14532d' : '#dcfce7') : (isDark ? '#450a0a' : '#fee2e2'))\n : (isDark ? '#374151' : '#f9fafb'),\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 150ms ease',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n };\n\n const iconSize = isTouch ? 28 : 24;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 16 : 12,\n }}\n role=\"group\"\n aria-label=\"Vote\"\n >\n <button\n type=\"button\"\n onClick={() => handleVote('up')}\n disabled={isLoading}\n style={getButtonStyles('up')}\n aria-label=\"Vote up - I like this\"\n aria-pressed={previousVote === 'up'}\n >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {previousVote === 'up' ? 'Liked' : 'Like'}\n </span>\n </>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleVote('down')}\n disabled={isLoading}\n style={getButtonStyles('down')}\n aria-label=\"Vote down - I don't like this\"\n aria-pressed={previousVote === 'down'}\n >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {previousVote === 'down' ? 'Disliked' : 'Dislike'}\n </span>\n </>\n )}\n </button>\n </div>\n );\n}\n\nfunction ThumbsUpIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17\" />\n </svg>\n );\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport { Theme, GotchaStyles, ResponseMode, ExistingResponse } from '../types';\nimport { cn } from '../utils/cn';\nimport { FeedbackMode } from './modes/FeedbackMode';\nimport { VoteMode } from './modes/VoteMode';\n\nexport interface GotchaModalProps {\n mode: ResponseMode;\n theme: Theme;\n customStyles?: GotchaStyles;\n promptText?: string;\n placeholder?: string;\n submitText: string;\n thankYouMessage: string;\n // State\n isLoading: boolean;\n isSubmitted: boolean;\n error: string | null;\n // Edit mode\n existingResponse?: ExistingResponse | null;\n isEditing?: boolean;\n // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => void;\n onClose: () => void;\n // Position info from parent\n anchorRect?: DOMRect;\n}\n\nexport function GotchaModal({\n mode,\n theme,\n customStyles,\n promptText,\n placeholder,\n submitText,\n thankYouMessage,\n isLoading,\n isSubmitted,\n error,\n existingResponse,\n isEditing = false,\n onSubmit,\n onClose,\n anchorRect,\n}: GotchaModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const firstFocusableRef = useRef<HTMLButtonElement>(null);\n const [isVisible, setIsVisible] = useState(false);\n const [isMobile, setIsMobile] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>('light');\n\n // Detect mobile and system theme after mount (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n\n // Detect system theme preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setSystemTheme(darkQuery.matches ? 'dark' : 'light');\n\n // Listen for theme changes\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Trigger animation after mount\n useEffect(() => {\n const timer = requestAnimationFrame(() => setIsVisible(true));\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Resolve theme\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const isDark = resolvedTheme === 'dark';\n\n // Determine if modal should appear above or below\n const modalHeight = 280; // approximate modal height\n const spaceBelow = anchorRect\n ? window.innerHeight - anchorRect.bottom\n : window.innerHeight / 2;\n const showAbove = spaceBelow < modalHeight + 20;\n\n // Focus trap\n useEffect(() => {\n const modal = modalRef.current;\n if (!modal) return;\n\n // Focus first element\n firstFocusableRef.current?.focus();\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n return;\n }\n\n if (e.key === 'Tab') {\n const focusableElements = modal.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement?.focus();\n } else if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement?.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n const defaultPrompt = mode === 'vote'\n ? 'What do you think?'\n : 'What do you think of this feature?';\n\n // Responsive sizing - on mobile, use fixed positioning centered on screen\n const modalPadding = isMobile ? 20 : 16;\n\n const modalStyles: React.CSSProperties = isMobile\n ? {\n // Mobile: fixed position, centered on screen\n position: 'fixed',\n left: '50%',\n top: '50%',\n width: 'calc(100vw - 32px)',\n maxWidth: 320,\n padding: modalPadding,\n borderRadius: 12,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: '0 10px 25px rgba(0, 0, 0, 0.2)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.95)',\n ...customStyles?.modal,\n }\n : {\n // Desktop: absolute position relative to button\n position: 'absolute',\n left: '50%',\n width: 320,\n padding: modalPadding,\n borderRadius: 8,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: '0 10px 25px rgba(0, 0, 0, 0.15)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.95) translateY(${showAbove ? '10px' : '-10px'})`,\n ...customStyles?.modal,\n };\n\n return (\n <div\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gotcha-modal-title\"\n style={modalStyles}\n className={cn('gotcha-modal', isDark && 'gotcha-modal--dark')}\n >\n {/* Close button - larger on touch devices */}\n <button\n ref={firstFocusableRef}\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close feedback form\"\n style={{\n position: 'absolute',\n top: isMobile ? 12 : 8,\n right: isMobile ? 12 : 8,\n width: isMobile ? 36 : 24,\n height: isMobile ? 36 : 24,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: isDark ? '#9ca3af' : '#6b7280',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 4,\n }}\n >\n <svg width={isMobile ? 18 : 14} height={isMobile ? 18 : 14} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 12px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 500,\n paddingRight: isMobile ? 40 : 24,\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '20px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ margin: '0 auto 8px' }}\n >\n <path\n d=\"M20 6L9 17L4 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <p style={{ margin: 0, fontSize: 14 }}>{thankYouMessage}</p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: 8,\n marginBottom: 12,\n borderRadius: 4,\n backgroundColor: isDark ? '#7f1d1d' : '#fef2f2',\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\n }}\n >\n {error}\n </div>\n )}\n\n {/* Form content based on mode */}\n {!isSubmitted && (\n <>\n {mode === 'feedback' && (\n <FeedbackMode\n theme={resolvedTheme}\n placeholder={placeholder}\n submitText={submitText}\n isLoading={isLoading}\n onSubmit={onSubmit}\n customStyles={customStyles}\n initialValues={existingResponse ? {\n content: existingResponse.content,\n rating: existingResponse.rating,\n } : undefined}\n isEditing={isEditing}\n />\n )}\n {mode === 'vote' && (\n <VoteMode\n theme={resolvedTheme}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialVote={existingResponse?.vote || undefined}\n isEditing={isEditing}\n />\n )}\n </>\n )}\n\n {/* Screen reader announcement */}\n <div aria-live=\"polite\" className=\"sr-only\" style={{ position: 'absolute', left: -9999 }}>\n {isSubmitted && 'Thank you! Your feedback has been submitted.'}\n {error && `Error: ${error}`}\n </div>\n </div>\n );\n}\n","import React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n ResponseMode,\n GotchaUser,\n Position,\n Size,\n Theme,\n TouchBehavior,\n GotchaStyles,\n GotchaResponse,\n GotchaError,\n} from '../types';\nimport { DEFAULTS } from '../constants';\nimport { useGotchaContext } from './GotchaProvider';\nimport { useSubmit } from '../hooks/useSubmit';\nimport { GotchaButton } from './GotchaButton';\nimport { GotchaModal } from './GotchaModal';\n\nexport interface GotchaProps {\n /** Unique identifier for this element */\n elementId: string;\n\n // User data\n /** User metadata for segmentation */\n user?: GotchaUser;\n\n // Behavior\n /** Feedback mode */\n mode?: ResponseMode;\n /** Required if mode is 'ab' */\n experimentId?: string;\n /** Current A/B variant shown to user */\n variant?: string;\n\n // Poll mode specific (Phase 2)\n /** Required if mode is 'poll' (2-6 options) */\n options?: string[];\n /** Allow selecting multiple options */\n allowMultiple?: boolean;\n /** Show results after voting */\n showResults?: boolean;\n\n // Appearance\n /** Button position relative to parent */\n position?: Position;\n /** Button size */\n size?: Size;\n /** Color theme */\n theme?: Theme;\n /** Custom style overrides */\n customStyles?: GotchaStyles;\n /** Control visibility programmatically */\n visible?: boolean;\n /** Only show when parent is hovered (default: true) */\n showOnHover?: boolean;\n /** Mobile behavior (default: 'always-visible') */\n touchBehavior?: TouchBehavior;\n\n // Content\n /** Custom prompt text */\n promptText?: string;\n /** Input placeholder text */\n placeholder?: string;\n /** Submit button text */\n submitText?: string;\n /** Post-submission message */\n thankYouMessage?: string;\n\n // Callbacks\n /** Called after successful submission */\n onSubmit?: (response: GotchaResponse) => void;\n /** Called when modal opens */\n onOpen?: () => void;\n /** Called when modal closes */\n onClose?: () => void;\n /** Called on error */\n onError?: (error: GotchaError) => void;\n}\n\nexport function Gotcha({\n elementId,\n user,\n mode = 'feedback',\n experimentId,\n variant,\n options,\n allowMultiple = false,\n showResults = true,\n position = DEFAULTS.POSITION,\n size = DEFAULTS.SIZE,\n theme = DEFAULTS.THEME,\n customStyles,\n visible = true,\n showOnHover = DEFAULTS.SHOW_ON_HOVER,\n touchBehavior = DEFAULTS.TOUCH_BEHAVIOR,\n promptText,\n placeholder,\n submitText = DEFAULTS.SUBMIT_TEXT,\n thankYouMessage = DEFAULTS.THANK_YOU_MESSAGE,\n onSubmit,\n onOpen,\n onClose,\n onError,\n}: GotchaProps) {\n const { disabled, activeModalId, openModal, closeModal } = useGotchaContext();\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [isParentHovered, setIsParentHovered] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const [isMobile, setIsMobile] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Detect mobile for portal rendering (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n }, []);\n\n // This instance's modal is open if activeModalId matches our elementId\n const isOpen = activeModalId === elementId;\n\n // Attach hover listeners to the parent element (not the button container)\n useEffect(() => {\n if (!showOnHover) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Find the parent element with position: relative\n const parent = container.parentElement;\n if (!parent) return;\n\n const handleMouseEnter = () => setIsParentHovered(true);\n const handleMouseLeave = () => setIsParentHovered(false);\n\n parent.addEventListener('mouseenter', handleMouseEnter);\n parent.addEventListener('mouseleave', handleMouseLeave);\n\n return () => {\n parent.removeEventListener('mouseenter', handleMouseEnter);\n parent.removeEventListener('mouseleave', handleMouseLeave);\n };\n }, [showOnHover]);\n\n const { submit, isLoading, error, existingResponse, isEditing } = useSubmit({\n elementId,\n mode,\n experimentId,\n variant,\n pollOptions: options,\n user,\n onSuccess: (response) => {\n setIsSubmitted(true);\n onSubmit?.(response);\n // Auto-close after 2.5 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 2500);\n },\n onError: (err) => {\n onError?.(err as unknown as GotchaError);\n },\n });\n\n const handleOpen = useCallback(() => {\n if (containerRef.current) {\n setAnchorRect(containerRef.current.getBoundingClientRect());\n }\n openModal(elementId);\n onOpen?.();\n }, [elementId, openModal, onOpen]);\n\n const handleClose = useCallback(() => {\n closeModal();\n setIsSubmitted(false);\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleSubmit = useCallback(\n (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => {\n submit(data);\n },\n [submit]\n );\n\n // Don't render if disabled or not visible\n if (disabled || !visible) return null;\n\n // Position styles\n const positionStyles: Record<Position, React.CSSProperties> = {\n 'top-right': { position: 'absolute', top: 0, right: 0, transform: 'translate(50%, -50%)' },\n 'top-left': { position: 'absolute', top: 0, left: 0, transform: 'translate(-50%, -50%)' },\n 'bottom-right': { position: 'absolute', bottom: 0, right: 0, transform: 'translate(50%, 50%)' },\n 'bottom-left': { position: 'absolute', bottom: 0, left: 0, transform: 'translate(-50%, 50%)' },\n 'inline': { position: 'relative', display: 'inline-flex' },\n };\n\n return (\n <div\n ref={containerRef}\n style={{\n ...positionStyles[position],\n zIndex: isOpen ? 10000 : 'auto',\n }}\n className=\"gotcha-container\"\n data-gotcha-element={elementId}\n >\n <GotchaButton\n size={size}\n theme={theme}\n customStyles={customStyles}\n showOnHover={showOnHover}\n touchBehavior={touchBehavior}\n onClick={handleOpen}\n isOpen={isOpen}\n isParentHovered={isParentHovered}\n />\n\n {isOpen && !isMobile && (\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n )}\n\n {/* On mobile, render modal via portal to escape parent transform */}\n {isOpen && isMobile && createPortal(\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n }}\n onClick={handleClose}\n aria-hidden=\"true\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useGotchaContext } from '../components/GotchaProvider';\n\n/**\n * Hook to access Gotcha context\n * Must be used within a GotchaProvider\n */\nexport function useGotcha() {\n const { client, disabled, defaultUser, debug } = useGotchaContext();\n\n return {\n /** The API client for manual submissions */\n client,\n /** Whether Gotcha is globally disabled */\n disabled,\n /** Default user metadata */\n defaultUser,\n /** Whether debug mode is enabled */\n debug,\n /** Submit feedback programmatically */\n submitFeedback: client.submitResponse.bind(client),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/utils/anonymous.ts","../src/api/client.ts","../src/components/GotchaProvider.tsx","../src/hooks/useSubmit.ts","../src/utils/cn.ts","../src/utils/device.ts","../src/components/GotchaButton.tsx","../src/components/Spinner.tsx","../src/components/modes/FeedbackMode.tsx","../src/components/modes/VoteMode.tsx","../src/components/GotchaModal.tsx","../src/components/Gotcha.tsx","../src/hooks/useGotcha.ts"],"names":["API_BASE_URL","STORAGE_KEYS","DEFAULTS","RETRY_CONFIG","getAnonymousId","stored","id","DEFAULT_RETRY_CONFIG","fetchWithRetry","url","options","config","debug","lastError","attempt","response","error","delay","resolve","createApiClient","apiKey","baseUrl","headers","request","method","endpoint","body","idempotencyKey","data","payload","user","fullPayload","elementId","userId","GotchaContext","createContext","GotchaProvider","children","disabled","defaultUser","activeModalId","setActiveModalId","useState","client","useMemo","openModal","useCallback","closeModal","value","jsx","useGotchaContext","context","useContext","useSubmit","isLoading","setIsLoading","isCheckingExisting","setIsCheckingExisting","setError","existingResponse","setExistingResponse","useEffect","cancelled","existing","err","errorMessage","cn","classes","isTouchDevice","getResponsiveSize","size","isTouch","sizes","getInitialSystemTheme","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","darkQuery","handler","e","shouldShow","handleClick","buttonSize","isDark","baseStyles","GotchaIcon","FONT_ID","useCarterOneFont","link","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","initialValues","isEditing","content","setContent","rating","setRating","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","initialVote","activeVote","setActiveVote","previousVote","setPreviousVote","handleVote","vote","getButtonStyles","voteType","isSelected","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","resolvedTheme","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","layeredShadow","modalStyles","Gotcha","experimentId","variant","allowMultiple","showResults","position","visible","onOpen","onError","setIsSubmitted","setIsParentHovered","setAnchorRect","containerRef","container","parent","handleMouseEnter","handleMouseLeave","submit","handleOpen","handleClose","createPortal","useGotcha"],"mappings":"8GACO,IAAMA,EAAAA,CAAe,0BAAA,CAcrB,IAAMC,EAAAA,CAAe,CAC1B,aAAc,qBAEhB,CAAA,CAGaC,EAAW,CACtB,QAAA,CAAU,YACV,IAAA,CAAM,IAAA,CACN,MAAO,OAAA,CACP,aAAA,CAAe,IAAA,CACf,cAAA,CAAgB,iBAChB,WAAA,CAAa,QAAA,CACb,kBAAmB,2BACrB,CAAA,CAUO,IAAMC,CAAAA,CAAe,CAC1B,WAAA,CAAa,CAAA,CACb,cAAe,GAAA,CACf,YAAA,CAAc,GAChB,CAAA,CCrCO,SAASC,IAAyB,CACvC,GAAI,OAAO,MAAA,CAAW,IAEpB,OAAO,CAAA,KAAA,EAAQ,OAAO,UAAA,EAAY,GAGpC,IAAMC,CAAAA,CAAS,YAAA,CAAa,OAAA,CAAQJ,GAAa,YAAY,CAAA,CAC7D,GAAII,CAAAA,CAAQ,OAAOA,EAEnB,IAAMC,CAAAA,CAAK,QAAQ,MAAA,CAAO,UAAA,EAAY,CAAA,CAAA,CACtC,OAAA,YAAA,CAAa,QAAQL,EAAAA,CAAa,YAAA,CAAcK,CAAE,CAAA,CAC3CA,CACT,CCFA,IAAMC,EAAoC,CACxC,UAAA,CAAYJ,EAAa,WAAA,CACzB,WAAA,CAAaA,EAAa,aAAA,CAC1B,UAAA,CAAYA,CAAAA,CAAa,YAC3B,EAKA,eAAeK,EAAAA,CACbC,EACAC,CAAAA,CACAC,CAAAA,CAAsBJ,EACtBK,CAAAA,CAAiB,KAAA,CACE,CACnB,IAAIC,EAA0B,IAAA,CAE9B,IAAA,IAASC,EAAU,CAAA,CAAGA,CAAAA,EAAWH,EAAO,UAAA,CAAYG,CAAAA,EAAAA,CAAW,CAC7D,GAAI,CACEF,CAAAA,EAASE,CAAAA,CAAU,GACrB,OAAA,CAAQ,GAAA,CAAI,0BAA0BA,CAAO,CAAA,CAAA,EAAIH,CAAAA,CAAO,UAAU,EAAE,CAAA,CAGtE,IAAMI,EAAW,MAAM,KAAA,CAAMN,EAAKC,CAAO,CAAA,CAQzC,GALIK,CAAAA,CAAS,QAAU,GAAA,EAAOA,CAAAA,CAAS,OAAS,GAAA,EAAOA,CAAAA,CAAS,SAAW,GAAA,EAKvEA,CAAAA,CAAS,EAAA,CACX,OAAOA,EAGTF,CAAAA,CAAY,IAAI,MAAM,CAAA,KAAA,EAAQE,CAAAA,CAAS,MAAM,CAAA,CAAE,EACjD,OAASC,CAAAA,CAAO,CAEdH,EAAYG,CAAAA,CACRJ,CAAAA,EACF,QAAQ,GAAA,CAAI,CAAA,wBAAA,EAA2BC,EAAU,OAAO,CAAA,CAAE,EAE9D,CAGA,GAAIC,CAAAA,CAAUH,CAAAA,CAAO,WAAY,CAC/B,IAAMM,EAAQ,IAAA,CAAK,GAAA,CACjBN,CAAAA,CAAO,WAAA,CAAc,KAAK,GAAA,CAAI,CAAA,CAAGG,CAAO,CAAA,CACxCH,CAAAA,CAAO,UACT,CAAA,CACA,MAAM,IAAI,OAAA,CAASO,GAAY,UAAA,CAAWA,CAAAA,CAASD,CAAK,CAAC,EAC3D,CACF,CAEA,MAAMJ,CACR,CAEO,SAASM,EAAAA,CAAgBR,CAAAA,CAAyB,CACvD,GAAM,CAAE,OAAAS,CAAAA,CAAQ,OAAA,CAAAC,CAAAA,CAAUrB,EAAAA,CAAc,MAAAY,CAAAA,CAAQ,KAAM,EAAID,CAAAA,CAEpDW,CAAAA,CAAU,CACd,cAAA,CAAgB,kBAAA,CAChB,aAAA,CAAe,CAAA,OAAA,EAAUF,CAAM,CAAA,CACjC,CAAA,CAEA,eAAeG,CAAAA,CACbC,CAAAA,CACAC,EACAC,CAAAA,CACY,CACZ,IAAMjB,CAAAA,CAAM,GAAGY,CAAO,CAAA,EAAGI,CAAQ,CAAA,CAAA,CAC3BE,CAAAA,CAAiB,OAAO,UAAA,EAAW,CAErCf,GACF,OAAA,CAAQ,GAAA,CAAI,YAAYY,CAAM,CAAA,CAAA,EAAIC,CAAQ,CAAA,CAAA,CAAIC,CAAI,EAGpD,IAAMX,CAAAA,CAAW,MAAMP,EAAAA,CACrBC,EACA,CACE,MAAA,CAAAe,EACA,OAAA,CAAS,CACP,GAAGF,CAAAA,CACH,iBAAA,CAAmBK,CACrB,CAAA,CACA,KAAMD,CAAAA,CAAO,IAAA,CAAK,UAAUA,CAAI,CAAA,CAAI,MACtC,CAAA,CACAnB,CAAAA,CACAK,CACF,CAAA,CAEMgB,EAAO,MAAMb,CAAAA,CAAS,MAAK,CAEjC,GAAI,CAACA,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMC,CAAAA,CAAQY,EAAK,KAAA,CACnB,MAAIhB,GACF,OAAA,CAAQ,KAAA,CAAM,mBAAmBI,CAAAA,CAAM,IAAI,CAAA,GAAA,EAAMA,CAAAA,CAAM,OAAO,CAAA,CAAE,CAAA,CAE5DA,CACR,CAEA,OAAIJ,GACF,OAAA,CAAQ,GAAA,CAAI,oBAAA,CAAsBgB,CAAI,EAGjCA,CACT,CAEA,OAAO,CAIL,MAAM,eACJC,CAAAA,CACyB,CAEzB,IAAMC,CAAAA,CAAOD,EAAQ,IAAA,EAAQ,GACxBC,CAAAA,CAAK,EAAA,GACRA,EAAK,EAAA,CAAK1B,EAAAA,IAGZ,IAAM2B,CAAAA,CAAqC,CACzC,GAAGF,CAAAA,CACH,KAAAC,CAAAA,CACA,OAAA,CAAS,CACP,GAAA,CAAK,OAAO,MAAA,CAAW,GAAA,CAAc,OAAO,QAAA,CAAS,IAAA,CAAO,OAC5D,SAAA,CAAW,OAAO,UAAc,GAAA,CAAc,SAAA,CAAU,SAAA,CAAY,MACtE,CACF,CAAA,CAEA,OAAOP,EAAwB,MAAA,CAAQ,YAAA,CAAcQ,CAAW,CAClE,CAAA,CAKA,MAAM,qBAAA,CACJC,EACAC,CAAAA,CACkC,CAClC,IAAMxB,CAAAA,CAAM,CAAA,EAAGY,CAAO,CAAA,2BAAA,EAA8B,kBAAA,CAAmBW,CAAS,CAAC,WAAW,kBAAA,CAAmBC,CAAM,CAAC,CAAA,CAAA,CAElHrB,CAAAA,EACF,QAAQ,GAAA,CAAI,+BAA+B,CAAA,CAG7C,IAAMG,EAAW,MAAMP,EAAAA,CACrBC,EACA,CACE,MAAA,CAAQ,MACR,OAAA,CAAAa,CACF,CAAA,CACAf,CAAAA,CACAK,CACF,CAAA,CAEMgB,CAAAA,CAAO,MAAMb,CAAAA,CAAS,IAAA,GAE5B,GAAI,CAACA,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMC,CAAAA,CAAQY,EAAK,KAAA,CACnB,MAAIhB,GACF,OAAA,CAAQ,KAAA,CAAM,mBAAmBI,CAAAA,CAAM,IAAI,MAAMA,CAAAA,CAAM,OAAO,EAAE,CAAA,CAE5DA,CACR,CAEA,OAAIY,CAAAA,CAAK,MAAA,EACHhB,CAAAA,EACF,QAAQ,GAAA,CAAI,mCAAA,CAAqCgB,EAAK,QAAQ,CAAA,CAEzDA,EAAK,QAAA,EAGP,IACT,CAAA,CAKA,MAAM,eACJtB,CAAAA,CACAuB,CAAAA,CAOAI,EACyB,CACzB,IAAMxB,EAAM,CAAA,EAAGY,CAAO,CAAA,WAAA,EAAcf,CAAE,GAAG2B,CAAAA,CAAS,CAAA,QAAA,EAAW,mBAAmBA,CAAM,CAAC,GAAK,EAAE,CAAA,CAAA,CAE1FrB,GACF,OAAA,CAAQ,GAAA,CAAI,6BAA6BN,CAAE,CAAA,CAAA,CAAIuB,CAAO,CAAA,CAGxD,IAAMd,EAAW,MAAMP,EAAAA,CACrBC,CAAAA,CACA,CACE,OAAQ,OAAA,CACR,OAAA,CAAAa,EACA,IAAA,CAAM,IAAA,CAAK,UAAUO,CAAO,CAC9B,CAAA,CACAtB,CAAAA,CACAK,CACF,CAAA,CAEMgB,CAAAA,CAAO,MAAMb,CAAAA,CAAS,IAAA,GAE5B,GAAI,CAACA,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMC,CAAAA,CAAQY,EAAK,KAAA,CACnB,MAAIhB,GACF,OAAA,CAAQ,KAAA,CAAM,mBAAmBI,CAAAA,CAAM,IAAI,MAAMA,CAAAA,CAAM,OAAO,EAAE,CAAA,CAE5DA,CACR,CAEA,OAAIJ,CAAAA,EACF,OAAA,CAAQ,GAAA,CAAI,6BAA8BgB,CAAI,CAAA,CAGzCA,CACT,CAAA,CAKA,UAAA,EAAqB,CACnB,OAAOP,CACT,CACF,CACF,CCzNA,IAAMa,EAAAA,CAAgBC,oBAAyC,IAAI,CAAA,CAE5D,SAASC,EAAAA,CAAe,CAC7B,MAAA,CAAAhB,CAAAA,CACA,SAAAiB,CAAAA,CACA,OAAA,CAAAhB,EACA,KAAA,CAAAT,CAAAA,CAAQ,KAAA,CACR,QAAA,CAAA0B,EAAW,KAAA,CACX,WAAA,CAAAC,EAAc,EAChB,EAAwB,CACtB,GAAM,CAACC,CAAAA,CAAeC,CAAgB,CAAA,CAAIC,cAAAA,CAAwB,IAAI,CAAA,CAEhEC,CAAAA,CAASC,cACb,IAAMzB,EAAAA,CAAgB,CAAE,MAAA,CAAAC,EAAQ,OAAA,CAAAC,CAAAA,CAAS,MAAAT,CAAM,CAAC,EAChD,CAACQ,CAAAA,CAAQC,CAAAA,CAAST,CAAK,CACzB,CAAA,CAEMiC,CAAAA,CAAYC,kBAAad,CAAAA,EAAsB,CACnDS,EAAiBT,CAAS,EAC5B,EAAG,EAAE,EAECe,CAAAA,CAAaD,iBAAAA,CAAY,IAAM,CACnCL,CAAAA,CAAiB,IAAI,EACvB,CAAA,CAAG,EAAE,EAECO,CAAAA,CAA4BJ,aAAAA,CAChC,KAAO,CACL,MAAA,CAAAD,EACA,QAAA,CAAAL,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,MAAA3B,CAAAA,CACA,aAAA,CAAA4B,EACA,SAAA,CAAAK,CAAAA,CACA,WAAAE,CACF,CAAA,CAAA,CACA,CAACJ,CAAAA,CAAQL,EAAUC,CAAAA,CAAa3B,CAAAA,CAAO4B,EAAeK,CAAAA,CAAWE,CAAU,CAC7E,CAAA,CAEA,OACEE,eAACf,EAAAA,CAAc,QAAA,CAAd,CAAuB,KAAA,CAAOc,CAAAA,CAAQ,SAAAX,CAAAA,CAAS,CAEpD,CAEO,SAASa,CAAAA,EAAuC,CACrD,IAAMC,EAAUC,gBAAAA,CAAWlB,EAAa,EACxC,GAAI,CAACiB,EACH,MAAM,IAAI,KAAA,CAAM,uDAAuD,EAEzE,OAAOA,CACT,CCxDO,SAASE,EAAAA,CAAU3C,CAAAA,CAA2B,CACnD,GAAM,CAAE,MAAA,CAAAiC,CAAAA,CAAQ,YAAAJ,CAAY,CAAA,CAAIW,GAAiB,CAC3C,CAACI,EAAWC,CAAY,CAAA,CAAIb,cAAAA,CAAS,KAAK,EAC1C,CAACc,CAAAA,CAAoBC,CAAqB,CAAA,CAAIf,cAAAA,CAAS,KAAK,CAAA,CAC5D,CAAC1B,CAAAA,CAAO0C,CAAQ,EAAIhB,cAAAA,CAAwB,IAAI,EAChD,CAACiB,CAAAA,CAAkBC,CAAmB,CAAA,CAAIlB,cAAAA,CAAkC,IAAI,CAAA,CAGtF,OAAAmB,eAAAA,CAAU,IAAM,CACd,IAAM5B,CAAAA,CAASvB,EAAQ,IAAA,EAAM,EAAA,EAAM6B,CAAAA,EAAa,EAAA,CAChD,GAAI,CAACN,CAAAA,CAAQ,CACX2B,CAAAA,CAAoB,IAAI,EACxB,MACF,CAEA,IAAIE,CAAAA,CAAY,MAqBhB,OAAA,CAnBsB,SAAY,CAChCL,CAAAA,CAAsB,IAAI,EAC1B,GAAI,CACF,IAAMM,CAAAA,CAAW,MAAMpB,CAAAA,CAAO,qBAAA,CAAsBjC,EAAQ,SAAA,CAAWuB,CAAM,EACxE6B,CAAAA,EACHF,CAAAA,CAAoBG,CAAQ,EAEhC,CAAA,KAAQ,CAEDD,CAAAA,EACHF,CAAAA,CAAoB,IAAI,EAE5B,CAAA,OAAE,CACKE,CAAAA,EACHL,CAAAA,CAAsB,KAAK,EAE/B,CACF,CAAA,GAEc,CAEP,IAAM,CACXK,CAAAA,CAAY,KACd,CACF,CAAA,CAAG,CAACnB,CAAAA,CAAQjC,EAAQ,SAAA,CAAWA,CAAAA,CAAQ,MAAM,EAAA,CAAI6B,CAAAA,EAAa,EAAE,CAAC,CAAA,CAsD1D,CACL,MAAA,CArDaO,kBACb,MAAOlB,CAAAA,EAAqB,CAC1B2B,CAAAA,CAAa,IAAI,EACjBG,CAAAA,CAAS,IAAI,CAAA,CAEb,GAAI,CACF,IAAMzB,CAAAA,CAASvB,EAAQ,IAAA,EAAM,EAAA,EAAM6B,GAAa,EAAA,CAC5CxB,CAAAA,CAGJ,OAAI4C,CAAAA,EAAoB1B,EACtBlB,CAAAA,CAAW,MAAM4B,EAAO,cAAA,CACtBgB,CAAAA,CAAiB,GACjB,CACE,OAAA,CAAS/B,CAAAA,CAAK,OAAA,CACd,MAAOA,CAAAA,CAAK,KAAA,CACZ,OAAQA,CAAAA,CAAK,MAAA,CACb,KAAMA,CAAAA,CAAK,IAAA,CACX,YAAA,CAAcA,CAAAA,CAAK,YACrB,CAAA,CACAK,CACF,EAEAlB,CAAAA,CAAW,MAAM4B,EAAO,cAAA,CAAe,CACrC,UAAWjC,CAAAA,CAAQ,SAAA,CACnB,KAAMA,CAAAA,CAAQ,IAAA,CACd,QAASkB,CAAAA,CAAK,OAAA,CACd,MAAOA,CAAAA,CAAK,KAAA,CACZ,MAAA,CAAQA,CAAAA,CAAK,OACb,IAAA,CAAMA,CAAAA,CAAK,KACX,WAAA,CAAalB,CAAAA,CAAQ,YACrB,YAAA,CAAckB,CAAAA,CAAK,YAAA,CACnB,YAAA,CAAclB,EAAQ,YAAA,CACtB,OAAA,CAASA,EAAQ,OAAA,CACjB,IAAA,CAAM,CAAE,GAAG6B,CAAAA,CAAa,GAAG7B,CAAAA,CAAQ,IAAK,CAC1C,CAAC,EAGHA,CAAAA,CAAQ,SAAA,GAAYK,CAAQ,CAAA,CACrBA,CACT,CAAA,MAASiD,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAeD,aAAe,KAAA,CAAQA,CAAAA,CAAI,QAAU,sBAAA,CAC1D,MAAAN,CAAAA,CAASO,CAAY,EACrBvD,CAAAA,CAAQ,OAAA,GAAUsD,aAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,KAAA,CAAMC,CAAY,CAAC,CAAA,CAChED,CACR,CAAA,OAAE,CACAT,EAAa,KAAK,EACpB,CACF,CAAA,CACA,CAACZ,CAAAA,CAAQJ,CAAAA,CAAa7B,EAASiD,CAAgB,CACjD,EAIE,SAAA,CAAAL,CAAAA,CACA,mBAAAE,CAAAA,CACA,KAAA,CAAAxC,EACA,gBAAA,CAAA2C,CAAAA,CACA,UAAW,CAAC,CAACA,EACb,UAAA,CAAY,IAAMD,EAAS,IAAI,CACjC,CACF,CC3HO,SAASQ,CAAAA,CAAAA,GAAMC,CAAAA,CAAwD,CAC5E,OAAOA,EAAQ,MAAA,CAAO,OAAO,EAAE,IAAA,CAAK,GAAG,CACzC,CCHO,IAAMC,CAAAA,CAAgB,IACvB,OAAO,MAAA,CAAW,GAAA,CAAoB,MACnC,cAAA,GAAkB,MAAA,EAAU,UAAU,cAAA,CAAiB,CAAA,CAMnDC,GAAoB,CAC/BC,CAAAA,CACAC,IACW,CACX,IAAMC,EAAQ,CACZ,EAAA,CAAI,CAAE,OAAA,CAAS,EAAA,CAAI,MAAA,CAAQ,EAAG,EAC9B,EAAA,CAAI,CAAE,QAAS,EAAA,CAAI,MAAA,CAAQ,EAAG,CAAA,CAC9B,EAAA,CAAI,CAAE,OAAA,CAAS,GAAI,MAAA,CAAQ,EAAG,CAChC,CAAA,CAEA,OAAOD,EAAUC,CAAAA,CAAMF,CAAI,CAAA,CAAE,MAAA,CAASE,EAAMF,CAAI,CAAA,CAAE,OACpD,CAAA,CCAA,SAASG,IAA0C,CACjD,OAAI,OAAO,MAAA,CAAW,GAAA,CAAoB,QACnC,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,CAAE,OAAA,CACrD,MAAA,CACA,OACN,CAEO,SAASC,EAAAA,CAAa,CAC3B,IAAA,CAAAJ,CAAAA,CACA,MAAAK,CAAAA,CACA,YAAA,CAAAC,CAAAA,CACA,WAAA,CAAAC,EACA,aAAA,CAAAC,CAAAA,CACA,QAAAC,CAAAA,CACA,MAAA,CAAAC,EACA,eAAA,CAAAC,CAAAA,CAAkB,KACpB,CAAA,CAAsB,CACpB,GAAM,CAACV,EAASW,CAAU,CAAA,CAAIxC,eAAS,KAAK,CAAA,CACtC,CAACyC,CAAAA,CAAaC,CAAc,CAAA,CAAI1C,cAAAA,CAAS,KAAK,CAAA,CAC9C,CAAC2C,EAAaC,CAAc,CAAA,CAAI5C,cAAAA,CAA2B+B,EAAqB,EAEtFZ,eAAAA,CAAU,IAAM,CACdqB,CAAAA,CAAWd,CAAAA,EAAe,CAAA,CAG1B,IAAMmB,CAAAA,CAAY,MAAA,CAAO,WAAW,8BAA8B,CAAA,CAC5DC,EAAWC,CAAAA,EACfH,CAAAA,CAAeG,EAAE,OAAA,CAAU,MAAA,CAAS,OAAO,CAAA,CAC7C,OAAAF,CAAAA,CAAU,gBAAA,CAAiB,SAAUC,CAAO,CAAA,CACrC,IAAMD,CAAAA,CAAU,mBAAA,CAAoB,SAAUC,CAAO,CAC9D,EAAG,EAAE,EAGL,IAAME,CAAAA,CACAV,EAAe,IAAA,CACf,CAACT,CAAAA,EAAWM,CAAAA,CAAoBI,EAChCV,CAAAA,EAAWO,CAAAA,GAAkB,gBAAwBK,CAAAA,CAClD,IAAA,CAGHQ,EAAc,IAAM,CACxB,GAAIpB,CAAAA,EAAWO,IAAkB,eAAA,EAAmB,CAACK,EAAa,CAChEC,CAAAA,CAAe,IAAI,CAAA,CACnB,MACF,CACAL,CAAAA,GACF,CAAA,CAEMa,CAAAA,CAAavB,GAAkBC,CAAAA,CAAMC,CAAO,EAQ5CsB,CAAAA,CAAAA,CADgBlB,CAAAA,GAAU,OAASU,CAAAA,CAAcV,CAAAA,IACtB,OAU3BmB,CAAAA,CAAkC,CACtC,MAAOF,CAAAA,CACP,MAAA,CAAQA,EACR,YAAA,CAAc,KAAA,CACd,MAAA,CAAQC,CAAAA,CACJ,mCACA,MAAA,CACJ,MAAA,CAAQ,UACR,OAAA,CAAS,MAAA,CACT,WAAY,QAAA,CACZ,cAAA,CAAgB,QAAA,CAChB,UAAA,CAAYA,EACR,uGAAA,CACA,0GAAA,CACJ,eAAgB,2BAAA,CAChB,oBAAA,CAAsB,4BACtB,KAAA,CAAOA,CAAAA,CAAS,wBAAA,CAA2B,kBAAA,CAC3C,UAAWA,CAAAA,CACP,CACE,8BACA,4BAAA,CACA,uCAAA,CACA,mCACF,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CACX,CACE,8BACA,yBAAA,CACA,wCAAA,CACA,mCACF,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CACf,UAAA,CAAY,uCAAA,CACZ,OAAA,CAASH,EAAa,CAAA,CAAI,CAAA,CAC1B,UAAWA,CAAAA,CAAa,UAAA,CAAa,aACrC,aAAA,CAAeA,CAAAA,CAAa,MAAA,CAAS,MAAA,CACrC,GAAGd,CAAAA,EAAc,MACnB,EAEA,OACE3B,cAAAA,CAAC,UACC,IAAA,CAAK,QAAA,CACL,OAAA,CAAS0C,CAAAA,CACT,MAAOG,CAAAA,CACP,SAAA,CAAW5B,EAAG,eAAA,CAAiBc,CAAAA,EAAU,qBAAqB,CAAA,CAC9D,YAAA,CAAW,+BAAA,CACX,eAAA,CAAeA,EACf,eAAA,CAAc,QAAA,CAEd,SAAA/B,cAAAA,CAAC8C,EAAAA,CAAA,CAAW,IAAA,CAAMH,CAAAA,CAAa,GAAA,CAAM,CAAA,CACvC,CAEJ,CAEA,IAAMI,GAAU,mBAAA,CAEhB,SAASC,IAAmB,CAC1BpC,eAAAA,CAAU,IAAM,CACd,GAAI,QAAA,CAAS,cAAA,CAAemC,EAAO,CAAA,CAAG,OACtC,IAAME,CAAAA,CAAO,QAAA,CAAS,aAAA,CAAc,MAAM,EAC1CA,CAAAA,CAAK,EAAA,CAAKF,GACVE,CAAAA,CAAK,GAAA,CAAM,aACXA,CAAAA,CAAK,IAAA,CAAO,mEACZ,QAAA,CAAS,IAAA,CAAK,YAAYA,CAAI,EAChC,EAAG,EAAE,EACP,CAEA,SAASH,EAAAA,CAAW,CAAE,KAAAzB,CAAK,CAAA,CAAqB,CAC9C,OAAA2B,EAAAA,GAEEhD,cAAAA,CAAC,MAAA,CAAA,CACC,aAAA,CAAY,MAAA,CACZ,MAAO,CACL,UAAA,CAAY,wBACZ,QAAA,CAAUqB,CAAAA,CACV,WAAY,CAAA,CACZ,OAAA,CAAS,MAAA,CACT,UAAA,CAAY,SACZ,cAAA,CAAgB,QAAA,CAChB,UAAWA,CAAAA,CAAO,GAAA,CAClB,YAAaA,CAAAA,CAAO,GAAA,CACpB,WAAY,MACd,CAAA,CACD,aAED,CAEJ,CCtKO,SAAS6B,CAAAA,CAAQ,CAAE,IAAA,CAAA7B,CAAAA,CAAO,GAAI,KAAA,CAAA8B,CAAAA,CAAQ,cAAe,CAAA,CAAiB,CAC3E,OACEC,eAAAA,CAAC,OACC,KAAA,CAAO/B,CAAAA,CACP,OAAQA,CAAAA,CACR,OAAA,CAAQ,YACR,IAAA,CAAK,MAAA,CACL,MAAO,CACL,SAAA,CAAW,kCACb,CAAA,CAEA,QAAA,CAAA,CAAArB,eAAC,OAAA,CAAA,CACE,QAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,CAAA,CAWH,CAAA,CACAA,cAAAA,CAAC,QAAA,CAAA,CACC,EAAA,CAAG,KACH,EAAA,CAAG,IAAA,CACH,CAAA,CAAE,IAAA,CACF,MAAA,CAAQmD,CAAAA,CACR,WAAA,CAAY,GAAA,CACZ,cAAc,MAAA,CAChB,CAAA,CACAnD,cAAAA,CAAC,QAAA,CAAA,CACC,EAAA,CAAG,IAAA,CACH,EAAA,CAAG,IAAA,CACH,EAAE,IAAA,CACF,MAAA,CAAQmD,CAAAA,CACR,WAAA,CAAY,IACZ,aAAA,CAAc,OAAA,CACd,KAAA,CAAO,CACL,UAAW,uCACb,CAAA,CACF,CAAA,CAAA,CACF,CAEJ,CCjCO,SAASE,EAAAA,CAAa,CAC3B,KAAA,CAAA3B,CAAAA,CACA,WAAA,CAAA4B,CAAAA,CACA,WAAAC,CAAAA,CACA,SAAA,CAAAlD,CAAAA,CACA,QAAA,CAAAmD,CAAAA,CACA,YAAA,CAAA7B,CAAAA,CACA,aAAA,CAAA8B,EACA,SAAA,CAAAC,CAAAA,CAAY,KACd,CAAA,CAAsB,CACpB,GAAM,CAACC,CAAAA,CAASC,CAAU,EAAInE,cAAAA,CAASgE,CAAAA,EAAe,OAAA,EAAW,EAAE,CAAA,CAC7D,CAACI,CAAAA,CAAQC,CAAS,EAAIrE,cAAAA,CAAwBgE,CAAAA,EAAe,MAAA,EAAU,IAAI,CAAA,CAC3E,CAACnC,CAAAA,CAASW,CAAU,EAAIxC,cAAAA,CAAS,KAAK,CAAA,CAE5CmB,eAAAA,CAAU,IAAM,CACdqB,CAAAA,CAAWd,CAAAA,EAAe,EAC5B,CAAA,CAAG,EAAE,EAGLP,eAAAA,CAAU,IAAM,CACV6C,CAAAA,EAAe,UAAY,MAAA,EAC7BG,CAAAA,CAAWH,CAAAA,CAAc,OAAA,EAAW,EAAE,CAAA,CAEpCA,CAAAA,EAAe,MAAA,GAAW,QAC5BK,CAAAA,CAAUL,CAAAA,CAAc,MAAA,EAAU,IAAI,EAE1C,CAAA,CAAG,CAACA,CAAAA,EAAe,OAAA,CAASA,GAAe,MAAM,CAAC,CAAA,CAElD,IAAMb,CAAAA,CAASlB,CAAAA,GAAU,MAAA,CAEnBqC,CAAAA,CAAgBvB,GAAuB,CAC3CA,CAAAA,CAAE,cAAA,EAAe,CACb,GAACmB,CAAAA,CAAQ,IAAA,EAAK,EAAKE,CAAAA,GAAW,OAClCL,CAAAA,CAAS,CAAE,OAAA,CAASG,CAAAA,CAAQ,IAAA,EAAK,EAAK,MAAA,CAAW,MAAA,CAAQE,GAAU,MAAU,CAAC,EAChF,CAAA,CAEMG,CAAAA,CAAmC,CACvC,KAAA,CAAO,MAAA,CACP,QAAS1C,CAAAA,CAAU,WAAA,CAAc,WAAA,CACjC,MAAA,CAAQ,CAAA,UAAA,EAAasB,CAAAA,CAAS,wBAAA,CAA2B,SAAS,GAClE,YAAA,CAAc,CAAA,CACd,eAAA,CAAiBA,CAAAA,CAAS,qBAAuB,SAAA,CACjD,KAAA,CAAOA,CAAAA,CAAS,SAAA,CAAY,UAC5B,QAAA,CAAUtB,CAAAA,CAAU,EAAA,CAAK,EAAA,CACzB,MAAA,CAAQ,UAAA,CACR,SAAA,CAAWA,CAAAA,CAAU,IAAM,EAAA,CAC3B,UAAA,CAAY,SAAA,CACZ,OAAA,CAAS,OACT,UAAA,CAAY,8FAAA,CACZ,UAAA,CAAY,GAAA,CACZ,GAAGK,CAAAA,EAAc,KACnB,CAAA,CAEMsC,CAAAA,CAAoC,CACxC,KAAA,CAAO,MAAA,CACP,OAAA,CAAS3C,EAAU,WAAA,CAAc,WAAA,CACjC,MAAA,CAAQ,MAAA,CACR,aAAc,CAAA,CACd,eAAA,CAAiBsB,CAAAA,CAAS,SAAA,CAAY,UACtC,KAAA,CAAOA,CAAAA,CAAS,SAAA,CAAY,SAAA,CAC5B,QAAA,CAAUtB,CAAAA,CAAU,EAAA,CAAK,EAAA,CACzB,WAAY,GAAA,CACZ,MAAA,CAAQjB,CAAAA,CAAY,aAAA,CAAgB,SAAA,CACpC,UAAA,CAAY,uCAAA,CACZ,aAAA,CAAe,SACf,GAAGsB,CAAAA,EAAc,YACnB,CAAA,CAEA,OACEyB,eAAAA,CAAC,MAAA,CAAA,CAAK,QAAA,CAAUW,EAEd,QAAA,CAAA,CAAA/D,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,YAAA,CAAcsB,CAAAA,CAAU,EAAA,CAAK,EAAG,EAC5C,QAAA,CAAAtB,cAAAA,CAACkE,EAAAA,CAAA,CAAW,KAAA,CAAOL,CAAAA,CAAQ,QAAA,CAAUC,CAAAA,CAAW,OAAQlB,CAAAA,CAAQ,OAAA,CAAStB,CAAAA,CAAS,CAAA,CACpF,EAGAtB,cAAAA,CAAC,UAAA,CAAA,CACC,KAAA,CAAO2D,CAAAA,CACP,SAAWnB,CAAAA,EAAMoB,CAAAA,CAAWpB,CAAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAC1C,WAAA,CAAac,CAAAA,EAAe,yBAC5B,KAAA,CAAOU,CAAAA,CACP,QAAA,CAAU3D,CAAAA,CACV,aAAW,eAAA,CACX,OAAA,CAAUmC,CAAAA,EAAM,CACdA,EAAE,aAAA,CAAc,KAAA,CAAM,WAAA,CAAc,SAAA,CACpCA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,SAAA,CAAY,gCAClCA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,eAAA,CAAkBI,CAAAA,CAAS,oBAAA,CAAuB,UAC1E,CAAA,CACA,OAASJ,CAAAA,EAAM,CACbA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,WAAA,CAAcI,CAAAA,CAAS,wBAAA,CAA2B,UACxEJ,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,SAAA,CAAY,OAClCA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,eAAA,CAAkBI,EAAS,oBAAA,CAAuB,UAC1E,CAAA,CACF,CAAA,CAGAQ,eAAAA,CAAC,QAAA,CAAA,CACC,IAAA,CAAK,QAAA,CACL,SAAU/C,CAAAA,EAAc,CAACsD,CAAAA,CAAQ,IAAA,EAAK,EAAKE,CAAAA,GAAW,IAAA,CACtD,KAAA,CAAO,CACL,GAAGI,CAAAA,CACH,SAAA,CAAW,EAAA,CACX,OAAA,CAAS5D,CAAAA,CAAY,EAAA,CAAM,CAAA,CAC3B,gBAAkB,CAACsD,CAAAA,CAAQ,IAAA,EAAK,EAAKE,IAAW,IAAA,CAC3CjB,CAAAA,CAAS,SAAA,CAAY,SAAA,CACrBA,EAAS,SAAA,CAAY,SAAA,CAC1B,KAAA,CAAQ,CAACe,CAAAA,CAAQ,IAAA,EAAK,EAAKE,CAAAA,GAAW,KACjCjB,CAAAA,CAAS,SAAA,CAAY,SAAA,CACrBA,CAAAA,CAAS,SAAA,CAAY,SAAA,CAC1B,OAAA,CAAS,MAAA,CACT,WAAY,QAAA,CACZ,cAAA,CAAgB,QAAA,CAChB,GAAA,CAAK,CACP,CAAA,CACA,YAAA,CAAeJ,CAAAA,EAAM,CACdA,CAAAA,CAAE,aAAA,CAAc,QAAA,GACnBA,CAAAA,CAAE,cAAc,KAAA,CAAM,eAAA,CAAkBI,CAAAA,CAAS,SAAA,CAAY,WAEjE,CAAA,CACA,YAAA,CAAeJ,CAAAA,EAAM,CACdA,CAAAA,CAAE,aAAA,CAAc,QAAA,GACnBA,CAAAA,CAAE,cAAc,KAAA,CAAM,eAAA,CAAkBI,CAAAA,CAAS,SAAA,CAAY,WAEjE,CAAA,CAEC,QAAA,CAAA,CAAAvC,CAAAA,EAAaL,cAAAA,CAACkD,EAAA,CAAQ,IAAA,CAAM5B,CAAAA,CAAU,EAAA,CAAK,EAAA,CAAI,KAAA,CAAOsB,CAAAA,CAAS,SAAA,CAAY,UAAW,CAAA,CACtFvC,CAAAA,CAAaqD,CAAAA,CAAY,aAAA,CAAgB,gBAAoBA,CAAAA,CAAY,QAAA,CAAWH,CAAAA,CAAAA,CACvF,CAAA,CAAA,CACF,CAEJ,CASA,SAASW,EAAAA,CAAW,CAAE,KAAA,CAAAnE,CAAAA,CAAO,QAAA,CAAAoE,CAAAA,CAAU,OAAAvB,CAAAA,CAAQ,OAAA,CAAAtB,CAAQ,CAAA,CAAoB,CACzE,GAAM,CAAC8C,CAAAA,CAASC,CAAU,CAAA,CAAI5E,cAAAA,CAAwB,IAAI,CAAA,CACpD6E,CAAAA,CAAWhD,CAAAA,CAAU,EAAA,CAAK,EAAA,CAC1BiD,EAAgBjD,CAAAA,CAAU,CAAA,CAAI,CAAA,CAEpC,OACEtB,eAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,OAAA,CAAS,OACT,GAAA,CAAKsB,CAAAA,CAAU,CAAA,CAAI,CACrB,CAAA,CACA,IAAA,CAAK,OAAA,CACL,YAAA,CAAW,SAEV,QAAA,CAAA,CAAC,CAAA,CAAG,CAAA,CAAG,CAAA,CAAG,EAAG,CAAC,CAAA,CAAE,GAAA,CAAKkD,CAAAA,EAAS,CAC7B,IAAMC,CAAAA,CAAAA,CAAYL,CAAAA,EAAWrE,CAAAA,EAAS,CAAA,GAAMyE,CAAAA,CAC5C,OACExE,cAAAA,CAAC,UAEC,IAAA,CAAK,QAAA,CACL,OAAA,CAAS,IAAMmE,EAASK,CAAI,CAAA,CAC5B,YAAA,CAAc,IAAMH,EAAWG,CAAI,CAAA,CACnC,YAAA,CAAc,IAAMH,CAAAA,CAAW,IAAI,CAAA,CACnC,YAAA,CAAY,QAAQG,CAAI,CAAA,SAAA,CAAA,CACxB,cAAA,CAAczE,CAAAA,GAAUyE,CAAAA,CACxB,KAAA,CAAO,CACL,UAAA,CAAY,OACZ,MAAA,CAAQ,MAAA,CACR,MAAA,CAAQ,SAAA,CACR,OAAA,CAASD,CAAAA,CACT,KAAA,CAAOE,CAAAA,CAAW,UAAa7B,CAAAA,CAAS,wBAAA,CAA2B,SAAA,CACnE,UAAA,CAAY,yFACZ,SAAA,CAAYwB,CAAAA,GAAY,IAAA,EAAQA,CAAAA,EAAWI,EAAQ,YAAA,CAAe,UACpE,CAAA,CAEA,QAAA,CAAAxE,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAOsE,CAAAA,CAAU,OAAQA,CAAAA,CAAU,OAAA,CAAQ,WAAA,CAAY,IAAA,CAAK,eAC/D,QAAA,CAAAtE,cAAAA,CAAC,MAAA,CAAA,CAAK,CAAA,CAAE,+FAA+F,CAAA,CACzG,CAAA,CAAA,CAnBKwE,CAoBP,CAEJ,CAAC,CAAA,CACH,CAEJ,CC7LO,SAASE,EAAAA,CAAS,CAAE,KAAA,CAAAhD,CAAAA,CAAO,SAAA,CAAArB,EAAW,QAAA,CAAAmD,CAAAA,CAAU,WAAA,CAAAmB,CAAAA,CAAa,SAAA,CAAAjB,CAAAA,CAAY,KAAM,CAAA,CAAkB,CACtG,GAAM,CAACpC,CAAAA,CAASW,CAAU,CAAA,CAAIxC,cAAAA,CAAS,KAAK,CAAA,CACtC,CAACmF,CAAAA,CAAYC,CAAa,CAAA,CAAIpF,cAAAA,CAA+BkF,GAAe,IAAI,CAAA,CAChF,CAACG,CAAAA,CAAcC,CAAe,CAAA,CAAItF,cAAAA,CAA+BkF,CAAAA,EAAe,IAAI,CAAA,CAE1F/D,eAAAA,CAAU,IAAM,CACdqB,EAAWd,CAAAA,EAAe,EAC5B,CAAA,CAAG,EAAE,CAAA,CAGLP,eAAAA,CAAU,IAAM,CACV+D,CAAAA,GAAgB,MAAA,GAClBI,CAAAA,CAAgBJ,CAAW,CAAA,CAC3BE,CAAAA,CAAcF,CAAW,GAE7B,CAAA,CAAG,CAACA,CAAW,CAAC,EAGhB/D,eAAAA,CAAU,IAAM,CACV,CAACP,GAAa,CAACqD,CAAAA,EACjBmB,CAAAA,CAAc,IAAI,EAEtB,CAAA,CAAG,CAACxE,CAAAA,CAAWqD,CAAS,CAAC,CAAA,CAEzB,IAAMsB,CAAAA,CAAcC,CAAAA,EAAwB,CAC1CJ,CAAAA,CAAcI,CAAI,EAClBzB,CAAAA,CAAS,CAAE,IAAA,CAAAyB,CAAK,CAAC,EACnB,CAAA,CAEMrC,CAAAA,CAASlB,IAAU,MAAA,CAEnBwD,CAAAA,CAAmBC,CAAAA,EAAiD,CACxE,IAAMC,CAAAA,CAAaN,CAAAA,GAAiBK,CAAAA,CAEpC,OAAO,CACL,IAAA,CAAM,CAAA,CACN,QAAA,CAAU,CAAA,CACV,QAAA,CAAU,QAAA,CACV,OAAA,CAAS7D,CAAAA,CAAU,YAAc,WAAA,CACjC,MAAA,CAAQ,CAAA,UAAA,EAAa8D,CAAAA,CAChBD,IAAa,IAAA,CACXvC,CAAAA,CAAS,sBAAA,CAAyB,uBAAA,CAClCA,EAAS,qBAAA,CAAwB,sBAAA,CACnCA,CAAAA,CAAS,wBAAA,CAA2B,SAAU,CAAA,CAAA,CACnD,YAAA,CAActB,CAAAA,CAAU,GAAK,CAAA,CAC7B,eAAA,CAAiB8D,CAAAA,CACZD,CAAAA,GAAa,KACXvC,CAAAA,CAAS,uBAAA,CAA0B,uBAAA,CACnCA,CAAAA,CAAS,uBAAyB,sBAAA,CACpCA,CAAAA,CAAS,oBAAA,CAAuB,SAAA,CACrC,KAAA,CAAOwC,CAAAA,CAjBaD,CAAAA,GAAa,IAAA,CAAO,UAAY,SAAA,CAmB/CvC,CAAAA,CAAS,SAAA,CAAY,SAAA,CAC1B,QAAA,CAAUtB,CAAAA,CAAU,EAAA,CAAK,EAAA,CACzB,OAAQjB,CAAAA,CAAY,aAAA,CAAgB,SAAA,CACpC,UAAA,CAAY,uFAAA,CACZ,OAAA,CAAS,MAAA,CACT,UAAA,CAAY,SACZ,cAAA,CAAgB,QAAA,CAChB,GAAA,CAAKiB,CAAAA,CAAU,GAAK,CACtB,CACF,CAAA,CAEM+D,CAAAA,CAAW/D,EAAU,EAAA,CAAK,EAAA,CAEhC,OACE8B,eAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,OAAA,CAAS,OACT,GAAA,CAAK9B,CAAAA,CAAU,EAAA,CAAK,EACtB,EACA,IAAA,CAAK,OAAA,CACL,YAAA,CAAW,MAAA,CAEX,UAAAtB,cAAAA,CAAC,QAAA,CAAA,CACC,IAAA,CAAK,QAAA,CACL,OAAA,CAAS,IAAMgF,CAAAA,CAAW,IAAI,EAC9B,QAAA,CAAU3E,CAAAA,CACV,KAAA,CAAO6E,CAAAA,CAAgB,IAAI,CAAA,CAC3B,YAAA,CAAW,uBAAA,CACX,cAAA,CAAcJ,IAAiB,IAAA,CAC/B,YAAA,CAAetC,CAAAA,EAAM,CACdnC,CAAAA,GACHmC,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,UAAY,kBAAA,CAClCA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,SAAA,CAAY,4BAAA,EAEtC,CAAA,CACA,YAAA,CAAeA,GAAM,CACnBA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,SAAA,CAAY,eAAA,CAClCA,CAAAA,CAAE,aAAA,CAAc,MAAM,SAAA,CAAY,OACpC,CAAA,CAEC,QAAA,CAAAnC,GAAauE,CAAAA,GAAe,IAAA,CAC3BxB,eAAAA,CAAAkC,mBAAAA,CAAA,CACE,QAAA,CAAA,CAAAtF,cAAAA,CAACkD,CAAAA,CAAA,CAAQ,IAAA,CAAMmC,CAAAA,CAAU,KAAA,CAAOzC,CAAAA,CAAS,UAAY,SAAA,CAAW,CAAA,CAChE5C,cAAAA,CAAC,MAAA,CAAA,CAAK,MAAO,CAAE,QAAA,CAAUsB,CAAAA,CAAU,EAAA,CAAK,GAAI,UAAA,CAAY,GAAA,CAAK,aAAA,CAAe,QAAS,CAAA,CAClF,QAAA,CAAAoC,CAAAA,CAAY,aAAA,CAAgB,aAC/B,CAAA,CAAA,CACF,CAAA,CAEAN,eAAAA,CAAAkC,mBAAAA,CAAA,CACE,QAAA,CAAA,CAAAtF,cAAAA,CAACuF,EAAAA,CAAA,CAAa,KAAMF,CAAAA,CAAU,CAAA,CAC9BrF,cAAAA,CAAC,MAAA,CAAA,CAAK,KAAA,CAAO,CAAE,QAAA,CAAUsB,CAAAA,CAAU,GAAK,EAAA,CAAI,UAAA,CAAY,GAAA,CAAK,aAAA,CAAe,QAAS,CAAA,CAClF,QAAA,CAAAwD,CAAAA,GAAiB,KAAO,OAAA,CAAU,MAAA,CACrC,CAAA,CAAA,CACF,CAAA,CAEJ,CAAA,CAEA9E,cAAAA,CAAC,QAAA,CAAA,CACC,IAAA,CAAK,SACL,OAAA,CAAS,IAAMgF,CAAAA,CAAW,MAAM,EAChC,QAAA,CAAU3E,CAAAA,CACV,KAAA,CAAO6E,CAAAA,CAAgB,MAAM,CAAA,CAC7B,YAAA,CAAW,+BAAA,CACX,cAAA,CAAcJ,CAAAA,GAAiB,MAAA,CAC/B,YAAA,CAAetC,CAAAA,EAAM,CACdnC,CAAAA,GACHmC,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,SAAA,CAAY,kBAAA,CAClCA,CAAAA,CAAE,aAAA,CAAc,MAAM,SAAA,CAAY,4BAAA,EAEtC,CAAA,CACA,YAAA,CAAeA,CAAAA,EAAM,CACnBA,CAAAA,CAAE,aAAA,CAAc,MAAM,SAAA,CAAY,eAAA,CAClCA,CAAAA,CAAE,aAAA,CAAc,MAAM,SAAA,CAAY,OACpC,CAAA,CAEC,QAAA,CAAAnC,GAAauE,CAAAA,GAAe,MAAA,CAC3BxB,eAAAA,CAAAkC,mBAAAA,CAAA,CACE,QAAA,CAAA,CAAAtF,cAAAA,CAACkD,CAAAA,CAAA,CAAQ,IAAA,CAAMmC,CAAAA,CAAU,KAAA,CAAOzC,CAAAA,CAAS,SAAA,CAAY,SAAA,CAAW,CAAA,CAChE5C,cAAAA,CAAC,QAAK,KAAA,CAAO,CAAE,QAAA,CAAUsB,CAAAA,CAAU,EAAA,CAAK,EAAA,CAAI,UAAA,CAAY,GAAA,CAAK,cAAe,QAAS,CAAA,CAClF,QAAA,CAAAoC,CAAAA,CAAY,cAAgB,YAAA,CAC/B,CAAA,CAAA,CACF,CAAA,CAEAN,eAAAA,CAAAkC,oBAAA,CACE,QAAA,CAAA,CAAAtF,cAAAA,CAACwF,EAAAA,CAAA,CAAe,IAAA,CAAMH,CAAAA,CAAU,CAAA,CAChCrF,eAAC,MAAA,CAAA,CAAK,KAAA,CAAO,CAAE,QAAA,CAAUsB,EAAU,EAAA,CAAK,EAAA,CAAI,UAAA,CAAY,GAAA,CAAK,cAAe,QAAS,CAAA,CAClF,QAAA,CAAAwD,CAAAA,GAAiB,MAAA,CAAS,UAAA,CAAa,SAAA,CAC1C,CAAA,CAAA,CACF,EAEJ,CAAA,CAAA,CACF,CAEJ,CAEA,SAASS,GAAa,CAAE,IAAA,CAAAlE,CAAAA,CAAO,EAAG,EAAsB,CACtD,OACErB,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAOqB,CAAAA,CAAM,MAAA,CAAQA,CAAAA,CAAM,QAAQ,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe,WAAA,CAAY,MAAA,CAAO,aAAA,CAAc,QAAQ,cAAA,CAAe,OAAA,CAC5I,QAAA,CAAArB,cAAAA,CAAC,MAAA,CAAA,CAAK,CAAA,CAAE,qHAAA,CAAsH,CAAA,CAChI,CAEJ,CAEA,SAASwF,EAAAA,CAAe,CAAE,KAAAnE,CAAAA,CAAO,EAAG,CAAA,CAAsB,CACxD,OACErB,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAOqB,CAAAA,CAAM,MAAA,CAAQA,CAAAA,CAAM,OAAA,CAAQ,WAAA,CAAY,KAAK,MAAA,CAAO,MAAA,CAAO,cAAA,CAAe,WAAA,CAAY,OAAO,aAAA,CAAc,OAAA,CAAQ,cAAA,CAAe,OAAA,CAC5I,SAAArB,cAAAA,CAAC,MAAA,CAAA,CAAK,CAAA,CAAE,uIAAA,CAAwI,CAAA,CAClJ,CAEJ,CCjJO,SAASyF,EAAAA,CAAY,CAC1B,KAAAC,CAAAA,CACA,KAAA,CAAAhE,CAAAA,CACA,YAAA,CAAAC,CAAAA,CACA,UAAA,CAAAgE,CAAAA,CACA,WAAA,CAAArC,EACA,UAAA,CAAAC,CAAAA,CACA,eAAA,CAAAqC,CAAAA,CACA,SAAA,CAAAvF,CAAAA,CACA,WAAA,CAAAwF,CAAAA,CACA,MAAA9H,CAAAA,CACA,gBAAA,CAAA2C,CAAAA,CACA,SAAA,CAAAgD,CAAAA,CAAY,KAAA,CACZ,QAAA,CAAAF,CAAAA,CACA,QAAAsC,CAAAA,CACA,UAAA,CAAAC,CACF,CAAA,CAAqB,CACnB,IAAMC,CAAAA,CAAWC,YAAAA,CAAuB,IAAI,EACtCC,CAAAA,CAAoBD,YAAAA,CAA0B,IAAI,CAAA,CAClD,CAACE,CAAAA,CAAWC,CAAY,CAAA,CAAI3G,eAAS,KAAK,CAAA,CAC1C,CAAC4G,CAAAA,CAAUC,CAAW,CAAA,CAAI7G,cAAAA,CAAS,KAAK,CAAA,CACxC,CAAC2C,CAAAA,CAAaC,CAAc,CAAA,CAAI5C,cAAAA,CAA2B,OAAO,CAAA,CAGxEmB,eAAAA,CAAU,IAAM,CACd0F,CAAAA,CAAY,MAAA,CAAO,UAAA,CAAa,GAAG,EAGnC,IAAMhE,CAAAA,CAAY,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,CAClED,CAAAA,CAAeC,CAAAA,CAAU,OAAA,CAAU,MAAA,CAAS,OAAO,CAAA,CAGnD,IAAMC,EAAWC,CAAAA,EAA2BH,CAAAA,CAAeG,CAAAA,CAAE,OAAA,CAAU,MAAA,CAAS,OAAO,CAAA,CACvF,OAAAF,EAAU,gBAAA,CAAiB,QAAA,CAAUC,CAAO,CAAA,CACrC,IAAMD,CAAAA,CAAU,mBAAA,CAAoB,QAAA,CAAUC,CAAO,CAC9D,CAAA,CAAG,EAAE,EAGL3B,eAAAA,CAAU,IAAM,CACd,IAAM2F,EAAQ,qBAAA,CAAsB,IAAMH,CAAAA,CAAa,IAAI,CAAC,CAAA,CAC5D,OAAO,IAAM,qBAAqBG,CAAK,CACzC,CAAA,CAAG,EAAE,CAAA,CAGL,IAAMC,CAAAA,CAAgB9E,IAAU,MAAA,CAASU,CAAAA,CAAcV,CAAAA,CAEjDkB,CAAAA,CAAS4D,CAAAA,GAAkB,MAAA,CAO3BC,CAAAA,CAAAA,CAHaV,CAAAA,CACf,OAAO,WAAA,CAAcA,CAAAA,CAAW,MAAA,CAChC,MAAA,CAAO,YAAc,CAAA,EAHL,GAAA,CAIyB,EAAA,CAG7CnF,eAAAA,CAAU,IAAM,CACd,IAAM8F,CAAAA,CAAQV,CAAAA,CAAS,OAAA,CACvB,GAAI,CAACU,CAAAA,CAAO,OAGZR,CAAAA,CAAkB,OAAA,EAAS,KAAA,EAAM,CAEjC,IAAMS,CAAAA,CAAiBnE,CAAAA,EAAqB,CAC1C,GAAIA,CAAAA,CAAE,GAAA,GAAQ,QAAA,CAAU,CACtBsD,CAAAA,EAAQ,CACR,MACF,CAEA,GAAItD,CAAAA,CAAE,GAAA,GAAQ,KAAA,CAAO,CACnB,IAAMoE,CAAAA,CAAoBF,CAAAA,CAAM,gBAAA,CAC9B,0EACF,EACMG,CAAAA,CAAeD,CAAAA,CAAkB,CAAC,CAAA,CAClCE,CAAAA,CAAcF,CAAAA,CAAkBA,CAAAA,CAAkB,MAAA,CAAS,CAAC,CAAA,CAE9DpE,CAAAA,CAAE,QAAA,EAAY,QAAA,CAAS,gBAAkBqE,CAAAA,EAC3CrE,CAAAA,CAAE,cAAA,EAAe,CACjBsE,GAAa,KAAA,EAAM,EACV,CAACtE,CAAAA,CAAE,QAAA,EAAY,QAAA,CAAS,aAAA,GAAkBsE,CAAAA,GACnDtE,EAAE,cAAA,EAAe,CACjBqE,CAAAA,EAAc,KAAA,IAElB,CACF,CAAA,CAEA,OAAA,QAAA,CAAS,gBAAA,CAAiB,UAAWF,CAAa,CAAA,CAC3C,IAAM,QAAA,CAAS,mBAAA,CAAoB,SAAA,CAAWA,CAAa,CACpE,EAAG,CAACb,CAAO,CAAC,CAAA,CAEZ,IAAMiB,CAAAA,CAAgBrB,CAAAA,GAAS,MAAA,CAC3B,qBACA,oCAAA,CAGEsB,CAAAA,CAAeX,CAAAA,CAAW,EAAA,CAAK,EAAA,CAE/BY,CAAAA,CAAgBrE,CAAAA,CAClB,oFAAA,CACA,wFAEEsE,CAAAA,CAAmCb,CAAAA,CACrC,CAEE,QAAA,CAAU,QACV,IAAA,CAAM,KAAA,CACN,GAAA,CAAK,KAAA,CACL,MAAO,oBAAA,CACP,QAAA,CAAU,GAAA,CACV,OAAA,CAASW,CAAAA,CACT,YAAA,CAAc,EAAA,CACd,eAAA,CAAiBpE,EAAS,SAAA,CAAY,SAAA,CACtC,KAAA,CAAOA,CAAAA,CAAS,UAAY,SAAA,CAC5B,SAAA,CAAWqE,CAAAA,CACX,MAAA,CAAQ,aAAarE,CAAAA,CAAS,wBAAA,CAA2B,kBAAkB,CAAA,CAAA,CAC3E,MAAA,CAAQ,IAAA,CACR,UAAA,CAAY,0FAAA,CACZ,QAASuD,CAAAA,CAAY,CAAA,CAAI,CAAA,CACzB,SAAA,CAAWA,EACP,gCAAA,CACA,mCAAA,CACJ,GAAGxE,CAAAA,EAAc,KACnB,CAAA,CACA,CAEE,QAAA,CAAU,UAAA,CACV,IAAA,CAAM,KAAA,CACN,KAAA,CAAO,GAAA,CACP,QAASqF,CAAAA,CACT,YAAA,CAAc,EAAA,CACd,eAAA,CAAiBpE,CAAAA,CAAS,SAAA,CAAY,SAAA,CACtC,KAAA,CAAOA,EAAS,SAAA,CAAY,SAAA,CAC5B,SAAA,CAAWqE,CAAAA,CACX,MAAA,CAAQ,CAAA,UAAA,EAAarE,CAAAA,CAAS,wBAAA,CAA2B,kBAAkB,CAAA,CAAA,CAC3E,MAAA,CAAQ,IAAA,CACR,GAAI6D,EACA,CAAE,MAAA,CAAQ,MAAA,CAAQ,YAAA,CAAc,CAAE,CAAA,CAClC,CAAE,GAAA,CAAK,MAAA,CAAQ,SAAA,CAAW,CAAE,CAAA,CAChC,UAAA,CAAY,2FACZ,OAAA,CAASN,CAAAA,CAAY,CAAA,CAAI,CAAA,CACzB,UAAWA,CAAAA,CACP,yCAAA,CACA,CAAA,wCAAA,EAA2CM,CAAAA,CAAY,MAAQ,MAAM,CAAA,CAAA,CAAA,CACzE,GAAG9E,CAAAA,EAAc,KACnB,CAAA,CAEJ,OACEyB,eAAAA,CAAC,OACC,GAAA,CAAK4C,CAAAA,CACL,IAAA,CAAK,QAAA,CACL,aAAW,MAAA,CACX,iBAAA,CAAgB,oBAAA,CAChB,KAAA,CAAOkB,EACP,SAAA,CAAWjG,CAAAA,CAAG,cAAA,CAAgB2B,CAAAA,EAAU,oBAAoB,CAAA,CAG5D,QAAA,CAAA,CAAA5C,cAAAA,CAAC,UACC,GAAA,CAAKkG,CAAAA,CACL,IAAA,CAAK,QAAA,CACL,OAAA,CAASJ,CAAAA,CACT,YAAA,CAAW,qBAAA,CACX,MAAO,CACL,QAAA,CAAU,UAAA,CACV,GAAA,CAAKO,CAAAA,CAAW,EAAA,CAAK,CAAA,CACrB,KAAA,CAAOA,EAAW,EAAA,CAAK,CAAA,CACvB,KAAA,CAAOA,CAAAA,CAAW,GAAK,EAAA,CACvB,MAAA,CAAQA,CAAAA,CAAW,EAAA,CAAK,GACxB,MAAA,CAAQ,MAAA,CACR,UAAA,CAAY,aAAA,CACZ,MAAA,CAAQ,SAAA,CACR,KAAA,CAAOzD,CAAAA,CAAS,UAAY,SAAA,CAC5B,OAAA,CAAS,MAAA,CACT,UAAA,CAAY,QAAA,CACZ,cAAA,CAAgB,QAAA,CAChB,YAAA,CAAc,EACd,UAAA,CAAY,wCACd,CAAA,CACA,YAAA,CAAeJ,CAAAA,EAAM,CACnBA,CAAAA,CAAE,aAAA,CAAc,MAAM,eAAA,CAAkBI,CAAAA,CAAS,wBAAA,CAA2B,kBAAA,CAC5EJ,EAAE,aAAA,CAAc,KAAA,CAAM,KAAA,CAAQI,CAAAA,CAAS,UAAY,UACrD,CAAA,CACA,YAAA,CAAeJ,CAAAA,EAAM,CACnBA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,gBAAkB,aAAA,CACxCA,CAAAA,CAAE,aAAA,CAAc,KAAA,CAAM,KAAA,CAAQI,CAAAA,CAAS,SAAA,CAAY,UACrD,EAEA,QAAA,CAAA5C,cAAAA,CAAC,KAAA,CAAA,CAAI,KAAA,CAAOqG,CAAAA,CAAW,EAAA,CAAK,EAAA,CAAI,MAAA,CAAQA,EAAW,EAAA,CAAK,EAAA,CAAI,OAAA,CAAQ,WAAA,CAAY,KAAK,MAAA,CACnF,QAAA,CAAArG,cAAAA,CAAC,MAAA,CAAA,CACC,EAAE,sBAAA,CACF,MAAA,CAAO,cAAA,CACP,WAAA,CAAY,KAAA,CACZ,aAAA,CAAc,OAAA,CAChB,CAAA,CACF,EACF,CAAA,CAGAA,cAAAA,CAAC,IAAA,CAAA,CACC,EAAA,CAAG,qBACH,KAAA,CAAO,CACL,MAAA,CAAQ,YAAA,CACR,SAAUqG,CAAAA,CAAW,EAAA,CAAK,EAAA,CAC1B,UAAA,CAAY,GAAA,CACZ,YAAA,CAAcA,CAAAA,CAAW,EAAA,CAAK,GAC9B,aAAA,CAAe,SAAA,CACf,UAAA,CAAY,GACd,EAEC,QAAA,CAAAV,CAAAA,EAAcoB,CAAAA,CACjB,CAAA,CAGClB,GACCzC,eAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,SAAA,CAAW,QAAA,CACX,OAAA,CAAS,QAAA,CACT,MAAOR,CAAAA,CAAS,SAAA,CAAY,SAC9B,CAAA,CAEA,QAAA,CAAA,CAAA5C,cAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,KAAA,CAAO,EAAA,CACP,MAAA,CAAQ,EAAA,CACR,YAAA,CAAc,KAAA,CACd,eAAA,CAAiB4C,CAAAA,CAAS,uBAAyB,sBAAA,CACnD,OAAA,CAAS,MAAA,CACT,UAAA,CAAY,SACZ,cAAA,CAAgB,QAAA,CAChB,MAAA,CAAQ,aACV,EAEA,QAAA,CAAA5C,cAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAM,IAAA,CACN,MAAA,CAAO,IAAA,CACP,OAAA,CAAQ,YACR,IAAA,CAAK,MAAA,CAEL,QAAA,CAAAA,cAAAA,CAAC,QACC,CAAA,CAAE,iBAAA,CACF,MAAA,CAAO,cAAA,CACP,YAAY,GAAA,CACZ,aAAA,CAAc,OAAA,CACd,cAAA,CAAe,OAAA,CACjB,CAAA,CACF,CAAA,CACF,CAAA,CACAA,eAAC,GAAA,CAAA,CAAE,KAAA,CAAO,CAAE,MAAA,CAAQ,EAAG,QAAA,CAAU,EAAA,CAAI,UAAA,CAAY,GAAA,CAAK,MAAO4C,CAAAA,CAAS,SAAA,CAAY,SAAU,CAAA,CACzF,QAAA,CAAAgD,CAAAA,CACH,CAAA,CAAA,CACF,CAAA,CAID7H,GAAS,CAAC8H,CAAAA,EACT7F,cAAAA,CAAC,KAAA,CAAA,CACC,KAAA,CAAO,CACL,OAAA,CAAS,UAAA,CACT,aAAc,EAAA,CACd,YAAA,CAAc,CAAA,CACd,eAAA,CAAiB4C,CAAAA,CAAS,qBAAA,CAAwB,SAAA,CAClD,MAAA,CAAQ,aAAaA,CAAAA,CAAS,uBAAA,CAA0B,qBAAqB,CAAA,CAAA,CAC7E,MAAOA,CAAAA,CAAS,SAAA,CAAY,SAAA,CAC5B,QAAA,CAAU,GACV,UAAA,CAAY,GACd,CAAA,CAEC,QAAA,CAAA7E,CAAAA,CACH,CAAA,CAID,CAAC8H,CAAAA,EACAzC,gBAAAkC,mBAAAA,CAAA,CACG,QAAA,CAAA,CAAAI,CAAAA,GAAS,YACR1F,cAAAA,CAACqD,EAAAA,CAAA,CACC,KAAA,CAAOmD,EACP,WAAA,CAAalD,CAAAA,CACb,UAAA,CAAYC,CAAAA,CACZ,SAAA,CAAWlD,CAAAA,CACX,QAAA,CAAUmD,CAAAA,CACV,aAAc7B,CAAAA,CACd,aAAA,CAAejB,CAAAA,CAAmB,CAChC,QAASA,CAAAA,CAAiB,OAAA,CAC1B,MAAA,CAAQA,CAAAA,CAAiB,MAC3B,CAAA,CAAI,MAAA,CACJ,SAAA,CAAWgD,CAAAA,CACb,CAAA,CAEDgC,CAAAA,GAAS,MAAA,EACR1F,cAAAA,CAAC0E,GAAA,CACC,KAAA,CAAO8B,CAAAA,CACP,SAAA,CAAWnG,CAAAA,CACX,QAAA,CAAUmD,CAAAA,CACV,WAAA,CAAa9C,GAAkB,IAAA,EAAQ,MAAA,CACvC,SAAA,CAAWgD,CAAAA,CACb,CAAA,CAAA,CAEJ,CAAA,CAIFN,eAAAA,CAAC,KAAA,CAAA,CAAI,YAAU,QAAA,CAAS,SAAA,CAAU,SAAA,CAAU,KAAA,CAAO,CAAE,QAAA,CAAU,UAAA,CAAY,IAAA,CAAM,KAAM,EACpF,QAAA,CAAA,CAAAyC,CAAAA,EAAe,8CAAA,CACf9H,CAAAA,EAAS,CAAA,OAAA,EAAUA,CAAK,CAAA,CAAA,CAAA,CAC3B,CAAA,CAAA,CACF,CAEJ,CChQO,SAASoJ,GAAO,CACrB,SAAA,CAAApI,CAAAA,CACA,IAAA,CAAAF,CAAAA,CACA,IAAA,CAAA6G,CAAAA,CAAO,UAAA,CACP,aAAA0B,CAAAA,CACA,OAAA,CAAAC,CAAAA,CACA,OAAA,CAAA5J,EACA,aAAA,CAAA6J,CAAAA,CAAgB,KAAA,CAChB,WAAA,CAAAC,EAAc,IAAA,CACd,QAAA,CAAAC,CAAAA,CAAWvK,CAAAA,CAAS,QAAA,CACpB,IAAA,CAAAoE,CAAAA,CAAOpE,CAAAA,CAAS,KAChB,KAAA,CAAAyE,CAAAA,CAAQzE,CAAAA,CAAS,KAAA,CACjB,YAAA,CAAA0E,CAAAA,CACA,OAAA,CAAA8F,CAAAA,CAAU,KACV,WAAA,CAAA7F,CAAAA,CAAc3E,CAAAA,CAAS,aAAA,CACvB,aAAA,CAAA4E,CAAAA,CAAgB5E,CAAAA,CAAS,cAAA,CACzB,WAAA0I,CAAAA,CACA,WAAA,CAAArC,CAAAA,CACA,UAAA,CAAAC,EAAatG,CAAAA,CAAS,WAAA,CACtB,eAAA,CAAA2I,CAAAA,CAAkB3I,EAAS,iBAAA,CAC3B,QAAA,CAAAuG,CAAAA,CACA,MAAA,CAAAkE,CAAAA,CACA,OAAA,CAAA5B,CAAAA,CACA,OAAA,CAAA6B,CACF,CAAA,CAAgB,CACd,GAAM,CAAE,SAAAtI,CAAAA,CAAU,aAAA,CAAAE,CAAAA,CAAe,SAAA,CAAAK,GAAW,UAAA,CAAAE,CAAW,CAAA,CAAIG,CAAAA,EAAiB,CACtE,CAAC4F,CAAAA,CAAa+B,CAAc,EAAInI,cAAAA,CAAS,KAAK,CAAA,CAC9C,CAACuC,EAAiB6F,CAAkB,CAAA,CAAIpI,cAAAA,CAAS,KAAK,EACtD,CAACsG,CAAAA,CAAY+B,CAAa,CAAA,CAAIrI,cAAAA,CAAyB,IAAI,CAAA,CAC3D,CAAC4G,EAAUC,CAAW,CAAA,CAAI7G,cAAAA,CAAS,KAAK,CAAA,CACxCsI,CAAAA,CAAe9B,YAAAA,CAAuB,IAAI,EAGhDrF,eAAAA,CAAU,IAAM,CACd0F,CAAAA,CAAY,MAAA,CAAO,UAAA,CAAa,GAAG,EACrC,EAAG,EAAE,CAAA,CAGL,IAAMvE,EAASxC,CAAAA,GAAkBR,CAAAA,CAGjC6B,eAAAA,CAAU,IAAM,CACd,GAAI,CAACgB,CAAAA,CAAa,OAElB,IAAMoG,CAAAA,CAAYD,CAAAA,CAAa,OAAA,CAC/B,GAAI,CAACC,CAAAA,CAAW,OAGhB,IAAMC,EAASD,CAAAA,CAAU,aAAA,CACzB,GAAI,CAACC,EAAQ,OAEb,IAAMC,EAAAA,CAAmB,IAAML,CAAAA,CAAmB,IAAI,CAAA,CAChDM,EAAAA,CAAmB,IAAMN,CAAAA,CAAmB,KAAK,CAAA,CAEvD,OAAAI,EAAO,gBAAA,CAAiB,YAAA,CAAcC,EAAgB,CAAA,CACtDD,EAAO,gBAAA,CAAiB,YAAA,CAAcE,EAAgB,CAAA,CAE/C,IAAM,CACXF,CAAAA,CAAO,mBAAA,CAAoB,aAAcC,EAAgB,CAAA,CACzDD,CAAAA,CAAO,mBAAA,CAAoB,YAAA,CAAcE,EAAgB,EAC3D,CACF,EAAG,CAACvG,CAAW,CAAC,CAAA,CAEhB,GAAM,CAAE,MAAA,CAAAwG,CAAAA,CAAQ,UAAA/H,EAAAA,CAAW,KAAA,CAAAtC,EAAAA,CAAO,gBAAA,CAAA2C,GAAkB,SAAA,CAAAgD,CAAU,CAAA,CAAItD,EAAAA,CAAU,CAC1E,SAAA,CAAArB,CAAAA,CACA,IAAA,CAAA2G,CAAAA,CACA,YAAA,CAAA0B,CAAAA,CACA,OAAA,CAAAC,CAAAA,CACA,YAAa5J,CAAAA,CACb,IAAA,CAAAoB,CAAAA,CACA,SAAA,CAAYf,GAAa,CACvB8J,CAAAA,CAAe,IAAI,CAAA,CACnBpE,IAAW1F,CAAQ,CAAA,CAEnB,UAAA,CAAW,IAAM,CACfgC,CAAAA,EAAW,CACX8H,CAAAA,CAAe,KAAK,EACtB,CAAA,CAAG,IAAI,EACT,EACA,OAAA,CAAU7G,CAAAA,EAAQ,CAChB4G,CAAAA,GAAU5G,CAA6B,EACzC,CACF,CAAC,CAAA,CAEKsH,EAAAA,CAAaxI,iBAAAA,CAAY,IAAM,CAC/BkI,EAAa,OAAA,EACfD,CAAAA,CAAcC,CAAAA,CAAa,OAAA,CAAQ,qBAAA,EAAuB,CAAA,CAE5DnI,EAAAA,CAAUb,CAAS,CAAA,CACnB2I,CAAAA,KACF,CAAA,CAAG,CAAC3I,CAAAA,CAAWa,EAAAA,CAAW8H,CAAM,CAAC,CAAA,CAE3BY,EAAAA,CAAczI,iBAAAA,CAAY,IAAM,CACpCC,CAAAA,EAAW,CACX8H,CAAAA,CAAe,KAAK,EACpB9B,CAAAA,KACF,CAAA,CAAG,CAAChG,CAAAA,CAAYgG,CAAO,CAAC,CAAA,CAElB/B,GAAelE,iBAAAA,CAClBlB,CAAAA,EAAsE,CACrEyJ,CAAAA,CAAOzJ,CAAI,EACb,CAAA,CACA,CAACyJ,CAAM,CACT,CAAA,CAGA,OAAI/I,CAAAA,EAAY,CAACoI,CAAAA,CAAgB,IAAA,CAY/BrE,eAAAA,CAAC,OACC,GAAA,CAAK2E,CAAAA,CACL,KAAA,CAAO,CACL,GAZwD,CAC5D,WAAA,CAAa,CAAE,QAAA,CAAU,WAAY,GAAA,CAAK,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,SAAA,CAAW,sBAAuB,CAAA,CACzF,UAAA,CAAY,CAAE,QAAA,CAAU,UAAA,CAAY,GAAA,CAAK,CAAA,CAAG,IAAA,CAAM,CAAA,CAAG,SAAA,CAAW,uBAAwB,EACxF,cAAA,CAAgB,CAAE,QAAA,CAAU,UAAA,CAAY,MAAA,CAAQ,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,UAAW,qBAAsB,CAAA,CAC9F,aAAA,CAAe,CAAE,SAAU,UAAA,CAAY,MAAA,CAAQ,CAAA,CAAG,IAAA,CAAM,EAAG,SAAA,CAAW,sBAAuB,CAAA,CAC7F,MAAA,CAAU,CAAE,QAAA,CAAU,UAAA,CAAY,OAAA,CAAS,aAAc,CAC3D,CAAA,CAMwBP,CAAQ,CAAA,CAC1B,OAAQzF,CAAAA,CAAS,GAAA,CAAQ,MAC3B,CAAA,CACA,UAAU,kBAAA,CACV,qBAAA,CAAqBhD,CAAAA,CAErB,QAAA,CAAA,CAAAiB,cAAAA,CAACyB,EAAAA,CAAA,CACC,IAAA,CAAMJ,EACN,KAAA,CAAOK,CAAAA,CACP,YAAA,CAAcC,CAAAA,CACd,YAAaC,CAAAA,CACb,aAAA,CAAeC,CAAAA,CACf,OAAA,CAASwG,GACT,MAAA,CAAQtG,CAAAA,CACR,eAAA,CAAiBC,CAAAA,CACnB,CAAA,CAECD,CAAAA,EAAU,CAACsE,CAAAA,EACVrG,eAACyF,EAAAA,CAAA,CACC,IAAA,CAAMC,CAAAA,CACN,KAAA,CAAOhE,CAAAA,CACP,YAAA,CAAcC,CAAAA,CACd,WAAYgE,CAAAA,CACZ,WAAA,CAAarC,CAAAA,CACb,UAAA,CAAYC,CAAAA,CACZ,eAAA,CAAiBG,CAAAA,CAAY,iCAAA,CAAoCkC,EACjE,SAAA,CAAWvF,EAAAA,CACX,WAAA,CAAawF,CAAAA,CACb,MAAO9H,EAAAA,CACP,gBAAA,CAAkB2C,EAAAA,CAClB,SAAA,CAAWgD,EACX,QAAA,CAAUK,EAAAA,CACV,OAAA,CAASuE,EAAAA,CACT,UAAA,CAAYvC,CAAAA,EAAc,MAAA,CAC5B,CAAA,CAIDhE,GAAUsE,CAAAA,EAAYkC,qBAAAA,CACrBvI,cAAAA,CAAC,KAAA,CAAA,CACC,MAAO,CACL,QAAA,CAAU,OAAA,CACV,KAAA,CAAO,EACP,MAAA,CAAQ,KAAA,CACR,eAAA,CAAiB,oBACnB,CAAA,CACA,OAAA,CAASsI,EAAAA,CACT,aAAA,CAAY,OAEZ,QAAA,CAAAtI,cAAAA,CAAC,KAAA,CAAA,CAAI,OAAA,CAAUwC,GAAMA,CAAAA,CAAE,eAAA,EAAgB,CACrC,QAAA,CAAAxC,eAACyF,EAAAA,CAAA,CACC,IAAA,CAAMC,CAAAA,CACN,KAAA,CAAOhE,CAAAA,CACP,YAAA,CAAcC,CAAAA,CACd,WAAYgE,CAAAA,CACZ,WAAA,CAAarC,CAAAA,CACb,UAAA,CAAYC,CAAAA,CACZ,eAAA,CAAiBG,CAAAA,CAAY,iCAAA,CAAoCkC,EACjE,SAAA,CAAWvF,EAAAA,CACX,WAAA,CAAawF,CAAAA,CACb,KAAA,CAAO9H,EAAAA,CACP,gBAAA,CAAkB2C,EAAAA,CAClB,UAAWgD,CAAAA,CACX,QAAA,CAAUK,EAAAA,CACV,OAAA,CAASuE,GACT,UAAA,CAAYvC,CAAAA,EAAc,MAAA,CAC5B,CAAA,CACF,EACF,CAAA,CACA,QAAA,CAAS,IACX,CAAA,CAAA,CACF,CAEJ,CC5QO,SAASyC,EAAAA,EAAY,CAC1B,GAAM,CAAE,MAAA,CAAA9I,CAAAA,CAAQ,SAAAL,CAAAA,CAAU,WAAA,CAAAC,CAAAA,CAAa,KAAA,CAAA3B,CAAM,CAAA,CAAIsC,CAAAA,EAAiB,CAElE,OAAO,CAEL,MAAA,CAAAP,CAAAA,CAEA,QAAA,CAAAL,EAEA,WAAA,CAAAC,CAAAA,CAEA,KAAA,CAAA3B,CAAAA,CAEA,eAAgB+B,CAAAA,CAAO,cAAA,CAAe,IAAA,CAAKA,CAAM,CACnD,CACF","file":"index.js","sourcesContent":["// API URL\nexport const API_BASE_URL = 'https://gotcha.cx/api/v1';\n\n// Error codes\nexport const ERROR_CODES = {\n INVALID_API_KEY: 'INVALID_API_KEY',\n ORIGIN_NOT_ALLOWED: 'ORIGIN_NOT_ALLOWED',\n RATE_LIMITED: 'RATE_LIMITED',\n QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',\n INVALID_REQUEST: 'INVALID_REQUEST',\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n} as const;\n\n// Local storage keys\nexport const STORAGE_KEYS = {\n ANONYMOUS_ID: 'gotcha_anonymous_id',\n OFFLINE_QUEUE: 'gotcha_offline_queue',\n} as const;\n\n// Default values\nexport const DEFAULTS = {\n POSITION: 'top-right' as const,\n SIZE: 'md' as const,\n THEME: 'light' as const,\n SHOW_ON_HOVER: true,\n TOUCH_BEHAVIOR: 'always-visible' as const,\n SUBMIT_TEXT: 'Submit',\n THANK_YOU_MESSAGE: 'Thanks for your feedback!',\n} as const;\n\n// Size mappings (desktop/mobile in pixels)\nexport const SIZE_MAP = {\n sm: { desktop: 24, mobile: 44 },\n md: { desktop: 32, mobile: 44 },\n lg: { desktop: 40, mobile: 48 },\n} as const;\n\n// Retry config\nexport const RETRY_CONFIG = {\n MAX_RETRIES: 2,\n BASE_DELAY_MS: 500,\n MAX_DELAY_MS: 5000,\n} as const;\n","import { STORAGE_KEYS } from '../constants';\n\n/**\n * Get or create an anonymous user ID\n * Stored in localStorage for consistency across sessions\n */\nexport function getAnonymousId(): string {\n if (typeof window === 'undefined') {\n // SSR fallback - generate but don't persist\n return `anon_${crypto.randomUUID()}`;\n }\n\n const stored = localStorage.getItem(STORAGE_KEYS.ANONYMOUS_ID);\n if (stored) return stored;\n\n const id = `anon_${crypto.randomUUID()}`;\n localStorage.setItem(STORAGE_KEYS.ANONYMOUS_ID, id);\n return id;\n}\n\n/**\n * Clear the anonymous ID (useful for testing)\n */\nexport function clearAnonymousId(): void {\n if (typeof window !== 'undefined') {\n localStorage.removeItem(STORAGE_KEYS.ANONYMOUS_ID);\n }\n}\n","import { API_BASE_URL, RETRY_CONFIG } from '../constants';\nimport { SubmitResponsePayload, GotchaResponse, GotchaError, ExistingResponse, VoteType } from '../types';\nimport { getAnonymousId } from '../utils/anonymous';\n\ninterface ApiClientConfig {\n apiKey: string;\n baseUrl?: string;\n debug?: boolean;\n}\n\ninterface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: RETRY_CONFIG.MAX_RETRIES,\n baseDelayMs: RETRY_CONFIG.BASE_DELAY_MS,\n maxDelayMs: RETRY_CONFIG.MAX_DELAY_MS,\n};\n\n/**\n * Fetch with automatic retry and exponential backoff\n */\nasync function fetchWithRetry(\n url: string,\n options: RequestInit,\n config: RetryConfig = DEFAULT_RETRY_CONFIG,\n debug: boolean = false\n): Promise<Response> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n if (debug && attempt > 0) {\n console.log(`[Gotcha] Retry attempt ${attempt}/${config.maxRetries}`);\n }\n\n const response = await fetch(url, options);\n\n // Don't retry client errors (4xx) except 429 (rate limit)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return response;\n }\n\n // Success - return immediately\n if (response.ok) {\n return response;\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (error) {\n // Network error - retry\n lastError = error as Error;\n if (debug) {\n console.log(`[Gotcha] Network error: ${lastError.message}`);\n }\n }\n\n // Don't delay after last attempt\n if (attempt < config.maxRetries) {\n const delay = Math.min(\n config.baseDelayMs * Math.pow(2, attempt),\n config.maxDelayMs\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n\nexport function createApiClient(config: ApiClientConfig) {\n const { apiKey, baseUrl = API_BASE_URL, debug = false } = config;\n\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n };\n\n async function request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${baseUrl}${endpoint}`;\n const idempotencyKey = crypto.randomUUID();\n\n if (debug) {\n console.log(`[Gotcha] ${method} ${endpoint}`, body);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method,\n headers: {\n ...headers,\n 'Idempotency-Key': idempotencyKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response:`, data);\n }\n\n return data as T;\n }\n\n return {\n /**\n * Submit a response (feedback, vote, etc.)\n */\n async submitResponse(\n payload: Omit<SubmitResponsePayload, 'context'>\n ): Promise<GotchaResponse> {\n // Ensure user has an ID (anonymous if not provided)\n const user = payload.user || {};\n if (!user.id) {\n user.id = getAnonymousId();\n }\n\n const fullPayload: SubmitResponsePayload = {\n ...payload,\n user,\n context: {\n url: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n };\n\n return request<GotchaResponse>('POST', '/responses', fullPayload);\n },\n\n /**\n * Check if a user has an existing response for an element\n */\n async checkExistingResponse(\n elementId: string,\n userId: string\n ): Promise<ExistingResponse | null> {\n const url = `${baseUrl}/responses/check?elementId=${encodeURIComponent(elementId)}&userId=${encodeURIComponent(userId)}`;\n\n if (debug) {\n console.log(`[Gotcha] GET /responses/check`);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'GET',\n headers,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (data.exists) {\n if (debug) {\n console.log(`[Gotcha] Found existing response:`, data.response);\n }\n return data.response as ExistingResponse;\n }\n\n return null;\n },\n\n /**\n * Update an existing response\n */\n async updateResponse(\n id: string,\n payload: {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n },\n userId?: string\n ): Promise<GotchaResponse> {\n const url = `${baseUrl}/responses/${id}${userId ? `?userId=${encodeURIComponent(userId)}` : ''}`;\n\n if (debug) {\n console.log(`[Gotcha] PATCH /responses/${id}`, payload);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'PATCH',\n headers,\n body: JSON.stringify(payload),\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response updated:`, data);\n }\n\n return data as GotchaResponse;\n },\n\n /**\n * Get the base URL (for debugging)\n */\n getBaseUrl(): string {\n return baseUrl;\n },\n };\n}\n\nexport type ApiClient = ReturnType<typeof createApiClient>;\n","import React, { createContext, useContext, useMemo, useState, useCallback } from 'react';\nimport { createApiClient, ApiClient } from '../api/client';\nimport { GotchaUser } from '../types';\n\nexport interface GotchaProviderProps {\n /** Your Gotcha API key */\n apiKey: string;\n /** React children */\n children: React.ReactNode;\n /** Override the API base URL (for testing/staging) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /** Disable all Gotcha buttons globally */\n disabled?: boolean;\n /** Default user metadata applied to all submissions */\n defaultUser?: GotchaUser;\n}\n\nexport interface GotchaContextValue {\n client: ApiClient;\n disabled: boolean;\n defaultUser: GotchaUser;\n debug: boolean;\n // Modal management - only one open at a time\n activeModalId: string | null;\n openModal: (elementId: string) => void;\n closeModal: () => void;\n}\n\nconst GotchaContext = createContext<GotchaContextValue | null>(null);\n\nexport function GotchaProvider({\n apiKey,\n children,\n baseUrl,\n debug = false,\n disabled = false,\n defaultUser = {},\n}: GotchaProviderProps) {\n const [activeModalId, setActiveModalId] = useState<string | null>(null);\n\n const client = useMemo(\n () => createApiClient({ apiKey, baseUrl, debug }),\n [apiKey, baseUrl, debug]\n );\n\n const openModal = useCallback((elementId: string) => {\n setActiveModalId(elementId);\n }, []);\n\n const closeModal = useCallback(() => {\n setActiveModalId(null);\n }, []);\n\n const value: GotchaContextValue = useMemo(\n () => ({\n client,\n disabled,\n defaultUser,\n debug,\n activeModalId,\n openModal,\n closeModal,\n }),\n [client, disabled, defaultUser, debug, activeModalId, openModal, closeModal]\n );\n\n return (\n <GotchaContext.Provider value={value}>{children}</GotchaContext.Provider>\n );\n}\n\nexport function useGotchaContext(): GotchaContextValue {\n const context = useContext(GotchaContext);\n if (!context) {\n throw new Error('useGotchaContext must be used within a GotchaProvider');\n }\n return context;\n}\n","import { useState, useCallback, useEffect } from 'react';\nimport { useGotchaContext } from '../components/GotchaProvider';\nimport { ResponseMode, GotchaUser, GotchaResponse, VoteType, ExistingResponse } from '../types';\n\ninterface UseSubmitOptions {\n elementId: string;\n mode: ResponseMode;\n experimentId?: string;\n variant?: string;\n pollOptions?: string[];\n user?: GotchaUser;\n onSuccess?: (response: GotchaResponse) => void;\n onError?: (error: Error) => void;\n}\n\ninterface SubmitData {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n}\n\nexport function useSubmit(options: UseSubmitOptions) {\n const { client, defaultUser } = useGotchaContext();\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [existingResponse, setExistingResponse] = useState<ExistingResponse | null>(null);\n\n // Check for existing response when user ID is provided\n useEffect(() => {\n const userId = options.user?.id || defaultUser?.id;\n if (!userId) {\n setExistingResponse(null);\n return;\n }\n\n let cancelled = false;\n\n const checkExisting = async () => {\n setIsCheckingExisting(true);\n try {\n const existing = await client.checkExistingResponse(options.elementId, userId);\n if (!cancelled) {\n setExistingResponse(existing);\n }\n } catch {\n // Ignore errors - just means no existing response found\n if (!cancelled) {\n setExistingResponse(null);\n }\n } finally {\n if (!cancelled) {\n setIsCheckingExisting(false);\n }\n }\n };\n\n checkExisting();\n\n return () => {\n cancelled = true;\n };\n }, [client, options.elementId, options.user?.id, defaultUser?.id]);\n\n const submit = useCallback(\n async (data: SubmitData) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const userId = options.user?.id || defaultUser?.id;\n let response: GotchaResponse;\n\n // If we have an existing response and a user ID, update instead of create\n if (existingResponse && userId) {\n response = await client.updateResponse(\n existingResponse.id,\n {\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollSelected: data.pollSelected,\n },\n userId\n );\n } else {\n response = await client.submitResponse({\n elementId: options.elementId,\n mode: options.mode,\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollOptions: options.pollOptions,\n pollSelected: data.pollSelected,\n experimentId: options.experimentId,\n variant: options.variant,\n user: { ...defaultUser, ...options.user },\n });\n }\n\n options.onSuccess?.(response);\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Something went wrong';\n setError(errorMessage);\n options.onError?.(err instanceof Error ? err : new Error(errorMessage));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [client, defaultUser, options, existingResponse]\n );\n\n return {\n submit,\n isLoading,\n isCheckingExisting,\n error,\n existingResponse,\n isEditing: !!existingResponse,\n clearError: () => setError(null),\n };\n}\n","/**\n * Simple class name utility\n * Combines class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n","/**\n * Detect if the device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n if (typeof window === 'undefined') return false;\n return 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get the appropriate size based on device type\n */\nexport const getResponsiveSize = (\n size: 'sm' | 'md' | 'lg',\n isTouch: boolean\n): number => {\n const sizes = {\n sm: { desktop: 24, mobile: 32 },\n md: { desktop: 32, mobile: 36 },\n lg: { desktop: 40, mobile: 40 },\n };\n\n return isTouch ? sizes[size].mobile : sizes[size].desktop;\n};\n","import React, { useState, useEffect } from 'react';\nimport { Size, Theme, GotchaStyles } from '../types';\nimport { cn } from '../utils/cn';\nimport { isTouchDevice, getResponsiveSize } from '../utils/device';\n\nexport interface GotchaButtonProps {\n size: Size;\n theme: Theme;\n customStyles?: GotchaStyles;\n showOnHover: boolean;\n touchBehavior: 'always-visible' | 'tap-to-reveal';\n onClick: () => void;\n isOpen: boolean;\n isParentHovered?: boolean;\n}\n\n/**\n * Detect system color-scheme preference synchronously where possible,\n * falling back to 'light'. This avoids the flash that occurred when\n * the old code always initialised state as 'light' and corrected it\n * inside useEffect.\n */\nfunction getInitialSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light';\n}\n\nexport function GotchaButton({\n size,\n theme,\n customStyles,\n showOnHover,\n touchBehavior,\n onClick,\n isOpen,\n isParentHovered = false,\n}: GotchaButtonProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [tapRevealed, setTapRevealed] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>(getInitialSystemTheme);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n\n // Keep systemTheme in sync when user changes OS preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) =>\n setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Determine visibility\n const shouldShow = (() => {\n if (isOpen) return true;\n if (!isTouch && showOnHover) return isParentHovered;\n if (isTouch && touchBehavior === 'tap-to-reveal') return tapRevealed;\n return true;\n })();\n\n const handleClick = () => {\n if (isTouch && touchBehavior === 'tap-to-reveal' && !tapRevealed) {\n setTapRevealed(true);\n return;\n }\n onClick();\n };\n\n const buttonSize = getResponsiveSize(size, isTouch);\n\n // ── Resolve theme ────────────────────────────────────────────────\n // \"auto\" must produce the *exact* same styles as the explicit theme\n // it resolves to. Previously the initial state defaulted to 'light'\n // regardless of the actual preference, causing a mismatch on the\n // first render when the system was dark.\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n const isDark = resolvedTheme === 'dark';\n\n // ── Glass-bubble styles ──────────────────────────────────────────\n // Simulates a raised glass dome / marble sitting on the surface:\n // - Bright borderTop highlight mimics light hitting the top edge\n // - Subtle darker base border grounds the bottom\n // - Vertical gradient: bright at top, more opaque at bottom\n // - Inset top shadow for inner refraction glow\n // - Inset bottom shadow for depth within the dome\n // - Outer shadow to anchor the bubble to the surface\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: isDark\n ? '1px solid rgba(255,255,255,0.15)'\n : 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: isDark\n ? 'linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.04) 60%, rgba(0,0,0,0.05) 100%)'\n : 'linear-gradient(160deg, rgba(255,255,255,0.7) 0%, rgba(200,210,230,0.4) 40%, rgba(180,192,220,0.5) 100%)',\n backdropFilter: 'blur(16px) saturate(170%)',\n WebkitBackdropFilter: 'blur(16px) saturate(170%)',\n color: isDark ? 'rgba(255,255,255,0.88)' : 'rgba(0,0,0,0.75)',\n boxShadow: isDark\n ? [\n '0 4px 14px rgba(0,0,0,0.45)',\n '0 1px 3px rgba(0,0,0,0.35)',\n 'inset 0 1px 2px rgba(255,255,255,0.1)',\n 'inset 0 -1px 2px rgba(0,0,0,0.08)',\n ].join(', ')\n : [\n '0 3px 12px rgba(0,0,0,0.12)',\n '0 0 1px rgba(0,0,0,0.2)',\n 'inset 0 4px 8px rgba(255,255,255,0.95)',\n 'inset 0 -4px 8px rgba(0,0,0,0.08)',\n ].join(', '),\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: shouldShow ? 1 : 0,\n transform: shouldShow ? 'scale(1)' : 'scale(0.6)',\n pointerEvents: shouldShow ? 'auto' : 'none',\n ...customStyles?.button,\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n style={baseStyles}\n className={cn('gotcha-button', isOpen && 'gotcha-button--open')}\n aria-label=\"Give feedback on this feature\"\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n >\n <GotchaIcon size={buttonSize * 0.65} />\n </button>\n );\n}\n\nconst FONT_ID = 'gotcha-carter-one';\n\nfunction useCarterOneFont() {\n useEffect(() => {\n if (document.getElementById(FONT_ID)) return;\n const link = document.createElement('link');\n link.id = FONT_ID;\n link.rel = 'stylesheet';\n link.href = 'https://fonts.googleapis.com/css2?family=Carter+One&display=swap';\n document.head.appendChild(link);\n }, []);\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n useCarterOneFont();\n return (\n <span\n aria-hidden=\"true\"\n style={{\n fontFamily: \"'Carter One', cursive\",\n fontSize: size,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: size * 0.05,\n marginRight: size * 0.05,\n userSelect: 'none',\n }}\n >\n G\n </span>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: number;\n color?: string;\n}\n\nexport function Spinner({ size = 16, color = 'currentColor' }: SpinnerProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n animation: 'gotcha-spin 0.8s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes gotcha-dash {\n 0% { stroke-dasharray: 1, 62; stroke-dashoffset: 0; }\n 50% { stroke-dasharray: 40, 62; stroke-dashoffset: -12; }\n 100% { stroke-dasharray: 1, 62; stroke-dashoffset: -62; }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeOpacity=\"0.12\"\n />\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n style={{\n animation: 'gotcha-dash 1.2s ease-in-out infinite',\n }}\n />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { GotchaStyles } from '../../types';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface FeedbackModeProps {\n theme: 'light' | 'dark' | 'custom';\n placeholder?: string;\n submitText: string;\n isLoading: boolean;\n onSubmit: (data: { content?: string; rating?: number }) => void;\n customStyles?: GotchaStyles;\n initialValues?: {\n content?: string | null;\n rating?: number | null;\n };\n isEditing?: boolean;\n}\n\nexport function FeedbackMode({\n theme,\n placeholder,\n submitText,\n isLoading,\n onSubmit,\n customStyles,\n initialValues,\n isEditing = false,\n}: FeedbackModeProps) {\n const [content, setContent] = useState(initialValues?.content || '');\n const [rating, setRating] = useState<number | null>(initialValues?.rating ?? null);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update local state when initialValues change (e.g., after loading existing response)\n useEffect(() => {\n if (initialValues?.content !== undefined) {\n setContent(initialValues.content || '');\n }\n if (initialValues?.rating !== undefined) {\n setRating(initialValues.rating ?? null);\n }\n }, [initialValues?.content, initialValues?.rating]);\n\n const isDark = theme === 'dark';\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!content.trim() && rating === null) return;\n onSubmit({ content: content.trim() || undefined, rating: rating ?? undefined });\n };\n\n const inputStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '12px 14px' : '10px 12px',\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0'}`,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc',\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 16 : 14, // 16px prevents iOS zoom on focus\n resize: 'vertical',\n minHeight: isTouch ? 100 : 80,\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n lineHeight: 1.5,\n ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: 8,\n backgroundColor: isDark ? '#e2e8f0' : '#1e293b',\n color: isDark ? '#1e293b' : '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n letterSpacing: '0.01em',\n ...customStyles?.submitButton,\n };\n\n return (\n <form onSubmit={handleSubmit}>\n {/* Rating (optional) */}\n <div style={{ marginBottom: isTouch ? 16 : 12 }}>\n <StarRating value={rating} onChange={setRating} isDark={isDark} isTouch={isTouch} />\n </div>\n\n {/* Text input */}\n <textarea\n value={content}\n onChange={(e) => setContent(e.target.value)}\n placeholder={placeholder || 'Share your thoughts...'}\n style={inputStyles}\n disabled={isLoading}\n aria-label=\"Your feedback\"\n onFocus={(e) => {\n e.currentTarget.style.borderColor = '#1e293b';\n e.currentTarget.style.boxShadow = '0 0 0 2px rgba(30,41,59,0.15)';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.7)' : '#ffffff';\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0';\n e.currentTarget.style.boxShadow = 'none';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc';\n }}\n />\n\n {/* Submit button */}\n <button\n type=\"submit\"\n disabled={isLoading || (!content.trim() && rating === null)}\n style={{\n ...buttonStyles,\n marginTop: 12,\n opacity: isLoading ? 0.8 : 1,\n backgroundColor: (!content.trim() && rating === null)\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b'),\n color: (!content.trim() && rating === null)\n ? (isDark ? '#6b7280' : '#94a3b8')\n : (isDark ? '#1e293b' : '#ffffff'),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n onMouseEnter={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#cbd5e1' : '#334155';\n }\n }}\n onMouseLeave={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#e2e8f0' : '#1e293b';\n }\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color={isDark ? '#1e293b' : '#ffffff'} />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : submitText)}\n </button>\n </form>\n );\n}\n\ninterface StarRatingProps {\n value: number | null;\n onChange: (rating: number) => void;\n isDark: boolean;\n isTouch: boolean;\n}\n\nfunction StarRating({ value, onChange, isDark, isTouch }: StarRatingProps) {\n const [hovered, setHovered] = useState<number | null>(null);\n const starSize = isTouch ? 28 : 18;\n const buttonPadding = isTouch ? 6 : 3;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 6 : 2,\n }}\n role=\"group\"\n aria-label=\"Rating\"\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const isFilled = (hovered ?? value ?? 0) >= star;\n return (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHovered(star)}\n onMouseLeave={() => setHovered(null)}\n aria-label={`Rate ${star} out of 5`}\n aria-pressed={value === star}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: buttonPadding,\n color: isFilled ? '#f59e0b' : (isDark ? 'rgba(255,255,255,0.12)' : '#e2e8f0'),\n transition: 'color 0.15s cubic-bezier(0.4, 0, 0.2, 1), transform 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n transform: (hovered !== null && hovered >= star) ? 'scale(1.1)' : 'scale(1)',\n }}\n >\n <svg width={starSize} height={starSize} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n </button>\n );\n })}\n </div>\n );\n}\n","import React, { useEffect, useState } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface VoteModeProps {\n theme: 'light' | 'dark' | 'custom';\n isLoading: boolean;\n onSubmit: (data: { vote: 'up' | 'down' }) => void;\n initialVote?: 'up' | 'down' | null;\n isEditing?: boolean;\n}\n\nexport function VoteMode({ theme, isLoading, onSubmit, initialVote, isEditing = false }: VoteModeProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [activeVote, setActiveVote] = useState<'up' | 'down' | null>(initialVote || null);\n const [previousVote, setPreviousVote] = useState<'up' | 'down' | null>(initialVote || null);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update when initialVote changes (e.g., after loading existing response)\n useEffect(() => {\n if (initialVote !== undefined) {\n setPreviousVote(initialVote);\n setActiveVote(initialVote);\n }\n }, [initialVote]);\n\n // Reset active vote when loading completes (but keep previous vote for edit mode)\n useEffect(() => {\n if (!isLoading && !isEditing) {\n setActiveVote(null);\n }\n }, [isLoading, isEditing]);\n\n const handleVote = (vote: 'up' | 'down') => {\n setActiveVote(vote);\n onSubmit({ vote });\n };\n\n const isDark = theme === 'dark';\n\n const getButtonStyles = (voteType: 'up' | 'down'): React.CSSProperties => {\n const isSelected = previousVote === voteType;\n const selectedColor = voteType === 'up' ? '#10b981' : '#ef4444';\n return {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden' as const,\n padding: isTouch ? '14px 18px' : '10px 14px',\n border: `1px solid ${isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.3)' : 'rgba(16,185,129,0.25)')\n : (isDark ? 'rgba(239,68,68,0.3)' : 'rgba(239,68,68,0.25)'))\n : (isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0')}`,\n borderRadius: isTouch ? 10 : 8,\n backgroundColor: isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.08)' : 'rgba(16,185,129,0.06)')\n : (isDark ? 'rgba(239,68,68,0.08)' : 'rgba(239,68,68,0.06)'))\n : (isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc'),\n color: isSelected\n ? selectedColor\n : (isDark ? '#d1d5db' : '#64748b'),\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s, box-shadow 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n };\n\n const iconSize = isTouch ? 24 : 20;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 12 : 10,\n }}\n role=\"group\"\n aria-label=\"Vote\"\n >\n <button\n type=\"button\"\n onClick={() => handleVote('up')}\n disabled={isLoading}\n style={getButtonStyles('up')}\n aria-label=\"Vote up - I like this\"\n aria-pressed={previousVote === 'up'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {previousVote === 'up' ? 'Liked' : 'Like'}\n </span>\n </>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleVote('down')}\n disabled={isLoading}\n style={getButtonStyles('down')}\n aria-label=\"Vote down - I don't like this\"\n aria-pressed={previousVote === 'down'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {previousVote === 'down' ? 'Disliked' : 'Dislike'}\n </span>\n </>\n )}\n </button>\n </div>\n );\n}\n\nfunction ThumbsUpIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17\" />\n </svg>\n );\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport { Theme, GotchaStyles, ResponseMode, ExistingResponse } from '../types';\nimport { cn } from '../utils/cn';\nimport { FeedbackMode } from './modes/FeedbackMode';\nimport { VoteMode } from './modes/VoteMode';\n\nexport interface GotchaModalProps {\n mode: ResponseMode;\n theme: Theme;\n customStyles?: GotchaStyles;\n promptText?: string;\n placeholder?: string;\n submitText: string;\n thankYouMessage: string;\n // State\n isLoading: boolean;\n isSubmitted: boolean;\n error: string | null;\n // Edit mode\n existingResponse?: ExistingResponse | null;\n isEditing?: boolean;\n // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => void;\n onClose: () => void;\n // Position info from parent\n anchorRect?: DOMRect;\n}\n\nexport function GotchaModal({\n mode,\n theme,\n customStyles,\n promptText,\n placeholder,\n submitText,\n thankYouMessage,\n isLoading,\n isSubmitted,\n error,\n existingResponse,\n isEditing = false,\n onSubmit,\n onClose,\n anchorRect,\n}: GotchaModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const firstFocusableRef = useRef<HTMLButtonElement>(null);\n const [isVisible, setIsVisible] = useState(false);\n const [isMobile, setIsMobile] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>('light');\n\n // Detect mobile and system theme after mount (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n\n // Detect system theme preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setSystemTheme(darkQuery.matches ? 'dark' : 'light');\n\n // Listen for theme changes\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Trigger animation after mount\n useEffect(() => {\n const timer = requestAnimationFrame(() => setIsVisible(true));\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Resolve theme\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const isDark = resolvedTheme === 'dark';\n\n // Determine if modal should appear above or below\n const modalHeight = 280; // approximate modal height\n const spaceBelow = anchorRect\n ? window.innerHeight - anchorRect.bottom\n : window.innerHeight / 2;\n const showAbove = spaceBelow < modalHeight + 20;\n\n // Focus trap\n useEffect(() => {\n const modal = modalRef.current;\n if (!modal) return;\n\n // Focus first element\n firstFocusableRef.current?.focus();\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n return;\n }\n\n if (e.key === 'Tab') {\n const focusableElements = modal.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement?.focus();\n } else if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement?.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n const defaultPrompt = mode === 'vote'\n ? 'What do you think?'\n : 'What do you think of this feature?';\n\n // Responsive sizing - on mobile, use fixed positioning centered on screen\n const modalPadding = isMobile ? 20 : 16;\n\n const layeredShadow = isDark\n ? '0 1px 2px rgba(0,0,0,0.2), 0 4px 12px rgba(0,0,0,0.3), 0 12px 32px rgba(0,0,0,0.2)'\n : '0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06), 0 12px 32px rgba(0,0,0,0.06)';\n\n const modalStyles: React.CSSProperties = isMobile\n ? {\n // Mobile: fixed position, centered on screen\n position: 'fixed',\n left: '50%',\n top: '50%',\n width: 'calc(100vw - 32px)',\n maxWidth: 320,\n padding: modalPadding,\n borderRadius: 12,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.96)',\n ...customStyles?.modal,\n }\n : {\n // Desktop: absolute position relative to button\n position: 'absolute',\n left: '50%',\n width: 320,\n padding: modalPadding,\n borderRadius: 10,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.96) translateY(${showAbove ? '6px' : '-6px'})`,\n ...customStyles?.modal,\n };\n\n return (\n <div\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gotcha-modal-title\"\n style={modalStyles}\n className={cn('gotcha-modal', isDark && 'gotcha-modal--dark')}\n >\n {/* Close button - larger on touch devices */}\n <button\n ref={firstFocusableRef}\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close feedback form\"\n style={{\n position: 'absolute',\n top: isMobile ? 12 : 8,\n right: isMobile ? 12 : 8,\n width: isMobile ? 36 : 28,\n height: isMobile ? 36 : 28,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: isDark ? '#6b7280' : '#9ca3af',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 6,\n transition: 'all 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)';\n e.currentTarget.style.color = isDark ? '#9ca3af' : '#6b7280';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = isDark ? '#6b7280' : '#9ca3af';\n }}\n >\n <svg width={isMobile ? 16 : 12} height={isMobile ? 16 : 12} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 16px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 600,\n paddingRight: isMobile ? 40 : 32,\n letterSpacing: '-0.01em',\n lineHeight: 1.4,\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '24px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <div\n style={{\n width: 44,\n height: 44,\n borderRadius: '50%',\n backgroundColor: isDark ? 'rgba(16,185,129,0.1)' : 'rgba(5,150,105,0.08)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 12px',\n }}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M20 6L9 17L4 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n <p style={{ margin: 0, fontSize: 13, fontWeight: 500, color: isDark ? '#d1d5db' : '#374151' }}>\n {thankYouMessage}\n </p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: '8px 10px',\n marginBottom: 12,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(127,29,29,0.3)' : '#fef2f2',\n border: `1px solid ${isDark ? 'rgba(254,202,202,0.1)' : 'rgba(220,38,38,0.1)'}`,\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\n lineHeight: 1.4,\n }}\n >\n {error}\n </div>\n )}\n\n {/* Form content based on mode */}\n {!isSubmitted && (\n <>\n {mode === 'feedback' && (\n <FeedbackMode\n theme={resolvedTheme}\n placeholder={placeholder}\n submitText={submitText}\n isLoading={isLoading}\n onSubmit={onSubmit}\n customStyles={customStyles}\n initialValues={existingResponse ? {\n content: existingResponse.content,\n rating: existingResponse.rating,\n } : undefined}\n isEditing={isEditing}\n />\n )}\n {mode === 'vote' && (\n <VoteMode\n theme={resolvedTheme}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialVote={existingResponse?.vote || undefined}\n isEditing={isEditing}\n />\n )}\n </>\n )}\n\n {/* Screen reader announcement */}\n <div aria-live=\"polite\" className=\"sr-only\" style={{ position: 'absolute', left: -9999 }}>\n {isSubmitted && 'Thank you! Your feedback has been submitted.'}\n {error && `Error: ${error}`}\n </div>\n </div>\n );\n}\n","import React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n ResponseMode,\n GotchaUser,\n Position,\n Size,\n Theme,\n TouchBehavior,\n GotchaStyles,\n GotchaResponse,\n GotchaError,\n} from '../types';\nimport { DEFAULTS } from '../constants';\nimport { useGotchaContext } from './GotchaProvider';\nimport { useSubmit } from '../hooks/useSubmit';\nimport { GotchaButton } from './GotchaButton';\nimport { GotchaModal } from './GotchaModal';\n\nexport interface GotchaProps {\n /** Unique identifier for this element */\n elementId: string;\n\n // User data\n /** User metadata for segmentation */\n user?: GotchaUser;\n\n // Behavior\n /** Feedback mode */\n mode?: ResponseMode;\n /** Required if mode is 'ab' */\n experimentId?: string;\n /** Current A/B variant shown to user */\n variant?: string;\n\n // Poll mode specific (Phase 2)\n /** Required if mode is 'poll' (2-6 options) */\n options?: string[];\n /** Allow selecting multiple options */\n allowMultiple?: boolean;\n /** Show results after voting */\n showResults?: boolean;\n\n // Appearance\n /** Button position relative to parent */\n position?: Position;\n /** Button size */\n size?: Size;\n /** Color theme */\n theme?: Theme;\n /** Custom style overrides */\n customStyles?: GotchaStyles;\n /** Control visibility programmatically */\n visible?: boolean;\n /** Only show when parent is hovered (default: true) */\n showOnHover?: boolean;\n /** Mobile behavior (default: 'always-visible') */\n touchBehavior?: TouchBehavior;\n\n // Content\n /** Custom prompt text */\n promptText?: string;\n /** Input placeholder text */\n placeholder?: string;\n /** Submit button text */\n submitText?: string;\n /** Post-submission message */\n thankYouMessage?: string;\n\n // Callbacks\n /** Called after successful submission */\n onSubmit?: (response: GotchaResponse) => void;\n /** Called when modal opens */\n onOpen?: () => void;\n /** Called when modal closes */\n onClose?: () => void;\n /** Called on error */\n onError?: (error: GotchaError) => void;\n}\n\nexport function Gotcha({\n elementId,\n user,\n mode = 'feedback',\n experimentId,\n variant,\n options,\n allowMultiple = false,\n showResults = true,\n position = DEFAULTS.POSITION,\n size = DEFAULTS.SIZE,\n theme = DEFAULTS.THEME,\n customStyles,\n visible = true,\n showOnHover = DEFAULTS.SHOW_ON_HOVER,\n touchBehavior = DEFAULTS.TOUCH_BEHAVIOR,\n promptText,\n placeholder,\n submitText = DEFAULTS.SUBMIT_TEXT,\n thankYouMessage = DEFAULTS.THANK_YOU_MESSAGE,\n onSubmit,\n onOpen,\n onClose,\n onError,\n}: GotchaProps) {\n const { disabled, activeModalId, openModal, closeModal } = useGotchaContext();\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [isParentHovered, setIsParentHovered] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const [isMobile, setIsMobile] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Detect mobile for portal rendering (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n }, []);\n\n // This instance's modal is open if activeModalId matches our elementId\n const isOpen = activeModalId === elementId;\n\n // Attach hover listeners to the parent element (not the button container)\n useEffect(() => {\n if (!showOnHover) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Find the parent element with position: relative\n const parent = container.parentElement;\n if (!parent) return;\n\n const handleMouseEnter = () => setIsParentHovered(true);\n const handleMouseLeave = () => setIsParentHovered(false);\n\n parent.addEventListener('mouseenter', handleMouseEnter);\n parent.addEventListener('mouseleave', handleMouseLeave);\n\n return () => {\n parent.removeEventListener('mouseenter', handleMouseEnter);\n parent.removeEventListener('mouseleave', handleMouseLeave);\n };\n }, [showOnHover]);\n\n const { submit, isLoading, error, existingResponse, isEditing } = useSubmit({\n elementId,\n mode,\n experimentId,\n variant,\n pollOptions: options,\n user,\n onSuccess: (response) => {\n setIsSubmitted(true);\n onSubmit?.(response);\n // Auto-close after 2.5 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 2500);\n },\n onError: (err) => {\n onError?.(err as unknown as GotchaError);\n },\n });\n\n const handleOpen = useCallback(() => {\n if (containerRef.current) {\n setAnchorRect(containerRef.current.getBoundingClientRect());\n }\n openModal(elementId);\n onOpen?.();\n }, [elementId, openModal, onOpen]);\n\n const handleClose = useCallback(() => {\n closeModal();\n setIsSubmitted(false);\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleSubmit = useCallback(\n (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => {\n submit(data);\n },\n [submit]\n );\n\n // Don't render if disabled or not visible\n if (disabled || !visible) return null;\n\n // Position styles\n const positionStyles: Record<Position, React.CSSProperties> = {\n 'top-right': { position: 'absolute', top: 0, right: 0, transform: 'translate(50%, -50%)' },\n 'top-left': { position: 'absolute', top: 0, left: 0, transform: 'translate(-50%, -50%)' },\n 'bottom-right': { position: 'absolute', bottom: 0, right: 0, transform: 'translate(50%, 50%)' },\n 'bottom-left': { position: 'absolute', bottom: 0, left: 0, transform: 'translate(-50%, 50%)' },\n 'inline': { position: 'relative', display: 'inline-flex' },\n };\n\n return (\n <div\n ref={containerRef}\n style={{\n ...positionStyles[position],\n zIndex: isOpen ? 10000 : 'auto',\n }}\n className=\"gotcha-container\"\n data-gotcha-element={elementId}\n >\n <GotchaButton\n size={size}\n theme={theme}\n customStyles={customStyles}\n showOnHover={showOnHover}\n touchBehavior={touchBehavior}\n onClick={handleOpen}\n isOpen={isOpen}\n isParentHovered={isParentHovered}\n />\n\n {isOpen && !isMobile && (\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n )}\n\n {/* On mobile, render modal via portal to escape parent transform */}\n {isOpen && isMobile && createPortal(\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n }}\n onClick={handleClose}\n aria-hidden=\"true\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useGotchaContext } from '../components/GotchaProvider';\n\n/**\n * Hook to access Gotcha context\n * Must be used within a GotchaProvider\n */\nexport function useGotcha() {\n const { client, disabled, defaultUser, debug } = useGotchaContext();\n\n return {\n /** The API client for manual submissions */\n client,\n /** Whether Gotcha is globally disabled */\n disabled,\n /** Default user metadata */\n defaultUser,\n /** Whether debug mode is enabled */\n debug,\n /** Submit feedback programmatically */\n submitFeedback: client.submitResponse.bind(client),\n };\n}\n"]}
|