@impakers/debug 1.4.4 → 1.4.5

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/react.js CHANGED
@@ -1568,6 +1568,89 @@ function findNearestComponentSource(element, maxAncestors = 10) {
1568
1568
  return getSourceLocation(element);
1569
1569
  }
1570
1570
 
1571
+ // src/utils/capture-element.ts
1572
+ async function captureElement(el, options = {}) {
1573
+ const { quality = 0.7, maxScale = 2 } = options;
1574
+ const rect = el.getBoundingClientRect();
1575
+ const scale = Math.min(window.devicePixelRatio, maxScale);
1576
+ const canvas = document.createElement("canvas");
1577
+ canvas.width = rect.width * scale;
1578
+ canvas.height = rect.height * scale;
1579
+ const ctx = canvas.getContext("2d");
1580
+ ctx.scale(scale, scale);
1581
+ const clone = el.cloneNode(true);
1582
+ inlineComputedStyles(el, clone);
1583
+ clone.style.margin = "0";
1584
+ clone.style.position = "static";
1585
+ const serializer = new XMLSerializer();
1586
+ const html = serializer.serializeToString(clone);
1587
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${rect.width}" height="${rect.height}">
1588
+ <foreignObject width="100%" height="100%">
1589
+ <div xmlns="http://www.w3.org/1999/xhtml" style="width:${rect.width}px;height:${rect.height}px;overflow:hidden">${html}</div>
1590
+ </foreignObject>
1591
+ </svg>`;
1592
+ const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
1593
+ const url = URL.createObjectURL(blob);
1594
+ try {
1595
+ const img = await loadImage(url);
1596
+ ctx.drawImage(img, 0, 0, rect.width, rect.height);
1597
+ return canvas.toDataURL("image/jpeg", quality);
1598
+ } finally {
1599
+ URL.revokeObjectURL(url);
1600
+ }
1601
+ }
1602
+ async function captureFullPage(options = {}) {
1603
+ const { quality = 0.5, hideSelectors = [] } = options;
1604
+ const defaultSelectors = ["[data-impakers-debug]", "[data-annotation-popup]", "[data-annotation-marker]"];
1605
+ const allSelectors = [...defaultSelectors, ...hideSelectors];
1606
+ const hiddenEls = document.querySelectorAll(allSelectors.join(", "));
1607
+ try {
1608
+ hiddenEls.forEach((el) => el.style.visibility = "hidden");
1609
+ const html2canvas = (await import("html2canvas")).default;
1610
+ const canvas = await html2canvas(document.body, {
1611
+ useCORS: true,
1612
+ allowTaint: true,
1613
+ scale: 1,
1614
+ logging: false,
1615
+ width: window.innerWidth,
1616
+ height: window.innerHeight,
1617
+ onclone: (clonedDoc) => {
1618
+ const unsupported = /oklab|oklch|color-mix/i;
1619
+ clonedDoc.querySelectorAll("style").forEach((styleEl) => {
1620
+ if (unsupported.test(styleEl.textContent || "")) {
1621
+ styleEl.textContent = (styleEl.textContent || "").replace(
1622
+ /[^{};\n]+:\s*[^;{}]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;{}]*/gi,
1623
+ ""
1624
+ );
1625
+ }
1626
+ });
1627
+ }
1628
+ });
1629
+ return canvas.toDataURL("image/jpeg", quality);
1630
+ } catch {
1631
+ return void 0;
1632
+ } finally {
1633
+ hiddenEls.forEach((el) => el.style.visibility = "");
1634
+ }
1635
+ }
1636
+ function loadImage(src) {
1637
+ return new Promise((resolve, reject) => {
1638
+ const img = new Image();
1639
+ img.onload = () => resolve(img);
1640
+ img.onerror = () => reject(new Error("\uC774\uBBF8\uC9C0 \uB85C\uB4DC \uC2E4\uD328"));
1641
+ img.src = src;
1642
+ });
1643
+ }
1644
+ function inlineComputedStyles(src, dst) {
1645
+ const cs = window.getComputedStyle(src);
1646
+ dst.style.cssText = cs.cssText;
1647
+ const srcChildren = src.children;
1648
+ const dstChildren = dst.children;
1649
+ for (let i = 0; i < srcChildren.length && i < dstChildren.length; i++) {
1650
+ inlineComputedStyles(srcChildren[i], dstChildren[i]);
1651
+ }
1652
+ }
1653
+
1571
1654
  // src/core/collector.ts
1572
1655
  var MAX_ERRORS = 20;
1573
1656
  var MAX_LOGS = 50;
@@ -2098,23 +2181,6 @@ async function uploadFile(endpoint, file, context, taskId) {
2098
2181
  }
2099
2182
  return res.json();
2100
2183
  }
2101
- async function updateTaskStatus(endpoint, taskId, status) {
2102
- const snapshots = snapshotCaches("feedbacks:");
2103
- mutateMatchingCaches(
2104
- "feedbacks:",
2105
- (items) => items.map((item) => item.id === taskId ? { ...item, status } : item)
2106
- );
2107
- try {
2108
- await apiFetch(`${endpoint}/${taskId}/status`, {
2109
- method: "PATCH",
2110
- body: JSON.stringify({ status })
2111
- });
2112
- revalidateCachedFeedbackLists(endpoint);
2113
- } catch (error) {
2114
- restoreSnapshots(snapshots);
2115
- throw error;
2116
- }
2117
- }
2118
2184
 
2119
2185
  // src/core/sourcemap-resolver.ts
2120
2186
  var import_trace_mapping = require("@jridgewell/trace-mapping");
@@ -2225,6 +2291,7 @@ var styles_module_default2 = classNames2;
2225
2291
 
2226
2292
  // src/components/annotation-marker/index.tsx
2227
2293
  var import_jsx_runtime3 = require("react/jsx-runtime");
2294
+ var IN_PROGRESS_MARKER_COLOR = "#3b82f6";
2228
2295
  var DONE_MARKER_COLOR = "#9ca3af";
2229
2296
  function AnnotationMarker({
2230
2297
  annotation,
@@ -2238,7 +2305,8 @@ function AnnotationMarker({
2238
2305
  }) {
2239
2306
  const animClass = !isAnimated ? styles_module_default2.enter : "";
2240
2307
  const isDone = annotation.status === "done" || annotation.status === "resolved";
2241
- const markerColor = isDone ? DONE_MARKER_COLOR : accentColor;
2308
+ const isInProgress = annotation.status === "in_progress";
2309
+ const markerColor = isDone ? DONE_MARKER_COLOR : isInProgress ? IN_PROGRESS_MARKER_COLOR : accentColor;
2242
2310
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2243
2311
  "div",
2244
2312
  {
@@ -2341,8 +2409,7 @@ function CommentThread({
2341
2409
  top,
2342
2410
  bottom,
2343
2411
  onClose,
2344
- onReply,
2345
- onResolve
2412
+ onReply
2346
2413
  }) {
2347
2414
  const [replyText, setReplyText] = (0, import_react3.useState)("");
2348
2415
  const [exiting, setExiting] = (0, import_react3.useState)(false);
@@ -2436,25 +2503,7 @@ function CommentThread({
2436
2503
  cleanup();
2437
2504
  if (!targetEl) return;
2438
2505
  try {
2439
- const html2canvas = (await import("html2canvas")).default;
2440
- const canvas = await html2canvas(targetEl, {
2441
- useCORS: true,
2442
- allowTaint: true,
2443
- scale: Math.min(window.devicePixelRatio, 2),
2444
- logging: false,
2445
- onclone: (clonedDoc) => {
2446
- const unsupported = /oklab|oklch|color-mix|(?<![a-z])lch|(?<![a-z])lab/i;
2447
- clonedDoc.querySelectorAll("style").forEach((styleEl) => {
2448
- if (unsupported.test(styleEl.textContent || "")) {
2449
- styleEl.textContent = (styleEl.textContent || "").replace(
2450
- /[^{};\n]+:\s*[^;{}]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;{}]*/gi,
2451
- ""
2452
- );
2453
- }
2454
- });
2455
- }
2456
- });
2457
- const base64 = canvas.toDataURL("image/jpeg", 0.7);
2506
+ const base64 = await captureElement(targetEl);
2458
2507
  setPendingImage(base64);
2459
2508
  } catch (err) {
2460
2509
  console.error("[@impakers/debug] DOM \uC2A4\uD06C\uB9B0\uC0F7 \uC2E4\uD328:", err);
@@ -2515,10 +2564,7 @@ function CommentThread({
2515
2564
  ] }),
2516
2565
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: styles_module_default3.title, children: feedbackTitle })
2517
2566
  ] }),
2518
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: styles_module_default3.headerActions, children: [
2519
- onResolve && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.headerAction, onClick: () => onResolve(task.id), title: "\uC644\uB8CC \uCC98\uB9AC", type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "20 6 9 17 4 12" }) }) }),
2520
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.headerAction, onClick: handleClose, title: "\uB2EB\uAE30", type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) }) })
2521
- ] })
2567
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: styles_module_default3.headerActions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.headerAction, onClick: handleClose, title: "\uB2EB\uAE30", type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) }) }) })
2522
2568
  ] }),
2523
2569
  task.comments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2524
2570
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: styles_module_default3.divider }),
@@ -2942,11 +2988,10 @@ function InboxPanel({
2942
2988
  endpoint,
2943
2989
  currentUserName,
2944
2990
  currentUserId,
2945
- onClose,
2946
- onStatusChange
2991
+ onClose
2947
2992
  }) {
2948
2993
  const [tab, setTab] = (0, import_react5.useState)("page");
2949
- const [statusFilter, setStatusFilter] = (0, import_react5.useState)("open");
2994
+ const [statusFilter, setStatusFilter] = (0, import_react5.useState)("todo");
2950
2995
  const [exiting, setExiting] = (0, import_react5.useState)(false);
2951
2996
  const [selectedItem, setSelectedItem] = (0, import_react5.useState)(null);
2952
2997
  const [comments, setComments] = (0, import_react5.useState)([]);
@@ -3021,17 +3066,11 @@ function InboxPanel({
3021
3066
  }
3022
3067
  if (e.key === "Escape") handleClose();
3023
3068
  }, [handleSendReply, handleClose]);
3024
- const handleToggleStatus = (0, import_react5.useCallback)((item, e) => {
3025
- e.stopPropagation();
3026
- const newStatus = item.status === "done" ? "todo" : "done";
3027
- onStatusChange?.(item.id, newStatus);
3028
- }, [onStatusChange]);
3029
3069
  const rawItems = tab === "page" ? pageItems : allItems;
3030
- const items = rawItems.filter(
3031
- (item) => statusFilter === "resolved" ? item.status === "done" : item.status !== "done"
3032
- );
3033
- const openCount = rawItems.filter((item) => item.status !== "done").length;
3034
- const resolvedCount = rawItems.filter((item) => item.status === "done").length;
3070
+ const items = rawItems.filter((item) => item.status === statusFilter);
3071
+ const todoCount = rawItems.filter((item) => item.status === "todo").length;
3072
+ const inProgressCount = rawItems.filter((item) => item.status === "in_progress").length;
3073
+ const doneCount = rawItems.filter((item) => item.status === "done").length;
3035
3074
  if (typeof document === "undefined") return null;
3036
3075
  return (0, import_react_dom.createPortal)(
3037
3076
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-impakers-debug": "", children: [
@@ -3154,24 +3193,36 @@ function InboxPanel({
3154
3193
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3155
3194
  "button",
3156
3195
  {
3157
- className: `${styles_module_default5.filterChip} ${statusFilter === "open" ? styles_module_default5.active : ""}`,
3158
- onClick: () => setStatusFilter("open"),
3196
+ className: `${styles_module_default5.filterChip} ${statusFilter === "todo" ? styles_module_default5.active : ""}`,
3197
+ onClick: () => setStatusFilter("todo"),
3198
+ type: "button",
3199
+ children: [
3200
+ "\uC9C4\uD589\uC804",
3201
+ todoCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filterCount, children: todoCount })
3202
+ ]
3203
+ }
3204
+ ),
3205
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3206
+ "button",
3207
+ {
3208
+ className: `${styles_module_default5.filterChip} ${statusFilter === "in_progress" ? styles_module_default5.active : ""}`,
3209
+ onClick: () => setStatusFilter("in_progress"),
3159
3210
  type: "button",
3160
3211
  children: [
3161
- "Open",
3162
- openCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filterCount, children: openCount })
3212
+ "\uC9C4\uD589\uC911",
3213
+ inProgressCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filterCount, children: inProgressCount })
3163
3214
  ]
3164
3215
  }
3165
3216
  ),
3166
3217
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3167
3218
  "button",
3168
3219
  {
3169
- className: `${styles_module_default5.filterChip} ${statusFilter === "resolved" ? styles_module_default5.active : ""}`,
3170
- onClick: () => setStatusFilter("resolved"),
3220
+ className: `${styles_module_default5.filterChip} ${statusFilter === "done" ? styles_module_default5.active : ""}`,
3221
+ onClick: () => setStatusFilter("done"),
3171
3222
  type: "button",
3172
3223
  children: [
3173
- "Resolved",
3174
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filterCount, children: resolvedCount })
3224
+ "\uC644\uB8CC",
3225
+ doneCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filterCount, children: doneCount })
3175
3226
  ]
3176
3227
  }
3177
3228
  )
@@ -3185,17 +3236,7 @@ function InboxPanel({
3185
3236
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: styles_module_default5.cardInfo, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: styles_module_default5.cardMeta, children: [
3186
3237
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.cardAuthor, children: item.authorName }),
3187
3238
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.cardTime, children: timeAgo2(item.createdAt) })
3188
- ] }) }),
3189
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3190
- "button",
3191
- {
3192
- className: `${styles_module_default5.checkBtn} ${item.status === "done" ? styles_module_default5.checked : ""}`,
3193
- onClick: (e) => handleToggleStatus(item, e),
3194
- type: "button",
3195
- title: item.status === "done" ? "\uBBF8\uC644\uB8CC\uB85C \uBCC0\uACBD" : "\uC644\uB8CC \uCC98\uB9AC",
3196
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "20 6 9 17 4 12" }) })
3197
- }
3198
- )
3239
+ ] }) })
3199
3240
  ] }),
3200
3241
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: styles_module_default5.cardTitle, children: item.title.replace(/^\[피드백\]\s*/, "") }),
3201
3242
  item.screenshot && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: styles_module_default5.cardScreenshot, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: item.screenshot, alt: "screenshot" }) }),
@@ -3700,35 +3741,7 @@ function DebugWidget({ endpoint, getUser, onHide }) {
3700
3741
  setSubmitting(true);
3701
3742
  try {
3702
3743
  const metadata = collectMetadata(getUser);
3703
- let screenshot;
3704
- const debugEls = document.querySelectorAll("[data-impakers-debug], [data-annotation-popup], [data-annotation-marker]");
3705
- try {
3706
- debugEls.forEach((el) => el.style.visibility = "hidden");
3707
- const html2canvas = (await import("html2canvas")).default;
3708
- const canvas = await html2canvas(document.body, {
3709
- useCORS: true,
3710
- allowTaint: true,
3711
- scale: 1,
3712
- logging: false,
3713
- width: window.innerWidth,
3714
- height: window.innerHeight,
3715
- onclone: (clonedDoc) => {
3716
- const unsupported = /oklab|oklch|color-mix|(?<![a-z])lch|(?<![a-z])lab/i;
3717
- clonedDoc.querySelectorAll("style").forEach((styleEl) => {
3718
- if (unsupported.test(styleEl.textContent || "")) {
3719
- styleEl.textContent = (styleEl.textContent || "").replace(
3720
- /[^{};\n]+:\s*[^;{}]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;{}]*/gi,
3721
- ""
3722
- );
3723
- }
3724
- });
3725
- }
3726
- });
3727
- screenshot = canvas.toDataURL("image/jpeg", 0.5);
3728
- } catch {
3729
- } finally {
3730
- debugEls.forEach((el) => el.style.visibility = "");
3731
- }
3744
+ const screenshot = await captureFullPage();
3732
3745
  let resolvedSource = pendingAnnotation.resolvedSource || pendingAnnotation.sourceFile || "";
3733
3746
  let resolvedName = pendingAnnotation.resolvedName || null;
3734
3747
  if (!pendingAnnotation.resolvedSource && pendingAnnotation.sourceFile?.includes("/chunks/")) {
@@ -3801,7 +3814,8 @@ ${elementInfo.join("\n")}`);
3801
3814
  isFixed: pendingAnnotation.isFixed || false,
