@qaiddev/thumbs-embed 1.0.5 → 1.0.7

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/qaid.js CHANGED
@@ -1,155 +1,179 @@
1
- var j = Object.defineProperty;
2
- var X = (i, t, e) => t in i ? j(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
- var d = (i, t, e) => X(i, typeof t != "symbol" ? t + "" : t, e);
4
- const k = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
1
+ var tt = Object.defineProperty;
2
+ var et = (e, t, o) => t in e ? tt(e, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : e[t] = o;
3
+ var h = (e, t, o) => et(e, typeof t != "symbol" ? t + "" : t, o);
4
+ const T = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
5
5
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"/>
6
- </svg>`, w = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
6
+ </svg>`, I = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
7
7
  <path stroke-linecap="round" stroke-linejoin="round" d="M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.737 3h4.018a2 2 0 01.485.06l3.76.94m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5-10h2a2 2 0 012 2v6a2 2 0 01-2 2h-2.5"/>
8
- </svg>`, Y = "body.qaid-targeting,body.qaid-targeting *{cursor:none!important}.qaid-widget,.qaid-widget *,.qaid-modal-container,.qaid-modal-container *{cursor:pointer!important}.qaid-widget.qaid-auto-container{position:fixed;z-index:50;display:flex;gap:.5rem}.qaid-widget.qaid-auto-container.qaid-bottom-right{bottom:1rem;right:1rem}.qaid-widget.qaid-auto-container.qaid-bottom-left{bottom:1rem;left:1rem}.qaid-widget.qaid-auto-container.qaid-top-right{top:1rem;right:1rem}.qaid-widget.qaid-auto-container.qaid-top-left{top:1rem;left:1rem}.qaid-widget.qaid-incognito{opacity:0;transition:opacity .2s ease-in-out}.qaid-widget.qaid-incognito:hover{opacity:1}button.qaid-btn-structural{display:inline-flex;align-items:center;justify-content:center;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.qaid-icon{width:24px;height:24px}.qaid-btn-structural:not(:has(svg)),.qaid-btn:not(:has(svg)){font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-emoji-icon{font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-tooltip-wrapper{position:relative}.qaid-tooltip-text{position:fixed;padding:.5rem .75rem;background:#1f2937;color:#fff;font-size:1rem;font-weight:600;border-radius:.5rem;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s;z-index:99999}.qaid-tooltip-text.qaid-tooltip-visible{opacity:1}.qaid-targeting-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;pointer-events:none}.qaid-capture-layer{position:fixed;top:0;right:0;bottom:0;left:0;cursor:crosshair;pointer-events:auto;z-index:9999}.qaid-banner{position:fixed;top:0;left:0;right:0;padding:.75rem 1rem;text-align:center;z-index:10000;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px);animation:qaid-slideDown .2s ease-out}.qaid-banner-up{background:color-mix(in srgb,var(--qaid-positive) 90%,transparent);color:#fff}.qaid-banner-down{background:color-mix(in srgb,var(--qaid-negative) 90%,transparent);color:#fff}.qaid-banner-text{font-weight:500}.qaid-banner-hint{margin-left:.5rem;opacity:.75}@keyframes qaid-slideDown{0%{transform:translateY(-100%)}to{transform:translateY(0)}}.qaid-vignette{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;background:radial-gradient(ellipse at center,transparent 30%,rgba(0,0,0,.3) 70%,rgba(0,0,0,.6) 100%);z-index:41}.qaid-crosshair-h,.qaid-crosshair-v{position:fixed;pointer-events:none;z-index:42}.qaid-crosshair-h{left:0;right:0;height:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-crosshair-v{top:0;bottom:0;width:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-type-up .qaid-crosshair-h,.qaid-type-up .qaid-crosshair-v{background:color-mix(in srgb,var(--qaid-positive) 60%,transparent)}.qaid-scope{position:fixed;width:80px;height:80px;pointer-events:none;z-index:43;transform:translate(-50%,-50%)}.qaid-scope-ring{position:absolute;top:10px;right:10px;bottom:10px;left:10px;border:2px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)}.qaid-scope-ring-inner{position:absolute;top:20px;right:20px;bottom:20px;left:20px;border:1px solid color-mix(in srgb,var(--qaid-negative) 50%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring-inner{border-color:color-mix(in srgb,var(--qaid-positive) 50%,transparent)}.qaid-scope-dot{position:absolute;top:50%;left:50%;width:4px;height:4px;background:var(--qaid-negative);border-radius:50%;transform:translate(-50%,-50%)}.qaid-type-up .qaid-scope-dot{background:var(--qaid-positive)}.qaid-highlight{outline:3px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent)!important;outline-offset:2px!important;background-color:color-mix(in srgb,var(--qaid-negative) 10%,transparent)!important;transition:outline .1s ease,background-color .1s ease}body.qaid-targeting.qaid-type-up .qaid-highlight{outline-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)!important;background-color:color-mix(in srgb,var(--qaid-positive) 10%,transparent)!important}.qaid-selected-marker{position:fixed;border:3px solid var(--qaid-marker, #6366f1);border-radius:50%;pointer-events:none;z-index:44;animation:qaid-markerPulse 1.5s ease-in-out infinite}@keyframes qaid-markerPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.05)}}.qaid-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:45;background:#0000004d}.qaid-modal-container{position:fixed;z-index:50;display:flex;flex-direction:column;align-items:flex-start;max-height:calc(100vh - 32px);font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-modal-container.qaid-above{flex-direction:column-reverse}.qaid-modal-arrow{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;position:relative;align-self:flex-start}.qaid-modal-container.qaid-below .qaid-modal-arrow{border-bottom:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-container.qaid-above .qaid-modal-arrow{border-top:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px light-dark(rgba(0,0,0,.25),rgba(0,0,0,.5));width:var(--qaid-modal-width, 400px);max-width:calc(100vw - 32px);max-height:calc(100vh - 60px);overflow-y:auto}.qaid-modal-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:1rem}button.qaid-type-toggle{border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;flex-shrink:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-type-toggle:hover{transform:scale(1.1)}button.qaid-type-toggle:not(.qaid-type-toggle-custom){width:2.5rem;height:2.5rem;border-radius:50%}button.qaid-type-toggle:not(.qaid-type-toggle-custom) svg{width:1.25rem;height:1.25rem}button.qaid-type-toggle.qaid-type-up{background:var(--qaid-positive);color:#fff}button.qaid-type-toggle.qaid-type-down{background:var(--qaid-negative);color:#fff}.qaid-modal-header-text{flex:1;min-width:0}.qaid-modal-title{font-size:1.125rem;font-weight:700;margin:0 0 .25rem;color:light-dark(#1f2937,#f9fafb)}.qaid-modal-subtitle{color:light-dark(#6b7280,#9ca3af);margin:0;font-size:.875rem}.qaid-textarea{width:100%;height:6rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:1rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-btn-row{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-btn-submit{padding:.5rem 1rem;background:var(--qaid-marker);color:var(--qaid-marker-text, white);border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-btn-submit:hover{filter:brightness(.85)}button.qaid-btn-submit:focus{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 30%,transparent)}.qaid-bottom-sheet{position:fixed;bottom:0;left:0;right:0;z-index:50;animation:qaid-slideUpSheet .3s ease-out;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-bottom-sheet-content{background:light-dark(#ffffff,#1f2937);border-radius:1rem 1rem 0 0;padding:1.5rem;padding-bottom:max(1.5rem,env(safe-area-inset-bottom))}.qaid-bottom-sheet-handle{width:36px;height:4px;background:light-dark(rgba(0,0,0,.2),rgba(255,255,255,.2));border-radius:2px;margin:0 auto 1rem}@keyframes qaid-slideUpSheet{0%{transform:translateY(100%)}to{transform:translateY(0)}}";
9
- let T = !1;
10
- const K = {
8
+ </svg>`, it = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
9
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z"/>
10
+ </svg>`, ot = ".qaid-buttons{display:flex;gap:.5rem}.qaid-buttons.qaid-vertical{flex-direction:column}.qaid-buttons.qaid-auto-container{position:fixed;z-index:50}.qaid-buttons.qaid-auto-container.qaid-bottom-right{bottom:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-bottom-left{bottom:1rem;left:1rem}.qaid-buttons.qaid-auto-container.qaid-top-right{top:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-top-left{top:1rem;left:1rem}.qaid-buttons.qaid-incognito{opacity:0;transition:opacity .2s ease-in-out}.qaid-buttons.qaid-incognito:hover{opacity:1}button.qaid-btn-structural{display:inline-flex;align-items:center;justify-content:center;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.qaid-icon{width:24px;height:24px}.qaid-btn-structural:not(:has(svg)),.qaid-btn:not(:has(svg)){font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-emoji-icon{font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-buttons,.qaid-buttons *,.qaid-modal-container,.qaid-modal-container *{cursor:pointer!important}.qaid-tooltip-wrapper{position:relative}.qaid-tooltip-text{position:fixed;padding:.5rem .75rem;background:#1f2937;color:#fff;font-size:1rem;font-weight:600;border-radius:.5rem;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s;z-index:99999}.qaid-tooltip-text.qaid-tooltip-visible{opacity:1}.qaid-targeting-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;pointer-events:none}.qaid-capture-layer{position:fixed;top:0;right:0;bottom:0;left:0;cursor:crosshair;pointer-events:auto;z-index:9999}@keyframes qaid-slideDown{0%{transform:translateY(-100%)}to{transform:translateY(0)}}.qaid-vignette{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;background:radial-gradient(ellipse at center,transparent 30%,rgba(0,0,0,.3) 70%,rgba(0,0,0,.6) 100%);z-index:41}.qaid-crosshair-h,.qaid-crosshair-v{position:fixed;pointer-events:none;z-index:42}.qaid-crosshair-h{left:0;right:0;height:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-crosshair-v{top:0;bottom:0;width:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-type-up .qaid-crosshair-h,.qaid-type-up .qaid-crosshair-v{background:color-mix(in srgb,var(--qaid-positive) 60%,transparent)}.qaid-scope{position:fixed;width:80px;height:80px;pointer-events:none;z-index:43;transform:translate(-50%,-50%)}.qaid-scope-ring{position:absolute;top:10px;right:10px;bottom:10px;left:10px;border:2px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)}.qaid-scope-ring-inner{position:absolute;top:20px;right:20px;bottom:20px;left:20px;border:1px solid color-mix(in srgb,var(--qaid-negative) 50%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring-inner{border-color:color-mix(in srgb,var(--qaid-positive) 50%,transparent)}.qaid-scope-dot{position:absolute;top:50%;left:50%;width:4px;height:4px;background:var(--qaid-negative);border-radius:50%;transform:translate(-50%,-50%)}.qaid-type-up .qaid-scope-dot{background:var(--qaid-positive)}.qaid-selected-marker{position:fixed;border:3px solid var(--qaid-marker, #6366f1);border-radius:50%;pointer-events:none;z-index:44;animation:qaid-markerPulse 1.5s ease-in-out infinite}@keyframes qaid-markerPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.05)}}.qaid-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:45;background:#0000004d}.qaid-modal-container{position:fixed;z-index:50;display:flex;flex-direction:column;align-items:flex-start;max-height:calc(100vh - 32px);font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-modal-container.qaid-above{flex-direction:column-reverse}.qaid-modal-arrow{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;position:relative;align-self:flex-start}.qaid-modal-container.qaid-below .qaid-modal-arrow{border-bottom:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-container.qaid-above .qaid-modal-arrow{border-top:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px light-dark(rgba(0,0,0,.25),rgba(0,0,0,.5));width:var(--qaid-modal-width, 400px);max-width:calc(100vw - 32px);max-height:calc(100vh - 60px);overflow-y:auto}.qaid-modal-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:1rem}button.qaid-type-toggle{border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;flex-shrink:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-type-toggle:hover{transform:scale(1.1)}button.qaid-type-toggle:not(.qaid-type-toggle-custom){width:2.5rem;height:2.5rem;border-radius:50%}button.qaid-type-toggle:not(.qaid-type-toggle-custom) svg{width:1.25rem;height:1.25rem}button.qaid-type-toggle.qaid-type-up{background:var(--qaid-positive);color:#fff}button.qaid-type-toggle.qaid-type-down{background:var(--qaid-negative);color:#fff}.qaid-modal-header-text{flex:1;min-width:0}.qaid-modal-title{font-size:1.125rem;font-weight:700;margin:0 0 .25rem;color:light-dark(#1f2937,#f9fafb)}.qaid-modal-subtitle{color:light-dark(#6b7280,#9ca3af);margin:0;font-size:.875rem}.qaid-textarea{width:100%;height:6rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:1rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-btn-row{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-btn-submit{padding:.5rem 1rem;background:var(--qaid-marker);color:var(--qaid-marker-text, white);border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-btn-submit:hover{filter:brightness(.85)}button.qaid-btn-submit:focus{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 30%,transparent)}.qaid-bottom-sheet{position:fixed;bottom:0;left:0;right:0;z-index:50;animation:qaid-slideUpSheet .3s ease-out;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-bottom-sheet-content{background:light-dark(#ffffff,#1f2937);border-radius:1rem 1rem 0 0;padding:1.5rem;padding-bottom:max(1.5rem,env(safe-area-inset-bottom))}.qaid-bottom-sheet-handle{width:36px;height:4px;background:light-dark(rgba(0,0,0,.2),rgba(255,255,255,.2));border-radius:2px;margin:0 auto 1rem}@keyframes qaid-slideUpSheet{0%{transform:translateY(100%)}to{transform:translateY(0)}}button.qaid-btn-record:hover{background:#dc2626;color:#fff}.qaid-recording-indicator{position:fixed;top:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background:light-dark(#1f2937,#374151);color:#fff;border-radius:9999px;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:.875rem;font-weight:500;box-shadow:0 4px 12px #0000004d;z-index:99999;animation:qaid-slideDown .2s ease-out}.qaid-recording-dot{width:10px;height:10px;background:#dc2626;border-radius:50%;animation:qaid-dotPulse 1.5s ease-in-out infinite}@keyframes qaid-dotPulse{0%,to{opacity:1}50%{opacity:.3}}.qaid-recording-time{font-variant-numeric:tabular-nums;min-width:2.5rem;text-align:center}button.qaid-recording-stop{padding:.25rem .75rem;background:#dc2626;color:#fff;border:none;border-radius:9999px;font-size:.75rem;font-weight:600;cursor:pointer;transition:background-color .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-recording-stop:hover{background:#b91c1c}.qaid-video-preview{position:fixed;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#0009;z-index:99998;animation:qaid-fadeIn .2s ease-out}@keyframes qaid-fadeIn{0%{opacity:0}to{opacity:1}}.qaid-video-preview-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px #00000080;width:560px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow-y:auto;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-video-preview-box h3{font-size:1.125rem;font-weight:700;margin:0 0 1rem;color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box video{width:100%;border-radius:.5rem;background:#000;margin-bottom:1rem}.qaid-video-preview-box textarea{width:100%;height:4rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:.875rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-video-preview-actions{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-video-btn{padding:.5rem 1rem;border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none}button.qaid-video-btn-cancel{background:light-dark(#f3f4f6,#374151);color:light-dark(#374151,#d1d5db)}button.qaid-video-btn-cancel:hover{background:light-dark(#e5e7eb,#4b5563)}button.qaid-video-btn-rerecord{background:light-dark(#fef3c7,#78350f);color:light-dark(#92400e,#fde68a)}button.qaid-video-btn-rerecord:hover{filter:brightness(.9)}button.qaid-video-btn-send{background:var(--qaid-marker);color:var(--qaid-marker-text, white)}button.qaid-video-btn-send:hover{filter:brightness(.85)}button.qaid-video-btn-send:disabled{opacity:.5;cursor:not-allowed}.qaid-video-sending{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:light-dark(#6b7280,#9ca3af)}", nt = "body.qaid-targeting,body.qaid-targeting *{cursor:none!important}.qaid-highlight{outline:3px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent)!important;outline-offset:2px!important;box-shadow:inset 0 0 0 9999px color-mix(in srgb,var(--qaid-negative) 8%,transparent)!important;transition:outline .1s ease!important}body.qaid-targeting.qaid-type-up .qaid-highlight{outline-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)!important;box-shadow:inset 0 0 0 9999px color-mix(in srgb,var(--qaid-positive) 8%,transparent)!important}";
11
+ let q = 0;
12
+ const at = "button.qaid-btn{width:var(--qaid-btn-size);height:var(--qaid-btn-size);border-radius:50%;border:none;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:background-color .2s,color .2s,transform .2s;-webkit-appearance:none;appearance:none;--qaid-hover-up-bg:var(--qaid-positive);--qaid-hover-up-color:#fff;--qaid-hover-down-bg:var(--qaid-negative);--qaid-hover-down-color:#fff}button.qaid-btn:hover{transform:scale(1.05)}button.qaid-btn-up:hover{background:var(--qaid-hover-up-bg);color:var(--qaid-hover-up-color)}button.qaid-btn-down:hover{background:var(--qaid-hover-down-bg);color:var(--qaid-hover-down-color)}button.qaid-btn svg{width:var(--qaid-icon-size);height:var(--qaid-icon-size)}", st = {
11
13
  small: 36,
12
14
  medium: 48,
13
15
  large: 64
14
- }, R = {
16
+ }, rt = {
15
17
  small: 18,
16
18
  medium: 24,
17
19
  large: 32
18
20
  };
19
- function _(i, t, e) {
20
- const [o, n, a] = [i, t, e].map((s) => (s = s / 255, s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4)));
21
- return 0.2126 * o + 0.7152 * n + 0.0722 * a;
21
+ function dt(e, t, o) {
22
+ const [i, n, a] = [e, t, o].map((s) => (s = s / 255, s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4)));
23
+ return 0.2126 * i + 0.7152 * n + 0.0722 * a;
22
24
  }
23
- function V(i) {
24
- if (i.startsWith("#")) {
25
- const e = i.slice(1), o = e.length === 3 ? e.split("").map((a) => a + a).join("") : e, n = parseInt(o, 16);
25
+ function ct(e) {
26
+ if (e.startsWith("#")) {
27
+ const o = e.slice(1), i = o.length === 3 ? o.split("").map((a) => a + a).join("") : o, n = parseInt(i, 16);
26
28
  return {
27
29
  r: n >> 16 & 255,
28
30
  g: n >> 8 & 255,
29
31
  b: n & 255
30
32
  };
31
33
  }
32
- const t = i.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
34
+ const t = e.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
33
35
  return t ? {
34
36
  r: parseInt(t[1]),
35
37
  g: parseInt(t[2]),
36
38
  b: parseInt(t[3])
37
39
  } : null;
38
40
  }
39
- function J(i) {
40
- const t = V(i);
41
- return t && _(t.r, t.g, t.b) > 0.4 ? "black" : "white";
41
+ function lt(e) {
42
+ const t = ct(e);
43
+ return t && dt(t.r, t.g, t.b) > 0.4 ? "black" : "white";
42
44
  }
43
- function G(i = {}) {
44
- if (T) return;
45
- T = !0;
45
+ function ht(e = {}) {
46
46
  const {
47
47
  positiveColor: t = "rgb(0, 200, 83)",
48
- negativeColor: e = "rgb(255, 0, 0)",
49
- markerColor: o = "#6366f1",
50
- // skipButtonStyles kept for backwards compatibility but no longer used
48
+ negativeColor: o = "rgb(255, 0, 0)",
49
+ markerColor: i = "#6366f1",
51
50
  buttonSize: n = "medium",
52
51
  modalWidth: a = 400,
53
52
  backdropOpacity: s = 0.3,
54
53
  fontFamily: l = "system-ui, -apple-system, sans-serif",
55
- fontSize: r = 16
56
- } = i, c = K[n], p = R[n], g = J(o), h = `:root{--qaid-positive:${t};--qaid-negative:${e};--qaid-marker:${o};--qaid-marker-text:${g};--qaid-btn-size:${c}px;--qaid-icon-size:${p}px;--qaid-modal-width:${a}px;--qaid-backdrop-opacity:${s};--qaid-font-family:${l};--qaid-font-size:${r}px}`, u = "button.qaid-btn{width:var(--qaid-btn-size);height:var(--qaid-btn-size);border-radius:50%;border:none;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:background-color .2s,color .2s,transform .2s;-webkit-appearance:none;appearance:none}button.qaid-btn:hover{transform:scale(1.05)}button.qaid-btn-up:hover{background:var(--qaid-positive);color:#fff}button.qaid-btn-down:hover{background:var(--qaid-negative);color:#fff}button.qaid-btn svg{width:var(--qaid-icon-size);height:var(--qaid-icon-size)}", m = document.createElement("style");
57
- m.id = "qaid-styles", m.textContent = h + Y + u, document.head.appendChild(m);
58
- }
59
- function Z() {
60
- const i = document.getElementById("qaid-styles");
61
- i && (i.remove(), T = !1);
62
- }
63
- const Q = ["data-comp", "data-qa", "data-testid", "data-id"];
64
- function F(i, t = document.body) {
65
- let e = i;
66
- for (; e && e !== t; ) {
67
- for (const o of Q) {
68
- const n = e.getAttribute(o);
54
+ fontSize: d = 16
55
+ } = e, r = st[n], c = rt[n], u = lt(i);
56
+ return {
57
+ "--qaid-positive": t,
58
+ "--qaid-negative": o,
59
+ "--qaid-marker": i,
60
+ "--qaid-marker-text": u,
61
+ "--qaid-btn-size": `${r}px`,
62
+ "--qaid-icon-size": `${c}px`,
63
+ "--qaid-modal-width": `${a}px`,
64
+ "--qaid-backdrop-opacity": String(s),
65
+ "--qaid-font-family": l,
66
+ "--qaid-font-size": `${d}px`
67
+ };
68
+ }
69
+ function ut(e, t) {
70
+ for (const [o, i] of Object.entries(t))
71
+ e.style.setProperty(o, i);
72
+ }
73
+ function A() {
74
+ return ot + at;
75
+ }
76
+ function pt() {
77
+ if (q++, q > 1) return;
78
+ const e = document.createElement("style");
79
+ e.id = "qaid-styles", e.textContent = nt, document.head.appendChild(e);
80
+ }
81
+ function mt() {
82
+ if (!(q <= 0) && (q--, q === 0)) {
83
+ const e = document.getElementById("qaid-styles");
84
+ e && e.remove();
85
+ }
86
+ }
87
+ const ft = ["data-comp", "data-qa", "data-testid", "data-id"];
88
+ function F(e, t = document.body) {
89
+ let o = e;
90
+ for (; o && o !== t; ) {
91
+ for (const i of ft) {
92
+ const n = o.getAttribute(i);
69
93
  if (n)
70
- return `${o}="${n}"`;
94
+ return `${i}="${n}"`;
71
95
  }
72
- e = e.parentElement;
96
+ o = o.parentElement;
73
97
  }
74
98
  return null;
75
99
  }
76
- function tt(i, t = 100) {
77
- var o;
78
- const e = ((o = i.textContent) == null ? void 0 : o.trim().slice(0, t)) || "";
79
- return e.length === t ? e + "..." : e;
100
+ function gt(e, t = 100) {
101
+ var i;
102
+ const o = ((i = e.textContent) == null ? void 0 : i.trim().slice(0, t)) || "";
103
+ return o.length === t ? o + "..." : o;
80
104
  }
81
- function et(i) {
82
- let t = 1, e = i.previousElementSibling;
83
- for (; e; )
84
- t++, e = e.previousElementSibling;
105
+ function bt(e) {
106
+ let t = 1, o = e.previousElementSibling;
107
+ for (; o; )
108
+ t++, o = o.previousElementSibling;
85
109
  return t;
86
110
  }
87
- function it(i) {
111
+ function vt(e) {
88
112
  const t = [];
89
- let e = i;
90
- for (; e && e !== document.body && e !== document.documentElement; ) {
91
- const o = e.tagName.toLowerCase(), n = et(e);
92
- t.unshift(`${o}:nth-child(${n})`), e = e.parentElement;
113
+ let o = e;
114
+ for (; o && o !== document.body && o !== document.documentElement; ) {
115
+ const i = o.tagName.toLowerCase(), n = bt(o);
116
+ t.unshift(`${i}:nth-child(${n})`), o = o.parentElement;
93
117
  }
94
118
  return t.length > 0 ? `body > ${t.join(" > ")}` : "body";
95
119
  }
96
- function ot(i) {
97
- return i.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
120
+ function yt(e) {
121
+ return e.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
98
122
  }
99
- function nt(i) {
100
- const t = F(i);
101
- return t ? `[${t}]` : i.id ? `#${ot(i.id)}` : it(i);
123
+ function wt(e) {
124
+ const t = F(e);
125
+ return t ? `[${t}]` : e.id ? `#${yt(e.id)}` : vt(e);
102
126
  }
103
- function at(i) {
104
- const t = tt(i), e = F(i);
105
- return { selector: nt(i), text: t, dataAttr: e };
127
+ function qt(e) {
128
+ const t = gt(e), o = F(e);
129
+ return { selector: wt(e), text: t, dataAttr: o };
106
130
  }
107
- const O = {
131
+ const W = {
108
132
  width: 400,
109
133
  height: 280,
110
134
  arrowHeight: 12,
111
135
  gap: 8,
112
136
  viewportPadding: 16
113
137
  };
114
- function st(i, t, e, o, n) {
115
- const a = i.y, s = t - (i.y + i.height);
116
- if (s >= e + o)
138
+ function xt(e, t, o, i, n) {
139
+ const a = e.y, s = t - (e.y + e.height);
140
+ if (s >= o + i)
117
141
  return {
118
- top: i.y + i.height + o,
142
+ top: e.y + e.height + i,
119
143
  position: "below"
120
144
  };
121
- if (a >= e + o)
145
+ if (a >= o + i)
122
146
  return {
123
- top: i.y - e - o,
147
+ top: e.y - o - i,
124
148
  position: "above"
125
149
  };
126
150
  const l = s > a ? "below" : "above";
127
- let r;
128
- return l === "below" ? r = Math.min(
129
- i.y + i.height + o,
130
- t - e - n
131
- ) : r = Math.max(n, i.y - e - o), { top: r, position: l };
132
- }
133
- function rt(i, t, e, o) {
134
- let a = i.x + i.width / 2 - e / 2;
135
- return a = Math.max(o, Math.min(a, t - e - o)), a;
136
- }
137
- function dt(i, t, e, o = 24, n = 24) {
138
- const s = i.clickX - t - n / 2;
139
- return Math.max(o, Math.min(s, e - o - n / 2));
140
- }
141
- function lt(i, t, e, o = O) {
142
- const n = o.height + o.arrowHeight, a = st(
143
- i,
151
+ let d;
152
+ return l === "below" ? d = Math.min(
153
+ e.y + e.height + i,
154
+ t - o - n
155
+ ) : d = Math.max(n, e.y - o - i), { top: d, position: l };
156
+ }
157
+ function kt(e, t, o, i) {
158
+ let a = e.x + e.width / 2 - o / 2;
159
+ return a = Math.max(i, Math.min(a, t - o - i)), a;
160
+ }
161
+ function Ct(e, t, o, i = 24, n = 24) {
162
+ const s = e.clickX - t - n / 2;
163
+ return Math.max(i, Math.min(s, o - i - n / 2));
164
+ }
165
+ function St(e, t, o, i = W) {
166
+ const n = i.height + i.arrowHeight, a = xt(
144
167
  e,
168
+ o,
145
169
  n,
146
- o.gap,
147
- o.viewportPadding
148
- ), s = rt(
149
- i,
170
+ i.gap,
171
+ i.viewportPadding
172
+ ), s = kt(
173
+ e,
150
174
  t,
151
- o.width,
152
- o.viewportPadding
175
+ i.width,
176
+ i.viewportPadding
153
177
  );
154
178
  return {
155
179
  top: a.top,
@@ -157,69 +181,205 @@ function lt(i, t, e, o = O) {
157
181
  position: a.position
158
182
  };
159
183
  }
160
- function ct(i, t, e, o = O) {
161
- const n = lt(i, t, e, o), a = dt(
162
- i,
184
+ function Et(e, t, o, i = W) {
185
+ const n = St(e, t, o, i), a = Ct(
186
+ e,
163
187
  n.left,
164
- o.width
188
+ i.width
165
189
  );
166
190
  return {
167
191
  modal: n,
168
192
  arrow: { left: a }
169
193
  };
170
194
  }
171
- const ht = 20;
172
- function pt(i) {
173
- const t = [], e = console.error, o = console.warn, n = console.log, a = (s, l) => {
174
- const r = {
175
- message: l.map((c) => String(c)).join(" "),
195
+ const Tt = 20;
196
+ function It(e) {
197
+ const t = [], o = console.error, i = console.warn, n = console.log, a = (s, l) => {
198
+ const d = {
199
+ message: l.map((r) => String(r)).join(" "),
176
200
  timestamp: Date.now(),
177
201
  level: s
178
202
  };
179
- t.length >= ht && t.shift(), t.push(r), i && i(r);
203
+ t.length >= Tt && t.shift(), t.push(d), e && e(d);
180
204
  };
181
205
  return console.error = function(...s) {
182
- a("error", s), e.apply(console, s);
206
+ a("error", s), o.apply(console, s);
183
207
  }, console.warn = function(...s) {
184
- a("warn", s), o.apply(console, s);
208
+ a("warn", s), i.apply(console, s);
185
209
  }, console.log = function(...s) {
186
210
  a("log", s), n.apply(console, s);
187
211
  }, {
188
212
  errors: t,
189
213
  restore: () => {
190
- console.error = e, console.warn = o, console.log = n;
214
+ console.error = o, console.warn = i, console.log = n;
215
+ }
216
+ };
217
+ }
218
+ const Lt = 20, O = 4096;
219
+ function k(e) {
220
+ if (e == null) return;
221
+ const t = typeof e == "string" ? e : JSON.stringify(e);
222
+ return t.length > O ? t.slice(0, O) + "…[truncated]" : t;
223
+ }
224
+ function P(e, t) {
225
+ e.length >= Lt && e.shift(), e.push(t);
226
+ }
227
+ async function Ht(e) {
228
+ try {
229
+ const t = await e.clone().text();
230
+ return k(t);
231
+ } catch {
232
+ return;
233
+ }
234
+ }
235
+ function Rt() {
236
+ const e = [], t = window.fetch;
237
+ window.fetch = async function(n, a) {
238
+ const s = typeof n == "string" ? n : n instanceof URL ? n.toString() : n.url, l = (a == null ? void 0 : a.method) ?? (typeof n == "object" && "method" in n ? n.method : "GET");
239
+ let d;
240
+ a != null && a.body && (d = k(a.body));
241
+ const r = await t.apply(window, [n, a]);
242
+ if (r.status >= 400) {
243
+ const c = await Ht(r);
244
+ P(e, {
245
+ url: s,
246
+ method: l.toUpperCase(),
247
+ status: r.status,
248
+ statusText: r.statusText,
249
+ requestBody: d,
250
+ responseBody: c,
251
+ timestamp: Date.now()
252
+ });
253
+ }
254
+ return r;
255
+ };
256
+ const o = XMLHttpRequest.prototype.open, i = XMLHttpRequest.prototype.send;
257
+ return XMLHttpRequest.prototype.open = function(n, a, ...s) {
258
+ return this._qaid_method = n, this._qaid_url = typeof a == "string" ? a : a.toString(), o.apply(this, [n, a, ...s]);
259
+ }, XMLHttpRequest.prototype.send = function(n) {
260
+ const a = this, s = n ? k(n) : void 0;
261
+ return a.addEventListener("load", function() {
262
+ a.status >= 400 && P(e, {
263
+ url: a._qaid_url,
264
+ method: a._qaid_method.toUpperCase(),
265
+ status: a.status,
266
+ statusText: a.statusText,
267
+ requestBody: s,
268
+ responseBody: k(a.responseText),
269
+ timestamp: Date.now()
270
+ });
271
+ }), i.apply(this, [n]);
272
+ }, {
273
+ errors: e,
274
+ restore: () => {
275
+ window.fetch = t, XMLHttpRequest.prototype.open = o, XMLHttpRequest.prototype.send = i;
191
276
  }
192
277
  };
193
278
  }
194
- function ut(i = 640) {
195
- return typeof window < "u" && window.innerWidth < i;
279
+ function Dt() {
280
+ return typeof navigator < "u" && !!navigator.mediaDevices && typeof navigator.mediaDevices.getDisplayMedia == "function" && typeof MediaRecorder < "u";
196
281
  }
197
- function D(i, t, e) {
198
- const o = e.style.pointerEvents;
199
- e.style.pointerEvents = "none";
200
- const n = document.elementFromPoint(i, t);
201
- return e.style.pointerEvents = o, n;
282
+ function Mt() {
283
+ if (typeof MediaRecorder > "u") return "";
284
+ const e = [
285
+ "video/webm;codecs=vp9",
286
+ "video/webm;codecs=vp8",
287
+ "video/webm",
288
+ "video/mp4"
289
+ ];
290
+ for (const t of e)
291
+ if (MediaRecorder.isTypeSupported(t))
292
+ return t;
293
+ return "";
202
294
  }
203
- function B(i) {
204
- return i ? !!(i.closest(".qaid-widget") || i.closest(".qaid-targeting-overlay") || i.closest(".qaid-modal-container") || i.closest(".qaid-bottom-sheet")) : !1;
295
+ function zt(e = {}) {
296
+ const t = e.maxDuration ?? 15, o = e.videoBitsPerSecond ?? 8e5;
297
+ let i = null, n = null, a = [], s = null, l = null, d = null, r = 0, c = null, u = null, p = !1, f = null;
298
+ function b() {
299
+ d !== null && (clearInterval(d), d = null), f !== null && (clearTimeout(f), f = null), i && (i.getTracks().forEach((m) => m.stop()), i = null), n = null, a = [], s = null, l = null, c = null, u = null;
300
+ }
301
+ function g() {
302
+ p || (p = !0, n && n.state !== "inactive" && n.stop());
303
+ }
304
+ return {
305
+ async start() {
306
+ p = !1, a = [];
307
+ const m = Mt();
308
+ if (!m)
309
+ throw new Error("No supported video MIME type found");
310
+ i = await navigator.mediaDevices.getDisplayMedia({
311
+ video: {
312
+ frameRate: 15
313
+ },
314
+ audio: !1,
315
+ // @ts-expect-error preferCurrentTab is not in the TS types yet
316
+ preferCurrentTab: !0
317
+ });
318
+ const v = i.getVideoTracks()[0];
319
+ v && v.addEventListener("ended", () => {
320
+ g();
321
+ }), n = new MediaRecorder(i, {
322
+ mimeType: m,
323
+ videoBitsPerSecond: o
324
+ }), n.ondataavailable = (y) => {
325
+ y.data.size > 0 && a.push(y.data);
326
+ }, n.onstop = () => {
327
+ const y = new Blob(a, { type: m });
328
+ c && c(y), l && l(y), i && i.getTracks().forEach((x) => x.stop());
329
+ }, n.onerror = () => {
330
+ u && u(new Error("MediaRecorder error"));
331
+ }, n.start(1e3), r = Date.now(), d = setInterval(() => {
332
+ const y = Math.floor((Date.now() - r) / 1e3);
333
+ s && s(y);
334
+ }, 1e3), f = setTimeout(() => {
335
+ g();
336
+ }, t * 1e3);
337
+ },
338
+ stop() {
339
+ return new Promise((m, v) => {
340
+ c = m, u = v, g();
341
+ });
342
+ },
343
+ onTick(m) {
344
+ s = m;
345
+ },
346
+ onStop(m) {
347
+ l = m;
348
+ },
349
+ destroy() {
350
+ g(), b();
351
+ }
352
+ };
353
+ }
354
+ function Bt(e = 640) {
355
+ return typeof window < "u" && window.innerWidth < e;
205
356
  }
206
- function mt(i, t = 0) {
207
- const e = i.getBoundingClientRect();
357
+ function $(e, t, o) {
358
+ const i = o.map((a) => a.style.visibility);
359
+ o.forEach((a) => a.style.visibility = "hidden");
360
+ const n = document.elementFromPoint(e, t);
361
+ return o.forEach((a, s) => a.style.visibility = i[s]), n;
362
+ }
363
+ function N(e) {
364
+ return e ? e.hasAttribute("data-qaid-embed") || e.hasAttribute("data-qaid-embed-overlay") ? !0 : !!e.closest("[data-qaid-embed], [data-qaid-embed-overlay]") : !1;
365
+ }
366
+ function At(e, t = 0) {
367
+ const o = e.getBoundingClientRect();
208
368
  return {
209
- x: e.left - t,
210
- y: e.top - t,
211
- width: e.width + t * 2,
212
- height: e.height + t * 2
369
+ x: o.left - t,
370
+ y: o.top - t,
371
+ width: o.width + t * 2,
372
+ height: o.height + t * 2
213
373
  };
214
374
  }
215
- function C(i) {
216
- document.querySelectorAll(`.${i}`).forEach((t) => {
217
- t.classList.remove(i);
375
+ function L(e) {
376
+ document.querySelectorAll(`.${e}`).forEach((t) => {
377
+ t.classList.remove(e);
218
378
  });
219
379
  }
220
- async function gt(i = {}) {
380
+ async function Ot(e = {}) {
221
381
  var n;
222
- const { quality: t = 1, maxWidth: e = 1280, maxHeight: o = 800 } = i;
382
+ const { quality: t = 1, maxWidth: o = 1280, maxHeight: i = 800 } = e;
223
383
  try {
224
384
  if (!((n = navigator.mediaDevices) != null && n.getDisplayMedia))
225
385
  return console.warn("Screen Capture API not available"), null;
@@ -228,45 +388,106 @@ async function gt(i = {}) {
228
388
  video: {
229
389
  displaySurface: "browser"
230
390
  }
231
- }), s = a.getVideoTracks()[0], l = s.getSettings(), r = document.createElement("video");
232
- r.srcObject = a, r.muted = !0, await new Promise((f) => {
233
- r.onloadedmetadata = () => {
234
- r.play(), f();
391
+ }), s = a.getVideoTracks()[0], l = s.getSettings(), d = document.createElement("video");
392
+ d.srcObject = a, d.muted = !0, await new Promise((m) => {
393
+ d.onloadedmetadata = () => {
394
+ d.play(), m();
235
395
  };
236
- }), await new Promise((f) => {
396
+ }), await new Promise((m) => {
237
397
  const v = () => {
238
- r.readyState >= 2 ? f() : requestAnimationFrame(v);
398
+ d.readyState >= 2 ? m() : requestAnimationFrame(v);
239
399
  };
240
400
  v();
241
- }), await new Promise((f) => setTimeout(f, 100));
242
- const c = l.width || r.videoWidth, p = l.height || r.videoHeight, g = Math.min(e / c, o / p, 1), h = Math.round(c * g), u = Math.round(p * g), m = document.createElement("canvas");
243
- m.width = h, m.height = u;
244
- const b = m.getContext("2d");
245
- return b ? (b.drawImage(r, 0, 0, h, u), s.stop(), m.toDataURL("image/webp", t)) : (s.stop(), null);
401
+ }), await new Promise((m) => setTimeout(m, 100));
402
+ const r = l.width || d.videoWidth, c = l.height || d.videoHeight, u = Math.min(o / r, i / c, 1), p = Math.round(r * u), f = Math.round(c * u), b = document.createElement("canvas");
403
+ b.width = p, b.height = f;
404
+ const g = b.getContext("2d");
405
+ return g ? (g.drawImage(d, 0, 0, p, f), s.stop(), b.toDataURL("image/webp", t)) : (s.stop(), null);
246
406
  } catch (a) {
247
407
  return console.warn("Screenshot capture failed:", a), null;
248
408
  }
249
409
  }
250
- const H = "qaid_visitor_id";
251
- function ft() {
410
+ const V = "https://qaid.dev/lib/html2canvas.min.js", Pt = 1e4, $t = 50;
411
+ let w = null;
412
+ function jt() {
413
+ if (typeof document > "u" || typeof window > "u")
414
+ return !1;
415
+ const e = document.createElement("canvas");
416
+ return typeof e.getContext == "function" && !!e.getContext("2d");
417
+ }
418
+ function Nt() {
419
+ return window.html2canvas ? Promise.resolve(!0) : w || (w = new Promise((e) => {
420
+ if (!document.querySelector(
421
+ `script[src="${V}"]`
422
+ )) {
423
+ const n = document.createElement("script");
424
+ n.src = V, n.async = !0, document.head.appendChild(n);
425
+ }
426
+ const o = Date.now(), i = () => {
427
+ if (window.html2canvas) {
428
+ e(!0);
429
+ return;
430
+ }
431
+ if (Date.now() - o > Pt) {
432
+ w = null, e(!1);
433
+ return;
434
+ }
435
+ setTimeout(i, $t);
436
+ };
437
+ i();
438
+ }), w);
439
+ }
440
+ async function Vt(e = {}) {
441
+ const { quality: t = 0.8, maxWidth: o = 1280, maxHeight: i = 800 } = e;
252
442
  try {
253
- let i = localStorage.getItem(H);
254
- return i || (i = crypto.randomUUID(), localStorage.setItem(H, i)), i;
443
+ if (!await Nt() || !window.html2canvas)
444
+ return console.warn("html2canvas failed to load"), null;
445
+ const a = await window.html2canvas(document.body, {
446
+ useCORS: !0,
447
+ allowTaint: !1,
448
+ logging: !1,
449
+ windowWidth: document.documentElement.clientWidth,
450
+ windowHeight: document.documentElement.clientHeight,
451
+ width: document.documentElement.clientWidth,
452
+ height: document.documentElement.clientHeight,
453
+ x: window.scrollX,
454
+ y: window.scrollY,
455
+ ignoreElements: (r) => {
456
+ var c, u, p;
457
+ return r instanceof HTMLElement ? r.classList.contains("qaid-buttons") || r.classList.contains("qaid-targeting-overlay") || r.classList.contains("qaid-modal-container") || r.classList.contains("qaid-bottom-sheet") || r.classList.contains("qaid-backdrop") || r.classList.contains("qaid-selected-marker") || r.classList.contains("qaid-tooltip-text") || r.classList.contains("qaid-recording-indicator") || r.classList.contains("qaid-video-preview") || ((p = (c = r.className) == null ? void 0 : (u = c.toString()).startsWith) == null ? void 0 : p.call(u, "qaid-")) : !1;
458
+ }
459
+ }), s = a.width, l = a.height, d = Math.min(o / s, i / l, 1);
460
+ if (d < 1) {
461
+ const r = Math.round(s * d), c = Math.round(l * d), u = document.createElement("canvas");
462
+ u.width = r, u.height = c;
463
+ const p = u.getContext("2d");
464
+ return p ? (p.drawImage(a, 0, 0, r, c), u.toDataURL("image/webp", t)) : null;
465
+ }
466
+ return a.toDataURL("image/webp", t);
467
+ } catch (n) {
468
+ return console.warn("DOM screenshot capture failed:", n), null;
469
+ }
470
+ }
471
+ const U = "qaid_visitor_id";
472
+ function Ut() {
473
+ try {
474
+ let e = localStorage.getItem(U);
475
+ return e || (e = crypto.randomUUID(), localStorage.setItem(U, e)), e;
255
476
  } catch {
256
477
  return crypto.randomUUID();
257
478
  }
258
479
  }
259
- class bt {
480
+ class Ft {
260
481
  constructor(t) {
261
- d(this, "config");
262
- d(this, "state", "IDLE");
263
- d(this, "feedbackData", {
482
+ h(this, "config");
483
+ h(this, "state", "IDLE");
484
+ h(this, "feedbackData", {
264
485
  feedbackType: null,
265
486
  elementSelector: null,
266
487
  elementText: null,
267
488
  consoleErrors: []
268
489
  });
269
- d(this, "selectedBounds", {
490
+ h(this, "selectedBounds", {
270
491
  x: 0,
271
492
  y: 0,
272
493
  width: 0,
@@ -275,42 +496,57 @@ class bt {
275
496
  clickY: 0,
276
497
  visible: !1
277
498
  });
278
- d(this, "feedbackId", null);
279
- d(this, "mousePos", { x: 0, y: 0 });
280
- d(this, "lastHighlighted", null);
281
- d(this, "isMobile", !1);
282
- d(this, "visitorId");
499
+ h(this, "feedbackId", null);
500
+ h(this, "mousePos", { x: 0, y: 0 });
501
+ h(this, "lastHighlighted", null);
502
+ h(this, "isMobile", !1);
503
+ h(this, "visitorId");
283
504
  // Console capture
284
- d(this, "consoleCapture", null);
285
- // Server-side feature flags
286
- d(this, "allowedFeatures", null);
287
- // DOM elements
288
- d(this, "container", null);
289
- d(this, "isUserProvidedContainer", !1);
290
- d(this, "overlayContainer", null);
291
- d(this, "captureLayer", null);
292
- d(this, "crosshairH", null);
293
- d(this, "crosshairV", null);
294
- d(this, "scope", null);
295
- d(this, "marker", null);
296
- d(this, "modalContainer", null);
297
- d(this, "backdrop", null);
505
+ h(this, "consoleCapture", null);
506
+ // Video recording
507
+ h(this, "videoRecorder", null);
508
+ h(this, "networkCapture", null);
509
+ h(this, "recordedBlob", null);
510
+ h(this, "recordingIndicator", null);
511
+ h(this, "videoPreview", null);
512
+ h(this, "isRecording", !1);
513
+ h(this, "isSendingVideo", !1);
514
+ // Shadow DOM
515
+ h(this, "shadowHost", null);
516
+ h(this, "shadowRoot", null);
517
+ // Overlay shadow DOM (always on document.body for full-page coverage)
518
+ h(this, "overlayShadowHost", null);
519
+ h(this, "overlayShadowRoot", null);
520
+ // DOM elements (inside shadow root)
521
+ h(this, "buttonsContainer", null);
522
+ h(this, "isUserProvidedContainer", !1);
523
+ h(this, "overlayContainer", null);
524
+ h(this, "captureLayer", null);
525
+ h(this, "crosshairH", null);
526
+ h(this, "crosshairV", null);
527
+ h(this, "scope", null);
528
+ h(this, "marker", null);
529
+ h(this, "modalContainer", null);
530
+ h(this, "backdrop", null);
531
+ // Per-instance CSS variables
532
+ h(this, "cssVars", {});
298
533
  // Bound event handlers
299
- d(this, "boundKeyDown");
300
- d(this, "boundMouseMove");
301
- d(this, "boundClick");
302
- d(this, "boundResize");
303
- d(this, "tooltipElement", null);
304
- var e, o, n, a, s, l, r, c, p, g, h, u, m, b, f, v;
534
+ h(this, "boundKeyDown");
535
+ h(this, "boundMouseMove");
536
+ h(this, "boundClick");
537
+ h(this, "boundResize");
538
+ h(this, "tooltipElement", null);
539
+ var o, i, n, a, s, l, d, r, c, u, p, f, b, g, m;
305
540
  this.config = {
306
541
  endpoint: t.endpoint,
307
542
  apiKey: t.apiKey ?? "",
308
543
  container: t.container ?? "",
309
544
  buttonClass: t.buttonClass ?? "",
545
+ direction: t.direction ?? "horizontal",
310
546
  position: t.position ?? "bottom-right",
311
547
  offset: {
312
- x: ((e = t.offset) == null ? void 0 : e.x) ?? 16,
313
- y: ((o = t.offset) == null ? void 0 : o.y) ?? 16
548
+ x: ((o = t.offset) == null ? void 0 : o.x) ?? 16,
549
+ y: ((i = t.offset) == null ? void 0 : i.y) ?? 16
314
550
  },
315
551
  zIndex: t.zIndex ?? 50,
316
552
  skipTargeting: t.skipTargeting ?? !1,
@@ -322,184 +558,208 @@ class bt {
322
558
  buttonSize: t.buttonSize ?? "medium",
323
559
  text: {
324
560
  tooltip: ((l = t.text) == null ? void 0 : l.tooltip) ?? "",
325
- bannerText: ((r = t.text) == null ? void 0 : r.bannerText) ?? "Click on any element to target it with your feedback",
326
- bannerHint: ((c = t.text) == null ? void 0 : c.bannerHint) ?? "(Press Escape to cancel)",
327
- modalTitle: ((p = t.text) == null ? void 0 : p.modalTitle) ?? "Thank you for your feedback!",
328
- modalSubtitle: ((g = t.text) == null ? void 0 : g.modalSubtitle) ?? "Would you like to add a message to help us understand your feedback better?",
329
- placeholder: ((h = t.text) == null ? void 0 : h.placeholder) ?? "Optional: Tell us more about your experience...",
561
+ modalTitle: ((d = t.text) == null ? void 0 : d.modalTitle) ?? "Thank you for your feedback!",
562
+ modalSubtitle: ((r = t.text) == null ? void 0 : r.modalSubtitle) ?? "Would you like to add a message to help us understand your feedback better?",
563
+ placeholder: ((c = t.text) == null ? void 0 : c.placeholder) ?? "Optional: Tell us more about your experience...",
330
564
  submitButton: ((u = t.text) == null ? void 0 : u.submitButton) ?? "Submit",
331
- skipButton: ((m = t.text) == null ? void 0 : m.skipButton) ?? "Skip"
565
+ skipButton: ((p = t.text) == null ? void 0 : p.skipButton) ?? "Skip"
332
566
  },
333
567
  modalWidth: t.modalWidth ?? 400,
334
568
  backdropOpacity: t.backdropOpacity ?? 0.3,
335
569
  fontFamily: t.fontFamily ?? "system-ui, -apple-system, sans-serif",
336
570
  fontSize: t.fontSize ?? 16,
337
571
  captureScreenshot: t.captureScreenshot ?? !1,
572
+ screenshotMethod: t.screenshotMethod ?? "permission",
338
573
  screenshotOptions: {
339
- quality: ((b = t.screenshotOptions) == null ? void 0 : b.quality) ?? 0.8,
340
- maxWidth: ((f = t.screenshotOptions) == null ? void 0 : f.maxWidth) ?? 1280,
341
- maxHeight: ((v = t.screenshotOptions) == null ? void 0 : v.maxHeight) ?? 800
574
+ quality: ((f = t.screenshotOptions) == null ? void 0 : f.quality) ?? 0.8,
575
+ maxWidth: ((b = t.screenshotOptions) == null ? void 0 : b.maxWidth) ?? 1280,
576
+ maxHeight: ((g = t.screenshotOptions) == null ? void 0 : g.maxHeight) ?? 800
342
577
  },
343
578
  incognito: t.incognito ?? !1,
344
579
  positiveIcon: t.positiveIcon ?? "",
345
- negativeIcon: t.negativeIcon ?? ""
346
- }, this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundResize = this.handleResize.bind(this), this.visitorId = ft(), this.init();
580
+ negativeIcon: t.negativeIcon ?? "",
581
+ hideThumbs: t.hideThumbs ?? !1,
582
+ css: t.css ?? "",
583
+ captureVideo: t.captureVideo ?? !1,
584
+ videoOptions: {
585
+ maxDuration: ((m = t.videoOptions) == null ? void 0 : m.maxDuration) ?? 15
586
+ },
587
+ recordIcon: t.recordIcon ?? ""
588
+ }, this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundResize = this.handleResize.bind(this), this.visitorId = Ut(), this.init();
589
+ }
590
+ applyVars(t) {
591
+ ut(t, this.cssVars);
347
592
  }
348
593
  init() {
349
- G({
594
+ pt(), this.cssVars = ht({
350
595
  positiveColor: this.config.colors.positive,
351
596
  negativeColor: this.config.colors.negative,
352
597
  markerColor: this.config.colors.marker,
353
- skipButtonStyles: !!this.config.buttonClass,
354
598
  buttonSize: this.config.buttonSize,
355
599
  modalWidth: this.config.modalWidth,
356
600
  backdropOpacity: this.config.backdropOpacity,
357
601
  fontFamily: this.config.fontFamily,
358
602
  fontSize: this.config.fontSize
359
- }), this.checkMobile(), window.addEventListener("resize", this.boundResize), this.createEmbed(), this.fetchAllowedFeatures(), this.consoleCapture = pt((t) => {
360
- var e;
361
- this.feedbackData.consoleErrors = ((e = this.consoleCapture) == null ? void 0 : e.errors) ?? [];
603
+ }), this.checkMobile(), window.addEventListener("resize", this.boundResize), this.createEmbed(), this.consoleCapture = It((t) => {
604
+ var o;
605
+ this.feedbackData.consoleErrors = ((o = this.consoleCapture) == null ? void 0 : o.errors) ?? [];
362
606
  }), this.feedbackData.consoleErrors = this.consoleCapture.errors;
363
607
  }
364
- async fetchAllowedFeatures() {
365
- if (this.config.apiKey)
366
- try {
367
- const e = `${this.config.endpoint.replace(/\/feedback\/?$/, "")}/features?apiKey=${encodeURIComponent(this.config.apiKey)}`, o = await fetch(e);
368
- o.ok && (this.allowedFeatures = await o.json());
369
- } catch {
370
- }
371
- }
372
608
  checkMobile() {
373
- this.isMobile = ut();
609
+ this.isMobile = Bt();
374
610
  }
375
611
  handleResize() {
376
612
  this.checkMobile();
377
613
  }
378
614
  createEmbed() {
615
+ this.shadowHost = document.createElement("div"), this.shadowHost.setAttribute("data-qaid-embed", ""), this.shadowHost.style.position = "static", this.shadowHost.style.display = "contents";
379
616
  let t = null;
380
- if (this.config.container && (t = document.querySelector(this.config.container)), t)
381
- this.container = t, this.container.classList.add("qaid-widget", `qaid-${this.config.position}`), this.config.incognito && this.container.classList.add("qaid-incognito"), this.isUserProvidedContainer = !0;
617
+ this.config.container && (t = document.querySelector(this.config.container)), t ? (t.appendChild(this.shadowHost), this.isUserProvidedContainer = !0) : (this.shadowHost.style.position = "fixed", this.shadowHost.style.display = "block", this.shadowHost.style.inset = "0", this.shadowHost.style.pointerEvents = "none", this.shadowHost.style.zIndex = String(this.config.zIndex), document.body.appendChild(this.shadowHost)), this.shadowRoot = this.shadowHost.attachShadow({ mode: "open" });
618
+ const o = document.createElement("style");
619
+ if (o.textContent = A(), this.shadowRoot.appendChild(o), this.config.css) {
620
+ const r = document.createElement("style");
621
+ r.textContent = this.config.css, this.shadowRoot.appendChild(r);
622
+ }
623
+ const i = this.config.direction === "vertical" ? "qaid-vertical" : "";
624
+ if (this.isUserProvidedContainer)
625
+ this.buttonsContainer = document.createElement("div"), this.buttonsContainer.className = `qaid-buttons qaid-${this.config.position} ${i}`.trim(), this.config.incognito && this.buttonsContainer.classList.add("qaid-incognito");
382
626
  else {
383
- this.container = document.createElement("div"), this.container.className = `qaid-widget qaid-auto-container qaid-${this.config.position}${this.config.incognito ? " qaid-incognito" : ""}`, this.container.style.zIndex = String(this.config.zIndex);
384
- const { x: u, y: m } = this.config.offset;
385
- this.config.position.includes("right") ? this.container.style.right = `${u}px` : this.container.style.left = `${u}px`, this.config.position.includes("bottom") ? this.container.style.bottom = `${m}px` : this.container.style.top = `${m}px`, document.body.appendChild(this.container);
627
+ this.buttonsContainer = document.createElement("div"), this.buttonsContainer.className = `qaid-buttons qaid-auto-container qaid-${this.config.position} ${i}${this.config.incognito ? " qaid-incognito" : ""}`.trim(), this.buttonsContainer.style.pointerEvents = "auto";
628
+ const { x: r, y: c } = this.config.offset;
629
+ this.config.position.includes("right") ? this.buttonsContainer.style.right = `${r}px` : this.buttonsContainer.style.left = `${r}px`, this.config.position.includes("bottom") ? this.buttonsContainer.style.bottom = `${c}px` : this.buttonsContainer.style.top = `${c}px`;
630
+ }
631
+ this.applyVars(this.buttonsContainer), this.shadowRoot.appendChild(this.buttonsContainer);
632
+ const n = !!this.config.buttonClass, a = n ? `qaid-btn-structural ${this.config.buttonClass}` : "qaid-btn", l = this.config.text.tooltip || "Feedback for us?", d = document.createElement("div");
633
+ if (d.className = "qaid-tooltip-text", d.textContent = l, this.applyVars(d), this.shadowRoot.appendChild(d), this.tooltipElement = d, !this.config.hideThumbs) {
634
+ const r = document.createElement("div");
635
+ r.className = "qaid-tooltip-wrapper";
636
+ const c = document.createElement("button");
637
+ c.type = "button", c.className = n ? `${a} qaid-btn-up` : "qaid-btn qaid-btn-up", c.innerHTML = this.config.positiveIcon || T, c.addEventListener("click", (f) => this.handleThumbClick("up", f.currentTarget)), c.addEventListener("mouseenter", () => this.showTooltip(c)), c.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(c);
638
+ const u = document.createElement("div");
639
+ u.className = "qaid-tooltip-wrapper";
640
+ const p = document.createElement("button");
641
+ p.type = "button", p.className = n ? `${a} qaid-btn-down` : "qaid-btn qaid-btn-down", p.innerHTML = this.config.negativeIcon || I, p.addEventListener("click", (f) => this.handleThumbClick("down", f.currentTarget)), p.addEventListener("mouseenter", () => this.showTooltip(p)), p.addEventListener("mouseleave", () => this.hideTooltip()), u.appendChild(p), this.buttonsContainer.appendChild(r), this.buttonsContainer.appendChild(u);
642
+ }
643
+ if (this.config.captureVideo && Dt()) {
644
+ const r = document.createElement("div");
645
+ r.className = "qaid-tooltip-wrapper";
646
+ const c = document.createElement("button");
647
+ c.type = "button", c.className = n ? `${a} qaid-btn-record` : "qaid-btn qaid-btn-record", c.innerHTML = this.config.recordIcon || it, c.addEventListener("click", () => this.startRecording()), c.addEventListener("mouseenter", () => this.showTooltip(c)), c.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(c), this.buttonsContainer.appendChild(r);
386
648
  }
387
- const e = this.config.fontFamily, o = e && e !== "system-ui, -apple-system, sans-serif";
388
- o && (this.container.style.fontFamily = e);
389
- const n = !!this.config.buttonClass, a = n ? `qaid-btn-structural ${this.config.buttonClass}` : "qaid-btn", s = this.config.skipTargeting ? "Send feedback" : "Any feedback? Click to start, Esc to cancel", l = this.config.text.tooltip || s, r = document.createElement("div");
390
- r.className = "qaid-tooltip-text", r.textContent = l, o && (r.style.fontFamily = e), document.body.appendChild(r), this.tooltipElement = r;
391
- const c = document.createElement("div");
392
- c.className = "qaid-tooltip-wrapper";
393
- const p = document.createElement("button");
394
- p.type = "button", p.className = n ? `${a} qaid-btn-up` : "qaid-btn qaid-btn-up", p.innerHTML = this.config.positiveIcon || k, p.addEventListener("click", (u) => this.handleThumbClick("up", u.currentTarget)), p.addEventListener("mouseenter", () => this.showTooltip(p)), p.addEventListener("mouseleave", () => this.hideTooltip()), c.appendChild(p);
395
- const g = document.createElement("div");
396
- g.className = "qaid-tooltip-wrapper";
397
- const h = document.createElement("button");
398
- h.type = "button", h.className = n ? `${a} qaid-btn-down` : "qaid-btn qaid-btn-down", h.innerHTML = this.config.negativeIcon || w, h.addEventListener("click", (u) => this.handleThumbClick("down", u.currentTarget)), h.addEventListener("mouseenter", () => this.showTooltip(h)), h.addEventListener("mouseleave", () => this.hideTooltip()), g.appendChild(h), this.container.appendChild(c), this.container.appendChild(g);
649
+ }
650
+ /**
651
+ * Lazily create a separate overlay shadow host on document.body.
652
+ * This host contains all full-page elements (targeting overlay, marker,
653
+ * backdrop, modal, recording indicator, video preview) so they escape
654
+ * clip-path / transform containing blocks in user containers.
655
+ */
656
+ ensureOverlayHost() {
657
+ if (this.overlayShadowRoot) return this.overlayShadowRoot;
658
+ this.overlayShadowHost = document.createElement("div"), this.overlayShadowHost.setAttribute("data-qaid-embed-overlay", ""), this.overlayShadowHost.style.position = "fixed", this.overlayShadowHost.style.inset = "0", this.overlayShadowHost.style.pointerEvents = "none", this.overlayShadowHost.style.zIndex = String(this.config.zIndex), document.body.appendChild(this.overlayShadowHost), this.overlayShadowRoot = this.overlayShadowHost.attachShadow({ mode: "open" });
659
+ const t = document.createElement("style");
660
+ if (t.textContent = A(), this.overlayShadowRoot.appendChild(t), this.config.css) {
661
+ const o = document.createElement("style");
662
+ o.textContent = this.config.css, this.overlayShadowRoot.appendChild(o);
663
+ }
664
+ return this.overlayShadowRoot;
399
665
  }
400
666
  showTooltip(t) {
401
667
  if (!this.tooltipElement) return;
402
- const e = this.tooltipElement, o = 8;
403
- e.style.visibility = "hidden", e.classList.add("qaid-tooltip-visible");
404
- const n = t.getBoundingClientRect(), a = e.getBoundingClientRect(), s = window.innerWidth, l = window.innerHeight;
405
- let r, c;
406
- r = n.bottom + o, r + a.height > l - o && (r = n.top - a.height - o), c = n.left, c < o ? c = o : c + a.width > s - o && (c = s - a.width - o), r < o ? r = o : r + a.height > l - o && (r = l - a.height - o), e.style.top = `${r}px`, e.style.left = `${c}px`, e.style.visibility = "visible";
668
+ const o = this.tooltipElement, i = 8;
669
+ o.style.visibility = "hidden", o.classList.add("qaid-tooltip-visible");
670
+ const n = t.getBoundingClientRect(), a = o.getBoundingClientRect(), s = window.innerWidth, l = window.innerHeight;
671
+ let d, r;
672
+ d = n.bottom + i, d + a.height > l - i && (d = n.top - a.height - i), r = n.left, r < i ? r = i : r + a.width > s - i && (r = s - a.width - i), d < i ? d = i : d + a.height > l - i && (d = l - a.height - i), o.style.top = `${d}px`, o.style.left = `${r}px`, o.style.visibility = "visible";
407
673
  }
408
674
  hideTooltip() {
409
675
  this.tooltipElement && this.tooltipElement.classList.remove("qaid-tooltip-visible");
410
676
  }
411
- handleThumbClick(t, e) {
412
- this.config.skipTargeting ? this.submitDirectFeedback(t, e) : this.startTargeting(t);
677
+ handleThumbClick(t, o) {
678
+ this.config.skipTargeting ? this.submitDirectFeedback(t, o) : this.startTargeting(t);
413
679
  }
414
- submitDirectFeedback(t, e) {
680
+ submitDirectFeedback(t, o) {
415
681
  this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null;
416
- const o = e.getBoundingClientRect();
682
+ const i = o.getBoundingClientRect();
417
683
  this.selectedBounds = {
418
- x: o.left,
419
- y: o.top,
420
- width: o.width,
421
- height: o.height,
422
- clickX: o.left + o.width / 2,
423
- clickY: o.top + o.height / 2,
684
+ x: i.left,
685
+ y: i.top,
686
+ width: i.width,
687
+ height: i.height,
688
+ clickX: i.left + i.width / 2,
689
+ clickY: i.top + i.height / 2,
424
690
  visible: !1
425
691
  }, this.submitFeedback();
426
692
  }
427
693
  startTargeting(t) {
428
- this.state = "TARGETING", this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, document.body.classList.add("qaid-targeting"), t === "up" ? document.body.classList.add("qaid-type-up") : document.body.classList.remove("qaid-type-up"), this.createTargetingOverlay(), document.addEventListener("keydown", this.boundKeyDown);
694
+ this.state = "TARGETING", this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, document.body.classList.add("qaid-targeting"), t === "up" ? document.body.classList.add("qaid-type-up") : document.body.classList.remove("qaid-type-up"), document.body.style.setProperty("--qaid-positive", this.cssVars["--qaid-positive"]), document.body.style.setProperty("--qaid-negative", this.cssVars["--qaid-negative"]), this.createTargetingOverlay(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto"), document.addEventListener("keydown", this.boundKeyDown);
429
695
  }
430
696
  createTargetingOverlay() {
697
+ const t = this.ensureOverlayHost();
431
698
  this.overlayContainer = document.createElement("div"), this.overlayContainer.className = `qaid-targeting-overlay qaid-type-${this.feedbackData.feedbackType}`, this.captureLayer = document.createElement("div"), this.captureLayer.className = "qaid-capture-layer", this.captureLayer.addEventListener("mousemove", this.boundMouseMove), this.captureLayer.addEventListener("click", this.boundClick);
432
- const t = document.createElement("div");
433
- t.className = `qaid-banner qaid-banner-${this.feedbackData.feedbackType}`;
434
- const e = this.config.fontFamily;
435
- e && e !== "system-ui, -apple-system, sans-serif" && (t.style.fontFamily = e), t.innerHTML = `
436
- <span class="qaid-banner-text">${this.config.text.bannerText}</span>
437
- <span class="qaid-banner-hint">${this.config.text.bannerHint}</span>
438
- `;
439
699
  const o = document.createElement("div");
440
700
  o.className = "qaid-vignette", this.crosshairH = document.createElement("div"), this.crosshairH.className = "qaid-crosshair-h", this.crosshairV = document.createElement("div"), this.crosshairV.className = "qaid-crosshair-v", this.scope = document.createElement("div"), this.scope.className = "qaid-scope", this.scope.innerHTML = `
441
701
  <div class="qaid-scope-ring"></div>
442
702
  <div class="qaid-scope-ring-inner"></div>
443
703
  <div class="qaid-scope-dot"></div>
444
- `, this.overlayContainer.appendChild(this.captureLayer), this.overlayContainer.appendChild(t), this.overlayContainer.appendChild(o), this.overlayContainer.appendChild(this.crosshairH), this.overlayContainer.appendChild(this.crosshairV), this.overlayContainer.appendChild(this.scope), document.body.appendChild(this.overlayContainer);
704
+ `, this.overlayContainer.appendChild(this.captureLayer), this.overlayContainer.appendChild(o), this.overlayContainer.appendChild(this.crosshairH), this.overlayContainer.appendChild(this.crosshairV), this.overlayContainer.appendChild(this.scope), this.applyVars(this.overlayContainer), t.appendChild(this.overlayContainer);
445
705
  }
446
706
  handleKeyDown(t) {
447
- t.key === "Escape" && (this.state === "TARGETING" ? this.cancelTargeting() : this.state === "MODAL_OPEN" && this.closeModal());
707
+ t.key === "Escape" && (this.isRecording ? this.stopRecording() : this.videoPreview ? this.cancelRecordingPreview() : this.state === "TARGETING" ? this.cancelTargeting() : this.state === "MODAL_OPEN" && this.closeModal());
448
708
  }
449
709
  handleMouseMove(t) {
450
- if (this.mousePos.x = t.clientX, this.mousePos.y = t.clientY, this.crosshairH && (this.crosshairH.style.top = `${t.clientY}px`), this.crosshairV && (this.crosshairV.style.left = `${t.clientX}px`), this.scope && (this.scope.style.left = `${t.clientX}px`, this.scope.style.top = `${t.clientY}px`), this.captureLayer) {
451
- const e = D(
710
+ if (this.mousePos.x = t.clientX, this.mousePos.y = t.clientY, this.crosshairH && (this.crosshairH.style.top = `${t.clientY}px`), this.crosshairV && (this.crosshairV.style.left = `${t.clientX}px`), this.scope && (this.scope.style.left = `${t.clientX}px`, this.scope.style.top = `${t.clientY}px`), this.captureLayer && this.shadowHost) {
711
+ const o = [this.shadowHost, this.overlayShadowHost].filter(Boolean), i = $(
452
712
  t.clientX,
453
713
  t.clientY,
454
- this.captureLayer
714
+ o
455
715
  );
456
- e && !B(e) ? (this.lastHighlighted && this.lastHighlighted !== e && this.lastHighlighted.classList.remove("qaid-highlight"), e.classList.add("qaid-highlight"), this.lastHighlighted = e) : this.lastHighlighted && (this.lastHighlighted.classList.remove("qaid-highlight"), this.lastHighlighted = null);
716
+ i && !N(i) ? (this.lastHighlighted && this.lastHighlighted !== i && this.lastHighlighted.classList.remove("qaid-highlight"), i.classList.add("qaid-highlight"), this.lastHighlighted = i) : this.lastHighlighted && (this.lastHighlighted.classList.remove("qaid-highlight"), this.lastHighlighted = null);
457
717
  }
458
718
  }
459
719
  handleClick(t) {
460
- if (!this.captureLayer) return;
461
- const e = D(
720
+ if (!this.captureLayer || !this.shadowHost) return;
721
+ const o = [this.shadowHost, this.overlayShadowHost].filter(Boolean), i = $(
462
722
  t.clientX,
463
723
  t.clientY,
464
- this.captureLayer
724
+ o
465
725
  );
466
- if (!e || B(e))
726
+ if (!i || N(i))
467
727
  return;
468
- e.classList.remove("qaid-highlight");
469
- const o = mt(e, 8);
728
+ i.classList.remove("qaid-highlight");
729
+ const n = At(i, 8);
470
730
  this.selectedBounds = {
471
- ...o,
731
+ ...n,
472
732
  clickX: t.clientX,
473
733
  clickY: t.clientY,
474
734
  visible: !0
475
735
  };
476
- const { selector: n, text: a } = at(e);
477
- this.feedbackData.elementSelector = n, this.feedbackData.elementText = a, C("qaid-highlight"), this.removeTargetingOverlay(), document.body.classList.remove("qaid-targeting", "qaid-type-up"), this.state = "SELECTED", this.showSelectedMarker(), this.submitFeedback();
736
+ const { selector: a, text: s } = qt(i);
737
+ this.feedbackData.elementSelector = a, this.feedbackData.elementText = s, L("qaid-highlight"), this.removeTargetingOverlay(), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "none"), this.state = "SELECTED", this.showSelectedMarker(), this.submitFeedback();
478
738
  }
479
739
  cancelTargeting() {
480
- C("qaid-highlight"), this.removeTargetingOverlay(), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.removeEventListener("keydown", this.boundKeyDown), this.state = "IDLE", this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, this.lastHighlighted = null;
740
+ L("qaid-highlight"), this.removeTargetingOverlay(), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), document.removeEventListener("keydown", this.boundKeyDown), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "none"), this.state = "IDLE", this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, this.lastHighlighted = null;
481
741
  }
482
742
  removeTargetingOverlay() {
483
743
  this.overlayContainer && (this.overlayContainer.remove(), this.overlayContainer = null), this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null;
484
744
  }
485
745
  showSelectedMarker() {
486
- this.selectedBounds.visible && (this.marker = document.createElement("div"), this.marker.className = "qaid-selected-marker", this.marker.style.left = `${this.selectedBounds.x}px`, this.marker.style.top = `${this.selectedBounds.y}px`, this.marker.style.width = `${this.selectedBounds.width}px`, this.marker.style.height = `${this.selectedBounds.height}px`, this.marker.style.zIndex = String(this.config.zIndex + 1), document.body.appendChild(this.marker));
746
+ if (!this.selectedBounds.visible) return;
747
+ const t = this.ensureOverlayHost();
748
+ this.marker = document.createElement("div"), this.marker.className = "qaid-selected-marker", this.marker.style.left = `${this.selectedBounds.x}px`, this.marker.style.top = `${this.selectedBounds.y}px`, this.marker.style.width = `${this.selectedBounds.width}px`, this.marker.style.height = `${this.selectedBounds.height}px`, this.marker.style.zIndex = String(this.config.zIndex + 1), this.applyVars(this.marker), t.appendChild(this.marker);
487
749
  }
488
750
  hideSelectedMarker() {
489
751
  this.marker && (this.marker.remove(), this.marker = null);
490
752
  }
491
753
  async submitFeedback() {
492
- var a;
493
754
  if (!this.feedbackData.feedbackType) return;
494
755
  let t = null;
495
- const e = ((a = this.allowedFeatures) == null ? void 0 : a.screenshots) !== !1;
496
- this.config.captureScreenshot && e && (t = await gt(this.config.screenshotOptions));
756
+ this.config.captureScreenshot && (this.config.screenshotMethod === "dom" ? t = await Vt(this.config.screenshotOptions) : t = await Ot(this.config.screenshotOptions));
497
757
  const o = this.feedbackData.elementSelector ? {
498
758
  x: this.selectedBounds.x,
499
759
  y: this.selectedBounds.y,
500
760
  width: this.selectedBounds.width,
501
761
  height: this.selectedBounds.height
502
- } : null, n = {
762
+ } : null, i = {
503
763
  feedbackType: this.feedbackData.feedbackType,
504
764
  pageUrl: window.location.href,
505
765
  apiKey: this.config.apiKey || void 0,
@@ -519,36 +779,35 @@ class bt {
519
779
  userAgent: navigator.userAgent
520
780
  };
521
781
  try {
522
- const s = await fetch(this.config.endpoint, {
782
+ const n = await fetch(this.config.endpoint, {
523
783
  method: "POST",
524
784
  headers: { "Content-Type": "application/json" },
525
- body: JSON.stringify(n)
785
+ body: JSON.stringify(i)
526
786
  });
527
- if (s.ok) {
528
- const l = await s.json();
529
- this.feedbackId = l.id;
787
+ if (n.ok) {
788
+ const a = await n.json();
789
+ this.feedbackId = a.id;
530
790
  }
531
- } catch (s) {
532
- console.error("Failed to submit feedback:", s);
791
+ } catch (n) {
792
+ console.error("Failed to submit feedback:", n);
533
793
  }
534
- this.state = "MODAL_OPEN", this.showModal();
794
+ this.state = "MODAL_OPEN", this.showModal(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto");
535
795
  }
536
796
  showModal() {
537
- this.backdrop = document.createElement("div"), this.backdrop.className = "qaid-backdrop", this.backdrop.style.zIndex = String(this.config.zIndex + 2), this.backdrop.style.background = `rgba(0, 0, 0, ${this.config.backdropOpacity})`, this.backdrop.addEventListener("click", () => this.closeModal()), this.isMobile ? this.showBottomSheet() : this.showPositionedModal(), document.body.appendChild(this.backdrop), document.addEventListener("keydown", this.boundKeyDown);
797
+ const t = this.ensureOverlayHost();
798
+ this.backdrop = document.createElement("div"), this.backdrop.className = "qaid-backdrop", this.backdrop.style.zIndex = String(this.config.zIndex + 2), this.backdrop.style.background = `rgba(0, 0, 0, ${this.config.backdropOpacity})`, this.backdrop.addEventListener("click", () => this.closeModal()), this.applyVars(this.backdrop), this.isMobile ? this.showBottomSheet() : this.showPositionedModal(), t.appendChild(this.backdrop), document.addEventListener("keydown", this.boundKeyDown);
538
799
  }
539
800
  showBottomSheet() {
540
- const t = document.createElement("div");
541
- t.className = "qaid-bottom-sheet", t.style.zIndex = String(this.config.zIndex + 3);
542
- const e = this.config.fontFamily;
543
- e && e !== "system-ui, -apple-system, sans-serif" && (t.style.fontFamily = e), t.innerHTML = `
801
+ const t = this.ensureOverlayHost(), o = document.createElement("div");
802
+ o.className = "qaid-bottom-sheet", o.style.zIndex = String(this.config.zIndex + 3), o.innerHTML = `
544
803
  <div class="qaid-bottom-sheet-content">
545
804
  <div class="qaid-bottom-sheet-handle"></div>
546
805
  ${this.getModalContent()}
547
806
  </div>
548
- `, document.body.appendChild(t), this.modalContainer = t, this.setupModalInteractions();
807
+ `, this.applyVars(o), t.appendChild(o), this.modalContainer = o, this.setupModalInteractions();
549
808
  }
550
809
  showPositionedModal() {
551
- const { modal: t, arrow: e } = ct(
810
+ const t = this.ensureOverlayHost(), { modal: o, arrow: i } = Et(
552
811
  this.selectedBounds,
553
812
  window.innerWidth,
554
813
  window.innerHeight,
@@ -560,20 +819,18 @@ class bt {
560
819
  viewportPadding: 16
561
820
  }
562
821
  );
563
- this.modalContainer = document.createElement("div"), this.modalContainer.className = `qaid-modal-container qaid-${t.position}`, this.modalContainer.style.top = `${t.top}px`, this.modalContainer.style.left = `${t.left}px`, this.modalContainer.style.zIndex = String(this.config.zIndex + 3);
564
- const o = this.config.fontFamily;
565
- o && o !== "system-ui, -apple-system, sans-serif" && (this.modalContainer.style.fontFamily = o);
822
+ this.modalContainer = document.createElement("div"), this.modalContainer.className = `qaid-modal-container qaid-${o.position}`, this.modalContainer.style.top = `${o.top}px`, this.modalContainer.style.left = `${o.left}px`, this.modalContainer.style.zIndex = String(this.config.zIndex + 3);
566
823
  const n = document.createElement("div");
567
- n.className = "qaid-modal-arrow", n.style.left = `${e.left}px`;
824
+ n.className = "qaid-modal-arrow", n.style.left = `${i.left}px`;
568
825
  const a = document.createElement("div");
569
- a.className = "qaid-modal-box", a.innerHTML = this.getModalContent(), this.modalContainer.appendChild(n), this.modalContainer.appendChild(a), document.body.appendChild(this.modalContainer), this.setupModalInteractions();
826
+ a.className = "qaid-modal-box", a.innerHTML = this.getModalContent(), this.modalContainer.appendChild(n), this.modalContainer.appendChild(a), this.applyVars(this.modalContainer), t.appendChild(this.modalContainer), this.setupModalInteractions();
570
827
  }
571
828
  getModalContent() {
572
- const t = this.feedbackData.feedbackType === "up", e = this.config.positiveIcon || k, o = this.config.negativeIcon || w;
829
+ const t = this.feedbackData.feedbackType === "up", o = this.config.positiveIcon || T, i = this.config.negativeIcon || I;
573
830
  return `
574
831
  <div class="qaid-modal-header">
575
832
  <button type="button" class="${this.config.buttonClass ? `qaid-type-toggle qaid-type-toggle-custom ${this.config.buttonClass} ${t ? "qaid-btn-up" : "qaid-btn-down"}` : `qaid-type-toggle ${t ? "qaid-type-up" : "qaid-type-down"}`}" title="Click to switch">
576
- ${t ? e : o}
833
+ ${t ? o : i}
577
834
  </button>
578
835
  <div class="qaid-modal-header-text">
579
836
  <h3 class="qaid-modal-title">${this.config.text.modalTitle}</h3>
@@ -588,19 +845,19 @@ class bt {
588
845
  }
589
846
  setupModalInteractions() {
590
847
  if (!this.modalContainer) return;
591
- const t = this.modalContainer.querySelector(".qaid-textarea"), e = this.modalContainer.querySelector(".qaid-btn-submit");
848
+ const t = this.modalContainer.querySelector(".qaid-textarea"), o = this.modalContainer.querySelector(".qaid-btn-submit");
592
849
  t && (setTimeout(() => t.focus(), 100), t.addEventListener("input", () => {
593
- e && (e.textContent = t.value.trim() ? this.config.text.submitButton : this.config.text.skipButton);
594
- })), e && e.addEventListener("click", () => {
850
+ o && (o.textContent = t.value.trim() ? this.config.text.submitButton : this.config.text.skipButton);
851
+ })), o && o.addEventListener("click", () => {
595
852
  const n = (t == null ? void 0 : t.value.trim()) || null;
596
853
  this.submitMessage(n);
597
854
  });
598
- const o = this.modalContainer.querySelector(".qaid-type-toggle");
599
- o && o.addEventListener("click", () => {
855
+ const i = this.modalContainer.querySelector(".qaid-type-toggle");
856
+ i && i.addEventListener("click", () => {
600
857
  const n = this.feedbackData.feedbackType === "up" ? "down" : "up";
601
- this.feedbackData.feedbackType = n, this.config.buttonClass ? (o.classList.toggle("qaid-btn-up", n === "up"), o.classList.toggle("qaid-btn-down", n === "down")) : (o.classList.toggle("qaid-type-up", n === "up"), o.classList.toggle("qaid-type-down", n === "down"));
602
- const a = this.config.positiveIcon || k, s = this.config.negativeIcon || w;
603
- o.innerHTML = n === "up" ? a : s, this.feedbackId && fetch(`${this.config.endpoint}/${this.feedbackId}`, {
858
+ this.feedbackData.feedbackType = n, this.config.buttonClass ? (i.classList.toggle("qaid-btn-up", n === "up"), i.classList.toggle("qaid-btn-down", n === "down")) : (i.classList.toggle("qaid-type-up", n === "up"), i.classList.toggle("qaid-type-down", n === "down"));
859
+ const a = this.config.positiveIcon || T, s = this.config.negativeIcon || I;
860
+ i.innerHTML = n === "up" ? a : s, this.feedbackId && fetch(`${this.config.endpoint}/${this.feedbackId}`, {
604
861
  method: "PATCH",
605
862
  headers: { "Content-Type": "application/json" },
606
863
  body: JSON.stringify({ feedbackType: n })
@@ -615,8 +872,8 @@ class bt {
615
872
  headers: { "Content-Type": "application/json" },
616
873
  body: JSON.stringify({ message: t })
617
874
  });
618
- } catch (e) {
619
- console.error("Failed to submit feedback message:", e);
875
+ } catch (o) {
876
+ console.error("Failed to submit feedback message:", o);
620
877
  }
621
878
  this.feedbackId = null;
622
879
  }
@@ -627,84 +884,213 @@ class bt {
627
884
  method: "PATCH",
628
885
  headers: { "Content-Type": "application/json" },
629
886
  body: JSON.stringify({ message: null })
630
- }).catch((t) => console.error("Failed to finalize feedback:", t)), this.modalContainer && (this.modalContainer.remove(), this.modalContainer = null), this.backdrop && (this.backdrop.remove(), this.backdrop = null), document.removeEventListener("keydown", this.boundKeyDown), this.hideSelectedMarker(), this.state = "IDLE", this.feedbackId = null, this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
887
+ }).catch((t) => console.error("Failed to finalize feedback:", t)), this.modalContainer && (this.modalContainer.remove(), this.modalContainer = null), this.backdrop && (this.backdrop.remove(), this.backdrop = null), document.removeEventListener("keydown", this.boundKeyDown), this.hideSelectedMarker(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "none"), this.state = "IDLE", this.feedbackId = null, this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
888
+ }
889
+ // ==================== Video Recording ====================
890
+ async startRecording() {
891
+ if (!(this.isRecording || this.state !== "IDLE"))
892
+ try {
893
+ this.networkCapture = Rt(), this.videoRecorder = zt({
894
+ maxDuration: this.config.videoOptions.maxDuration
895
+ }), this.videoRecorder.onTick((t) => {
896
+ this.updateRecordingTimer(t);
897
+ }), this.videoRecorder.onStop((t) => {
898
+ this.isRecording && (this.recordedBlob = t, this.isRecording = !1, this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.setButtonsDisabled(!1), t && t.size > 0 ? this.showRecordingPreview() : this.cleanupRecording());
899
+ }), await this.videoRecorder.start(), this.isRecording = !0, this.setButtonsDisabled(!0), this.showRecordingIndicator(), document.addEventListener("keydown", this.boundKeyDown);
900
+ } catch {
901
+ this.cleanupRecording();
902
+ }
903
+ }
904
+ async stopRecording() {
905
+ if (!(!this.isRecording || !this.videoRecorder)) {
906
+ try {
907
+ this.recordedBlob = await this.videoRecorder.stop();
908
+ } catch {
909
+ this.recordedBlob = null;
910
+ }
911
+ this.isRecording = !1, this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.recordedBlob && this.recordedBlob.size > 0 ? this.showRecordingPreview() : this.cleanupRecording();
912
+ }
913
+ }
914
+ showRecordingIndicator() {
915
+ const t = this.ensureOverlayHost();
916
+ this.recordingIndicator = document.createElement("div"), this.recordingIndicator.className = "qaid-recording-indicator", this.recordingIndicator.style.zIndex = String(this.config.zIndex + 100);
917
+ const o = document.createElement("div");
918
+ o.className = "qaid-recording-dot";
919
+ const i = document.createElement("span");
920
+ i.className = "qaid-recording-time", i.textContent = this.formatTime(this.config.videoOptions.maxDuration);
921
+ const n = document.createElement("button");
922
+ n.type = "button", n.className = "qaid-recording-stop", n.textContent = "Stop", n.addEventListener("click", () => this.stopRecording()), this.recordingIndicator.appendChild(o), this.recordingIndicator.appendChild(i), this.recordingIndicator.appendChild(n), this.applyVars(this.recordingIndicator), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.recordingIndicator);
923
+ }
924
+ updateRecordingTimer(t) {
925
+ if (!this.recordingIndicator) return;
926
+ const o = this.recordingIndicator.querySelector(".qaid-recording-time");
927
+ if (o) {
928
+ const i = Math.max(0, this.config.videoOptions.maxDuration - t);
929
+ o.textContent = this.formatTime(i);
930
+ }
931
+ }
932
+ formatTime(t) {
933
+ const o = Math.floor(t / 60), i = t % 60;
934
+ return `${o}:${i.toString().padStart(2, "0")}`;
935
+ }
936
+ removeRecordingIndicator() {
937
+ this.recordingIndicator && (this.recordingIndicator.remove(), this.recordingIndicator = null);
938
+ }
939
+ showRecordingPreview() {
940
+ if (!this.recordedBlob) return;
941
+ const t = this.ensureOverlayHost(), o = URL.createObjectURL(this.recordedBlob);
942
+ this.videoPreview = document.createElement("div"), this.videoPreview.className = "qaid-video-preview", this.videoPreview.style.zIndex = String(this.config.zIndex + 100);
943
+ const i = document.createElement("div");
944
+ i.className = "qaid-video-preview-box";
945
+ const n = document.createElement("h3");
946
+ n.textContent = "Review your recording";
947
+ const a = document.createElement("video");
948
+ a.src = o, a.controls = !0, a.autoplay = !0, a.muted = !0;
949
+ const s = document.createElement("textarea");
950
+ s.placeholder = "Optional: Describe the issue you recorded...";
951
+ const l = document.createElement("div");
952
+ l.className = "qaid-video-preview-actions";
953
+ const d = document.createElement("button");
954
+ d.type = "button", d.className = "qaid-video-btn qaid-video-btn-cancel", d.textContent = "Cancel", d.addEventListener("click", () => this.cancelRecordingPreview());
955
+ const r = document.createElement("button");
956
+ r.type = "button", r.className = "qaid-video-btn qaid-video-btn-rerecord", r.textContent = "Re-record", r.addEventListener("click", () => {
957
+ this.cancelRecordingPreview(), this.startRecording();
958
+ });
959
+ const c = document.createElement("button");
960
+ c.type = "button", c.className = "qaid-video-btn qaid-video-btn-send", c.textContent = "Send", c.addEventListener("click", () => {
961
+ const u = s.value.trim() || null;
962
+ this.submitVideoFeedback(u, c);
963
+ }), l.appendChild(d), l.appendChild(r), l.appendChild(c), i.appendChild(n), i.appendChild(a), i.appendChild(s), i.appendChild(l), this.videoPreview.appendChild(i), this.applyVars(this.videoPreview), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.videoPreview), document.addEventListener("keydown", this.boundKeyDown);
964
+ }
965
+ cancelRecordingPreview() {
966
+ this.removeVideoPreview(), this.cleanupRecording();
967
+ }
968
+ removeVideoPreview() {
969
+ if (this.videoPreview) {
970
+ const t = this.videoPreview.querySelector("video");
971
+ t != null && t.src && URL.revokeObjectURL(t.src), this.videoPreview.remove(), this.videoPreview = null;
972
+ }
973
+ document.removeEventListener("keydown", this.boundKeyDown);
974
+ }
975
+ async submitVideoFeedback(t, o) {
976
+ if (!this.recordedBlob || this.isSendingVideo) return;
977
+ this.isSendingVideo = !0, o.disabled = !0, o.textContent = "Sending...";
978
+ const i = new FormData();
979
+ i.append("video", this.recordedBlob, `recording.${this.recordedBlob.type.includes("mp4") ? "mp4" : "webm"}`), i.append("pageUrl", window.location.href), i.append("visitorId", this.visitorId), this.config.apiKey && i.append("apiKey", this.config.apiKey), t && i.append("message", t), this.consoleCapture && i.append("consoleErrors", JSON.stringify(this.consoleCapture.errors)), this.networkCapture && i.append("networkErrors", JSON.stringify(this.networkCapture.errors));
980
+ try {
981
+ const n = await fetch(`${this.config.endpoint}/video`, {
982
+ method: "POST",
983
+ body: i
984
+ });
985
+ n.ok || console.error("Failed to submit video feedback:", await n.text());
986
+ } catch (n) {
987
+ console.error("Failed to submit video feedback:", n);
988
+ }
989
+ this.isSendingVideo = !1, this.removeVideoPreview(), this.cleanupRecording();
990
+ }
991
+ cleanupRecording() {
992
+ this.isRecording = !1, this.removeRecordingIndicator(), this.videoRecorder && (this.videoRecorder.destroy(), this.videoRecorder = null), this.networkCapture && (this.networkCapture.restore(), this.networkCapture = null), this.recordedBlob && (this.recordedBlob = null), this.setButtonsDisabled(!1), this.overlayShadowHost && this.state === "IDLE" && (this.overlayShadowHost.style.pointerEvents = "none");
993
+ }
994
+ setButtonsDisabled(t) {
995
+ if (!this.buttonsContainer) return;
996
+ this.buttonsContainer.querySelectorAll("button.qaid-btn, button.qaid-btn-structural").forEach((i) => {
997
+ t ? i.classList.contains("qaid-btn-record") || (i.disabled = !0, i.style.opacity = "0.5") : (i.disabled = !1, i.style.opacity = "");
998
+ });
631
999
  }
632
1000
  /**
633
1001
  * Destroy the embed and clean up all resources
634
1002
  */
635
1003
  destroy() {
636
- this.consoleCapture && (this.consoleCapture.restore(), this.consoleCapture = null), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown), C("qaid-highlight"), document.body.classList.remove("qaid-targeting", "qaid-type-up"), this.container && (this.isUserProvidedContainer ? (this.container.innerHTML = "", this.container.classList.remove("qaid-widget", `qaid-${this.config.position}`)) : this.container.remove(), this.container = null), this.removeTargetingOverlay(), this.hideSelectedMarker(), this.modalContainer && (this.modalContainer.remove(), this.modalContainer = null), this.backdrop && (this.backdrop.remove(), this.backdrop = null), this.tooltipElement && (this.tooltipElement.remove(), this.tooltipElement = null), Z();
1004
+ this.cleanupRecording(), this.removeVideoPreview(), this.consoleCapture && (this.consoleCapture.restore(), this.consoleCapture = null), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown), L("qaid-highlight"), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.shadowHost && (this.shadowHost.remove(), this.shadowHost = null, this.shadowRoot = null), this.overlayShadowHost && (this.overlayShadowHost.remove(), this.overlayShadowHost = null, this.overlayShadowRoot = null), this.buttonsContainer = null, this.overlayContainer = null, this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null, this.marker = null, this.modalContainer = null, this.backdrop = null, this.tooltipElement = null, mt();
637
1005
  }
638
1006
  }
639
- function vt() {
640
- var e;
641
- const i = document.querySelector(
1007
+ function _(e) {
1008
+ var o;
1009
+ const t = document.querySelector(e);
1010
+ return ((o = t == null ? void 0 : t.textContent) == null ? void 0 : o.trim()) ?? "";
1011
+ }
1012
+ function Wt() {
1013
+ var o;
1014
+ const e = document.querySelector(
642
1015
  'script[type="application/json"][data-feedback-config]'
643
1016
  );
644
- if (!i) return null;
645
- const t = (e = i.textContent) == null ? void 0 : e.trim();
1017
+ if (!e) return null;
1018
+ const t = (o = e.textContent) == null ? void 0 : o.trim();
646
1019
  if (!t) return null;
647
1020
  try {
648
- return JSON.parse(t);
1021
+ const i = JSON.parse(t);
1022
+ return i.cssSelector && !i.css && (i.css = _(i.cssSelector), delete i.cssSelector), i;
649
1023
  } catch {
650
1024
  return null;
651
1025
  }
652
1026
  }
653
- function yt(i) {
654
- const t = i.getAttribute("data-endpoint");
1027
+ function _t(e) {
1028
+ const t = e.getAttribute("data-endpoint");
655
1029
  if (!t) return null;
656
- const e = i.getAttribute("data-position"), o = i.getAttribute("data-zindex"), n = i.getAttribute("data-positive-color"), a = i.getAttribute("data-negative-color"), s = i.getAttribute("data-marker-color"), l = i.getAttribute("data-container"), r = i.getAttribute("data-button-class"), c = i.getAttribute("data-skip-targeting"), p = i.getAttribute("data-incognito"), g = i.getAttribute("data-button-size"), h = i.getAttribute("data-offset-x"), u = i.getAttribute("data-offset-y"), m = i.getAttribute("data-modal-width"), b = i.getAttribute("data-backdrop-opacity"), f = i.getAttribute("data-font-family"), v = i.getAttribute("data-font-size"), S = i.getAttribute("data-tooltip"), E = i.getAttribute("data-banner-text"), I = i.getAttribute("data-banner-hint"), z = i.getAttribute("data-modal-title"), L = i.getAttribute("data-modal-subtitle"), M = i.getAttribute("data-placeholder"), $ = i.getAttribute("data-submit-button"), A = i.getAttribute("data-skip-button"), N = i.getAttribute("data-positive-icon"), P = i.getAttribute("data-negative-icon"), W = i.getAttribute("data-api-key"), U = i.getAttribute("data-capture-screenshot"), y = i.getAttribute("data-screenshot-quality"), q = i.getAttribute("data-screenshot-max-width"), x = i.getAttribute("data-screenshot-max-height");
1030
+ const o = e.getAttribute("data-position"), i = e.getAttribute("data-zindex"), n = e.getAttribute("data-positive-color"), a = e.getAttribute("data-negative-color"), s = e.getAttribute("data-marker-color"), l = e.getAttribute("data-container"), d = e.getAttribute("data-button-class"), r = e.getAttribute("data-skip-targeting"), c = e.getAttribute("data-incognito"), u = e.getAttribute("data-button-size"), p = e.getAttribute("data-offset-x"), f = e.getAttribute("data-offset-y"), b = e.getAttribute("data-modal-width"), g = e.getAttribute("data-backdrop-opacity"), m = e.getAttribute("data-font-family"), v = e.getAttribute("data-font-size"), y = e.getAttribute("data-tooltip"), x = e.getAttribute("data-modal-title"), H = e.getAttribute("data-modal-subtitle"), R = e.getAttribute("data-placeholder"), D = e.getAttribute("data-submit-button"), M = e.getAttribute("data-skip-button"), X = e.getAttribute("data-positive-icon"), j = e.getAttribute("data-negative-icon"), K = e.getAttribute("data-api-key"), Y = e.getAttribute("data-capture-screenshot"), C = e.getAttribute("data-screenshot-quality"), S = e.getAttribute("data-screenshot-max-width"), E = e.getAttribute("data-screenshot-max-height"), J = e.getAttribute("data-capture-video"), G = e.getAttribute("data-hide-thumbs"), z = e.getAttribute("data-video-max-duration"), Z = e.getAttribute("data-screenshot-method"), Q = e.getAttribute("data-direction"), B = e.getAttribute("data-css-selector");
657
1031
  return {
658
1032
  endpoint: t,
659
- apiKey: W ?? void 0,
660
- captureScreenshot: U === "true" ? !0 : void 0,
661
- screenshotOptions: y || q || x ? {
662
- quality: y ? parseFloat(y) : void 0,
663
- maxWidth: q ? parseInt(q, 10) : void 0,
664
- maxHeight: x ? parseInt(x, 10) : void 0
1033
+ css: B ? _(B) : void 0,
1034
+ apiKey: K ?? void 0,
1035
+ captureScreenshot: Y === "true" ? !0 : void 0,
1036
+ screenshotOptions: C || S || E ? {
1037
+ quality: C ? parseFloat(C) : void 0,
1038
+ maxWidth: S ? parseInt(S, 10) : void 0,
1039
+ maxHeight: E ? parseInt(E, 10) : void 0
665
1040
  } : void 0,
666
1041
  container: l ?? void 0,
667
- buttonClass: r ?? void 0,
668
- position: e ?? void 0,
669
- zIndex: o ? parseInt(o, 10) : void 0,
670
- skipTargeting: c === "true" ? !0 : void 0,
671
- incognito: p === "true" ? !0 : void 0,
672
- buttonSize: g ?? void 0,
673
- offset: h || u ? {
674
- x: h ? parseInt(h, 10) : void 0,
675
- y: u ? parseInt(u, 10) : void 0
1042
+ buttonClass: d ?? void 0,
1043
+ direction: Q ?? void 0,
1044
+ position: o ?? void 0,
1045
+ zIndex: i ? parseInt(i, 10) : void 0,
1046
+ skipTargeting: r === "true" ? !0 : void 0,
1047
+ incognito: c === "true" ? !0 : void 0,
1048
+ buttonSize: u ?? void 0,
1049
+ offset: p || f ? {
1050
+ x: p ? parseInt(p, 10) : void 0,
1051
+ y: f ? parseInt(f, 10) : void 0
676
1052
  } : void 0,
677
- modalWidth: m ? parseInt(m, 10) : void 0,
678
- backdropOpacity: b ? parseFloat(b) : void 0,
679
- fontFamily: f ?? void 0,
1053
+ modalWidth: b ? parseInt(b, 10) : void 0,
1054
+ backdropOpacity: g ? parseFloat(g) : void 0,
1055
+ fontFamily: m ?? void 0,
680
1056
  fontSize: v ? parseInt(v, 10) : void 0,
681
1057
  colors: {
682
1058
  positive: n ?? void 0,
683
1059
  negative: a ?? void 0,
684
1060
  marker: s ?? void 0
685
1061
  },
686
- text: S || E || I || z || L || M || $ || A ? {
687
- tooltip: S ?? void 0,
688
- bannerText: E ?? void 0,
689
- bannerHint: I ?? void 0,
690
- modalTitle: z ?? void 0,
691
- modalSubtitle: L ?? void 0,
692
- placeholder: M ?? void 0,
693
- submitButton: $ ?? void 0,
694
- skipButton: A ?? void 0
1062
+ text: y || x || H || R || D || M ? {
1063
+ tooltip: y ?? void 0,
1064
+ modalTitle: x ?? void 0,
1065
+ modalSubtitle: H ?? void 0,
1066
+ placeholder: R ?? void 0,
1067
+ submitButton: D ?? void 0,
1068
+ skipButton: M ?? void 0
695
1069
  } : void 0,
696
- positiveIcon: N ?? void 0,
697
- negativeIcon: P ?? void 0
1070
+ positiveIcon: X ?? void 0,
1071
+ negativeIcon: j ?? void 0,
1072
+ screenshotMethod: Z ?? void 0,
1073
+ captureVideo: J === "true" ? !0 : void 0,
1074
+ hideThumbs: G === "true" ? !0 : void 0,
1075
+ videoOptions: z ? {
1076
+ maxDuration: parseInt(z, 10)
1077
+ } : void 0
698
1078
  };
699
1079
  }
700
1080
  if (typeof document < "u") {
701
- const i = () => {
702
- const t = document.currentScript, e = vt(), o = t ? yt(t) : null, n = e ?? o;
703
- n != null && n.endpoint && new bt(n);
1081
+ const e = () => {
1082
+ const t = document.currentScript, o = Wt(), i = t ? _t(t) : null, n = o ?? i;
1083
+ n != null && n.endpoint && new Ft(n);
704
1084
  };
705
- document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", i) : i();
1085
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", e) : e();
706
1086
  }
707
1087
  export {
708
- bt as FeedbackEmbed
1088
+ Ft as QaidFeedback,
1089
+ Vt as captureDomScreenshot,
1090
+ Rt as captureNetworkErrors,
1091
+ zt as createVideoRecorder,
1092
+ Mt as getSupportedMimeType,
1093
+ jt as isDomScreenshotSupported,
1094
+ Dt as isVideoRecordingSupported
709
1095
  };
710
1096
  //# sourceMappingURL=qaid.js.map