makethisbetter 1.26.0 → 1.26.1

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">makethisbetter</h1>
6
6
 
7
7
  <p align="center">
8
- Embeddable feedback widget with AI triage.
8
+ Feedback widget with screenshots, annotations, and AI triage.
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -171,5 +171,5 @@
171
171
  </div>
172
172
  <div class="mtb-failure-title">${l(e.error.submit)}</div>
173
173
  ${n}
174
- `,t.append(this.el),r.onRetry&&this.el.querySelector(".mtb-failure-retry").addEventListener("click",r.onRetry),this.el.querySelector(".mtb-failure-close").addEventListener("click",r.onClose)}destroy(){this.el.remove()}}function Zr(){return{page_url:U(window.location.href),user_agent:navigator.userAgent,browser:Jr(),os:Qr(),screen_width:window.screen.width,screen_height:window.screen.height}}function Jr(){const i=navigator.userAgent;return/Edg\//.test(i)?`Edge ${i.match(/Edg\/(\S+)/)?.[1]??""}`:/OPR\//.test(i)?`Opera ${i.match(/OPR\/(\S+)/)?.[1]??""}`:/Chrome\//.test(i)?`Chrome ${i.match(/Chrome\/(\S+)/)?.[1]??""}`:/Safari\//.test(i)&&/Version\//.test(i)?`Safari ${i.match(/Version\/(\S+)/)?.[1]??""}`:/Firefox\//.test(i)?`Firefox ${i.match(/Firefox\/(\S+)/)?.[1]??""}`:"Unknown"}function Qr(){const i=navigator.userAgent;return/Windows NT 10/.test(i)?"Windows 10/11":/Windows NT/.test(i)?"Windows":/Mac OS X 10_15|macOS 1[56789]/.test(i)||/Mac OS X/.test(i)?"macOS":/Android/.test(i)?`Android ${i.match(/Android (\d+)/)?.[1]??""}`:/iPhone|iPad|iPod/.test(i)?"iOS":/Linux/.test(i)?"Linux":"Unknown"}function tn(i){const{description:t,pageContext:e,consoleErrors:r,annotation:n,user:s,recording:o,anonId:a,anonEmail:c,breadcrumbs:d}=i;return{...Z({description:t,...e,page_url:U(e.page_url),console_errors:r,annotations:n?[n]:[],target_element:n?.targetSelector?{selector:n.targetSelector,text:n.targetText??"",name:n.targetName??""}:void 0,recording_events:o?.events,recording_duration:o?.duration,breadcrumbs:d}),user_id:s?.id,user_email:s?.email,user_name:s?.name,reporter_external_id:s?void 0:a,reporter_email:s?void 0:c}}const en=300,rn=900;class nn{constructor(t,e){this.deps=t,this.host=e,this.activeSubmission=null,this.pendingSubmissionRequest=null,this.submissionAttempt=0,this.pendingBaseCapture=null,this.idleCaptureTimer=null,this.failure=null,this.screenshotEnabled=!0}isScreenshotEnabled(){return this.screenshotEnabled}resetScreenshotConsent(){this.screenshotEnabled=!0}setScreenshotEnabled(t){if(this.screenshotEnabled=t,t){this.beginBaseCapture();return}this.clearIdleCaptureTimer(),this.pendingBaseCapture=null}beginBaseCapture(){this.screenshotEnabled&&(this.pendingBaseCapture||(this.clearIdleCaptureTimer(),this.idleCaptureTimer=setTimeout(()=>{this.idleCaptureTimer=null,this.pendingBaseCapture??(this.pendingBaseCapture=Pt())},rn)))}clearIdleCaptureTimer(){this.idleCaptureTimer!==null&&(clearTimeout(this.idleCaptureTimer),this.idleCaptureTimer=null)}start(t,e,r){const n=++this.submissionAttempt,s=this.createSubmission(t,e,r,n);return this.pendingSubmissionRequest=s,s}async createSubmission(t,e,r,n){if(await qt(),n!==this.submissionAttempt)return null;this.clearIdleCaptureTimer();const s=this.screenshotEnabled?this.pendingBaseCapture??Pt():null;this.pendingBaseCapture=null;const o=Zr(),a=await s;if(n!==this.submissionAttempt)return null;const c=a?await Wi(a,e?[e]:[],this.deps.brandColors):null;if(n!==this.submissionAttempt)return null;const d=tn({description:t,pageContext:o,consoleErrors:this.deps.consoleCollector.getErrors(),annotation:e,user:this.deps.user(),recording:r,anonId:we(),anonEmail:xe(),breadcrumbs:this.deps.breadcrumbCollector.getBreadcrumbs()});try{const h=await this.deps.apiClient.createSubmissionSession(d,c);return n!==this.submissionAttempt?(await this.deps.apiClient.abandonSubmissionSession(h.id,h.token).catch(()=>{}),null):(this.activeSubmission=h,h)}catch{return null}}async finalize(){const t=this.submissionAttempt,e=this.host.isBackground(),r=this.activeSubmission??await(this.pendingSubmissionRequest??Promise.resolve(null));if(t!==this.submissionAttempt)return;if(!r){if(e)return this.showFinalizeFailure({canRetry:!1});throw new Error("No active submission session")}const n=e?Promise.resolve():new Promise(o=>setTimeout(o,en));let s;try{s=await this.deps.apiClient.finalizeSubmissionSession(r.id,r.token)}catch(o){if(e)return this.showFinalizeFailure({canRetry:!0});throw o}await Promise.all([n,qt()]),!(t!==this.submissionAttempt||this.activeSubmission!==r)&&(this.activeSubmission=null,this.pendingSubmissionRequest=null,this.host.onFinalized(s,r))}showFinalizeFailure(t){this.host.onReleaseForFailureCard(),this.failure?.destroy(),this.failure=new Gr(this.deps.shadow(),this.deps.messages(),{onRetry:t.canRetry?()=>this.retryBackgroundFinalization():void 0,onClose:()=>this.dismissFinalizeFailure()})}retryBackgroundFinalization(){this.dismissFinalizeFailure(),this.host.onReenterBackground(),this.finalize().catch(()=>this.showFinalizeFailure({canRetry:!0}))}dismissFinalizeFailure(){this.failure?.destroy(),this.failure=null}abandon(){this.submissionAttempt+=1,this.clearIdleCaptureTimer(),this.pendingBaseCapture=null,this.resetScreenshotConsent();const t=this.activeSubmission;this.activeSubmission=null,this.pendingSubmissionRequest=null,t&&this.deps.apiClient.abandonSubmissionSession(t.id,t.token).catch(()=>{})}}function qt(){return new Promise(i=>requestAnimationFrame(()=>setTimeout(i,0)))}function nt(i){i.preventDefault(),i.stopPropagation()}class x{constructor(t){this.host=t,this.launcherLit=!0,this.acceptsFrustrationPrompt=!1}enter(){}exit(){}handleOpen(){}handleClose(){this.host.exitAll()}handleEscape(t){}handleTabClick(){this.host.exitAll()}handleToolbarModeChange(t){}handleDrawStroke(){}}class W extends x{constructor(){super(...arguments),this.kind="idle",this.launcherLit=!1,this.acceptsFrustrationPrompt=!0}handleOpen(){this.host.dismissFrustrationPrompt(),this.host.dismissSuccess(),this.host.transitionTo(new k(this.host))}handleClose(){}handleTabClick(){this.handleOpen()}}class k extends x{constructor(){super(...arguments),this.kind="annotating"}enter(){if(!this.host.hasAnnotationChrome()){this.host.mountAnnotationChrome();return}this.host.destroyRecordingManager(),this.host.teardownDrawBar(),this.host.ensureSession()}handleEscape(t){nt(t),this.host.exitAll()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):this.host.transitionTo(new k(this.host))}handleDrawStroke(){this.host.transitionTo(new sn(this.host,y()?"sheet":"bar"))}}class xt extends x{constructor(){super(...arguments),this.kind="recording"}enter(){this.host.clearCurrentAnnotation(),this.host.teardownDrawBar(),this.host.destroySession(),this.host.startRecorder()}handleEscape(t){nt(t),this.host.stopRecordingIntoNote()}handleToolbarModeChange(t){t!=="record"&&this.host.transitionTo(new k(this.host))}}class sn extends x{constructor(t,e){super(t),this.surface=e,this.kind="drawing"}enter(){this.surface==="sheet"?this.host.mountDrawSheet():(this.host.mountDrawBar(),this.host.refreshDrawBar())}handleEscape(t){nt(t),this.host.cancelDraw()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):this.host.transitionTo(new k(this.host))}handleDrawStroke(){this.surface==="bar"&&this.host.refreshDrawBar()}}class Wt extends x{constructor(t,e){super(t),this.opts=e,this.kind="popup"}enter(){this.host.mountNotePopup(this.opts)}handleEscape(t){nt(t),this.host.exitAll()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):(this.host.dismissNotePopup(),this.host.transitionTo(new k(this.host)))}}class on extends x{constructor(t,e,r){super(t),this.pos=e,this.opts=r,this.kind="clarifying"}enter(){this.host.mountClarifyCard(this.pos,this.opts)}handleEscape(t){}handleToolbarModeChange(t){this.host.revertToolbarDuringClarify()}}class Yt extends x{constructor(){super(...arguments),this.kind="submitting",this.launcherLit=!1}enter(){this.host.releaseClarifyUi()}handleTabClick(){}}const an=/^#[0-9a-f]{6}$/i;function ln(i){return i===void 0?void 0:typeof i!="object"||i===null||![i.primary,i.hover,i.active,i.onPrimary].every(e=>typeof e=="string"&&an.test(e))?Kt():{primary:i.primary.toLowerCase(),hover:i.hover.toLowerCase(),active:i.active.toLowerCase(),onPrimary:i.onPrimary.toLowerCase()}}function Kt(){console.warn("[MakeThisBetter] brandColors requires primary, hover, active, and onPrimary as six-digit hex colors.")}function Vt(){const{hostname:i}=window.location;return i==="localhost"||i==="127.0.0.1"||i==="[::1]"||i.endsWith(".localhost")||i.endsWith(".local")||i.endsWith(".test")}class cn{constructor(t){this.tab=null,this.toolbar=null,this.session=null,this.drawBar=null,this.dim=null,this.pageOffset=new Ne,this.pinPopup=null,this.scrollLock=null,this.drawSheet=null,this.clarify=null,this.success=null,this.frustrationPrompt=null,this.frustrationDetector=null,this.state=new W(this),this.via="pin",this.currentAnnotation=null,this.submittingUi=null,this.lastPopupPos=null,this.recordingManager=null,this.touchHintShown=!1,this.lastHandoff={},this.handleKeydown=e=>{e.key==="Escape"&&($(e)||this.state.handleEscape(e))},this.stopRecordingIntoNote=()=>{this.recordingManager&&(this.recordingManager.stop(),this.via="record",this.transitionTo(new Wt(this,{x:window.innerWidth/2,y:window.innerHeight/2,targetName:this.messages.record.timer_label})))},this.config=t,t.projectKey||console.warn("[MakeThisBetter] projectKey is missing. Feedback submission will be rejected."),this.brandColors=ln(t.brandColors),this.messages=zt(t.locale??document.documentElement.lang??"en"),this.apiClient=new Ai({projectKey:t.projectKey,apiUrl:t.apiUrl,userToken:t.userToken,userTokenFn:t.userTokenFn}),this.consoleCollector=new lr,this.consoleCollector.start(),this.breadcrumbCollector=new mr,this.breadcrumbCollector.start(),this.lifecycle=new nn({apiClient:this.apiClient,consoleCollector:this.consoleCollector,breadcrumbCollector:this.breadcrumbCollector,brandColors:this.brandColors,shadow:()=>this.shadow,messages:()=>this.messages,user:()=>this.config.user},{isBackground:()=>this.state.kind==="submitting",onReleaseForFailureCard:()=>this.transitionTo(new W(this)),onReenterBackground:()=>this.transitionTo(new Yt(this)),onFinalized:(e,r)=>this.handleFinalized(e,r)});try{this.buildUI()}catch(e){this.consoleCollector.stop(),this.breadcrumbCollector.stop(),console.warn("[MakeThisBetter] Widget failed to start:",e);return}t.frustrationDetection!==!1&&(this.frustrationDetector=new mt(()=>this.handleFrustration()),this.frustrationDetector.start()),document.addEventListener("keydown",this.handleKeydown,!0)}transitionTo(t){const e=this.state;this.state=t,e.exit(),t.enter(),this.tab?.setActive(t.launcherLit)}buildUI(){if(this.shadow=new ht(this.config.theme??"auto",this.brandColors),this.config.entryMode==="api"){Vt()&&console.warn('[MakeThisBetter] entryMode: "api" renders no launcher. Call MakeThisBetter.open() from your own UI.');return}if(y()){Vt()&&console.warn("[MakeThisBetter] No launcher is rendered on touch devices. Call MakeThisBetter.open() from your own mobile UI.");return}this.mountTab()}mountTab(){this.tab||!this.shadow||(this.tab=new Re(this.shadow,this.messages,this.config.position??"right",()=>this.state.handleTabClick(),this.config.tabText,this.brandColors?void 0:this.config.tabColor))}open(){this.shadow&&this.state.handleOpen()}close(){this.state.handleClose()}showLauncher(){y()||(this.mountTab(),this.tab?.setActive(this.state.launcherLit))}hideLauncher(){this.tab?.destroy(),this.tab=null}setLocale(t){this.config.locale=t,this.messages=zt(t),this.tab?.setMessages(this.messages)}handleFrustration(){!this.state.acceptsFrustrationPrompt||this.frustrationPrompt||pr()||(this.frustrationPrompt=new Fe(this.shadow,this.messages,{onTell:()=>{this.dismissFrustrationPrompt(),this.state.handleOpen()},onDismiss:()=>{fr(),this.dismissFrustrationPrompt()},onAutoHide:()=>this.dismissFrustrationPrompt()}))}dismissSuccess(){this.success?.destroy(),this.success=null}dismissFrustrationPrompt(){this.frustrationPrompt?.destroy(),this.frustrationPrompt=null}hasAnnotationChrome(){return this.toolbar!==null}mountAnnotationChrome(){he(),this.engageScrollLock();const t=y();this.toolbar=new qe(this.shadow,this.messages,()=>this.exitAll(),e=>this.state.handleToolbarModeChange(e),this.config.position??"right",!t||!this.touchHintShown),t&&(this.touchHintShown=!0),this.ensureSession(),t&&this.toolbar&&this.pageOffset.reserve(this.toolbar.height())}ensureSession(){this.session||(this.session=new si(this.shadow,this.messages,{onPin:(t,e)=>{this.currentAnnotation=t,this.via="pin",this.transitionTo(new Wt(this,{x:t.x,y:t.y,targetName:e,targetRect:t.targetRect}))},onDrawStroke:()=>this.state.handleDrawStroke()}))}destroySession(){this.session?.destroy(),this.session=null}clearCurrentAnnotation(){this.currentAnnotation=null}startRecorder(){this.recordingManager=new Xr,this.recordingManager.start(this.shadow,this.messages,this.stopRecordingIntoNote).catch(t=>{console.warn("[MakeThisBetter] Interaction replay unavailable, falling back to markup:",t),this.state.kind==="recording"&&(this.toolbar?.setMode("markup"),this.state.handleToolbarModeChange("markup"))})}destroyRecordingManager(){this.recordingManager?.destroy(),this.recordingManager=null}mountDrawBar(){this.drawBar=new di(this.shadow,{messages:this.messages,onUndo:()=>this.handleDrawUndoRedo("undo"),onRedo:()=>this.handleDrawUndoRedo("redo"),onCancel:()=>this.cancelDraw(),onSubmit:(t,e)=>this.handleDrawSubmit(t,e),onActivity:()=>this.lifecycle.beginBaseCapture()}),this.lifecycle.setScreenshotEnabled(!0),this.lifecycle.beginBaseCapture()}mountDrawSheet(){this.drawSheet=new _t(this.shadow,{targetName:this.messages.annotation.drawing,x:window.innerWidth/2,y:window.innerHeight/2,messages:this.messages,onSubmit:(t,e)=>this.handleDrawSubmit(t,e),onClose:()=>this.cancelDraw(),onActivity:()=>this.lifecycle.beginBaseCapture(),position:this.config.position??"right"}),this.submittingUi=this.drawSheet,this.lifecycle.setScreenshotEnabled(!0),this.lifecycle.beginBaseCapture()}handleDrawUndoRedo(t){t==="undo"?this.session?.undoDraw():this.session?.redoDraw(),this.refreshDrawBar()}refreshDrawBar(){this.session&&this.drawBar?.setUndoRedo(this.session.canUndoDraw(),this.session.canRedoDraw())}cancelDraw(){this.session?.clearDraw(),this.teardownDrawBar(),this.drawSheet?.destroy(),this.drawSheet=null,this.dim?.destroy(),this.dim=null,this.submittingUi=null,this.transitionTo(new k(this))}teardownDrawBar(){this.drawBar?.destroy(),this.drawBar=null}handleDrawSubmit(t,e){const r=this.session?.getDrawAnnotation();if(!r){this.cancelDraw();return}this.currentAnnotation=r,this.via="draw",this.session?.dismissInteraction(),this.submittingUi=this.drawBar??this.drawSheet,this.handleSubmit(t||this.messages.annotation.drawing,e)}mountNotePopup({x:t,y:e,targetName:r,targetRect:n}){this.lastPopupPos={x:t,y:e},this.teardownDrawBar(),this.session?.dismissInteraction(),this.pinPopup?.destroy(),this.pinPopup=null,this.dim?.destroy(),this.dim=null,this.dim=new Be(this.shadow,()=>this.exitAll());const s=this.recordingManager?.getRecording();s&&this.lifecycle.setScreenshotEnabled(!0),this.pinPopup=new _t(this.shadow,{targetName:r,x:t,y:e,targetRect:n,messages:this.messages,onSubmit:(o,a)=>this.handleSubmit(o,a),onClose:()=>this.exitAll(),onActivity:()=>this.lifecycle.beginBaseCapture(),onMyFeedback:this.buildMyFeedbackHandler(),...s?{recordingSeconds:s.duration}:{onScreenshotToggle:o=>this.lifecycle.setScreenshotEnabled(o),screenshotEnabled:this.lifecycle.isScreenshotEnabled()},position:this.config.position??"right"}),this.submittingUi=this.pinPopup,this.engageScrollLock(),this.lifecycle.beginBaseCapture()}dismissNotePopup(){this.pinPopup?.destroy(),this.pinPopup=null,this.dim?.destroy(),this.dim=null,this.submittingUi=null,this.clearCurrentAnnotation(),this.destroySession()}engageScrollLock(){this.scrollLock||(this.scrollLock=Ue())}releaseScrollLock(){this.scrollLock?.release(),this.scrollLock=null}buildMyFeedbackHandler(){if(!this.config.user&&Mr())return async()=>{const t=await this.apiClient.createIdentityToken(we());!t?.identity_token||!t.board_url||(Nt(t.board_url),window.open(`${t.board_url}?identity=${encodeURIComponent(t.identity_token)}`,"_blank"))}}handleSubmit(t,e){if(!this.submittingUi)return;const r=this.currentAnnotation,n=this.recordingManager?.getRecording()??void 0,s=this.teardownSubmittingUi(!0),o=()=>this.lifecycle.start(t,r,n);this.transitionTo(new on(this,this.lastPopupPos,{element:s,pendingSession:o(),onRetrySubmission:o,initiatingKeydown:e}))}teardownSubmittingUi(t=!1){const e=this.pinPopup??this.drawSheet,r=t?e?.releaseElement():void 0;return this.teardownDrawBar(),r||e?.destroy(),this.releaseScrollLock(),this.pinPopup=null,this.drawSheet=null,this.dim?.destroy(),this.dim=null,this.session?.hideHighlight(),this.session?.destroy(),this.session=null,this.recordingManager?.destroy(),this.recordingManager=null,this.submittingUi=null,r}mountClarifyCard(t,e){this.clarify=new Ni(this.shadow,{apiClient:this.apiClient,messages:this.messages,element:e.element,position:this.config.position??"right",x:t?.x,y:t?.y,onFinalize:()=>this.lifecycle.finalize(),initiatingKeydown:e.initiatingKeydown,onSkip:()=>this.transitionTo(new Yt(this)),onCancel:()=>this.exitAll(),pendingSession:e.pendingSession,onRetrySubmission:e.onRetrySubmission})}revertToolbarDuringClarify(){this.toolbar?.setMode(this.via==="record"?"record":"markup")}releaseClarifyUi(){this.teardownToolbar(),this.currentAnnotation=null,this.clarify=null}handleFinalized(t,e){this.lastHandoff={feedbackId:t.id,boardUrl:t.board_url,identityToken:t.identity_token},t.board_url&&Nt(t.board_url),this.clarify?.destroy(),this.clarify=null,this.teardownToolbar(),this.lifecycle.resetScreenshotConsent(),this.showSuccess({skipFollowup:e.ai_clarify_available===!1})}showSuccess(t){this.lifecycle.dismissFinalizeFailure(),this.transitionTo(new W(this)),this.success=new zi(this.shadow,this.messages,()=>{this.success?.destroy(),this.success=null},this.buildViewFeedbackHandler(),{...t,emailCapture:this.buildEmailCapture()})}buildEmailCapture(){if(this.config.user)return;const{feedbackId:t,identityToken:e}=this.lastHandoff;if(!(!t||!e)&&!xe())return{onSubmit:async r=>{const n=await this.apiClient.updateReporter(t,r,e);return n&&Pr(r),n}}}buildViewFeedbackHandler(){const{boardUrl:t,identityToken:e}=this.lastHandoff;if(t){if(e)return()=>{window.open(`${t}?identity=${encodeURIComponent(e)}`,"_blank")};if(this.config.userToken||this.config.userTokenFn)return async()=>{try{const r=await this.apiClient.resolveUserToken();r&&window.open(`${t}?identity=${encodeURIComponent(r)}`,"_blank")}catch{}}}}teardownToolbar(){this.pageOffset.release(),this.toolbar?.destroy(),this.toolbar=null}exitAll(){this.lifecycle.abandon(),this.via="pin",this.transitionTo(new W(this)),this.teardownToolbar(),this.teardownDrawBar(),this.releaseScrollLock(),this.session?.hideHighlight(),this.session?.destroy(),this.session=null,this.dim?.destroy(),this.dim=null,this.pinPopup?.destroy(),this.pinPopup=null,this.drawSheet?.destroy(),this.drawSheet=null,this.clarify?.destroy(),this.clarify=null,this.currentAnnotation=null,this.submittingUi=null,this.recordingManager?.destroy(),this.recordingManager=null}destroy(){document.removeEventListener("keydown",this.handleKeydown,!0),this.exitAll(),this.consoleCollector.stop(),this.breadcrumbCollector.stop(),this.frustrationDetector?.stop(),this.dismissFrustrationPrompt(),this.clarify?.destroy(),this.success?.destroy(),this.lifecycle.dismissFinalizeFailure(),this.tab?.destroy(),this.recordingManager?.destroy(),this.shadow?.destroy()}}let v=null,E=null,T=null;function dn(){T&&(document.removeEventListener("DOMContentLoaded",T),T=null)}function M(i){dn(),v?.destroy(),v=i?new cn(i):null}const ke={init(i){typeof document>"u"||(M(),E=i,document.readyState==="loading"?(T=()=>{T=null,M(i)},document.addEventListener("DOMContentLoaded",T,{once:!0})):M(i))},destroy(){M(),E=null},setLocale(i){E&&(E.locale=i),v?.setLocale(i)},open(){v?.open()},close(){v?.close()},showLauncher(){v?.showLauncher()},hideLauncher(){v?.hideLauncher()}};typeof window<"u"&&(window.MakeThisBetter=ke,document.addEventListener("turbo:load",()=>{const i=document.getElementById(w);E&&(!i||!i.shadowRoot)&&(i?.remove(),M(E))}));exports.MakeThisBetter=ke;
174
+ `,t.append(this.el),r.onRetry&&this.el.querySelector(".mtb-failure-retry").addEventListener("click",r.onRetry),this.el.querySelector(".mtb-failure-close").addEventListener("click",r.onClose)}destroy(){this.el.remove()}}function Zr(){return{page_url:U(window.location.href),user_agent:navigator.userAgent,browser:Jr(),os:Qr(),screen_width:window.screen.width,screen_height:window.screen.height}}function Jr(){const i=navigator.userAgent;return/Edg\//.test(i)?`Edge ${i.match(/Edg\/(\S+)/)?.[1]??""}`:/OPR\//.test(i)?`Opera ${i.match(/OPR\/(\S+)/)?.[1]??""}`:/Chrome\//.test(i)?`Chrome ${i.match(/Chrome\/(\S+)/)?.[1]??""}`:/Safari\//.test(i)&&/Version\//.test(i)?`Safari ${i.match(/Version\/(\S+)/)?.[1]??""}`:/Firefox\//.test(i)?`Firefox ${i.match(/Firefox\/(\S+)/)?.[1]??""}`:"Unknown"}function Qr(){const i=navigator.userAgent;return/Windows NT 10/.test(i)?"Windows 10/11":/Windows NT/.test(i)?"Windows":/Mac OS X 10_15|macOS 1[56789]/.test(i)||/Mac OS X/.test(i)?"macOS":/Android/.test(i)?`Android ${i.match(/Android (\d+)/)?.[1]??""}`:/iPhone|iPad|iPod/.test(i)?"iOS":/Linux/.test(i)?"Linux":"Unknown"}function tn(i){const{description:t,pageContext:e,consoleErrors:r,annotation:n,user:s,recording:o,anonId:a,anonEmail:c,breadcrumbs:d}=i;return{...Z({description:t,...e,page_url:U(e.page_url),console_errors:r,annotations:n?[n]:[],target_element:n?.targetSelector?{selector:n.targetSelector,text:n.targetText??"",name:n.targetName??""}:void 0,recording_events:o?.events,recording_duration:o?.duration,breadcrumbs:d}),user_id:s?.id,user_email:s?.email,user_name:s?.name,reporter_external_id:s?void 0:a,reporter_email:s?void 0:c}}const en=300,rn=900;class nn{constructor(t,e){this.deps=t,this.host=e,this.activeSubmission=null,this.pendingSubmissionRequest=null,this.submissionAttempt=0,this.pendingBaseCapture=null,this.idleCaptureTimer=null,this.failure=null,this.screenshotEnabled=!0}isScreenshotEnabled(){return this.screenshotEnabled}resetScreenshotConsent(){this.screenshotEnabled=!0}setScreenshotEnabled(t){if(this.screenshotEnabled=t,t){this.beginBaseCapture();return}this.clearIdleCaptureTimer(),this.pendingBaseCapture=null}beginBaseCapture(){this.screenshotEnabled&&(this.pendingBaseCapture||(this.clearIdleCaptureTimer(),this.idleCaptureTimer=setTimeout(()=>{this.idleCaptureTimer=null,this.pendingBaseCapture??(this.pendingBaseCapture=Pt())},rn)))}clearIdleCaptureTimer(){this.idleCaptureTimer!==null&&(clearTimeout(this.idleCaptureTimer),this.idleCaptureTimer=null)}start(t,e,r){const n=++this.submissionAttempt,s=this.createSubmission(t,e,r,n);return this.pendingSubmissionRequest=s,s}async createSubmission(t,e,r,n){if(await qt(),n!==this.submissionAttempt)return null;this.clearIdleCaptureTimer();const s=this.screenshotEnabled?this.pendingBaseCapture??Pt():null;this.pendingBaseCapture=null;const o=Zr(),a=await s;if(n!==this.submissionAttempt)return null;const c=a?await Wi(a,e?[e]:[],this.deps.brandColors):null;if(n!==this.submissionAttempt)return null;const d=tn({description:t,pageContext:o,consoleErrors:this.deps.consoleCollector.getErrors(),annotation:e,user:this.deps.user(),recording:r,anonId:we(),anonEmail:xe(),breadcrumbs:this.deps.breadcrumbCollector.getBreadcrumbs()});try{const h=await this.deps.apiClient.createSubmissionSession(d,c);return n!==this.submissionAttempt?(await this.deps.apiClient.abandonSubmissionSession(h.id,h.token).catch(()=>{}),null):(this.activeSubmission=h,h)}catch{return null}}async finalize(){const t=this.submissionAttempt,e=this.host.isBackground(),r=this.activeSubmission??await(this.pendingSubmissionRequest??Promise.resolve(null));if(t!==this.submissionAttempt)return;if(!r){if(e)return this.showFinalizeFailure({canRetry:!1});throw new Error("No active submission session")}const n=e?Promise.resolve():new Promise(o=>setTimeout(o,en));let s;try{s=await this.deps.apiClient.finalizeSubmissionSession(r.id,r.token)}catch(o){if(e)return this.showFinalizeFailure({canRetry:!0});throw o}await Promise.all([n,qt()]),!(t!==this.submissionAttempt||this.activeSubmission!==r)&&(this.activeSubmission=null,this.pendingSubmissionRequest=null,this.host.onFinalized(s,r))}showFinalizeFailure(t){this.host.onReleaseForFailureCard(),this.failure?.destroy(),this.failure=new Gr(this.deps.shadow(),this.deps.messages(),{onRetry:t.canRetry?()=>this.retryBackgroundFinalization():void 0,onClose:()=>this.dismissFinalizeFailure()})}retryBackgroundFinalization(){this.dismissFinalizeFailure(),this.host.onReenterBackground(),this.finalize().catch(()=>this.showFinalizeFailure({canRetry:!0}))}dismissFinalizeFailure(){this.failure?.destroy(),this.failure=null}abandon(){this.submissionAttempt+=1,this.clearIdleCaptureTimer(),this.pendingBaseCapture=null,this.resetScreenshotConsent();const t=this.activeSubmission;this.activeSubmission=null,this.pendingSubmissionRequest=null,t&&this.deps.apiClient.abandonSubmissionSession(t.id,t.token).catch(()=>{})}}function qt(){return new Promise(i=>requestAnimationFrame(()=>setTimeout(i,0)))}function nt(i){i.preventDefault(),i.stopPropagation()}class x{constructor(t){this.host=t,this.launcherLit=!0,this.acceptsFrustrationPrompt=!1}enter(){}exit(){}handleOpen(){}handleClose(){this.host.exitAll()}handleEscape(t){}handleTabClick(){this.host.exitAll()}handleToolbarModeChange(t){}handleDrawStroke(){}}class W extends x{constructor(){super(...arguments),this.kind="idle",this.launcherLit=!1,this.acceptsFrustrationPrompt=!0}handleOpen(){this.host.dismissFrustrationPrompt(),this.host.dismissSuccess(),this.host.transitionTo(new k(this.host))}handleClose(){}handleTabClick(){this.handleOpen()}}class k extends x{constructor(){super(...arguments),this.kind="annotating"}enter(){if(!this.host.hasAnnotationChrome()){this.host.mountAnnotationChrome();return}this.host.destroyRecordingManager(),this.host.teardownDrawBar(),this.host.ensureSession()}handleEscape(t){nt(t),this.host.exitAll()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):this.host.transitionTo(new k(this.host))}handleDrawStroke(){this.host.transitionTo(new sn(this.host,y()?"sheet":"bar"))}}class xt extends x{constructor(){super(...arguments),this.kind="recording"}enter(){this.host.clearCurrentAnnotation(),this.host.teardownDrawBar(),this.host.destroySession(),this.host.startRecorder()}handleEscape(t){nt(t),this.host.stopRecordingIntoNote()}handleToolbarModeChange(t){t!=="record"&&this.host.transitionTo(new k(this.host))}}class sn extends x{constructor(t,e){super(t),this.surface=e,this.kind="drawing"}enter(){this.surface==="sheet"?this.host.mountDrawSheet():(this.host.mountDrawBar(),this.host.refreshDrawBar())}handleEscape(t){nt(t),this.host.cancelDraw()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):this.host.transitionTo(new k(this.host))}handleDrawStroke(){this.surface==="bar"&&this.host.refreshDrawBar()}}class Wt extends x{constructor(t,e){super(t),this.opts=e,this.kind="popup"}enter(){this.host.mountNotePopup(this.opts)}handleEscape(t){nt(t),this.host.exitAll()}handleToolbarModeChange(t){t==="record"?this.host.transitionTo(new xt(this.host)):(this.host.dismissNotePopup(),this.host.transitionTo(new k(this.host)))}}class on extends x{constructor(t,e,r){super(t),this.pos=e,this.opts=r,this.kind="clarifying"}enter(){this.host.mountClarifyCard(this.pos,this.opts)}handleEscape(t){}handleToolbarModeChange(t){this.host.revertToolbarDuringClarify()}}class Yt extends x{constructor(){super(...arguments),this.kind="submitting",this.launcherLit=!1}enter(){this.host.releaseClarifyUi()}handleTabClick(){}}const an=/^#[0-9a-f]{6}$/i;function ln(i){return i===void 0?void 0:typeof i!="object"||i===null||![i.primary,i.hover,i.active,i.onPrimary].every(e=>typeof e=="string"&&an.test(e))?Kt():{primary:i.primary.toLowerCase(),hover:i.hover.toLowerCase(),active:i.active.toLowerCase(),onPrimary:i.onPrimary.toLowerCase()}}function Kt(){console.warn("[MakeThisBetter] brandColors requires primary, hover, active, and onPrimary as six-digit hex colors.")}function Vt(){const{hostname:i}=window.location;return i==="localhost"||i==="127.0.0.1"||i==="[::1]"||i.endsWith(".localhost")||i.endsWith(".local")||i.endsWith(".test")}class cn{constructor(t){this.tab=null,this.toolbar=null,this.session=null,this.drawBar=null,this.dim=null,this.pageOffset=new Ne,this.pinPopup=null,this.scrollLock=null,this.drawSheet=null,this.clarify=null,this.success=null,this.frustrationPrompt=null,this.frustrationDetector=null,this.state=new W(this),this.via="pin",this.currentAnnotation=null,this.submittingUi=null,this.lastPopupPos=null,this.recordingManager=null,this.touchHintShown=!1,this.lastHandoff={},this.handleKeydown=e=>{e.key==="Escape"&&($(e)||this.state.handleEscape(e))},this.stopRecordingIntoNote=()=>{this.recordingManager&&(this.recordingManager.stop(),this.via="record",this.transitionTo(new Wt(this,{x:window.innerWidth/2,y:window.innerHeight/2,targetName:this.messages.record.timer_label})))},this.config=t,t.projectKey||console.warn("[MakeThisBetter] projectKey is missing. Feedback submission will be rejected."),this.brandColors=ln(t.brandColors),this.messages=zt(t.locale??document.documentElement.lang??"en"),this.apiClient=new Ai({projectKey:t.projectKey,apiUrl:t.apiUrl,userToken:t.userToken,userTokenFn:t.userTokenFn}),this.consoleCollector=new lr,this.consoleCollector.start(),this.breadcrumbCollector=new mr,this.breadcrumbCollector.start(),this.lifecycle=new nn({apiClient:this.apiClient,consoleCollector:this.consoleCollector,breadcrumbCollector:this.breadcrumbCollector,brandColors:this.brandColors,shadow:()=>this.shadow,messages:()=>this.messages,user:()=>this.config.user},{isBackground:()=>this.state.kind==="submitting",onReleaseForFailureCard:()=>this.transitionTo(new W(this)),onReenterBackground:()=>this.transitionTo(new Yt(this)),onFinalized:(e,r)=>this.handleFinalized(e,r)});try{this.buildUI()}catch(e){this.consoleCollector.stop(),this.breadcrumbCollector.stop(),console.warn("[MakeThisBetter] Widget failed to start:",e);return}t.frustrationDetection!==!1&&(this.frustrationDetector=new mt(()=>this.handleFrustration()),this.frustrationDetector.start()),document.addEventListener("keydown",this.handleKeydown,!0)}transitionTo(t){const e=this.state;this.state=t,e.exit(),t.enter(),this.tab?.setActive(t.launcherLit)}buildUI(){if(this.shadow=new ht(this.config.theme??"auto",this.brandColors),this.config.entryMode==="api"){Vt()&&console.warn('[MakeThisBetter] entryMode: "api" renders no launcher. Call MakeThisBetter.open() from your own UI.');return}if(y()){Vt()&&console.warn("[MakeThisBetter] No launcher is rendered on touch devices. Call MakeThisBetter.open() from your own mobile UI.");return}this.mountTab()}mountTab(){this.tab||!this.shadow||(this.tab=new Re(this.shadow,this.messages,this.config.position??"right",()=>this.state.handleTabClick(),this.config.tabText,this.brandColors?void 0:this.config.tabColor))}open(){this.shadow&&this.state.handleOpen()}close(){this.state.handleClose()}showLauncher(){y()||(this.mountTab(),this.tab?.setActive(this.state.launcherLit))}hideLauncher(){this.tab?.destroy(),this.tab=null}setLocale(t){this.config.locale=t,this.messages=zt(t),this.tab?.setMessages(this.messages)}handleFrustration(){!this.state.acceptsFrustrationPrompt||this.frustrationPrompt||pr()||(this.frustrationPrompt=new Fe(this.shadow,this.messages,{onTell:()=>{this.dismissFrustrationPrompt(),this.state.handleOpen()},onDismiss:()=>{fr(),this.dismissFrustrationPrompt()},onAutoHide:()=>this.dismissFrustrationPrompt()}))}dismissSuccess(){this.success?.destroy(),this.success=null}dismissFrustrationPrompt(){this.frustrationPrompt?.destroy(),this.frustrationPrompt=null}hasAnnotationChrome(){return this.toolbar!==null}mountAnnotationChrome(){he();const t=y();this.toolbar=new qe(this.shadow,this.messages,()=>this.exitAll(),e=>this.state.handleToolbarModeChange(e),this.config.position??"right",!t||!this.touchHintShown),t&&(this.touchHintShown=!0),this.ensureSession(),t&&this.toolbar&&this.pageOffset.reserve(this.toolbar.height())}ensureSession(){this.session||(this.session=new si(this.shadow,this.messages,{onPin:(t,e)=>{this.currentAnnotation=t,this.via="pin",this.transitionTo(new Wt(this,{x:t.x,y:t.y,targetName:e,targetRect:t.targetRect}))},onDrawStroke:()=>this.state.handleDrawStroke()}))}destroySession(){this.session?.destroy(),this.session=null}clearCurrentAnnotation(){this.currentAnnotation=null}startRecorder(){this.recordingManager=new Xr,this.recordingManager.start(this.shadow,this.messages,this.stopRecordingIntoNote).catch(t=>{console.warn("[MakeThisBetter] Interaction replay unavailable, falling back to markup:",t),this.state.kind==="recording"&&(this.toolbar?.setMode("markup"),this.state.handleToolbarModeChange("markup"))})}destroyRecordingManager(){this.recordingManager?.destroy(),this.recordingManager=null}mountDrawBar(){this.engageScrollLock(),this.drawBar=new di(this.shadow,{messages:this.messages,onUndo:()=>this.handleDrawUndoRedo("undo"),onRedo:()=>this.handleDrawUndoRedo("redo"),onCancel:()=>this.cancelDraw(),onSubmit:(t,e)=>this.handleDrawSubmit(t,e),onActivity:()=>this.lifecycle.beginBaseCapture()}),this.lifecycle.setScreenshotEnabled(!0),this.lifecycle.beginBaseCapture()}mountDrawSheet(){this.engageScrollLock(),this.drawSheet=new _t(this.shadow,{targetName:this.messages.annotation.drawing,x:window.innerWidth/2,y:window.innerHeight/2,messages:this.messages,onSubmit:(t,e)=>this.handleDrawSubmit(t,e),onClose:()=>this.cancelDraw(),onActivity:()=>this.lifecycle.beginBaseCapture(),position:this.config.position??"right"}),this.submittingUi=this.drawSheet,this.lifecycle.setScreenshotEnabled(!0),this.lifecycle.beginBaseCapture()}handleDrawUndoRedo(t){t==="undo"?this.session?.undoDraw():this.session?.redoDraw(),this.refreshDrawBar()}refreshDrawBar(){this.session&&this.drawBar?.setUndoRedo(this.session.canUndoDraw(),this.session.canRedoDraw())}cancelDraw(){this.session?.clearDraw(),this.releaseScrollLock(),this.teardownDrawBar(),this.drawSheet?.destroy(),this.drawSheet=null,this.dim?.destroy(),this.dim=null,this.submittingUi=null,this.transitionTo(new k(this))}teardownDrawBar(){this.drawBar?.destroy(),this.drawBar=null}handleDrawSubmit(t,e){const r=this.session?.getDrawAnnotation();if(!r){this.cancelDraw();return}this.currentAnnotation=r,this.via="draw",this.session?.dismissInteraction(),this.submittingUi=this.drawBar??this.drawSheet,this.handleSubmit(t||this.messages.annotation.drawing,e)}mountNotePopup({x:t,y:e,targetName:r,targetRect:n}){this.lastPopupPos={x:t,y:e},this.teardownDrawBar(),this.session?.dismissInteraction(),this.pinPopup?.destroy(),this.pinPopup=null,this.dim?.destroy(),this.dim=null,this.dim=new Be(this.shadow,()=>this.exitAll());const s=this.recordingManager?.getRecording();s&&this.lifecycle.setScreenshotEnabled(!0),this.pinPopup=new _t(this.shadow,{targetName:r,x:t,y:e,targetRect:n,messages:this.messages,onSubmit:(o,a)=>this.handleSubmit(o,a),onClose:()=>this.exitAll(),onActivity:()=>this.lifecycle.beginBaseCapture(),onMyFeedback:this.buildMyFeedbackHandler(),...s?{recordingSeconds:s.duration}:{onScreenshotToggle:o=>this.lifecycle.setScreenshotEnabled(o),screenshotEnabled:this.lifecycle.isScreenshotEnabled()},position:this.config.position??"right"}),this.submittingUi=this.pinPopup,this.engageScrollLock(),this.lifecycle.beginBaseCapture()}dismissNotePopup(){this.pinPopup?.destroy(),this.pinPopup=null,this.dim?.destroy(),this.dim=null,this.releaseScrollLock(),this.submittingUi=null,this.clearCurrentAnnotation(),this.destroySession()}engageScrollLock(){this.scrollLock||(this.scrollLock=Ue())}releaseScrollLock(){this.scrollLock?.release(),this.scrollLock=null}buildMyFeedbackHandler(){if(!this.config.user&&Mr())return async()=>{const t=await this.apiClient.createIdentityToken(we());!t?.identity_token||!t.board_url||(Nt(t.board_url),window.open(`${t.board_url}?identity=${encodeURIComponent(t.identity_token)}`,"_blank"))}}handleSubmit(t,e){if(!this.submittingUi)return;const r=this.currentAnnotation,n=this.recordingManager?.getRecording()??void 0,s=this.teardownSubmittingUi(!0),o=()=>this.lifecycle.start(t,r,n);this.transitionTo(new on(this,this.lastPopupPos,{element:s,pendingSession:o(),onRetrySubmission:o,initiatingKeydown:e}))}teardownSubmittingUi(t=!1){const e=this.pinPopup??this.drawSheet,r=t?e?.releaseElement():void 0;return this.teardownDrawBar(),r||e?.destroy(),this.releaseScrollLock(),this.pinPopup=null,this.drawSheet=null,this.dim?.destroy(),this.dim=null,this.session?.hideHighlight(),this.session?.destroy(),this.session=null,this.recordingManager?.destroy(),this.recordingManager=null,this.submittingUi=null,r}mountClarifyCard(t,e){this.clarify=new Ni(this.shadow,{apiClient:this.apiClient,messages:this.messages,element:e.element,position:this.config.position??"right",x:t?.x,y:t?.y,onFinalize:()=>this.lifecycle.finalize(),initiatingKeydown:e.initiatingKeydown,onSkip:()=>this.transitionTo(new Yt(this)),onCancel:()=>this.exitAll(),pendingSession:e.pendingSession,onRetrySubmission:e.onRetrySubmission})}revertToolbarDuringClarify(){this.toolbar?.setMode(this.via==="record"?"record":"markup")}releaseClarifyUi(){this.teardownToolbar(),this.currentAnnotation=null,this.clarify=null}handleFinalized(t,e){this.lastHandoff={feedbackId:t.id,boardUrl:t.board_url,identityToken:t.identity_token},t.board_url&&Nt(t.board_url),this.clarify?.destroy(),this.clarify=null,this.teardownToolbar(),this.lifecycle.resetScreenshotConsent(),this.showSuccess({skipFollowup:e.ai_clarify_available===!1})}showSuccess(t){this.lifecycle.dismissFinalizeFailure(),this.transitionTo(new W(this)),this.success=new zi(this.shadow,this.messages,()=>{this.success?.destroy(),this.success=null},this.buildViewFeedbackHandler(),{...t,emailCapture:this.buildEmailCapture()})}buildEmailCapture(){if(this.config.user)return;const{feedbackId:t,identityToken:e}=this.lastHandoff;if(!(!t||!e)&&!xe())return{onSubmit:async r=>{const n=await this.apiClient.updateReporter(t,r,e);return n&&Pr(r),n}}}buildViewFeedbackHandler(){const{boardUrl:t,identityToken:e}=this.lastHandoff;if(t){if(e)return()=>{window.open(`${t}?identity=${encodeURIComponent(e)}`,"_blank")};if(this.config.userToken||this.config.userTokenFn)return async()=>{try{const r=await this.apiClient.resolveUserToken();r&&window.open(`${t}?identity=${encodeURIComponent(r)}`,"_blank")}catch{}}}}teardownToolbar(){this.pageOffset.release(),this.toolbar?.destroy(),this.toolbar=null}exitAll(){this.lifecycle.abandon(),this.via="pin",this.transitionTo(new W(this)),this.teardownToolbar(),this.teardownDrawBar(),this.releaseScrollLock(),this.session?.hideHighlight(),this.session?.destroy(),this.session=null,this.dim?.destroy(),this.dim=null,this.pinPopup?.destroy(),this.pinPopup=null,this.drawSheet?.destroy(),this.drawSheet=null,this.clarify?.destroy(),this.clarify=null,this.currentAnnotation=null,this.submittingUi=null,this.recordingManager?.destroy(),this.recordingManager=null}destroy(){document.removeEventListener("keydown",this.handleKeydown,!0),this.exitAll(),this.consoleCollector.stop(),this.breadcrumbCollector.stop(),this.frustrationDetector?.stop(),this.dismissFrustrationPrompt(),this.clarify?.destroy(),this.success?.destroy(),this.lifecycle.dismissFinalizeFailure(),this.tab?.destroy(),this.recordingManager?.destroy(),this.shadow?.destroy()}}let v=null,E=null,T=null;function dn(){T&&(document.removeEventListener("DOMContentLoaded",T),T=null)}function M(i){dn(),v?.destroy(),v=i?new cn(i):null}const ke={init(i){typeof document>"u"||(M(),E=i,document.readyState==="loading"?(T=()=>{T=null,M(i)},document.addEventListener("DOMContentLoaded",T,{once:!0})):M(i))},destroy(){M(),E=null},setLocale(i){E&&(E.locale=i),v?.setLocale(i)},open(){v?.open()},close(){v?.close()},showLauncher(){v?.showLauncher()},hideLauncher(){v?.hideLauncher()}};typeof window<"u"&&(window.MakeThisBetter=ke,document.addEventListener("turbo:load",()=>{const i=document.getElementById(w);E&&(!i||!i.shadowRoot)&&(i?.remove(),M(E))}));exports.MakeThisBetter=ke;
175
175
  //# sourceMappingURL=makethisbetter.cjs.map