@mahmulp/feedback-sdk 0.0.4 → 0.0.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/index.js CHANGED
@@ -316,11 +316,34 @@ var PopoverManager = class {
316
316
  });
317
317
  return el;
318
318
  }
319
+ /** True when a thread for this feedback is already open. */
320
+ isThreadOpenFor(feedbackId) {
321
+ return this.current?.type === "thread" && this.current.feedbackId === feedbackId;
322
+ }
319
323
  showThread(feedback, anchor, cb) {
324
+ if (this.current?.type === "thread" && this.current.feedbackId === feedback.id) {
325
+ const fresh = this.buildThread(feedback, cb);
326
+ this.current.el.replaceWith(fresh);
327
+ this.current = {
328
+ type: "thread",
329
+ el: fresh,
330
+ pageX: anchor.pageX,
331
+ pageY: anchor.pageY,
332
+ feedbackId: feedback.id
333
+ };
334
+ this.repositionInternal();
335
+ return fresh;
336
+ }
320
337
  this.hide();
321
338
  const el = this.buildThread(feedback, cb);
322
339
  this.layer.appendChild(el);
323
- this.current = { type: "thread", el, pageX: anchor.pageX, pageY: anchor.pageY };
340
+ this.current = {
341
+ type: "thread",
342
+ el,
343
+ pageX: anchor.pageX,
344
+ pageY: anchor.pageY,
345
+ feedbackId: feedback.id
346
+ };
324
347
  this.repositionInternal();
325
348
  return el;
326
349
  }
@@ -1028,33 +1051,65 @@ var Overlay = class {
1028
1051
  });
1029
1052
  }
1030
1053
  layoutPins() {
1031
- const next = document.createDocumentFragment();
1054
+ const existing = /* @__PURE__ */ new Map();
1055
+ for (const node of Array.from(this.pinLayer.children)) {
1056
+ const id = node.dataset.feedbackId;
1057
+ if (id) existing.set(id, node);
1058
+ }
1059
+ const desiredOrder = [];
1060
+ const seen = /* @__PURE__ */ new Set();
1032
1061
  for (const fb of this.pendingFeedback) {
1062
+ seen.add(fb.id);
1033
1063
  const target = findElement(fb.selector);
1034
1064
  const projected = projectCoordinates(target, fb.coordinates);
1035
- const pin = document.createElement("button");
1036
- pin.type = "button";
1037
- const classes = ["pin"];
1038
- if (projected.orphaned) classes.push("orphaned");
1039
- if (fb.status === "resolved") classes.push("resolved");
1040
- if (fb.status === "archived") classes.push("archived");
1041
- pin.className = classes.join(" ");
1042
- pin.setAttribute("data-feedback-id", fb.id);
1043
- pin.setAttribute("aria-label", `Feedback ${fb.id}`);
1044
- pin.style.left = `${projected.x - window.scrollX}px`;
1045
- pin.style.top = `${projected.y - window.scrollY}px`;
1046
- const label = document.createElement("span");
1047
- label.textContent = String(fb.thread.length || 1);
1048
- pin.appendChild(label);
1049
- pin.addEventListener("click", (e) => {
1050
- e.stopPropagation();
1051
- if (this.draggingPin === fb.id) return;
1052
- this.onPinClick?.(fb);
1053
- });
1054
- this.attachDragHandlers(pin, fb);
1055
- next.appendChild(pin);
1065
+ const left = `${projected.x - window.scrollX}px`;
1066
+ const top = `${projected.y - window.scrollY}px`;
1067
+ let pin = existing.get(fb.id);
1068
+ if (pin) {
1069
+ const classes = ["pin"];
1070
+ if (projected.orphaned) classes.push("orphaned");
1071
+ if (fb.status === "resolved") classes.push("resolved");
1072
+ if (fb.status === "archived") classes.push("archived");
1073
+ if (pin.classList.contains("dragging")) classes.push("dragging");
1074
+ pin.className = classes.join(" ");
1075
+ if (pin.style.left !== left) pin.style.left = left;
1076
+ if (pin.style.top !== top) pin.style.top = top;
1077
+ const label = pin.firstElementChild;
1078
+ const nextLabel = String(fb.thread.length || 1);
1079
+ if (label && label.textContent !== nextLabel) label.textContent = nextLabel;
1080
+ } else {
1081
+ pin = document.createElement("button");
1082
+ pin.type = "button";
1083
+ const classes = ["pin"];
1084
+ if (projected.orphaned) classes.push("orphaned");
1085
+ if (fb.status === "resolved") classes.push("resolved");
1086
+ if (fb.status === "archived") classes.push("archived");
1087
+ pin.className = classes.join(" ");
1088
+ pin.dataset.feedbackId = fb.id;
1089
+ pin.setAttribute("aria-label", `Feedback ${fb.id}`);
1090
+ pin.style.left = left;
1091
+ pin.style.top = top;
1092
+ const label = document.createElement("span");
1093
+ label.textContent = String(fb.thread.length || 1);
1094
+ pin.appendChild(label);
1095
+ pin.addEventListener("click", (e) => {
1096
+ e.stopPropagation();
1097
+ if (this.draggingPin === fb.id) return;
1098
+ const fresh = this.pendingFeedback.find((f) => f.id === fb.id) ?? fb;
1099
+ this.onPinClick?.(fresh);
1100
+ });
1101
+ this.attachDragHandlers(pin, fb);
1102
+ }
1103
+ desiredOrder.push(pin);
1104
+ }
1105
+ for (const [id, node] of existing) {
1106
+ if (!seen.has(id)) node.remove();
1107
+ }
1108
+ for (let i = 0; i < desiredOrder.length; i++) {
1109
+ const want = desiredOrder[i];
1110
+ const have = this.pinLayer.children[i];
1111
+ if (have !== want) this.pinLayer.insertBefore(want, have ?? null);
1056
1112
  }
1057
- this.pinLayer.replaceChildren(next);
1058
1113
  }
1059
1114
  destroy() {
1060
1115
  if (this.rafHandle !== null) {
@@ -1507,8 +1562,6 @@ function initFeedback(options) {
1507
1562
  const updated = await transport.reply(fb.id, { author, body });
1508
1563
  setAuthor(author);
1509
1564
  replaceFeedback(updated);
1510
- overlay.popoverManager().hide();
1511
- activeThreadId = null;
1512
1565
  openThread(updated);
1513
1566
  } catch (err) {
1514
1567
  reportError(err);
@@ -1518,8 +1571,6 @@ function initFeedback(options) {
1518
1571
  try {
1519
1572
  const updated = await transport.setStatus(fb.id, status);
1520
1573
  replaceFeedback(updated);
1521
- overlay.popoverManager().hide();
1522
- activeThreadId = null;
1523
1574
  openThread(updated);
1524
1575
  } catch (err) {
1525
1576
  reportError(err);