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