@fieldnotes/core 0.44.0 → 0.46.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.cjs +153 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -10
- package/dist/index.d.ts +58 -10
- package/dist/index.js +150 -33
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -162,6 +162,14 @@ interface ElementUpdateEvent {
|
|
|
162
162
|
previous: CanvasElement;
|
|
163
163
|
current: CanvasElement;
|
|
164
164
|
}
|
|
165
|
+
interface ElementChangeMeta {
|
|
166
|
+
/**
|
|
167
|
+
* Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo
|
|
168
|
+
* history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied
|
|
169
|
+
* change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.
|
|
170
|
+
*/
|
|
171
|
+
origin?: string;
|
|
172
|
+
}
|
|
165
173
|
interface ElementStoreEvents {
|
|
166
174
|
add: CanvasElement;
|
|
167
175
|
remove: CanvasElement;
|
|
@@ -184,19 +192,19 @@ declare class ElementStore {
|
|
|
184
192
|
type: T;
|
|
185
193
|
}>[];
|
|
186
194
|
private indexBounds;
|
|
187
|
-
add(element: CanvasElement): void;
|
|
188
|
-
update(id: string, partial: Partial<CanvasElement
|
|
189
|
-
remove(id: string): void;
|
|
190
|
-
clear(): void;
|
|
195
|
+
add(element: CanvasElement, meta?: ElementChangeMeta): void;
|
|
196
|
+
update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void;
|
|
197
|
+
remove(id: string, meta?: ElementChangeMeta): void;
|
|
198
|
+
clear(meta?: ElementChangeMeta): void;
|
|
191
199
|
snapshot(): CanvasElement[];
|
|
192
|
-
loadSnapshot(elements: CanvasElement[]): void;
|
|
200
|
+
loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void;
|
|
193
201
|
bringToFront(id: string): void;
|
|
194
202
|
sendToBack(id: string): void;
|
|
195
203
|
bringForward(id: string): void;
|
|
196
204
|
sendBackward(id: string): void;
|
|
197
205
|
queryRect(rect: Bounds): CanvasElement[];
|
|
198
206
|
queryPoint(point: Point): CanvasElement[];
|
|
199
|
-
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
|
|
207
|
+
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void): () => void;
|
|
200
208
|
onChange(listener: () => void): () => void;
|
|
201
209
|
}
|
|
202
210
|
|
|
@@ -304,10 +312,17 @@ declare class LayerManager {
|
|
|
304
312
|
private findFallbackLayer;
|
|
305
313
|
}
|
|
306
314
|
|
|
315
|
+
interface StorageAdapter {
|
|
316
|
+
load(key: string): Promise<string | null>;
|
|
317
|
+
save(key: string, value: string): Promise<void>;
|
|
318
|
+
clear(key: string): Promise<void>;
|
|
319
|
+
}
|
|
320
|
+
|
|
307
321
|
interface AutoSaveOptions {
|
|
308
322
|
key?: string;
|
|
309
323
|
debounceMs?: number;
|
|
310
324
|
layerManager?: LayerManager;
|
|
325
|
+
adapter?: StorageAdapter;
|
|
311
326
|
onError?: (error: Error) => void;
|
|
312
327
|
}
|
|
313
328
|
declare class AutoSave {
|
|
@@ -316,19 +331,52 @@ declare class AutoSave {
|
|
|
316
331
|
private readonly key;
|
|
317
332
|
private readonly debounceMs;
|
|
318
333
|
private readonly layerManager?;
|
|
334
|
+
private readonly adapter;
|
|
319
335
|
private timerId;
|
|
320
336
|
private unsubscribers;
|
|
321
337
|
private readonly onError?;
|
|
338
|
+
private saving;
|
|
339
|
+
private pendingSave;
|
|
322
340
|
constructor(store: ElementStore, camera: Camera, options?: AutoSaveOptions);
|
|
323
341
|
start(): void;
|
|
324
342
|
stop(): void;
|
|
325
|
-
load(): CanvasState | null
|
|
326
|
-
clear(): void
|
|
343
|
+
load(): Promise<CanvasState | null>;
|
|
344
|
+
clear(): Promise<void>;
|
|
327
345
|
private scheduleSave;
|
|
328
346
|
private cancelPending;
|
|
329
347
|
private save;
|
|
330
348
|
}
|
|
331
349
|
|
|
350
|
+
declare class MemoryAdapter implements StorageAdapter {
|
|
351
|
+
private store;
|
|
352
|
+
load(key: string): Promise<string | null>;
|
|
353
|
+
save(key: string, value: string): Promise<void>;
|
|
354
|
+
clear(key: string): Promise<void>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
declare class LocalStorageAdapter implements StorageAdapter {
|
|
358
|
+
load(key: string): Promise<string | null>;
|
|
359
|
+
save(key: string, value: string): Promise<void>;
|
|
360
|
+
clear(key: string): Promise<void>;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
interface IndexedDBAdapterOptions {
|
|
364
|
+
dbName?: string;
|
|
365
|
+
storeName?: string;
|
|
366
|
+
indexedDB?: IDBFactory;
|
|
367
|
+
}
|
|
368
|
+
declare class IndexedDBAdapter implements StorageAdapter {
|
|
369
|
+
private readonly dbName;
|
|
370
|
+
private readonly storeName;
|
|
371
|
+
private readonly idb;
|
|
372
|
+
private dbPromise;
|
|
373
|
+
constructor(options?: IndexedDBAdapterOptions);
|
|
374
|
+
private open;
|
|
375
|
+
load(key: string): Promise<string | null>;
|
|
376
|
+
save(key: string, value: string): Promise<void>;
|
|
377
|
+
clear(key: string): Promise<void>;
|
|
378
|
+
}
|
|
379
|
+
|
|
332
380
|
type BackgroundPattern = 'dots' | 'grid' | 'none';
|
|
333
381
|
interface BackgroundOptions {
|
|
334
382
|
pattern?: BackgroundPattern;
|
|
@@ -1065,6 +1113,6 @@ declare class LaserTool implements Tool {
|
|
|
1065
1113
|
private notifyOptionsChange;
|
|
1066
1114
|
}
|
|
1067
1115
|
|
|
1068
|
-
declare const VERSION = "0.
|
|
1116
|
+
declare const VERSION = "0.46.0";
|
|
1069
1117
|
|
|
1070
|
-
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1118
|
+
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.d.ts
CHANGED
|
@@ -162,6 +162,14 @@ interface ElementUpdateEvent {
|
|
|
162
162
|
previous: CanvasElement;
|
|
163
163
|
current: CanvasElement;
|
|
164
164
|
}
|
|
165
|
+
interface ElementChangeMeta {
|
|
166
|
+
/**
|
|
167
|
+
* Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo
|
|
168
|
+
* history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied
|
|
169
|
+
* change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.
|
|
170
|
+
*/
|
|
171
|
+
origin?: string;
|
|
172
|
+
}
|
|
165
173
|
interface ElementStoreEvents {
|
|
166
174
|
add: CanvasElement;
|
|
167
175
|
remove: CanvasElement;
|
|
@@ -184,19 +192,19 @@ declare class ElementStore {
|
|
|
184
192
|
type: T;
|
|
185
193
|
}>[];
|
|
186
194
|
private indexBounds;
|
|
187
|
-
add(element: CanvasElement): void;
|
|
188
|
-
update(id: string, partial: Partial<CanvasElement
|
|
189
|
-
remove(id: string): void;
|
|
190
|
-
clear(): void;
|
|
195
|
+
add(element: CanvasElement, meta?: ElementChangeMeta): void;
|
|
196
|
+
update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void;
|
|
197
|
+
remove(id: string, meta?: ElementChangeMeta): void;
|
|
198
|
+
clear(meta?: ElementChangeMeta): void;
|
|
191
199
|
snapshot(): CanvasElement[];
|
|
192
|
-
loadSnapshot(elements: CanvasElement[]): void;
|
|
200
|
+
loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void;
|
|
193
201
|
bringToFront(id: string): void;
|
|
194
202
|
sendToBack(id: string): void;
|
|
195
203
|
bringForward(id: string): void;
|
|
196
204
|
sendBackward(id: string): void;
|
|
197
205
|
queryRect(rect: Bounds): CanvasElement[];
|
|
198
206
|
queryPoint(point: Point): CanvasElement[];
|
|
199
|
-
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
|
|
207
|
+
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void): () => void;
|
|
200
208
|
onChange(listener: () => void): () => void;
|
|
201
209
|
}
|
|
202
210
|
|
|
@@ -304,10 +312,17 @@ declare class LayerManager {
|
|
|
304
312
|
private findFallbackLayer;
|
|
305
313
|
}
|
|
306
314
|
|
|
315
|
+
interface StorageAdapter {
|
|
316
|
+
load(key: string): Promise<string | null>;
|
|
317
|
+
save(key: string, value: string): Promise<void>;
|
|
318
|
+
clear(key: string): Promise<void>;
|
|
319
|
+
}
|
|
320
|
+
|
|
307
321
|
interface AutoSaveOptions {
|
|
308
322
|
key?: string;
|
|
309
323
|
debounceMs?: number;
|
|
310
324
|
layerManager?: LayerManager;
|
|
325
|
+
adapter?: StorageAdapter;
|
|
311
326
|
onError?: (error: Error) => void;
|
|
312
327
|
}
|
|
313
328
|
declare class AutoSave {
|
|
@@ -316,19 +331,52 @@ declare class AutoSave {
|
|
|
316
331
|
private readonly key;
|
|
317
332
|
private readonly debounceMs;
|
|
318
333
|
private readonly layerManager?;
|
|
334
|
+
private readonly adapter;
|
|
319
335
|
private timerId;
|
|
320
336
|
private unsubscribers;
|
|
321
337
|
private readonly onError?;
|
|
338
|
+
private saving;
|
|
339
|
+
private pendingSave;
|
|
322
340
|
constructor(store: ElementStore, camera: Camera, options?: AutoSaveOptions);
|
|
323
341
|
start(): void;
|
|
324
342
|
stop(): void;
|
|
325
|
-
load(): CanvasState | null
|
|
326
|
-
clear(): void
|
|
343
|
+
load(): Promise<CanvasState | null>;
|
|
344
|
+
clear(): Promise<void>;
|
|
327
345
|
private scheduleSave;
|
|
328
346
|
private cancelPending;
|
|
329
347
|
private save;
|
|
330
348
|
}
|
|
331
349
|
|
|
350
|
+
declare class MemoryAdapter implements StorageAdapter {
|
|
351
|
+
private store;
|
|
352
|
+
load(key: string): Promise<string | null>;
|
|
353
|
+
save(key: string, value: string): Promise<void>;
|
|
354
|
+
clear(key: string): Promise<void>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
declare class LocalStorageAdapter implements StorageAdapter {
|
|
358
|
+
load(key: string): Promise<string | null>;
|
|
359
|
+
save(key: string, value: string): Promise<void>;
|
|
360
|
+
clear(key: string): Promise<void>;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
interface IndexedDBAdapterOptions {
|
|
364
|
+
dbName?: string;
|
|
365
|
+
storeName?: string;
|
|
366
|
+
indexedDB?: IDBFactory;
|
|
367
|
+
}
|
|
368
|
+
declare class IndexedDBAdapter implements StorageAdapter {
|
|
369
|
+
private readonly dbName;
|
|
370
|
+
private readonly storeName;
|
|
371
|
+
private readonly idb;
|
|
372
|
+
private dbPromise;
|
|
373
|
+
constructor(options?: IndexedDBAdapterOptions);
|
|
374
|
+
private open;
|
|
375
|
+
load(key: string): Promise<string | null>;
|
|
376
|
+
save(key: string, value: string): Promise<void>;
|
|
377
|
+
clear(key: string): Promise<void>;
|
|
378
|
+
}
|
|
379
|
+
|
|
332
380
|
type BackgroundPattern = 'dots' | 'grid' | 'none';
|
|
333
381
|
interface BackgroundOptions {
|
|
334
382
|
pattern?: BackgroundPattern;
|
|
@@ -1065,6 +1113,6 @@ declare class LaserTool implements Tool {
|
|
|
1065
1113
|
private notifyOptionsChange;
|
|
1066
1114
|
}
|
|
1067
1115
|
|
|
1068
|
-
declare const VERSION = "0.
|
|
1116
|
+
declare const VERSION = "0.46.0";
|
|
1069
1117
|
|
|
1070
|
-
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1118
|
+
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.js
CHANGED
|
@@ -285,6 +285,22 @@ function migrateElement(obj) {
|
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
// src/core/storage/local-storage-adapter.ts
|
|
289
|
+
var LocalStorageAdapter = class {
|
|
290
|
+
async load(key) {
|
|
291
|
+
if (typeof localStorage === "undefined") return null;
|
|
292
|
+
return localStorage.getItem(key);
|
|
293
|
+
}
|
|
294
|
+
async save(key, value) {
|
|
295
|
+
if (typeof localStorage === "undefined") return;
|
|
296
|
+
localStorage.setItem(key, value);
|
|
297
|
+
}
|
|
298
|
+
async clear(key) {
|
|
299
|
+
if (typeof localStorage === "undefined") return;
|
|
300
|
+
localStorage.removeItem(key);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
288
304
|
// src/core/auto-save.ts
|
|
289
305
|
var DEFAULT_KEY = "fieldnotes-autosave";
|
|
290
306
|
var DEFAULT_DEBOUNCE_MS = 1e3;
|
|
@@ -295,14 +311,18 @@ var AutoSave = class {
|
|
|
295
311
|
this.key = options.key ?? DEFAULT_KEY;
|
|
296
312
|
this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
297
313
|
this.layerManager = options.layerManager;
|
|
314
|
+
this.adapter = options.adapter ?? new LocalStorageAdapter();
|
|
298
315
|
this.onError = options.onError;
|
|
299
316
|
}
|
|
300
317
|
key;
|
|
301
318
|
debounceMs;
|
|
302
319
|
layerManager;
|
|
320
|
+
adapter;
|
|
303
321
|
timerId = null;
|
|
304
322
|
unsubscribers = [];
|
|
305
323
|
onError;
|
|
324
|
+
saving = false;
|
|
325
|
+
pendingSave = false;
|
|
306
326
|
start() {
|
|
307
327
|
const schedule = () => this.scheduleSave();
|
|
308
328
|
this.unsubscribers = [
|
|
@@ -320,9 +340,8 @@ var AutoSave = class {
|
|
|
320
340
|
this.unsubscribers.forEach((fn) => fn());
|
|
321
341
|
this.unsubscribers = [];
|
|
322
342
|
}
|
|
323
|
-
load() {
|
|
324
|
-
|
|
325
|
-
const json = localStorage.getItem(this.key);
|
|
343
|
+
async load() {
|
|
344
|
+
const json = await this.adapter.load(this.key);
|
|
326
345
|
if (!json) return null;
|
|
327
346
|
try {
|
|
328
347
|
return parseState(json);
|
|
@@ -330,13 +349,12 @@ var AutoSave = class {
|
|
|
330
349
|
return null;
|
|
331
350
|
}
|
|
332
351
|
}
|
|
333
|
-
clear() {
|
|
334
|
-
|
|
335
|
-
localStorage.removeItem(this.key);
|
|
352
|
+
async clear() {
|
|
353
|
+
await this.adapter.clear(this.key);
|
|
336
354
|
}
|
|
337
355
|
scheduleSave() {
|
|
338
356
|
this.cancelPending();
|
|
339
|
-
this.timerId = setTimeout(() => this.save(), this.debounceMs);
|
|
357
|
+
this.timerId = setTimeout(() => void this.save(), this.debounceMs);
|
|
340
358
|
}
|
|
341
359
|
cancelPending() {
|
|
342
360
|
if (this.timerId !== null) {
|
|
@@ -344,19 +362,108 @@ var AutoSave = class {
|
|
|
344
362
|
this.timerId = null;
|
|
345
363
|
}
|
|
346
364
|
}
|
|
347
|
-
save() {
|
|
348
|
-
if (
|
|
349
|
-
|
|
350
|
-
|
|
365
|
+
async save() {
|
|
366
|
+
if (this.saving) {
|
|
367
|
+
this.pendingSave = true;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
this.saving = true;
|
|
351
371
|
try {
|
|
352
|
-
|
|
372
|
+
const layers = this.layerManager?.snapshot() ?? [];
|
|
373
|
+
const state = exportState(this.store.snapshot(), this.camera, layers);
|
|
374
|
+
await this.adapter.save(this.key, JSON.stringify(state));
|
|
353
375
|
} catch (e) {
|
|
354
|
-
console.warn("Auto-save failed: storage quota exceeded. State too large for localStorage.");
|
|
355
376
|
this.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
377
|
+
} finally {
|
|
378
|
+
this.saving = false;
|
|
379
|
+
if (this.pendingSave) {
|
|
380
|
+
this.pendingSave = false;
|
|
381
|
+
void this.save();
|
|
382
|
+
}
|
|
356
383
|
}
|
|
357
384
|
}
|
|
358
385
|
};
|
|
359
386
|
|
|
387
|
+
// src/core/storage/memory-adapter.ts
|
|
388
|
+
var MemoryAdapter = class {
|
|
389
|
+
store = /* @__PURE__ */ new Map();
|
|
390
|
+
async load(key) {
|
|
391
|
+
return this.store.get(key) ?? null;
|
|
392
|
+
}
|
|
393
|
+
async save(key, value) {
|
|
394
|
+
this.store.set(key, value);
|
|
395
|
+
}
|
|
396
|
+
async clear(key) {
|
|
397
|
+
this.store.delete(key);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// src/core/storage/indexeddb-adapter.ts
|
|
402
|
+
var DEFAULT_DB = "fieldnotes";
|
|
403
|
+
var DEFAULT_STORE = "state";
|
|
404
|
+
var IndexedDBAdapter = class {
|
|
405
|
+
dbName;
|
|
406
|
+
storeName;
|
|
407
|
+
idb;
|
|
408
|
+
dbPromise = null;
|
|
409
|
+
constructor(options = {}) {
|
|
410
|
+
this.dbName = options.dbName ?? DEFAULT_DB;
|
|
411
|
+
this.storeName = options.storeName ?? DEFAULT_STORE;
|
|
412
|
+
this.idb = options.indexedDB ?? (typeof indexedDB !== "undefined" ? indexedDB : null);
|
|
413
|
+
}
|
|
414
|
+
open() {
|
|
415
|
+
const idb = this.idb;
|
|
416
|
+
if (!idb) return Promise.reject(new Error("IndexedDB unavailable"));
|
|
417
|
+
if (!this.dbPromise) {
|
|
418
|
+
const storeName = this.storeName;
|
|
419
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
420
|
+
const req = idb.open(this.dbName, 1);
|
|
421
|
+
req.onupgradeneeded = () => {
|
|
422
|
+
const db = req.result;
|
|
423
|
+
if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName);
|
|
424
|
+
};
|
|
425
|
+
req.onsuccess = () => resolve(req.result);
|
|
426
|
+
req.onerror = () => reject(req.error ?? new Error("IndexedDB open failed"));
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
return this.dbPromise;
|
|
430
|
+
}
|
|
431
|
+
async load(key) {
|
|
432
|
+
if (!this.idb) return null;
|
|
433
|
+
const db = await this.open();
|
|
434
|
+
return new Promise((resolve, reject) => {
|
|
435
|
+
const req = db.transaction(this.storeName, "readonly").objectStore(this.storeName).get(key);
|
|
436
|
+
req.onsuccess = () => {
|
|
437
|
+
const v = req.result;
|
|
438
|
+
resolve(typeof v === "string" ? v : null);
|
|
439
|
+
};
|
|
440
|
+
req.onerror = () => reject(req.error ?? new Error("IndexedDB read failed"));
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
async save(key, value) {
|
|
444
|
+
if (!this.idb) return;
|
|
445
|
+
const db = await this.open();
|
|
446
|
+
return new Promise((resolve, reject) => {
|
|
447
|
+
const tx = db.transaction(this.storeName, "readwrite");
|
|
448
|
+
tx.objectStore(this.storeName).put(value, key);
|
|
449
|
+
tx.oncomplete = () => resolve();
|
|
450
|
+
tx.onerror = () => reject(tx.error ?? new Error("IndexedDB write failed"));
|
|
451
|
+
tx.onabort = () => reject(tx.error ?? new Error("IndexedDB write aborted"));
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
async clear(key) {
|
|
455
|
+
if (!this.idb) return;
|
|
456
|
+
const db = await this.open();
|
|
457
|
+
return new Promise((resolve, reject) => {
|
|
458
|
+
const tx = db.transaction(this.storeName, "readwrite");
|
|
459
|
+
tx.objectStore(this.storeName).delete(key);
|
|
460
|
+
tx.oncomplete = () => resolve();
|
|
461
|
+
tx.onerror = () => reject(tx.error ?? new Error("IndexedDB delete failed"));
|
|
462
|
+
tx.onabort = () => reject(tx.error ?? new Error("IndexedDB delete aborted"));
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
360
467
|
// src/canvas/camera.ts
|
|
361
468
|
var DEFAULT_MIN_ZOOM = 0.1;
|
|
362
469
|
var DEFAULT_MAX_ZOOM = 10;
|
|
@@ -2039,6 +2146,7 @@ var Background = class {
|
|
|
2039
2146
|
};
|
|
2040
2147
|
|
|
2041
2148
|
// src/core/event-bus.ts
|
|
2149
|
+
var EMPTY_META = Object.freeze({});
|
|
2042
2150
|
var EventBus = class {
|
|
2043
2151
|
listeners = /* @__PURE__ */ new Map();
|
|
2044
2152
|
on(event, listener) {
|
|
@@ -2054,10 +2162,10 @@ var EventBus = class {
|
|
|
2054
2162
|
off(event, listener) {
|
|
2055
2163
|
this.listeners.get(event)?.delete(listener);
|
|
2056
2164
|
}
|
|
2057
|
-
emit(event, data) {
|
|
2165
|
+
emit(event, data, meta = EMPTY_META) {
|
|
2058
2166
|
this.listeners.get(event)?.forEach((listener) => {
|
|
2059
2167
|
try {
|
|
2060
|
-
listener(data);
|
|
2168
|
+
listener(data, meta);
|
|
2061
2169
|
} catch (err) {
|
|
2062
2170
|
console.error(`[fieldnotes] listener error for "${String(event)}"`, err);
|
|
2063
2171
|
}
|
|
@@ -2377,15 +2485,15 @@ var ElementStore = class {
|
|
|
2377
2485
|
const angle = element.rotation ?? 0;
|
|
2378
2486
|
return angle === 0 ? bounds : rotatedAABB(bounds, angle);
|
|
2379
2487
|
}
|
|
2380
|
-
add(element) {
|
|
2488
|
+
add(element, meta) {
|
|
2381
2489
|
this.sortedCache = null;
|
|
2382
2490
|
this._versions.set(element.id, 0);
|
|
2383
2491
|
this.elements.set(element.id, element);
|
|
2384
2492
|
const bounds = this.indexBounds(element);
|
|
2385
2493
|
if (bounds) this.spatialIndex.insert(element.id, bounds);
|
|
2386
|
-
this.bus.emit("add", element);
|
|
2494
|
+
this.bus.emit("add", element, meta);
|
|
2387
2495
|
}
|
|
2388
|
-
update(id, partial) {
|
|
2496
|
+
update(id, partial, meta) {
|
|
2389
2497
|
const existing = this.elements.get(id);
|
|
2390
2498
|
if (!existing) return;
|
|
2391
2499
|
this.sortedCache = null;
|
|
@@ -2412,28 +2520,28 @@ var ElementStore = class {
|
|
|
2412
2520
|
if (newBounds) {
|
|
2413
2521
|
this.spatialIndex.update(id, newBounds);
|
|
2414
2522
|
}
|
|
2415
|
-
this.bus.emit("update", { previous: existing, current: updated });
|
|
2523
|
+
this.bus.emit("update", { previous: existing, current: updated }, meta);
|
|
2416
2524
|
}
|
|
2417
|
-
remove(id) {
|
|
2525
|
+
remove(id, meta) {
|
|
2418
2526
|
const element = this.elements.get(id);
|
|
2419
2527
|
if (!element) return;
|
|
2420
2528
|
this.sortedCache = null;
|
|
2421
2529
|
this._versions.delete(id);
|
|
2422
2530
|
this.elements.delete(id);
|
|
2423
2531
|
this.spatialIndex.remove(id);
|
|
2424
|
-
this.bus.emit("remove", element);
|
|
2532
|
+
this.bus.emit("remove", element, meta);
|
|
2425
2533
|
}
|
|
2426
|
-
clear() {
|
|
2534
|
+
clear(meta) {
|
|
2427
2535
|
this.sortedCache = null;
|
|
2428
2536
|
this._versions.clear();
|
|
2429
2537
|
this.elements.clear();
|
|
2430
2538
|
this.spatialIndex.clear();
|
|
2431
|
-
this.bus.emit("clear", null);
|
|
2539
|
+
this.bus.emit("clear", null, meta);
|
|
2432
2540
|
}
|
|
2433
2541
|
snapshot() {
|
|
2434
2542
|
return this.getAll().map((el) => ({ ...el }));
|
|
2435
2543
|
}
|
|
2436
|
-
loadSnapshot(elements) {
|
|
2544
|
+
loadSnapshot(elements, meta) {
|
|
2437
2545
|
this.sortedCache = null;
|
|
2438
2546
|
this._versions.clear();
|
|
2439
2547
|
this.elements.clear();
|
|
@@ -2450,9 +2558,9 @@ var ElementStore = class {
|
|
|
2450
2558
|
el.cachedControlPoint = getArrowControlPoint(el.from, el.to, el.bend);
|
|
2451
2559
|
}
|
|
2452
2560
|
}
|
|
2453
|
-
this.bus.emit("clear", null);
|
|
2561
|
+
this.bus.emit("clear", null, meta);
|
|
2454
2562
|
for (const el of elements) {
|
|
2455
|
-
this.bus.emit("add", el);
|
|
2563
|
+
this.bus.emit("add", el, meta);
|
|
2456
2564
|
}
|
|
2457
2565
|
}
|
|
2458
2566
|
bringToFront(id) {
|
|
@@ -4727,15 +4835,18 @@ var UpdateLayerCommand = class {
|
|
|
4727
4835
|
};
|
|
4728
4836
|
|
|
4729
4837
|
// src/history/history-recorder.ts
|
|
4838
|
+
function isExternalChange(meta) {
|
|
4839
|
+
return meta.origin !== void 0 && meta.origin !== "local";
|
|
4840
|
+
}
|
|
4730
4841
|
var HistoryRecorder = class {
|
|
4731
4842
|
constructor(store, stack, layerManager) {
|
|
4732
4843
|
this.store = store;
|
|
4733
4844
|
this.stack = stack;
|
|
4734
4845
|
this.layerManager = layerManager;
|
|
4735
4846
|
this.unsubscribers = [
|
|
4736
|
-
store.on("add", (el) => this.onAdd(el)),
|
|
4737
|
-
store.on("remove", (el) => this.onRemove(el)),
|
|
4738
|
-
store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
|
|
4847
|
+
store.on("add", (el, meta) => this.onAdd(el, meta)),
|
|
4848
|
+
store.on("remove", (el, meta) => this.onRemove(el, meta)),
|
|
4849
|
+
store.on("update", ({ previous, current }, meta) => this.onUpdate(previous, current, meta))
|
|
4739
4850
|
];
|
|
4740
4851
|
if (layerManager) {
|
|
4741
4852
|
this.unsubscribers.push(
|
|
@@ -4791,18 +4902,21 @@ var HistoryRecorder = class {
|
|
|
4791
4902
|
this.stack.push(command);
|
|
4792
4903
|
}
|
|
4793
4904
|
}
|
|
4794
|
-
onAdd(element) {
|
|
4905
|
+
onAdd(element, meta) {
|
|
4906
|
+
if (isExternalChange(meta)) return;
|
|
4795
4907
|
if (!this.recording) return;
|
|
4796
4908
|
this.record(new AddElementCommand(element));
|
|
4797
4909
|
}
|
|
4798
|
-
onRemove(element) {
|
|
4910
|
+
onRemove(element, meta) {
|
|
4911
|
+
if (isExternalChange(meta)) return;
|
|
4799
4912
|
if (!this.recording) return;
|
|
4800
4913
|
if (this.transaction && this.updateSnapshots.has(element.id)) {
|
|
4801
4914
|
this.updateSnapshots.delete(element.id);
|
|
4802
4915
|
}
|
|
4803
4916
|
this.record(new RemoveElementCommand(element));
|
|
4804
4917
|
}
|
|
4805
|
-
onUpdate(previous, current) {
|
|
4918
|
+
onUpdate(previous, current, meta) {
|
|
4919
|
+
if (isExternalChange(meta)) return;
|
|
4806
4920
|
if (!this.recording) return;
|
|
4807
4921
|
if (this.transaction) {
|
|
4808
4922
|
if (!this.updateSnapshots.has(current.id)) {
|
|
@@ -9974,7 +10088,7 @@ var LaserTool = class {
|
|
|
9974
10088
|
};
|
|
9975
10089
|
|
|
9976
10090
|
// src/index.ts
|
|
9977
|
-
var VERSION = "0.
|
|
10091
|
+
var VERSION = "0.46.0";
|
|
9978
10092
|
export {
|
|
9979
10093
|
ArrowTool,
|
|
9980
10094
|
AutoSave,
|
|
@@ -9985,9 +10099,12 @@ export {
|
|
|
9985
10099
|
HandTool,
|
|
9986
10100
|
HistoryStack,
|
|
9987
10101
|
ImageTool,
|
|
10102
|
+
IndexedDBAdapter,
|
|
9988
10103
|
LaserTool,
|
|
9989
10104
|
LayerManager,
|
|
10105
|
+
LocalStorageAdapter,
|
|
9990
10106
|
MeasureTool,
|
|
10107
|
+
MemoryAdapter,
|
|
9991
10108
|
NoteTool,
|
|
9992
10109
|
PencilTool,
|
|
9993
10110
|
SelectTool,
|