web-remarq 0.4.9 → 0.6.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/index.d.cts CHANGED
@@ -43,6 +43,7 @@ interface WebRemarqOptions {
43
43
  dataAttribute?: string;
44
44
  position?: ToolbarPosition;
45
45
  shortcuts?: boolean;
46
+ storage?: StorageAdapter;
46
47
  }
47
48
  interface ImportResult {
48
49
  total: number;
@@ -83,6 +84,19 @@ interface AgentExport {
83
84
  viewportBucket: number;
84
85
  annotations: AgentAnnotation[];
85
86
  }
87
+ interface StorageChangeEvent {
88
+ type: 'add' | 'update' | 'remove' | 'clear';
89
+ annotation?: Annotation;
90
+ id?: string;
91
+ }
92
+ interface StorageAdapter {
93
+ load(): Promise<AnnotationStore | null>;
94
+ save(annotation: Annotation): Promise<void>;
95
+ remove(id: string): Promise<void>;
96
+ clear(): Promise<void>;
97
+ subscribe?(callback: (event: StorageChangeEvent) => void): () => void;
98
+ readonly isMemoryOnly?: boolean;
99
+ }
86
100
 
87
101
  declare const WebRemarq: {
88
102
  init(opts?: WebRemarqOptions): void;
@@ -95,4 +109,16 @@ declare const WebRemarq: {
95
109
  clearAll(): void;
96
110
  };
97
111
 
98
- export { type AgentAnnotation, type AgentExport, type Annotation, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type ImportResult, type ToolbarPosition, WebRemarq, type WebRemarqOptions };
112
+ declare class LocalStorageAdapter implements StorageAdapter {
113
+ isMemoryOnly: boolean;
114
+ private extraFields;
115
+ private memoryStore;
116
+ load(): Promise<AnnotationStore | null>;
117
+ save(annotation: Annotation): Promise<void>;
118
+ remove(id: string): Promise<void>;
119
+ clear(): Promise<void>;
120
+ private ensureStore;
121
+ private persist;
122
+ }
123
+
124
+ export { type AgentAnnotation, type AgentExport, type Annotation, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type ImportResult, LocalStorageAdapter, type StorageAdapter, type StorageChangeEvent, type ToolbarPosition, WebRemarq, type WebRemarqOptions };
package/dist/index.d.ts CHANGED
@@ -43,6 +43,7 @@ interface WebRemarqOptions {
43
43
  dataAttribute?: string;
44
44
  position?: ToolbarPosition;
45
45
  shortcuts?: boolean;
46
+ storage?: StorageAdapter;
46
47
  }
47
48
  interface ImportResult {
48
49
  total: number;
@@ -83,6 +84,19 @@ interface AgentExport {
83
84
  viewportBucket: number;
84
85
  annotations: AgentAnnotation[];
85
86
  }
87
+ interface StorageChangeEvent {
88
+ type: 'add' | 'update' | 'remove' | 'clear';
89
+ annotation?: Annotation;
90
+ id?: string;
91
+ }
92
+ interface StorageAdapter {
93
+ load(): Promise<AnnotationStore | null>;
94
+ save(annotation: Annotation): Promise<void>;
95
+ remove(id: string): Promise<void>;
96
+ clear(): Promise<void>;
97
+ subscribe?(callback: (event: StorageChangeEvent) => void): () => void;
98
+ readonly isMemoryOnly?: boolean;
99
+ }
86
100
 
87
101
  declare const WebRemarq: {
88
102
  init(opts?: WebRemarqOptions): void;
@@ -95,4 +109,16 @@ declare const WebRemarq: {
95
109
  clearAll(): void;
96
110
  };
97
111
 
98
- export { type AgentAnnotation, type AgentExport, type Annotation, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type ImportResult, type ToolbarPosition, WebRemarq, type WebRemarqOptions };
112
+ declare class LocalStorageAdapter implements StorageAdapter {
113
+ isMemoryOnly: boolean;
114
+ private extraFields;
115
+ private memoryStore;
116
+ load(): Promise<AnnotationStore | null>;
117
+ save(annotation: Annotation): Promise<void>;
118
+ remove(id: string): Promise<void>;
119
+ clear(): Promise<void>;
120
+ private ensureStore;
121
+ private persist;
122
+ }
123
+
124
+ export { type AgentAnnotation, type AgentExport, type Annotation, type AnnotationStore, type CSSModuleClass, type ElementFingerprint, type ImportResult, LocalStorageAdapter, type StorageAdapter, type StorageChangeEvent, type ToolbarPosition, WebRemarq, type WebRemarqOptions };
package/dist/index.js CHANGED
@@ -65,79 +65,133 @@ function destroyViewportListener() {
65
65
  }
66
66
 
67
67
  // src/core/storage.ts
68
- var STORAGE_KEY = "remarq:annotations";
69
68
  var AnnotationStorage = class {
70
- constructor() {
71
- this.annotations = [];
72
- this.extraFields = {};
73
- this.isMemoryOnly = false;
74
- this.load();
69
+ constructor(adapter) {
70
+ this.adapter = adapter;
71
+ this.cache = [];
72
+ this.ready = this.init();
73
+ }
74
+ get isMemoryOnly() {
75
+ var _a3;
76
+ return (_a3 = this.adapter.isMemoryOnly) != null ? _a3 : false;
75
77
  }
76
78
  getAll() {
77
- return [...this.annotations];
79
+ return [...this.cache];
78
80
  }
79
81
  getByRoute(route) {
80
- return this.annotations.filter((a) => a.route === route);
82
+ return this.cache.filter((a) => a.route === route);
81
83
  }
82
- add(annotation) {
83
- this.annotations.push(annotation);
84
- this.save();
84
+ async add(annotation) {
85
+ this.cache.push(annotation);
86
+ await this.adapter.save(annotation);
85
87
  }
86
- remove(id) {
87
- this.annotations = this.annotations.filter((a) => a.id !== id);
88
- this.save();
88
+ async remove(id) {
89
+ this.cache = this.cache.filter((a) => a.id !== id);
90
+ await this.adapter.remove(id);
89
91
  }
90
- update(id, changes) {
91
- const idx = this.annotations.findIndex((a) => a.id === id);
92
- if (idx !== -1) {
93
- this.annotations[idx] = __spreadValues(__spreadValues({}, this.annotations[idx]), changes);
94
- this.save();
95
- }
92
+ async update(id, changes) {
93
+ const idx = this.cache.findIndex((a) => a.id === id);
94
+ if (idx === -1) return;
95
+ const updated = __spreadValues(__spreadValues({}, this.cache[idx]), changes);
96
+ this.cache[idx] = updated;
97
+ await this.adapter.save(updated);
96
98
  }
97
- clearAll() {
98
- this.annotations = [];
99
- this.save();
99
+ async clearAll() {
100
+ this.cache = [];
101
+ await this.adapter.clear();
100
102
  }
101
103
  exportJSON() {
102
104
  return {
103
105
  version: 1,
104
- annotations: [...this.annotations]
106
+ annotations: [...this.cache]
105
107
  };
106
108
  }
107
- importJSON(data) {
108
- this.annotations = [...data.annotations];
109
+ async importJSON(data) {
110
+ this.cache = [...data.annotations];
109
111
  this.migrateViewportBuckets();
110
- this.save();
112
+ await this.adapter.clear();
113
+ for (const ann of this.cache) {
114
+ await this.adapter.save(ann);
115
+ }
116
+ }
117
+ async init() {
118
+ const data = await this.adapter.load();
119
+ if (data) {
120
+ this.cache = data.annotations;
121
+ this.migrateViewportBuckets();
122
+ }
111
123
  }
112
124
  migrateViewportBuckets() {
113
- for (const ann of this.annotations) {
125
+ for (const ann of this.cache) {
114
126
  if (ann.viewportBucket == null && ann.viewport) {
115
127
  const width = parseInt(ann.viewport.split("x")[0], 10);
116
128
  ann.viewportBucket = toBucket(width);
117
129
  }
118
130
  }
119
131
  }
120
- load() {
132
+ };
133
+
134
+ // src/core/local-storage-adapter.ts
135
+ var STORAGE_KEY = "remarq:annotations";
136
+ var LocalStorageAdapter = class {
137
+ constructor() {
138
+ this.isMemoryOnly = false;
139
+ this.extraFields = {};
140
+ this.memoryStore = null;
141
+ }
142
+ async load() {
143
+ if (this.isMemoryOnly) return this.memoryStore;
121
144
  try {
122
145
  const raw = localStorage.getItem(STORAGE_KEY);
123
- if (raw) {
124
- const parsed = JSON.parse(raw);
125
- const _a3 = parsed, { version, annotations } = _a3, rest = __objRest(_a3, ["version", "annotations"]);
126
- this.annotations = annotations != null ? annotations : [];
127
- this.extraFields = rest;
128
- this.migrateViewportBuckets();
129
- }
146
+ if (!raw) return null;
147
+ const parsed = JSON.parse(raw);
148
+ const _a3 = parsed, { version, annotations } = _a3, rest = __objRest(_a3, ["version", "annotations"]);
149
+ this.extraFields = rest;
150
+ const store = {
151
+ version: 1,
152
+ annotations: Array.isArray(annotations) ? annotations : []
153
+ };
154
+ this.memoryStore = store;
155
+ return store;
130
156
  } catch (e) {
131
157
  this.isMemoryOnly = true;
158
+ return this.memoryStore;
159
+ }
160
+ }
161
+ async save(annotation) {
162
+ const store = await this.ensureStore();
163
+ const idx = store.annotations.findIndex((a) => a.id === annotation.id);
164
+ if (idx === -1) {
165
+ store.annotations.push(annotation);
166
+ } else {
167
+ store.annotations[idx] = annotation;
132
168
  }
169
+ this.persist(store);
170
+ }
171
+ async remove(id) {
172
+ const store = await this.ensureStore();
173
+ store.annotations = store.annotations.filter((a) => a.id !== id);
174
+ this.persist(store);
175
+ }
176
+ async clear() {
177
+ const store = await this.ensureStore();
178
+ store.annotations = [];
179
+ this.persist(store);
133
180
  }
134
- save() {
181
+ async ensureStore() {
182
+ if (this.memoryStore) return this.memoryStore;
183
+ const loaded = await this.load();
184
+ if (loaded) return loaded;
185
+ this.memoryStore = { version: 1, annotations: [] };
186
+ return this.memoryStore;
187
+ }
188
+ persist(store) {
135
189
  if (this.isMemoryOnly) return;
136
190
  try {
137
191
  const data = __spreadProps(__spreadValues({
138
192
  version: 1
139
193
  }, this.extraFields), {
140
- annotations: this.annotations
194
+ annotations: store.annotations
141
195
  });
142
196
  localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
143
197
  } catch (e) {
@@ -2617,18 +2671,18 @@ function setupMutationObserver() {
2617
2671
  }
2618
2672
  var WebRemarq = {
2619
2673
  init(opts) {
2620
- var _a3;
2674
+ var _a3, _b;
2621
2675
  if (initialized) return;
2622
2676
  options = opts != null ? opts : {};
2623
2677
  try {
2624
2678
  injectStyles();
2625
- storage = new AnnotationStorage();
2679
+ storage = new AnnotationStorage((_a3 = options.storage) != null ? _a3 : new LocalStorageAdapter());
2626
2680
  themeManager = new ThemeManager(document.body, options.theme);
2627
2681
  overlay = new Overlay(themeManager.container);
2628
2682
  spacingOverlay = new SpacingOverlay(themeManager.container);
2629
2683
  popup = new Popup(themeManager.container);
2630
2684
  markers = new MarkerManager(themeManager.container, handleMarkerClick);
2631
- const position = (_a3 = options.position) != null ? _a3 : "bottom-right";
2685
+ const position = (_b = options.position) != null ? _b : "bottom-right";
2632
2686
  detachedPanel = new DetachedPanel(themeManager.container, (id) => {
2633
2687
  elementCache.delete(id);
2634
2688
  storage.remove(id);
@@ -2661,9 +2715,6 @@ var WebRemarq = {
2661
2715
  onThemeToggle: () => themeManager.toggle(),
2662
2716
  onHelp: () => showShortcutsModal(themeManager.container)
2663
2717
  }, position);
2664
- if (storage.isMemoryOnly) {
2665
- toolbar.setMemoryWarning(true);
2666
- }
2667
2718
  routeObserver = new RouteObserver();
2668
2719
  unsubRoute = routeObserver.onChange(() => refreshMarkers());
2669
2720
  document.addEventListener("click", handleInspectClick, true);
@@ -2671,8 +2722,13 @@ var WebRemarq = {
2671
2722
  document.addEventListener("keydown", handleInspectKeydown);
2672
2723
  setupMutationObserver();
2673
2724
  initViewportListener(() => refreshMarkers());
2725
+ storage.ready.then(() => {
2726
+ if (storage.isMemoryOnly) {
2727
+ toolbar.setMemoryWarning(true);
2728
+ }
2729
+ refreshMarkers();
2730
+ });
2674
2731
  console.debug(`[web-remarq] Initialized on route: ${currentRoute()}`);
2675
- refreshMarkers();
2676
2732
  initialized = true;
2677
2733
  } catch (err) {
2678
2734
  console.error("[web-remarq] Init failed:", err);
@@ -2754,6 +2810,7 @@ var WebRemarq = {
2754
2810
  }
2755
2811
  };
2756
2812
  export {
2813
+ LocalStorageAdapter,
2757
2814
  WebRemarq
2758
2815
  };
2759
2816
  //# sourceMappingURL=index.js.map