@firstlook-uat/sdk 0.4.0 โ†’ 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- const T = [
1
+ const I = [
2
2
  'input[type="password"]',
3
3
  "[data-sensitive]",
4
4
  "[data-mask]",
5
5
  ".uat-mask"
6
6
  ];
7
- function q(a) {
7
+ function M(a) {
8
8
  var t, e, s, i, n, o, l, c, h, d;
9
9
  if (!a.endpoint)
10
10
  throw new Error("[FirstLook] 'endpoint' is required. Set your Supabase ingest-session URL.");
@@ -23,7 +23,7 @@ function q(a) {
23
23
  },
24
24
  security: {
25
25
  watermark: ((n = a.security) == null ? void 0 : n.watermark) ?? !0,
26
- maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? T
26
+ maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? I
27
27
  },
28
28
  recording: {
29
29
  domSnapshot: ((l = a.recording) == null ? void 0 : l.domSnapshot) ?? !0,
@@ -33,7 +33,7 @@ function q(a) {
33
33
  }
34
34
  };
35
35
  }
36
- function w() {
36
+ function y() {
37
37
  return {
38
38
  userAgent: navigator.userAgent,
39
39
  platform: navigator.platform,
@@ -44,7 +44,7 @@ function w() {
44
44
  touchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0
45
45
  };
46
46
  }
47
- class C {
47
+ class E {
48
48
  constructor() {
49
49
  this.listeners = /* @__PURE__ */ new Map();
50
50
  }
@@ -75,7 +75,7 @@ class C {
75
75
  this.listeners.clear();
76
76
  }
77
77
  }
78
- class I {
78
+ class R {
79
79
  constructor(t) {
80
80
  this.events = t, this.quests = [], this.results = [], this.currentIndex = -1, this.sessionStartTime = 0, this.blocked = !1, this.pendingFeedbacks = [];
81
81
  }
@@ -116,15 +116,16 @@ class I {
116
116
  logs: t,
117
117
  comment: e == null ? void 0 : e.comment,
118
118
  concern: (e == null ? void 0 : e.concern) ?? !1,
119
- feedbacks: this.drainFeedbacks()
119
+ feedbacks: this.drainFeedbacks(),
120
+ checklist: e == null ? void 0 : e.checklist
120
121
  };
121
122
  return this.results.push(i), this.events.emit({ type: "quest:completed", questId: s.id }), this.advance(), i;
122
123
  }
123
- failCurrentQuest(t, e, s) {
124
- const i = this.getCurrentQuest();
125
- if (!i) return null;
126
- const n = {
127
- questId: i.id,
124
+ failCurrentQuest(t, e, s, i) {
125
+ const n = this.getCurrentQuest();
126
+ if (!n) return null;
127
+ const o = {
128
+ questId: n.id,
128
129
  status: "FAILED",
129
130
  timestamp: Date.now(),
130
131
  relativeTime: Date.now() - this.sessionStartTime,
@@ -132,9 +133,10 @@ class I {
132
133
  logs: t,
133
134
  comment: e,
134
135
  concern: !1,
135
- feedbacks: this.drainFeedbacks()
136
+ feedbacks: this.drainFeedbacks(),
137
+ checklist: i
136
138
  };
137
- return this.results.push(n), this.events.emit({ type: "quest:failed", questId: i.id }), i.blocking ? (this.blocked = !0, this.events.emit({ type: "quest:blocked", questId: i.id })) : this.advance(), n;
139
+ return this.results.push(o), this.events.emit({ type: "quest:failed", questId: n.id }), n.blocking ? (this.blocked = !0, this.events.emit({ type: "quest:blocked", questId: n.id })) : this.advance(), o;
138
140
  }
139
141
  addFeedback(t) {
140
142
  this.pendingFeedbacks.push(t);
@@ -160,16 +162,34 @@ function r(a, t, e) {
160
162
  typeof i == "string" ? s.appendChild(document.createTextNode(i)) : s.appendChild(i);
161
163
  return s;
162
164
  }
163
- function M() {
165
+ function L() {
164
166
  return `fl_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
165
167
  }
166
- function R(a) {
168
+ function A(a) {
167
169
  const t = Math.floor(a / 60), e = a % 60;
168
170
  return `${t.toString().padStart(2, "0")}:${e.toString().padStart(2, "0")}`;
169
171
  }
170
- class E {
172
+ function D(a) {
173
+ const t = a.split(`
174
+ `), e = [], s = [];
175
+ let i = !1;
176
+ for (const n of t) {
177
+ const o = n.trim(), l = o.match(/^(?:(\d+)[\.\)]\s+|[-*]\s+)(.+)$/);
178
+ l ? (i = !0, s.push({
179
+ index: s.length,
180
+ text: l[2],
181
+ checked: !1
182
+ })) : !i && o && e.push(o);
183
+ }
184
+ return {
185
+ preamble: e.join(`
186
+ `),
187
+ items: s
188
+ };
189
+ }
190
+ class N {
171
191
  constructor(t, e) {
172
- this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
192
+ this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.checklist = [], this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
173
193
  for (const s of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
174
194
  this.root.addEventListener(s, (i) => i.stopPropagation());
175
195
  this.shadowRoot.appendChild(this.root);
@@ -186,37 +206,54 @@ class E {
186
206
  this.root.appendChild(n);
187
207
  const o = r("div", { className: "fl-quest-content" }), l = r("div", { className: "fl-quest-progress" });
188
208
  for (const f of e) {
189
- const g = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
190
- l.appendChild(r("div", { className: `fl-quest-progress-dot ${g}` }));
209
+ const p = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
210
+ l.appendChild(r("div", { className: `fl-quest-progress-dot ${p}` }));
191
211
  }
192
- const c = r("div", { className: "fl-quest-body" }, [
193
- l,
194
- r("p", { className: "fl-quest-description" }, [t.description]),
195
- r("div", { className: "fl-quest-memo-row" }, [
196
- this.createButton("fl-btn fl-btn-memo", "๐Ÿ“ ใƒกใƒขใ‚’ๆฎ‹ใ™", () => this.renderFeedbackModal(t.title))
197
- ]),
198
- r("div", { className: "fl-quest-actions" }, [
199
- this.createButton("fl-btn fl-btn-ok", "โœ“ OK", () => this.renderFeedbackModal(t.title, "ok")),
200
- this.createButton("fl-btn fl-btn-concern", "โš  ๆฐ—ใซใชใ‚‹", () => this.renderFeedbackModal(t.title, "concern")),
201
- this.createButton("fl-btn fl-btn-ng", "โœ— NG", this.callbacks.onNg)
202
- ])
203
- ]);
204
- o.appendChild(c), s && o.appendChild(
212
+ const c = D(t.description);
213
+ this.checklist = c.items;
214
+ const h = r("div", { className: "fl-quest-body" });
215
+ if (h.appendChild(l), c.items.length > 0) {
216
+ const f = r("div", { className: "fl-checklist-counter" }), p = () => {
217
+ const b = this.checklist.filter((k) => k.checked).length;
218
+ f.textContent = `โœ“ ${b}/${this.checklist.length} ็ขบ่ชๆธˆใฟ`;
219
+ };
220
+ p(), h.appendChild(f), c.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [c.preamble]));
221
+ const m = r("ul", { className: "fl-checklist" });
222
+ for (const b of this.checklist) {
223
+ const k = r("li", { className: "fl-checklist-item" }), v = document.createElement("input");
224
+ v.type = "checkbox", v.className = "fl-checklist-checkbox", v.checked = b.checked;
225
+ const T = r("span", { className: "fl-checklist-text" }, [b.text]);
226
+ v.onchange = () => {
227
+ b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p();
228
+ }, k.onclick = (q) => {
229
+ q.target !== v && (v.checked = !v.checked, b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p());
230
+ }, k.appendChild(v), k.appendChild(T), m.appendChild(k);
231
+ }
232
+ h.appendChild(m);
233
+ } else
234
+ h.appendChild(r("p", { className: "fl-quest-description" }, [t.description]));
235
+ h.appendChild(r("div", { className: "fl-quest-memo-row" }, [
236
+ this.createButton("fl-btn fl-btn-memo", "๐Ÿ“ ใƒกใƒขใ‚’ๆฎ‹ใ™", () => this.renderFeedbackModal(t.title))
237
+ ])), h.appendChild(r("div", { className: "fl-quest-actions" }, [
238
+ this.createButton("fl-btn fl-btn-ok", "โœ“ OK", () => this.renderFeedbackModal(t.title, "ok")),
239
+ this.createButton("fl-btn fl-btn-concern", "โš  ๆฐ—ใซใชใ‚‹", () => this.renderFeedbackModal(t.title, "concern")),
240
+ this.createButton("fl-btn fl-btn-ng", "โœ— NG", this.callbacks.onNg)
241
+ ])), o.appendChild(h), s && o.appendChild(
205
242
  r("div", { className: "fl-voice-indicator" }, [
206
243
  r("span", { className: "fl-voice-dot" }),
207
244
  "Recording..."
208
245
  ])
209
246
  );
210
- const h = r("div", { className: "fl-status-bar" });
211
- s && h.appendChild(
247
+ const d = r("div", { className: "fl-status-bar" });
248
+ s && d.appendChild(
212
249
  r("span", { className: "fl-status-recording" }, [
213
250
  r("span", { className: "fl-voice-dot" }),
214
251
  "REC"
215
252
  ])
216
253
  );
217
- const d = r("span", { className: "fl-status-timer" }, ["00:00"]);
218
- h.appendChild(d), o.appendChild(h), this.root.appendChild(o), this.startTimer(d), this.root.onclick = () => {
219
- this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(d));
254
+ const g = r("span", { className: "fl-status-timer" }, ["00:00"]);
255
+ d.appendChild(g), o.appendChild(d), this.root.appendChild(o), this.startTimer(g), this.root.onclick = () => {
256
+ this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(g));
220
257
  };
221
258
  }
222
259
  renderFeedbackModal(t, e = "memo") {
@@ -249,11 +286,11 @@ class E {
249
286
  memo: "ๆฐ—ใฅใ„ใŸใ“ใจใ‚’ใƒกใƒข...๐Ÿ“"
250
287
  }, d = document.createElement("textarea");
251
288
  d.className = "fl-feedback-textarea fl-feedback-textarea-modal", d.placeholder = h[e], d.rows = 3, c.appendChild(d);
252
- const f = "้€ไฟก", g = e === "ok" ? "ใ‚นใ‚ญใƒƒใƒ—" : "ใ‚ญใƒฃใƒณใ‚ปใƒซ", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
253
- this.createButton("fl-btn fl-btn-skip", g, () => {
289
+ const g = "้€ไฟก", f = e === "ok" ? "ใ‚นใ‚ญใƒƒใƒ—" : "ใ‚ญใƒฃใƒณใ‚ปใƒซ", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
290
+ this.createButton("fl-btn fl-btn-skip", f, () => {
254
291
  e === "ng" ? this.callbacks.onNgWithFeedback("") : e === "ok" && this.callbacks.onOkWithFeedback(""), s.remove();
255
292
  }),
256
- this.createButton("fl-btn fl-btn-finish", f, () => {
293
+ this.createButton("fl-btn fl-btn-finish", g, () => {
257
294
  const m = d.value.trim();
258
295
  if (e === "ng")
259
296
  this.callbacks.onNgWithFeedback(m);
@@ -304,6 +341,9 @@ class E {
304
341
  ]);
305
342
  this.root.appendChild(e);
306
343
  }
344
+ getChecklist() {
345
+ return this.checklist.length > 0 ? [...this.checklist] : void 0;
346
+ }
307
347
  destroy() {
308
348
  this.stopTimer(), this.root.remove();
309
349
  }
@@ -330,15 +370,15 @@ class E {
330
370
  startTimer(t) {
331
371
  this.stopTimer(), this.startTime || (this.startTime = Date.now()), this.timerInterval = setInterval(() => {
332
372
  const e = Math.floor((Date.now() - this.startTime) / 1e3);
333
- t.textContent = R(e);
373
+ t.textContent = A(e);
334
374
  }, 1e3);
335
375
  }
336
376
  stopTimer() {
337
377
  this.timerInterval && (clearInterval(this.timerInterval), this.timerInterval = null);
338
378
  }
339
379
  }
340
- const L = 100, A = 2 * 1024 * 1024;
341
- class D {
380
+ const F = 100, P = 2 * 1024 * 1024;
381
+ class z {
342
382
  constructor(t, e, s) {
343
383
  this.config = t, this.events = e, this.maskSelector = s, this.actionLogs = [], this.snapshots = [], this.snapshotTimer = null, this.startTime = 0, this.running = !1, this.handleClick = this.onClick.bind(this), this.handleScroll = this.throttle(this.onScroll.bind(this), 500), this.handleInput = this.onInput.bind(this);
344
384
  }
@@ -405,8 +445,8 @@ class D {
405
445
  const s = t.querySelector("#firstlook-sdk-root");
406
446
  s == null || s.remove();
407
447
  const i = t.outerHTML;
408
- if (i.length > A) return;
409
- this.snapshots.length >= L && this.snapshots.shift(), this.snapshots.push({
448
+ if (i.length > P) return;
449
+ this.snapshots.length >= F && this.snapshots.shift(), this.snapshots.push({
410
450
  type: "dom-snapshot",
411
451
  timestamp: Date.now() - this.startTime,
412
452
  data: i
@@ -427,7 +467,7 @@ function x(a) {
427
467
  const t = a.tagName.toLowerCase(), e = a.id ? `#${a.id}` : "", s = a.className && typeof a.className == "string" ? `.${a.className.trim().split(/\s+/).slice(0, 2).join(".")}` : "", i = ((n = a.textContent) == null ? void 0 : n.trim().slice(0, 30)) || "";
428
468
  return `${t}${e}${s}${i ? ` "${i}"` : ""}`;
429
469
  }
430
- class N {
470
+ class O {
431
471
  constructor(t) {
432
472
  this.events = t, this.mediaRecorder = null, this.stream = null, this.chunks = [], this._recording = !1;
433
473
  }
@@ -486,7 +526,7 @@ class N {
486
526
  return "";
487
527
  }
488
528
  }
489
- class F {
529
+ class Q {
490
530
  constructor(t, e) {
491
531
  this.shadowRoot = t, this.config = e, this.container = null, this.refreshInterval = null, this.cachedIp = null;
492
532
  }
@@ -516,7 +556,7 @@ class F {
516
556
  }
517
557
  }
518
558
  }
519
- class P {
559
+ class B {
520
560
  constructor(t) {
521
561
  this.selectors = t, this.observer = null, this.maskedElements = /* @__PURE__ */ new Set();
522
562
  }
@@ -554,20 +594,20 @@ class P {
554
594
  }
555
595
  }
556
596
  }
557
- const z = "firstlook_uat", O = 1, u = {
597
+ const $ = "firstlook_uat", U = 1, u = {
558
598
  sessions: "sessions",
559
599
  recordings: "recordings",
560
600
  annotations: "annotations",
561
601
  uploadQueue: "upload_queue"
562
602
  };
563
- class Q {
603
+ class j {
564
604
  constructor() {
565
605
  this.db = null;
566
606
  }
567
607
  async open() {
568
608
  if (!this.db)
569
609
  return new Promise((t, e) => {
570
- const s = indexedDB.open(z, O);
610
+ const s = indexedDB.open($, U);
571
611
  s.onupgradeneeded = () => {
572
612
  const i = s.result;
573
613
  i.objectStoreNames.contains(u.sessions) || i.createObjectStore(u.sessions, { keyPath: "sessionId" }), i.objectStoreNames.contains(u.recordings) || i.createObjectStore(u.recordings, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.annotations) || i.createObjectStore(u.annotations, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.uploadQueue) || i.createObjectStore(u.uploadQueue, { autoIncrement: !0 });
@@ -677,10 +717,10 @@ class Q {
677
717
  });
678
718
  }
679
719
  }
680
- const y = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
681
- class B {
720
+ const S = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
721
+ class K {
682
722
  constructor(t) {
683
- this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = y[0], this.screenshotDataUrl = "";
723
+ this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = S[0], this.screenshotDataUrl = "";
684
724
  }
685
725
  async open() {
686
726
  return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((t) => {
@@ -692,7 +732,7 @@ class B {
692
732
  type: "text",
693
733
  placeholder: "Add a comment..."
694
734
  }), i = r("div", { className: "fl-color-picker" });
695
- for (const c of y) {
735
+ for (const c of S) {
696
736
  const h = r("div", { className: `fl-color-swatch ${c === this.selectedColor ? "fl-selected" : ""}` });
697
737
  h.style.background = c, h.onclick = () => {
698
738
  this.selectedColor = c, i.querySelectorAll(".fl-color-swatch").forEach((d) => d.classList.remove("fl-selected")), h.classList.add("fl-selected");
@@ -742,13 +782,13 @@ class B {
742
782
  <foreignObject width="100%" height="100%">
743
783
  ${l}
744
784
  </foreignObject>
745
- </svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), f = document.createElement("canvas");
746
- f.width = t * window.devicePixelRatio, f.height = e * window.devicePixelRatio;
747
- const g = f.getContext("2d");
748
- return g.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
785
+ </svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), g = document.createElement("canvas");
786
+ g.width = t * window.devicePixelRatio, g.height = e * window.devicePixelRatio;
787
+ const f = g.getContext("2d");
788
+ return f.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
749
789
  const m = new Image();
750
790
  m.onload = () => {
751
- g.drawImage(m, 0, 0, t, e), URL.revokeObjectURL(d), p(f.toDataURL("image/png"));
791
+ f.drawImage(m, 0, 0, t, e), URL.revokeObjectURL(d), p(g.toDataURL("image/png"));
752
792
  }, m.onerror = () => {
753
793
  URL.revokeObjectURL(d), p(this.captureScreenshotFallback(t, e));
754
794
  }, m.src = d;
@@ -796,11 +836,11 @@ class B {
796
836
  return ((t = this.canvas) == null ? void 0 : t.toDataURL("image/png")) || this.screenshotDataUrl;
797
837
  }
798
838
  }
799
- class U {
839
+ class H {
800
840
  constructor(t, e) {
801
841
  this.shadowRoot = t, this.events = e, this.annotations = [], this.active = !1, this.onKeydown = (s) => {
802
842
  s.ctrlKey && s.shiftKey && s.key === "R" && (s.preventDefault(), this.trigger());
803
- }, this.annotationCanvas = new B(t);
843
+ }, this.annotationCanvas = new K(t);
804
844
  }
805
845
  start() {
806
846
  document.addEventListener("keydown", this.onKeydown);
@@ -823,7 +863,7 @@ class U {
823
863
  }
824
864
  }
825
865
  }
826
- class j {
866
+ class _ {
827
867
  constructor(t, e) {
828
868
  this.requiredTaps = t, this.onActivate = e, this.tapCount = 0, this.tapTimer = null, this.handler = null;
829
869
  }
@@ -840,8 +880,8 @@ class j {
840
880
  this.tapCount = 0, this.tapTimer && (clearTimeout(this.tapTimer), this.tapTimer = null);
841
881
  }
842
882
  }
843
- const k = "firstlook:uat-active";
844
- class S {
883
+ const w = "firstlook:uat-active";
884
+ class C {
845
885
  constructor(t) {
846
886
  this.onActivate = t, this.handlers = [];
847
887
  }
@@ -866,7 +906,7 @@ class S {
866
906
  }
867
907
  static clearPersisted() {
868
908
  try {
869
- sessionStorage.removeItem(k);
909
+ sessionStorage.removeItem(w);
870
910
  } catch {
871
911
  }
872
912
  }
@@ -884,19 +924,19 @@ class S {
884
924
  }
885
925
  persist() {
886
926
  try {
887
- sessionStorage.setItem(k, "1");
927
+ sessionStorage.setItem(w, "1");
888
928
  } catch {
889
929
  }
890
930
  }
891
931
  hasPersisted() {
892
932
  try {
893
- return sessionStorage.getItem(k) === "1";
933
+ return sessionStorage.getItem(w) === "1";
894
934
  } catch {
895
935
  return !1;
896
936
  }
897
937
  }
898
938
  }
899
- class $ {
939
+ class W {
900
940
  constructor(t) {
901
941
  this.onActivate = t, this.handler = null;
902
942
  }
@@ -909,7 +949,7 @@ class $ {
909
949
  this.handler && (window.removeEventListener("keydown", this.handler), this.handler = null);
910
950
  }
911
951
  }
912
- class K {
952
+ class V {
913
953
  constructor(t, e) {
914
954
  this.shadowRoot = t, this.callbacks = e, this.root = null, this.outsideClickHandler = null;
915
955
  }
@@ -946,7 +986,7 @@ class K {
946
986
  return this.root !== null;
947
987
  }
948
988
  }
949
- const H = (
989
+ const X = (
950
990
  /* css */
951
991
  `
952
992
  :host {
@@ -1157,6 +1197,51 @@ const H = (
1157
1197
  50% { opacity: 0.3; }
1158
1198
  }
1159
1199
 
1200
+ /* === Checklist === */
1201
+ .fl-checklist-counter {
1202
+ font-size: 13px;
1203
+ font-weight: 600;
1204
+ color: #6c5ce7;
1205
+ margin-bottom: 8px;
1206
+ }
1207
+ .fl-checklist {
1208
+ list-style: none;
1209
+ padding: 0;
1210
+ margin: 0 0 12px;
1211
+ max-height: 240px;
1212
+ overflow-y: auto;
1213
+ -webkit-overflow-scrolling: touch;
1214
+ }
1215
+ .fl-checklist-item {
1216
+ display: flex;
1217
+ align-items: flex-start;
1218
+ gap: 8px;
1219
+ padding: 8px 4px;
1220
+ border-bottom: 1px solid rgba(0,0,0,.06);
1221
+ font-size: 13px;
1222
+ color: #4a4a5a;
1223
+ cursor: pointer;
1224
+ min-height: 40px;
1225
+ transition: background .2s;
1226
+ }
1227
+ .fl-checklist-item:last-child { border-bottom: none; }
1228
+ .fl-checklist-item:active { background: rgba(108,92,231,.05); }
1229
+ .fl-checklist-item.fl-checked { color: #aaa; }
1230
+ .fl-checklist-item.fl-checked .fl-checklist-text { text-decoration: line-through; }
1231
+ .fl-checklist-checkbox {
1232
+ margin-top: 2px;
1233
+ width: 18px;
1234
+ height: 18px;
1235
+ accent-color: #6c5ce7;
1236
+ flex-shrink: 0;
1237
+ cursor: pointer;
1238
+ }
1239
+ .fl-checklist-text {
1240
+ flex: 1;
1241
+ line-height: 1.4;
1242
+ word-break: break-word;
1243
+ }
1244
+
1160
1245
  /* === Annotation overlay === */
1161
1246
  .fl-annotation-overlay {
1162
1247
  position: fixed;
@@ -1402,10 +1487,10 @@ const H = (
1402
1487
  }
1403
1488
  .fl-feedback-modal-actions { padding: 0 16px 16px; }
1404
1489
  `
1405
- ), _ = 5;
1406
- class W {
1490
+ ), Y = 5;
1491
+ class G {
1407
1492
  constructor() {
1408
- this.config = null, this.events = new C(), this.state = "idle", this.hostElement = null, this.shadowRoot = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.watermark = null, this.fieldMasker = null, this.storage = null, this.issueReporter = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.sessionId = null, this.sessionStartTime = 0, this.maxDurationTimer = null, this.backupTimer = null, this.isFlushing = !1;
1493
+ this.config = null, this.events = new E(), this.state = "idle", this.hostElement = null, this.shadowRoot = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.watermark = null, this.fieldMasker = null, this.storage = null, this.issueReporter = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.sessionId = null, this.sessionStartTime = 0, this.maxDurationTimer = null, this.backupTimer = null, this.isFlushing = !1;
1409
1494
  }
1410
1495
  // ----------------------------------------------------------------
1411
1496
  // Public API
@@ -1419,7 +1504,7 @@ class W {
1419
1504
  console.warn("[FirstLook] SDK already initialized.");
1420
1505
  return;
1421
1506
  }
1422
- this.config = q(t), this.storage = new Q(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new P(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
1507
+ this.config = M(t), this.storage = new j(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new B(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
1423
1508
  }
1424
1509
  /**
1425
1510
  * Manually activate the SDK UI (bypassing triggers).
@@ -1438,11 +1523,11 @@ class W {
1438
1523
  var s;
1439
1524
  if (this.state !== "active")
1440
1525
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1441
- (s = this.debugMenu) == null || s.hide(), this.sessionId = M(), this.sessionStartTime = Date.now(), this.questManager = new I(this.events), this.questManager.loadQuests(t), this.sessionRecorder = new D(
1526
+ (s = this.debugMenu) == null || s.hide(), this.sessionId = L(), this.sessionStartTime = Date.now(), this.questManager = new R(this.events), this.questManager.loadQuests(t), this.sessionRecorder = new z(
1442
1527
  this.config,
1443
1528
  this.events,
1444
1529
  this.fieldMasker.getCombinedSelector()
1445
- ), this.voiceRecorder = new N(this.events), this.issueReporter = new U(this.shadowRoot, this.events), this.issueReporter.start(), this.sessionRecorder.start(), this.fieldMasker.start(), this.config.recording.voice && await this.voiceRecorder.start(), this.config.security.watermark && (this.watermark = new F(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new E(this.shadowRoot, {
1530
+ ), this.voiceRecorder = new O(this.events), this.issueReporter = new H(this.shadowRoot, this.events), this.issueReporter.start(), this.sessionRecorder.start(), this.fieldMasker.start(), this.config.recording.voice && await this.voiceRecorder.start(), this.config.security.watermark && (this.watermark = new Q(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new N(this.shadowRoot, {
1446
1531
  onOkWithFeedback: (i) => this.handleQuestOk(i),
1447
1532
  onConcern: (i) => this.handleConcern(i),
1448
1533
  onNg: () => this.handleQuestNg(),
@@ -1475,7 +1560,7 @@ class W {
1475
1560
  * End the current session, persist data, and trigger upload.
1476
1561
  */
1477
1562
  async endSession() {
1478
- var i, n, o, l, c, h, d, f, g, p, m;
1563
+ var i, n, o, l, c, h, d, g, f, p, m;
1479
1564
  if (this.state !== "recording" || !this.sessionId) return null;
1480
1565
  this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (i = this.sessionRecorder) == null || i.stop(), await ((n = this.voiceRecorder) == null ? void 0 : n.stopAsync()), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide();
1481
1566
  const t = this.questManager.getResults();
@@ -1489,13 +1574,13 @@ class W {
1489
1574
  delete b.voiceMemoBlob;
1490
1575
  }
1491
1576
  await Promise.allSettled(
1492
- b.feedbacks.map(async (v) => {
1493
- if (v.voiceMemoBlob) {
1577
+ b.feedbacks.map(async (k) => {
1578
+ if (k.voiceMemoBlob) {
1494
1579
  try {
1495
- v.voiceMemoBase64 = await this.blobToBase64(v.voiceMemoBlob);
1580
+ k.voiceMemoBase64 = await this.blobToBase64(k.voiceMemoBlob);
1496
1581
  } catch {
1497
1582
  }
1498
- delete v.voiceMemoBlob;
1583
+ delete k.voiceMemoBlob;
1499
1584
  }
1500
1585
  })
1501
1586
  );
@@ -1506,7 +1591,7 @@ class W {
1506
1591
  projectId: this.config.projectId,
1507
1592
  userId: this.config.userId,
1508
1593
  role: this.config.role,
1509
- deviceInfo: w(),
1594
+ deviceInfo: y(),
1510
1595
  startedAt: new Date(this.sessionStartTime).toISOString(),
1511
1596
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
1512
1597
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
@@ -1514,9 +1599,9 @@ class W {
1514
1599
  recordings: ((h = this.sessionRecorder) == null ? void 0 : h.getSnapshots()) ?? []
1515
1600
  };
1516
1601
  await ((d = this.storage) == null ? void 0 : d.saveSession(e));
1517
- const s = ((f = this.issueReporter) == null ? void 0 : f.getAnnotations()) ?? [];
1602
+ const s = ((g = this.issueReporter) == null ? void 0 : g.getAnnotations()) ?? [];
1518
1603
  for (const b of s)
1519
- await ((g = this.storage) == null ? void 0 : g.saveAnnotation(this.sessionId, b));
1604
+ await ((f = this.storage) == null ? void 0 : f.saveAnnotation(this.sessionId, b));
1520
1605
  return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: e, annotations: s })), (m = this.questOverlay) == null || m.destroy(), this.questOverlay = null, this.state = "finished", this.events.emit({ type: "session:ended", sessionId: this.sessionId }), this.flushUploadQueue(!1), e;
1521
1606
  }
1522
1607
  /**
@@ -1535,9 +1620,9 @@ class W {
1535
1620
  * Completely destroy the SDK instance and clean up all resources.
1536
1621
  */
1537
1622
  destroy() {
1538
- var t, e, s, i, n, o, l, c, h, d, f, g;
1539
- this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), S.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
1540
- }), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (f = this.hostElement) == null || f.remove(), (g = this.storage) == null || g.close(), this.events.removeAll(), this.config = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.issueReporter = null, this.fieldMasker = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.storage = null, this.hostElement = null, this.shadowRoot = null, this.sessionId = null, this.state = "idle";
1623
+ var t, e, s, i, n, o, l, c, h, d, g, f;
1624
+ this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), C.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
1625
+ }), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (g = this.hostElement) == null || g.remove(), (f = this.storage) == null || f.close(), this.events.removeAll(), this.config = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.issueReporter = null, this.fieldMasker = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.storage = null, this.hostElement = null, this.shadowRoot = null, this.sessionId = null, this.state = "idle";
1541
1626
  }
1542
1627
  // ----------------------------------------------------------------
1543
1628
  // Private methods
@@ -1546,15 +1631,15 @@ class W {
1546
1631
  var e;
1547
1632
  (e = document.getElementById("firstlook-sdk-root")) == null || e.remove(), this.hostElement = document.createElement("div"), this.hostElement.id = "firstlook-sdk-root", this.hostElement.style.cssText = "position:fixed;inset:0;z-index:2147483647;pointer-events:none;", document.body.appendChild(this.hostElement), this.shadowRoot = this.hostElement.attachShadow({ mode: "closed" });
1548
1633
  const t = document.createElement("style");
1549
- t.textContent = H, this.shadowRoot.appendChild(t);
1634
+ t.textContent = X, this.shadowRoot.appendChild(t);
1550
1635
  }
1551
1636
  setupTriggers() {
1552
1637
  const t = this.config.triggers;
1553
- this.tapTrigger = new j(t.tapCount, () => this.onActivate()), this.tapTrigger.start(), t.deepLink && (this.deepLinkTrigger = new S(() => this.onActivate()), this.deepLinkTrigger.start()), t.keyboard && (this.keyboardTrigger = new $(() => this.onActivate()), this.keyboardTrigger.start()), t.customCheck && t.customCheck() && this.onActivate();
1638
+ this.tapTrigger = new _(t.tapCount, () => this.onActivate()), this.tapTrigger.start(), t.deepLink && (this.deepLinkTrigger = new C(() => this.onActivate()), this.deepLinkTrigger.start()), t.keyboard && (this.keyboardTrigger = new W(() => this.onActivate()), this.keyboardTrigger.start()), t.customCheck && t.customCheck() && this.onActivate();
1554
1639
  }
1555
1640
  onActivate() {
1556
1641
  var t, e, s;
1557
- this.state === "initialized" && (this.state = "active", (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new K(this.shadowRoot, {
1642
+ this.state === "initialized" && (this.state = "active", (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new V(this.shadowRoot, {
1558
1643
  onStartSession: () => {
1559
1644
  this.events.emit({ type: "sdk:activated" });
1560
1645
  },
@@ -1568,18 +1653,22 @@ class W {
1568
1653
  }), this.debugMenu.show());
1569
1654
  }
1570
1655
  handleQuestOk(t) {
1656
+ var i;
1571
1657
  if (!this.questManager || !this.sessionRecorder) return;
1572
- const e = this.sessionRecorder.getActionLogs();
1658
+ const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1573
1659
  this.questManager.completeCurrentQuest(e, {
1574
- comment: t || void 0
1660
+ comment: t || void 0,
1661
+ checklist: s
1575
1662
  }), this.renderCurrentQuest();
1576
1663
  }
1577
1664
  handleConcern(t) {
1665
+ var i;
1578
1666
  if (!this.questManager || !this.sessionRecorder) return;
1579
- const e = this.sessionRecorder.getActionLogs();
1667
+ const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1580
1668
  this.questManager.completeCurrentQuest(e, {
1581
1669
  comment: t,
1582
- concern: !0
1670
+ concern: !0,
1671
+ checklist: s
1583
1672
  }), this.renderCurrentQuest();
1584
1673
  }
1585
1674
  handleQuestNg() {
@@ -1588,9 +1677,10 @@ class W {
1588
1677
  t && this.questOverlay.renderFeedbackModal(t.title, "ng");
1589
1678
  }
1590
1679
  handleNgFeedbackSubmit(t) {
1680
+ var i;
1591
1681
  if (!this.questManager || !this.sessionRecorder) return;
1592
- const e = this.sessionRecorder.getActionLogs();
1593
- this.questManager.failCurrentQuest(e, t || void 0), this.renderCurrentQuest();
1682
+ const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1683
+ this.questManager.failCurrentQuest(e, t || void 0, void 0, s), this.renderCurrentQuest();
1594
1684
  }
1595
1685
  handleMemo(t) {
1596
1686
  if (!this.questManager || !t) return;
@@ -1632,7 +1722,7 @@ class W {
1632
1722
  }
1633
1723
  const e = await this.storage.getPendingUploads();
1634
1724
  for (const s of e) {
1635
- if (s.attempts >= _) {
1725
+ if (s.attempts >= Y) {
1636
1726
  await this.storage.removeFromQueue(s.key);
1637
1727
  continue;
1638
1728
  }
@@ -1668,7 +1758,7 @@ class W {
1668
1758
  projectId: this.config.projectId,
1669
1759
  userId: this.config.userId,
1670
1760
  role: this.config.role,
1671
- deviceInfo: w(),
1761
+ deviceInfo: y(),
1672
1762
  startedAt: new Date(this.sessionStartTime).toISOString(),
1673
1763
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1674
1764
  quests: ((t = this.questManager) == null ? void 0 : t.getResults()) ?? [],
@@ -1686,6 +1776,6 @@ class W {
1686
1776
  }
1687
1777
  }
1688
1778
  export {
1689
- W as FirstLookSDK
1779
+ G as FirstLookSDK
1690
1780
  };
1691
1781
  //# sourceMappingURL=firstlook.es.js.map