web-remarq 0.1.2 → 0.1.4

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
@@ -164,8 +164,17 @@ function getStableId(el) {
164
164
  return id;
165
165
  }
166
166
  function getTextContent(el) {
167
- var _a, _b;
168
- const text = (_b = (_a = el.textContent) == null ? void 0 : _a.trim()) != null ? _b : null;
167
+ var _a, _b, _c;
168
+ let text = "";
169
+ for (const node of Array.from(el.childNodes)) {
170
+ if (node.nodeType === Node.TEXT_NODE) {
171
+ text += (_a = node.textContent) != null ? _a : "";
172
+ }
173
+ }
174
+ text = text.trim();
175
+ if (!text && el.children.length <= 3) {
176
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
177
+ }
169
178
  if (!text) return null;
170
179
  return text.length > TEXT_MAX_LENGTH ? text.slice(0, TEXT_MAX_LENGTH) : text;
171
180
  }
@@ -454,7 +463,7 @@ var CSS = `
454
463
  .remarq-marker[data-status="resolved"] { background: var(--remarq-resolved); opacity: 0.7; }
455
464
 
456
465
  .remarq-popup {
457
- position: fixed;
466
+ position: absolute;
458
467
  z-index: 2147483647;
459
468
  width: 300px;
460
469
  background: var(--remarq-bg);
@@ -757,13 +766,13 @@ var Toolbar = class {
757
766
  this.exportMenu = document.createElement("div");
758
767
  this.exportMenu.className = "remarq-export-menu";
759
768
  const mdBtn = document.createElement("button");
760
- mdBtn.textContent = "Markdown (clipboard)";
769
+ mdBtn.textContent = "Markdown (file)";
761
770
  mdBtn.addEventListener("click", () => {
762
771
  this.callbacks.onExportMd();
763
772
  this.closeExportMenu();
764
773
  });
765
774
  const jsonBtn = document.createElement("button");
766
- jsonBtn.textContent = "JSON (file)";
775
+ jsonBtn.textContent = "JSON (clipboard)";
767
776
  jsonBtn.addEventListener("click", () => {
768
777
  this.callbacks.onExportJson();
769
778
  this.closeExportMenu();
@@ -796,7 +805,6 @@ var Overlay = class {
796
805
  container.appendChild(this.tooltipEl);
797
806
  }
798
807
  show(target) {
799
- var _a;
800
808
  try {
801
809
  const rect = target.getBoundingClientRect();
802
810
  this.overlayEl.style.display = "block";
@@ -804,13 +812,7 @@ var Overlay = class {
804
812
  this.overlayEl.style.left = `${rect.left}px`;
805
813
  this.overlayEl.style.width = `${rect.width}px`;
806
814
  this.overlayEl.style.height = `${rect.height}px`;
807
- const tag = target.tagName.toLowerCase();
808
- const text = ((_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) || "";
809
- const dataAnnotate = target.getAttribute("data-annotate");
810
- let label = `<${tag}>`;
811
- if (text) label += ` "${text}"`;
812
- if (dataAnnotate) label += ` [${dataAnnotate}]`;
813
- this.tooltipEl.textContent = label;
815
+ this.tooltipEl.textContent = describeElement(target);
814
816
  this.tooltipEl.style.display = "block";
815
817
  this.tooltipEl.style.top = `${rect.top - 28}px`;
816
818
  this.tooltipEl.style.left = `${rect.left}px`;
@@ -831,6 +833,43 @@ var Overlay = class {
831
833
  this.tooltipEl.remove();
832
834
  }
833
835
  };
836
+ function describeElement(el) {
837
+ const tag = el.tagName.toLowerCase();
838
+ const parts = [`<${tag}>`];
839
+ const dataAnnotate = el.getAttribute("data-annotate");
840
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
841
+ if (dataAnnotate) {
842
+ parts.push(`[${dataAnnotate}]`);
843
+ } else if (dataTestId) {
844
+ parts.push(`[${dataTestId}]`);
845
+ }
846
+ if (el.id) {
847
+ parts.push(`#${el.id}`);
848
+ }
849
+ const classes = Array.from(el.classList).filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/)).slice(0, 2);
850
+ if (classes.length) {
851
+ parts.push(`.${classes.join(".")}`);
852
+ }
853
+ const directText = getDirectText(el);
854
+ if (directText) {
855
+ parts.push(`"${directText}"`);
856
+ }
857
+ return parts.join(" ");
858
+ }
859
+ function getDirectText(el) {
860
+ var _a, _b, _c;
861
+ let text = "";
862
+ for (const node of Array.from(el.childNodes)) {
863
+ if (node.nodeType === Node.TEXT_NODE) {
864
+ text += (_a = node.textContent) != null ? _a : "";
865
+ }
866
+ }
867
+ text = text.trim();
868
+ if (!text && el.children.length <= 2) {
869
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
870
+ }
871
+ return text.slice(0, 30);
872
+ }
834
873
 
