@unhingged/vizu-core 0.1.22 → 0.2.0

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/internal.cjs CHANGED
@@ -9,9 +9,9 @@ var __export = (target, all) => {
9
9
  };
10
10
  var __copyProps = (to, from, except, desc) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ for (let key2 of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key2) && key2 !== except)
14
+ __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
15
15
  }
16
16
  return to;
17
17
  };
@@ -21,6 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var internal_exports = {};
22
22
  __export(internal_exports, {
23
23
  Highlighter: () => Highlighter,
24
+ InMemoryStorageAdapter: () => InMemoryStorageAdapter,
25
+ LocalStorageAdapter: () => LocalStorageAdapter,
26
+ NullStorageAdapter: () => NullStorageAdapter,
24
27
  Pill: () => Pill,
25
28
  Popover: () => Popover,
26
29
  Sidebar: () => Sidebar,
@@ -28,6 +31,9 @@ __export(internal_exports, {
28
31
  });
29
32
  module.exports = __toCommonJS(internal_exports);
30
33
 
34
+ // src/types.ts
35
+ var SCHEMA_VERSION = 2;
36
+
31
37
  // src/util.ts
32
38
  function isInside(target, selector) {
33
39
  return !!target.closest(selector);
@@ -104,6 +110,41 @@ function renderAttachmentsHtml(attachments) {
104
110
  }).join("");
105
111
  return `<div class="vz-attachment-grid">${items}</div>`;
106
112
  }
113
+ function migrateComment(raw) {
114
+ if (!raw || typeof raw !== "object") return raw;
115
+ const next = { ...raw };
116
+ if (next.id == null && next._id != null) {
117
+ next.id = next._id;
118
+ }
119
+ if (!Array.isArray(next.fingerprints) || next.fingerprints.length === 0) {
120
+ if (next.fingerprint) {
121
+ next.fingerprints = [next.fingerprint];
122
+ }
123
+ }
124
+ delete next.fingerprint;
125
+ if (next.url && !next.pageUrl) {
126
+ next.pageUrl = next.url;
127
+ }
128
+ if (!("status" in next) || !isValidStatus(next.status)) next.status = "open";
129
+ if (!Array.isArray(next.replies)) next.replies = [];
130
+ if (!Array.isArray(next.attachments)) next.attachments = [];
131
+ if (!Array.isArray(next.mentions)) next.mentions = [];
132
+ if (!("fingerprintsRefreshedAt" in next)) next.fingerprintsRefreshedAt = null;
133
+ next.schemaVersion = SCHEMA_VERSION;
134
+ return next;
135
+ }
136
+ function isValidStatus(s) {
137
+ return s === "open" || s === "resolved" || s === "wontfix";
138
+ }
139
+ function migrateComments(raws) {
140
+ if (!Array.isArray(raws)) return [];
141
+ const out = [];
142
+ for (const raw of raws) {
143
+ if (!raw || typeof raw !== "object") continue;
144
+ out.push(migrateComment(raw));
145
+ }
146
+ return out;
147
+ }
107
148
 
108
149
  // src/pill.ts
109
150
  var Pill = class {
@@ -418,8 +459,8 @@ var Popover = class {
418
459
  const removeBtn = target.closest('[data-vz="remove-anchor"]');
419
460
  if (removeBtn) {
420
461
  e.stopPropagation();
421
- const key = removeBtn.getAttribute("data-fp-key");
422
- if (key) this.removeAnchor(key);
462
+ const key2 = removeBtn.getAttribute("data-fp-key");
463
+ if (key2) this.removeAnchor(key2);
423
464
  return;
424
465
  }
425
466
  const refEl = target.closest('[data-vz="ref"]');
@@ -514,8 +555,8 @@ var Popover = class {
514
555
  }
515
556
  /** Add another anchor to the in-progress comment (Shift+Click flow). */
516
557
  addAnchor(fp, target) {
517
- const key = fingerprintKey(fp);
518
- if (this.anchorFingerprints.some((x) => fingerprintKey(x) === key)) return false;
558
+ const key2 = fingerprintKey(fp);
559
+ if (this.anchorFingerprints.some((x) => fingerprintKey(x) === key2)) return false;
519
560
  this.anchorFingerprints.push(fp);
520
561
  if (target) this.anchorTargets.push(target);
521
562
  this.callbacks.onAnchorsChanged([...this.anchorFingerprints]);
@@ -524,9 +565,9 @@ var Popover = class {
524
565
  return true;
525
566
  }
526
567
  /** Remove an anchor by fingerprint key. Never removes the last anchor. */
527
- removeAnchor(key) {
568
+ removeAnchor(key2) {
528
569
  if (this.anchorFingerprints.length <= 1) return false;
529
- const idx = this.anchorFingerprints.findIndex((x) => fingerprintKey(x) === key);
570
+ const idx = this.anchorFingerprints.findIndex((x) => fingerprintKey(x) === key2);
530
571
  if (idx < 0) return false;
531
572
  this.anchorFingerprints.splice(idx, 1);
532
573
  this.anchorTargets.splice(idx, 1);
@@ -636,9 +677,9 @@ var Popover = class {
636
677
  return;
637
678
  }
638
679
  const chips = this.anchorFingerprints.map((fp) => {
639
- const key = fingerprintKey(fp);
680
+ const key2 = fingerprintKey(fp);
640
681
  const label = fingerprintLabel(fp);
641
- return `<span class="vz-anchor-chip" data-fp-key="${escapeHtml(key)}">${escapeHtml(label)}<button class="vz-anchor-chip-remove" data-vz="remove-anchor" data-fp-key="${escapeHtml(key)}" aria-label="Remove anchor">\xD7</button></span>`;
682
+ return `<span class="vz-anchor-chip" data-fp-key="${escapeHtml(key2)}">${escapeHtml(label)}<button class="vz-anchor-chip-remove" data-vz="remove-anchor" data-fp-key="${escapeHtml(key2)}" aria-label="Remove anchor">\xD7</button></span>`;
642
683
  }).join("");
643
684
  wrap.innerHTML = `
644
685
  <div class="vz-anchor-hint">Anchored to ${this.anchorFingerprints.length} elements:</div>
@@ -1359,10 +1400,10 @@ var Sidebar = class {
1359
1400
  const fps = c.fingerprints || [];
1360
1401
  const primary = fps[0];
1361
1402
  if (!primary) continue;
1362
- const key = fingerprintKey(primary);
1363
- const g = groups.get(key);
1403
+ const key2 = fingerprintKey(primary);
1404
+ const g = groups.get(key2);
1364
1405
  if (g) g.comments.push(c);
1365
- else groups.set(key, { fp: primary, comments: [c] });
1406
+ else groups.set(key2, { fp: primary, comments: [c] });
1366
1407
  }
1367
1408
  const groupHtml = [];
1368
1409
  let gi = 0;
@@ -1423,8 +1464,8 @@ var Sidebar = class {
1423
1464
  }
1424
1465
  const chips = this.el.querySelectorAll('[data-vz="jump-fp"]');
1425
1466
  for (const chip of chips) {
1426
- const key = chip.getAttribute("data-fp-key");
1427
- const fp = findFingerprintByKey(visible, key || "");
1467
+ const key2 = chip.getAttribute("data-fp-key");
1468
+ const fp = findFingerprintByKey(visible, key2 || "");
1428
1469
  chip.__fp = fp;
1429
1470
  }
1430
1471
  }
@@ -1512,10 +1553,10 @@ function renderOrphansHtml(orphans) {
1512
1553
  </div>
1513
1554
  `;
1514
1555
  }
1515
- function findFingerprintByKey(comments, key) {
1556
+ function findFingerprintByKey(comments, key2) {
1516
1557
  for (const c of comments) {
1517
1558
  for (const fp of c.fingerprints || []) {
1518
- if (fingerprintKey(fp) === key) return fp;
1559
+ if (fingerprintKey(fp) === key2) return fp;
1519
1560
  }
1520
1561
  }
1521
1562
  return null;
@@ -2547,9 +2588,155 @@ function injectStyles() {
2547
2588
  style.textContent = STYLES;
2548
2589
  (document.head || document.documentElement).appendChild(style);
2549
2590
  }
2591
+
2592
+ // src/storage.ts
2593
+ var key = (ns) => `vizu:comments:${ns}`;
2594
+ var LocalStorageAdapter = class {
2595
+ async load(namespace) {
2596
+ return readArray(namespace);
2597
+ }
2598
+ async addComment(namespace, comment) {
2599
+ const list = readArray(namespace);
2600
+ list.push(comment);
2601
+ writeArray(namespace, list);
2602
+ }
2603
+ async updateComment(namespace, id, patch) {
2604
+ const list = readArray(namespace);
2605
+ const idx = list.findIndex((c) => c.id === id);
2606
+ if (idx === -1) return null;
2607
+ const next = { ...list[idx], ...patch, id: list[idx].id };
2608
+ list[idx] = next;
2609
+ writeArray(namespace, list);
2610
+ return next;
2611
+ }
2612
+ async removeComment(namespace, id) {
2613
+ const list = readArray(namespace);
2614
+ writeArray(namespace, list.filter((c) => c.id !== id));
2615
+ }
2616
+ async setAll(namespace, comments) {
2617
+ writeArray(namespace, comments);
2618
+ }
2619
+ async clear(namespace) {
2620
+ if (typeof localStorage === "undefined") return;
2621
+ localStorage.removeItem(key(namespace));
2622
+ }
2623
+ async addReply(namespace, commentId, reply) {
2624
+ const list = readArray(namespace);
2625
+ const idx = list.findIndex((c) => c.id === commentId);
2626
+ if (idx === -1) return null;
2627
+ const next = { ...list[idx], replies: [...list[idx].replies ?? [], reply] };
2628
+ list[idx] = next;
2629
+ writeArray(namespace, list);
2630
+ return next;
2631
+ }
2632
+ async removeReply(namespace, commentId, replyId) {
2633
+ const list = readArray(namespace);
2634
+ const idx = list.findIndex((c) => c.id === commentId);
2635
+ if (idx === -1) return null;
2636
+ const next = {
2637
+ ...list[idx],
2638
+ replies: (list[idx].replies ?? []).filter((r) => r.id !== replyId)
2639
+ };
2640
+ list[idx] = next;
2641
+ writeArray(namespace, list);
2642
+ return next;
2643
+ }
2644
+ };
2645
+ function readArray(namespace) {
2646
+ if (typeof localStorage === "undefined") return [];
2647
+ const raw = localStorage.getItem(key(namespace));
2648
+ if (!raw) return [];
2649
+ try {
2650
+ const parsed = JSON.parse(raw);
2651
+ return Array.isArray(parsed) ? migrateComments(parsed) : [];
2652
+ } catch {
2653
+ return [];
2654
+ }
2655
+ }
2656
+ function writeArray(namespace, comments) {
2657
+ if (typeof localStorage === "undefined") return;
2658
+ localStorage.setItem(key(namespace), JSON.stringify(comments));
2659
+ }
2660
+ var InMemoryStorageAdapter = class {
2661
+ constructor() {
2662
+ this.store = /* @__PURE__ */ new Map();
2663
+ }
2664
+ async load(namespace) {
2665
+ return [...this.store.get(namespace) || []];
2666
+ }
2667
+ async addComment(namespace, comment) {
2668
+ const list = this.store.get(namespace) ?? [];
2669
+ this.store.set(namespace, [...list, comment]);
2670
+ }
2671
+ async updateComment(namespace, id, patch) {
2672
+ const list = this.store.get(namespace) ?? [];
2673
+ const idx = list.findIndex((c) => c.id === id);
2674
+ if (idx === -1) return null;
2675
+ const next = { ...list[idx], ...patch, id: list[idx].id };
2676
+ const copy = [...list];
2677
+ copy[idx] = next;
2678
+ this.store.set(namespace, copy);
2679
+ return next;
2680
+ }
2681
+ async removeComment(namespace, id) {
2682
+ const list = this.store.get(namespace) ?? [];
2683
+ this.store.set(
2684
+ namespace,
2685
+ list.filter((c) => c.id !== id)
2686
+ );
2687
+ }
2688
+ async setAll(namespace, comments) {
2689
+ this.store.set(namespace, [...comments]);
2690
+ }
2691
+ async clear(namespace) {
2692
+ this.store.delete(namespace);
2693
+ }
2694
+ async addReply(namespace, commentId, reply) {
2695
+ const list = this.store.get(namespace) ?? [];
2696
+ const idx = list.findIndex((c) => c.id === commentId);
2697
+ if (idx === -1) return null;
2698
+ const next = { ...list[idx], replies: [...list[idx].replies ?? [], reply] };
2699
+ const copy = [...list];
2700
+ copy[idx] = next;
2701
+ this.store.set(namespace, copy);
2702
+ return next;
2703
+ }
2704
+ async removeReply(namespace, commentId, replyId) {
2705
+ const list = this.store.get(namespace) ?? [];
2706
+ const idx = list.findIndex((c) => c.id === commentId);
2707
+ if (idx === -1) return null;
2708
+ const next = {
2709
+ ...list[idx],
2710
+ replies: (list[idx].replies ?? []).filter((r) => r.id !== replyId)
2711
+ };
2712
+ const copy = [...list];
2713
+ copy[idx] = next;
2714
+ this.store.set(namespace, copy);
2715
+ return next;
2716
+ }
2717
+ };
2718
+ var NullStorageAdapter = class {
2719
+ async load() {
2720
+ return [];
2721
+ }
2722
+ async addComment() {
2723
+ }
2724
+ async updateComment() {
2725
+ return null;
2726
+ }
2727
+ async removeComment() {
2728
+ }
2729
+ async setAll() {
2730
+ }
2731
+ async clear() {
2732
+ }
2733
+ };
2550
2734
  // Annotate the CommonJS export names for ESM import in node:
2551
2735
  0 && (module.exports = {
2552
2736
  Highlighter,
2737
+ InMemoryStorageAdapter,
2738
+ LocalStorageAdapter,
2739
+ NullStorageAdapter,
2553
2740
  Pill,
2554
2741
  Popover,
2555
2742
  Sidebar,