3802
3815
  element: pendingAnnotation.element,
3803
3816
  boundingBox: pendingAnnotation.boundingBox
3804
- }
3817
+ },
3818
+ authorName: getUser?.()?.name ? String(getUser().name) : void 0
3805
3819
  });
3806
3820
  setShowToast(true);
3807
3821
  originalSetTimeout(() => setShowToast(false), 3e3);
@@ -3970,7 +3984,7 @@ ${elementInfo.join("\n")}`);
3970
3984
  title: task.title || "\uD53C\uB4DC\uBC31",
3971
3985
  status: task.status,
3972
3986
  priority: task.priority,
3973
- authorName: getUser?.()?.name ? String(getUser().name) : "\uC775\uBA85",
3987
+ authorName: task.authorName || "\uC775\uBA85",
3974
3988
  feedbackUrl: task.feedbackUrl || currentPath,
3975
3989
  createdAt: task.createdAt,
3976
3990
  commentCount: task.commentCount || 0
@@ -4022,14 +4036,7 @@ ${elementInfo.join("\n")}`);
4022
4036
  endpoint,
4023
4037
  currentUserName: getUser?.()?.name ? String(getUser().name) : "\uC775\uBA85",
4024
4038
  currentUserId: getUser?.()?.id ? String(getUser().id) : void 0,
4025
- onClose: () => setShowInbox(false),
4026
- onStatusChange: async (taskId, status) => {
4027
- try {
4028
- await updateTaskStatus(endpoint, taskId, status);
4029
- } catch (err) {
4030
- console.error("[@impakers/debug] \uC0C1\uD0DC \uBCC0\uACBD \uC2E4\uD328:", err);
4031
- }
4032
- }
4039
+ onClose: () => setShowInbox(false)
4033
4040
  }
4034
4041
  ),
4035
4042
  showSettings && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(