835
874
  // src/ui/popup.ts
836
875
  var POPUP_WIDTH = 300;
@@ -877,7 +916,10 @@ var Popup = class {
877
916
  popup2.appendChild(actions);
878
917
  this.container.appendChild(popup2);
879
918
  this.popupEl = popup2;
880
- this.adjustPosition(popup2, position);
919
+ requestAnimationFrame(() => {
920
+ this.adjustPosition(popup2, position);
921
+ textarea.focus();
922
+ });
881
923
  this.keyHandler = (e) => {
882
924
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
883
925
  const comment = textarea.value.trim();
@@ -891,7 +933,6 @@ var Popup = class {
891
933
  }
892
934
  };
893
935
  document.addEventListener("keydown", this.keyHandler);
894
- requestAnimationFrame(() => textarea.focus());
895
936
  }
896
937
  showDetail(info, position, callbacks) {
897
938
  this.hide();
@@ -934,7 +975,9 @@ var Popup = class {
934
975
  popup2.appendChild(actions);
935
976
  this.container.appendChild(popup2);
936
977
  this.popupEl = popup2;
937
- this.adjustPosition(popup2, position);
978
+ requestAnimationFrame(() => {
979
+ this.adjustPosition(popup2, position);
980
+ });
938
981
  this.keyHandler = (e) => {
939
982
  if (e.key === "Escape") {
940
983
  this.hide();
@@ -957,22 +1000,22 @@ var Popup = class {
957
1000
  this.hide();
958
1001
  }
959
1002
  adjustPosition(popup2, position) {
960
- const popupRect = popup2.getBoundingClientRect();
961
- const viewH = window.innerHeight;
962
- const viewW = window.innerWidth;
1003
+ const popupHeight = popup2.offsetHeight;
1004
+ const viewportBottom = window.scrollY + window.innerHeight;
1005
+ const viewportRight = window.scrollX + window.innerWidth;
963
1006
  let top = position.top;
964
1007
  let left = position.left;
965
- if (top + popupRect.height > viewH - POPUP_MARGIN) {
966
- top = position.top - popupRect.height - 16;
1008
+ if (top + popupHeight > viewportBottom - POPUP_MARGIN) {
1009
+ top = position.anchorBottom - popupHeight;
967
1010
  }
968
- if (top < POPUP_MARGIN) {
969
- top = POPUP_MARGIN;
1011
+ if (top < window.scrollY + POPUP_MARGIN) {
1012
+ top = window.scrollY + POPUP_MARGIN;
970
1013
  }
971
- if (left + POPUP_WIDTH > viewW - POPUP_MARGIN) {
972
- left = viewW - POPUP_WIDTH - POPUP_MARGIN;
1014
+ if (left + POPUP_WIDTH > viewportRight - POPUP_MARGIN) {
1015
+ left = viewportRight - POPUP_WIDTH - POPUP_MARGIN;
973
1016
  }
974
- if (left < POPUP_MARGIN) {
975
- left = POPUP_MARGIN;
1017
+ if (left < window.scrollX + POPUP_MARGIN) {
1018
+ left = window.scrollX + POPUP_MARGIN;
976
1019
  }
977
1020
  popup2.style.top = `${top}px`;
978
1021
  popup2.style.left = `${left}px`;
@@ -1175,6 +1218,25 @@ var mutationObserver = null;
1175
1218
  var unsubRoute = null;
1176
1219
  var refreshScheduled = false;
1177
1220
  var elementCache = /* @__PURE__ */ new Map();
1221
+ function describeTarget(el) {
1222
+ var _a, _b, _c, _d;
1223
+ const parts = [];
1224
+ if (el.id) parts.push(`#${el.id}`);
1225
+ const dataAnnotate = el.getAttribute((_a = options.dataAttribute) != null ? _a : "data-annotate");
1226
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
1227
+ if (dataAnnotate) parts.push(`[${dataAnnotate}]`);
1228
+ else if (dataTestId) parts.push(`[${dataTestId}]`);
1229
+ const classes = Array.from(el.classList).filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/)).slice(0, 2);
1230
+ if (classes.length) parts.push(`.${classes.join(".")}`);
1231
+ let text = "";
1232
+ for (const node of Array.from(el.childNodes)) {
1233
+ if (node.nodeType === Node.TEXT_NODE) text += (_b = node.textContent) != null ? _b : "";
1234
+ }
1235
+ text = text.trim();
1236
+ if (!text && el.children.length <= 2) text = (_d = (_c = el.textContent) == null ? void 0 : _c.trim()) != null ? _d : "";
1237
+ if (text) parts.push(`"${text.slice(0, 30)}"`);
1238
+ return parts.join(" ") || "";
1239
+ }
1178
1240
  function currentRoute() {
1179
1241
  return location.pathname + location.hash;
1180
1242
  }
@@ -1232,7 +1294,6 @@ function scheduleRefresh() {
1232
1294
  });
1233
1295
  }
1234
1296
  function handleInspectClick(e) {
1235
- var _a, _b;
1236
1297
  if (!inspecting) return;
1237
1298
  const target = e.target;
1238
1299
  if (!target || target.closest("[data-remarq-theme]")) return;
@@ -1244,11 +1305,12 @@ function handleInspectClick(e) {
1244
1305
  popup.show(
1245
1306
  {
1246
1307
  tag: target.tagName.toLowerCase(),
1247
- text: (_b = (_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) != null ? _b : ""
1308
+ text: describeTarget(target)
1248
1309
  },
1249
1310
  {
1250
- top: rect.bottom + 8,
1251
- left: rect.left
1311
+ top: window.scrollY + rect.bottom + 8,
1312
+ left: window.scrollX + rect.left,
1313
+ anchorBottom: window.scrollY + rect.top - 8
1252
1314
  },
1253
1315
  (comment) => {
1254
1316
  const fp = createFingerprint(target, {
@@ -1260,6 +1322,7 @@ function handleInspectClick(e) {
1260
1322
  comment,
1261
1323
  fingerprint: fp,
1262
1324
  route: currentRoute(),
1325
+ viewport: `${window.innerWidth}x${window.innerHeight}`,
1263
1326
  timestamp: Date.now(),
1264
1327
  status: "pending"
1265
1328
  };
@@ -1303,7 +1366,11 @@ function handleMarkerClick(annotationId) {
1303
1366
  comment: ann.comment,
1304
1367
  status: ann.status
1305
1368
  },
1306
- { top: rect.bottom + 8, left: rect.left },
1369
+ {
1370
+ top: window.scrollY + rect.bottom + 8,
1371
+ left: window.scrollX + rect.left,
1372
+ anchorBottom: window.scrollY + rect.top - 8
1373
+ },
1307
1374
  {
1308
1375
  onResolve: () => {
1309
1376
  storage.update(ann.id, { status: "resolved" });
@@ -1330,26 +1397,27 @@ function exportMarkdown() {
1330
1397
  if (fp.textContent) desc += ` "${fp.textContent}"`;
1331
1398
  if (fp.parentAnchor) desc += ` (${fp.parentAnchor})`;
1332
1399
  if (fp.dataAnnotate) desc += fp.parentAnchor ? ` > ${fp.dataAnnotate}` : ` (${fp.dataAnnotate})`;
1333
- lines.push(`${i + 1}. [${ann.status}] ${desc}: "${ann.comment}"`);
1400
+ const viewport = ann.viewport ? ` @${ann.viewport}` : "";
1401
+ lines.push(`${i + 1}. [${ann.status}]${viewport} ${desc}: "${ann.comment}"`);
1334
1402
  });
1335
1403
  const text = lines.join("\n");
1336
- try {
1337
- navigator.clipboard.writeText(text);
1338
- } catch (e) {
1339
- console.warn("[web-remarq] Clipboard write failed");
1340
- }
1341
- }
1342
- function exportJSON() {
1343
- const data = storage.exportJSON();
1344
- const json = JSON.stringify(data, null, 2);
1345
- const blob = new Blob([json], { type: "application/json" });
1404
+ const blob = new Blob([text], { type: "text/markdown" });
1346
1405
  const url = URL.createObjectURL(blob);
1347
1406
  const a = document.createElement("a");
1348
1407
  a.href = url;
1349
- a.download = `remarq-annotations-${Date.now()}.json`;
1408
+ a.download = `remarq-annotations-${Date.now()}.md`;
1350
1409
  a.click();
1351
1410
  URL.revokeObjectURL(url);
1352
1411
  }
1412
+ function exportJSON() {
1413
+ const data = storage.exportJSON();
1414
+ const json = JSON.stringify(data, null, 2);
1415
+ try {
1416
+ navigator.clipboard.writeText(json);
1417
+ } catch (e) {
1418
+ console.warn("[web-remarq] Clipboard write failed");
1419
+ }
1420
+ }
1353
1421
  function setupMutationObserver() {
1354
1422
  mutationObserver = new MutationObserver((mutations) => {
1355
1423
  for (const m of mutations) {