@tsdraw/core 0.4.0 → 0.5.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 +175 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +174 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -39,9 +39,53 @@ declare const DRAG_DISTANCE_SQUARED = 36;
|
|
|
39
39
|
declare const DEFAULT_COLORS: Record<string, string>;
|
|
40
40
|
declare const MAX_POINTS_PER_SHAPE = 200;
|
|
41
41
|
|
|
42
|
+
interface TsdrawPageRecord {
|
|
43
|
+
id: string;
|
|
44
|
+
typeName: 'page';
|
|
45
|
+
pageId: string;
|
|
46
|
+
shapeIds: ShapeId[];
|
|
47
|
+
erasingShapeIds: ShapeId[];
|
|
48
|
+
}
|
|
49
|
+
interface TsdrawShapeRecord {
|
|
50
|
+
id: ShapeId;
|
|
51
|
+
typeName: 'shape';
|
|
52
|
+
shape: Shape;
|
|
53
|
+
}
|
|
54
|
+
type TsdrawPersistedRecord = TsdrawPageRecord | TsdrawShapeRecord;
|
|
55
|
+
interface TsdrawDocumentSnapshot {
|
|
56
|
+
records: TsdrawPersistedRecord[];
|
|
57
|
+
}
|
|
58
|
+
interface TsdrawSessionStateSnapshot {
|
|
59
|
+
version: 1;
|
|
60
|
+
viewport: {
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
zoom: number;
|
|
64
|
+
};
|
|
65
|
+
currentToolId: string;
|
|
66
|
+
drawStyle: {
|
|
67
|
+
color: ColorStyle;
|
|
68
|
+
dash: DashStyle;
|
|
69
|
+
size: SizeStyle;
|
|
70
|
+
};
|
|
71
|
+
selectedShapeIds: ShapeId[];
|
|
72
|
+
}
|
|
73
|
+
interface TsdrawEditorSnapshot {
|
|
74
|
+
document: TsdrawDocumentSnapshot;
|
|
75
|
+
state: TsdrawSessionStateSnapshot;
|
|
76
|
+
}
|
|
77
|
+
interface DocumentStoreSnapshot {
|
|
78
|
+
page: PageState;
|
|
79
|
+
order: ShapeId[];
|
|
80
|
+
}
|
|
81
|
+
declare function documentSnapshotToRecords(snapshot: DocumentStoreSnapshot): TsdrawPersistedRecord[];
|
|
82
|
+
declare function recordsToDocumentSnapshot(records: TsdrawPersistedRecord[]): DocumentStoreSnapshot | null;
|
|
83
|
+
|
|
84
|
+
type DocumentStoreListener = () => void;
|
|
42
85
|
declare class DocumentStore {
|
|
43
86
|
private state;
|
|
44
87
|
private order;
|
|
88
|
+
private readonly listeners;
|
|
45
89
|
getPage(): PageState;
|
|
46
90
|
getShape(id: ShapeId): Shape | undefined;
|
|
47
91
|
getCurrentPageShapesSorted(): Shape[];
|
|
@@ -58,6 +102,10 @@ declare class DocumentStore {
|
|
|
58
102
|
maxX: number;
|
|
59
103
|
maxY: number;
|
|
60
104
|
}): Set<ShapeId>;
|
|
105
|
+
getSnapshot(): DocumentStoreSnapshot;
|
|
106
|
+
loadSnapshot(snapshot: DocumentStoreSnapshot): void;
|
|
107
|
+
listen(listener: DocumentStoreListener): () => void;
|
|
108
|
+
private emitChange;
|
|
61
109
|
}
|
|
62
110
|
|
|
63
111
|
interface PointerInput {
|
|
@@ -228,6 +276,7 @@ interface EditorOptions {
|
|
|
228
276
|
toolDefinitions?: ToolDefinition[];
|
|
229
277
|
initialToolId?: ToolId;
|
|
230
278
|
}
|
|
279
|
+
type EditorListener = () => void;
|
|
231
280
|
declare class Editor {
|
|
232
281
|
readonly store: DocumentStore;
|
|
233
282
|
readonly input: InputManager;
|
|
@@ -239,6 +288,7 @@ declare class Editor {
|
|
|
239
288
|
};
|
|
240
289
|
private drawStyle;
|
|
241
290
|
private readonly toolStateContext;
|
|
291
|
+
private readonly listeners;
|
|
242
292
|
constructor(opts?: EditorOptions);
|
|
243
293
|
registerToolDefinition(toolDefinition: ToolDefinition): void;
|
|
244
294
|
private getDefaultToolDefinitions;
|
|
@@ -269,12 +319,25 @@ declare class Editor {
|
|
|
269
319
|
dash: DashStyle;
|
|
270
320
|
size: SizeStyle;
|
|
271
321
|
}>): void;
|
|
322
|
+
setViewport(partial: Partial<Viewport>): void;
|
|
272
323
|
panBy(dx: number, dy: number): void;
|
|
324
|
+
getDocumentSnapshot(): TsdrawDocumentSnapshot;
|
|
325
|
+
loadDocumentSnapshot(snapshot: TsdrawDocumentSnapshot): void;
|
|
326
|
+
getSessionStateSnapshot(args?: {
|
|
327
|
+
selectedShapeIds?: ShapeId[];
|
|
328
|
+
}): TsdrawSessionStateSnapshot;
|
|
329
|
+
loadSessionStateSnapshot(snapshot: TsdrawSessionStateSnapshot): ShapeId[];
|
|
330
|
+
getPersistenceSnapshot(args?: {
|
|
331
|
+
selectedShapeIds?: ShapeId[];
|
|
332
|
+
}): TsdrawEditorSnapshot;
|
|
333
|
+
loadPersistenceSnapshot(snapshot: Partial<TsdrawEditorSnapshot>): ShapeId[];
|
|
334
|
+
listen(listener: EditorListener): () => void;
|
|
273
335
|
screenToPage(screenX: number, screenY: number): {
|
|
274
336
|
x: number;
|
|
275
337
|
y: number;
|
|
276
338
|
};
|
|
277
339
|
render(ctx: CanvasRenderingContext2D): void;
|
|
340
|
+
private emitChange;
|
|
278
341
|
}
|
|
279
342
|
|
|
280
343
|
declare class PenIdleState extends StateNode {
|
|
@@ -461,4 +524,4 @@ declare function decodePathToPoints(segments: {
|
|
|
461
524
|
y: number;
|
|
462
525
|
}[];
|
|
463
526
|
|
|
464
|
-
export { type Bounds, CanvasRenderer, type ColorStyle, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, type DashStyle, type DefaultToolId, DocumentStore, type DrawSegment, type DrawShape, ERASER_MARGIN, Editor, type EditorOptions, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, type ICanvasRenderer, type IEditor, InputManager, MAX_POINTS_PER_SHAPE, type PageState, PenDrawingState, PenIdleState, type PointerInput, type ResizeHandle, STROKE_WIDTHS, type SegmentType, SelectIdleState, type SelectionBounds, type Shape, type ShapeId, type SizeStyle, StateNode, type StateNodeConstructor, type ToolDefinition, type ToolId, type ToolKeyInfo, ToolManager, type ToolPointerDownInfo, type ToolPointerMoveInfo, type ToolStateContext, type ToolStateTransitionInfo, type TransformSnapshot, type TsdrawRenderTheme, type Vec3, type Viewport, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, encodePoints, getSelectionBoundsPage, getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
527
|
+
export { type Bounds, CanvasRenderer, type ColorStyle, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, type DashStyle, type DefaultToolId, DocumentStore, type DocumentStoreSnapshot, type DrawSegment, type DrawShape, ERASER_MARGIN, Editor, type EditorOptions, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, type ICanvasRenderer, type IEditor, InputManager, MAX_POINTS_PER_SHAPE, type PageState, PenDrawingState, PenIdleState, type PointerInput, type ResizeHandle, STROKE_WIDTHS, type SegmentType, SelectIdleState, type SelectionBounds, type Shape, type ShapeId, type SizeStyle, StateNode, type StateNodeConstructor, type ToolDefinition, type ToolId, type ToolKeyInfo, ToolManager, type ToolPointerDownInfo, type ToolPointerMoveInfo, type ToolStateContext, type ToolStateTransitionInfo, type TransformSnapshot, type TsdrawDocumentSnapshot, type TsdrawEditorSnapshot, type TsdrawPageRecord, type TsdrawPersistedRecord, type TsdrawRenderTheme, type TsdrawSessionStateSnapshot, type TsdrawShapeRecord, type Vec3, type Viewport, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, documentSnapshotToRecords, encodePoints, getSelectionBoundsPage, getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, recordsToDocumentSnapshot, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,9 +39,53 @@ declare const DRAG_DISTANCE_SQUARED = 36;
|
|
|
39
39
|
declare const DEFAULT_COLORS: Record<string, string>;
|
|
40
40
|
declare const MAX_POINTS_PER_SHAPE = 200;
|
|
41
41
|
|
|
42
|
+
interface TsdrawPageRecord {
|
|
43
|
+
id: string;
|
|
44
|
+
typeName: 'page';
|
|
45
|
+
pageId: string;
|
|
46
|
+
shapeIds: ShapeId[];
|
|
47
|
+
erasingShapeIds: ShapeId[];
|
|
48
|
+
}
|
|
49
|
+
interface TsdrawShapeRecord {
|
|
50
|
+
id: ShapeId;
|
|
51
|
+
typeName: 'shape';
|
|
52
|
+
shape: Shape;
|
|
53
|
+
}
|
|
54
|
+
type TsdrawPersistedRecord = TsdrawPageRecord | TsdrawShapeRecord;
|
|
55
|
+
interface TsdrawDocumentSnapshot {
|
|
56
|
+
records: TsdrawPersistedRecord[];
|
|
57
|
+
}
|
|
58
|
+
interface TsdrawSessionStateSnapshot {
|
|
59
|
+
version: 1;
|
|
60
|
+
viewport: {
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
zoom: number;
|
|
64
|
+
};
|
|
65
|
+
currentToolId: string;
|
|
66
|
+
drawStyle: {
|
|
67
|
+
color: ColorStyle;
|
|
68
|
+
dash: DashStyle;
|
|
69
|
+
size: SizeStyle;
|
|
70
|
+
};
|
|
71
|
+
selectedShapeIds: ShapeId[];
|
|
72
|
+
}
|
|
73
|
+
interface TsdrawEditorSnapshot {
|
|
74
|
+
document: TsdrawDocumentSnapshot;
|
|
75
|
+
state: TsdrawSessionStateSnapshot;
|
|
76
|
+
}
|
|
77
|
+
interface DocumentStoreSnapshot {
|
|
78
|
+
page: PageState;
|
|
79
|
+
order: ShapeId[];
|
|
80
|
+
}
|
|
81
|
+
declare function documentSnapshotToRecords(snapshot: DocumentStoreSnapshot): TsdrawPersistedRecord[];
|
|
82
|
+
declare function recordsToDocumentSnapshot(records: TsdrawPersistedRecord[]): DocumentStoreSnapshot | null;
|
|
83
|
+
|
|
84
|
+
type DocumentStoreListener = () => void;
|
|
42
85
|
declare class DocumentStore {
|
|
43
86
|
private state;
|
|
44
87
|
private order;
|
|
88
|
+
private readonly listeners;
|
|
45
89
|
getPage(): PageState;
|
|
46
90
|
getShape(id: ShapeId): Shape | undefined;
|
|
47
91
|
getCurrentPageShapesSorted(): Shape[];
|
|
@@ -58,6 +102,10 @@ declare class DocumentStore {
|
|
|
58
102
|
maxX: number;
|
|
59
103
|
maxY: number;
|
|
60
104
|
}): Set<ShapeId>;
|
|
105
|
+
getSnapshot(): DocumentStoreSnapshot;
|
|
106
|
+
loadSnapshot(snapshot: DocumentStoreSnapshot): void;
|
|
107
|
+
listen(listener: DocumentStoreListener): () => void;
|
|
108
|
+
private emitChange;
|
|
61
109
|
}
|
|
62
110
|
|
|
63
111
|
interface PointerInput {
|
|
@@ -228,6 +276,7 @@ interface EditorOptions {
|
|
|
228
276
|
toolDefinitions?: ToolDefinition[];
|
|
229
277
|
initialToolId?: ToolId;
|
|
230
278
|
}
|
|
279
|
+
type EditorListener = () => void;
|
|
231
280
|
declare class Editor {
|
|
232
281
|
readonly store: DocumentStore;
|
|
233
282
|
readonly input: InputManager;
|
|
@@ -239,6 +288,7 @@ declare class Editor {
|
|
|
239
288
|
};
|
|
240
289
|
private drawStyle;
|
|
241
290
|
private readonly toolStateContext;
|
|
291
|
+
private readonly listeners;
|
|
242
292
|
constructor(opts?: EditorOptions);
|
|
243
293
|
registerToolDefinition(toolDefinition: ToolDefinition): void;
|
|
244
294
|
private getDefaultToolDefinitions;
|
|
@@ -269,12 +319,25 @@ declare class Editor {
|
|
|
269
319
|
dash: DashStyle;
|
|
270
320
|
size: SizeStyle;
|
|
271
321
|
}>): void;
|
|
322
|
+
setViewport(partial: Partial<Viewport>): void;
|
|
272
323
|
panBy(dx: number, dy: number): void;
|
|
324
|
+
getDocumentSnapshot(): TsdrawDocumentSnapshot;
|
|
325
|
+
loadDocumentSnapshot(snapshot: TsdrawDocumentSnapshot): void;
|
|
326
|
+
getSessionStateSnapshot(args?: {
|
|
327
|
+
selectedShapeIds?: ShapeId[];
|
|
328
|
+
}): TsdrawSessionStateSnapshot;
|
|
329
|
+
loadSessionStateSnapshot(snapshot: TsdrawSessionStateSnapshot): ShapeId[];
|
|
330
|
+
getPersistenceSnapshot(args?: {
|
|
331
|
+
selectedShapeIds?: ShapeId[];
|
|
332
|
+
}): TsdrawEditorSnapshot;
|
|
333
|
+
loadPersistenceSnapshot(snapshot: Partial<TsdrawEditorSnapshot>): ShapeId[];
|
|
334
|
+
listen(listener: EditorListener): () => void;
|
|
273
335
|
screenToPage(screenX: number, screenY: number): {
|
|
274
336
|
x: number;
|
|
275
337
|
y: number;
|
|
276
338
|
};
|
|
277
339
|
render(ctx: CanvasRenderingContext2D): void;
|
|
340
|
+
private emitChange;
|
|
278
341
|
}
|
|
279
342
|
|
|
280
343
|
declare class PenIdleState extends StateNode {
|
|
@@ -461,4 +524,4 @@ declare function decodePathToPoints(segments: {
|
|
|
461
524
|
y: number;
|
|
462
525
|
}[];
|
|
463
526
|
|
|
464
|
-
export { type Bounds, CanvasRenderer, type ColorStyle, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, type DashStyle, type DefaultToolId, DocumentStore, type DrawSegment, type DrawShape, ERASER_MARGIN, Editor, type EditorOptions, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, type ICanvasRenderer, type IEditor, InputManager, MAX_POINTS_PER_SHAPE, type PageState, PenDrawingState, PenIdleState, type PointerInput, type ResizeHandle, STROKE_WIDTHS, type SegmentType, SelectIdleState, type SelectionBounds, type Shape, type ShapeId, type SizeStyle, StateNode, type StateNodeConstructor, type ToolDefinition, type ToolId, type ToolKeyInfo, ToolManager, type ToolPointerDownInfo, type ToolPointerMoveInfo, type ToolStateContext, type ToolStateTransitionInfo, type TransformSnapshot, type TsdrawRenderTheme, type Vec3, type Viewport, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, encodePoints, getSelectionBoundsPage, getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
527
|
+
export { type Bounds, CanvasRenderer, type ColorStyle, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, type DashStyle, type DefaultToolId, DocumentStore, type DocumentStoreSnapshot, type DrawSegment, type DrawShape, ERASER_MARGIN, Editor, type EditorOptions, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, type ICanvasRenderer, type IEditor, InputManager, MAX_POINTS_PER_SHAPE, type PageState, PenDrawingState, PenIdleState, type PointerInput, type ResizeHandle, STROKE_WIDTHS, type SegmentType, SelectIdleState, type SelectionBounds, type Shape, type ShapeId, type SizeStyle, StateNode, type StateNodeConstructor, type ToolDefinition, type ToolId, type ToolKeyInfo, ToolManager, type ToolPointerDownInfo, type ToolPointerMoveInfo, type ToolStateContext, type ToolStateTransitionInfo, type TransformSnapshot, type TsdrawDocumentSnapshot, type TsdrawEditorSnapshot, type TsdrawPageRecord, type TsdrawPersistedRecord, type TsdrawRenderTheme, type TsdrawSessionStateSnapshot, type TsdrawShapeRecord, type Vec3, type Viewport, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, documentSnapshotToRecords, encodePoints, getSelectionBoundsPage, getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, recordsToDocumentSnapshot, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
package/dist/index.js
CHANGED
|
@@ -69,6 +69,12 @@ function decodePathToPoints(segments, ox, oy) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// src/store/documentStore.ts
|
|
72
|
+
function cloneValue(value) {
|
|
73
|
+
if (typeof structuredClone === "function") {
|
|
74
|
+
return structuredClone(value);
|
|
75
|
+
}
|
|
76
|
+
return JSON.parse(JSON.stringify(value));
|
|
77
|
+
}
|
|
72
78
|
var DocumentStore = class {
|
|
73
79
|
state = {
|
|
74
80
|
id: "page-1",
|
|
@@ -76,6 +82,7 @@ var DocumentStore = class {
|
|
|
76
82
|
erasingShapeIds: []
|
|
77
83
|
};
|
|
78
84
|
order = [];
|
|
85
|
+
listeners = /* @__PURE__ */ new Set();
|
|
79
86
|
getPage() {
|
|
80
87
|
return this.state;
|
|
81
88
|
}
|
|
@@ -96,15 +103,18 @@ var DocumentStore = class {
|
|
|
96
103
|
}
|
|
97
104
|
setErasingShapes(ids) {
|
|
98
105
|
this.state.erasingShapeIds = ids;
|
|
106
|
+
this.emitChange();
|
|
99
107
|
}
|
|
100
108
|
createShape(shape) {
|
|
101
109
|
this.state.shapes[shape.id] = shape;
|
|
102
110
|
this.order.push(shape.id);
|
|
111
|
+
this.emitChange();
|
|
103
112
|
}
|
|
104
113
|
updateShape(id, partial) {
|
|
105
114
|
const existing = this.state.shapes[id];
|
|
106
115
|
if (!existing) return;
|
|
107
116
|
this.state.shapes[id] = { ...existing, ...partial, id };
|
|
117
|
+
this.emitChange();
|
|
108
118
|
}
|
|
109
119
|
deleteShapes(ids) {
|
|
110
120
|
for (const id of ids) {
|
|
@@ -112,6 +122,7 @@ var DocumentStore = class {
|
|
|
112
122
|
this.order = this.order.filter((i) => i !== id);
|
|
113
123
|
}
|
|
114
124
|
this.state.erasingShapeIds = this.state.erasingShapeIds.filter((i) => !ids.includes(i));
|
|
125
|
+
this.emitChange();
|
|
115
126
|
}
|
|
116
127
|
getCurrentPageShapes() {
|
|
117
128
|
return Object.values(this.state.shapes);
|
|
@@ -127,6 +138,35 @@ var DocumentStore = class {
|
|
|
127
138
|
}
|
|
128
139
|
return ids;
|
|
129
140
|
}
|
|
141
|
+
getSnapshot() {
|
|
142
|
+
return {
|
|
143
|
+
page: cloneValue(this.state),
|
|
144
|
+
order: [...this.order]
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// Load snapshot into the document when loading a persistence snapshot (so on page reload)
|
|
148
|
+
loadSnapshot(snapshot) {
|
|
149
|
+
const pageState = cloneValue(snapshot.page);
|
|
150
|
+
const normalizedOrder = [...snapshot.order].filter((shapeId) => pageState.shapes[shapeId] != null);
|
|
151
|
+
this.state = {
|
|
152
|
+
id: pageState.id,
|
|
153
|
+
shapes: pageState.shapes,
|
|
154
|
+
erasingShapeIds: pageState.erasingShapeIds.filter((shapeId) => pageState.shapes[shapeId] != null)
|
|
155
|
+
};
|
|
156
|
+
this.order = normalizedOrder;
|
|
157
|
+
this.emitChange();
|
|
158
|
+
}
|
|
159
|
+
listen(listener) {
|
|
160
|
+
this.listeners.add(listener);
|
|
161
|
+
return () => {
|
|
162
|
+
this.listeners.delete(listener);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
emitChange() {
|
|
166
|
+
for (const listener of this.listeners) {
|
|
167
|
+
listener();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
130
170
|
};
|
|
131
171
|
function getShapeBounds(shape) {
|
|
132
172
|
if (shape.type !== "draw") {
|
|
@@ -1288,10 +1328,68 @@ var HandDraggingState = class extends StateNode {
|
|
|
1288
1328
|
}
|
|
1289
1329
|
};
|
|
1290
1330
|
|
|
1331
|
+
// src/persistence/snapshots.ts
|
|
1332
|
+
var PAGE_RECORD_ID = "page:current";
|
|
1333
|
+
function cloneValue2(value) {
|
|
1334
|
+
if (typeof structuredClone === "function") {
|
|
1335
|
+
return structuredClone(value);
|
|
1336
|
+
}
|
|
1337
|
+
return JSON.parse(JSON.stringify(value));
|
|
1338
|
+
}
|
|
1339
|
+
function asDrawShape(value) {
|
|
1340
|
+
return cloneValue2(value);
|
|
1341
|
+
}
|
|
1342
|
+
function documentSnapshotToRecords(snapshot) {
|
|
1343
|
+
const shapeIds = [...snapshot.order].filter((id) => snapshot.page.shapes[id] != null);
|
|
1344
|
+
const pageRecord = {
|
|
1345
|
+
id: PAGE_RECORD_ID,
|
|
1346
|
+
typeName: "page",
|
|
1347
|
+
pageId: snapshot.page.id,
|
|
1348
|
+
shapeIds,
|
|
1349
|
+
erasingShapeIds: [...snapshot.page.erasingShapeIds]
|
|
1350
|
+
};
|
|
1351
|
+
const shapeRecords = shapeIds.map((shapeId) => snapshot.page.shapes[shapeId]).filter((shape) => shape != null).map((shape) => ({
|
|
1352
|
+
id: shape.id,
|
|
1353
|
+
typeName: "shape",
|
|
1354
|
+
shape: asDrawShape(shape)
|
|
1355
|
+
}));
|
|
1356
|
+
return [pageRecord, ...shapeRecords];
|
|
1357
|
+
}
|
|
1358
|
+
function recordsToDocumentSnapshot(records) {
|
|
1359
|
+
const pageRecord = records.find((record) => record.typeName === "page");
|
|
1360
|
+
if (!pageRecord) {
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
const shapeRecordMap = /* @__PURE__ */ new Map();
|
|
1364
|
+
for (const record of records) {
|
|
1365
|
+
if (record.typeName === "shape") {
|
|
1366
|
+
shapeRecordMap.set(record.id, record);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const shapes = {};
|
|
1370
|
+
const order = [];
|
|
1371
|
+
for (const shapeId of pageRecord.shapeIds) {
|
|
1372
|
+
const shapeRecord = shapeRecordMap.get(shapeId);
|
|
1373
|
+
if (!shapeRecord) continue;
|
|
1374
|
+
shapes[shapeId] = asDrawShape(shapeRecord.shape);
|
|
1375
|
+
order.push(shapeId);
|
|
1376
|
+
}
|
|
1377
|
+
return {
|
|
1378
|
+
page: {
|
|
1379
|
+
id: pageRecord.pageId,
|
|
1380
|
+
shapes,
|
|
1381
|
+
erasingShapeIds: [...pageRecord.erasingShapeIds].filter((shapeId) => shapes[shapeId] != null)
|
|
1382
|
+
},
|
|
1383
|
+
order
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1291
1387
|
// src/editor/Editor.ts
|
|
1292
1388
|
var shapeIdCounter = 0;
|
|
1389
|
+
var shapeIdRuntimeSeed = Math.random().toString(36).slice(2, 8);
|
|
1293
1390
|
function createShapeId() {
|
|
1294
|
-
|
|
1391
|
+
shapeIdCounter += 1;
|
|
1392
|
+
return `shape:${Date.now().toString(36)}-${shapeIdRuntimeSeed}-${shapeIdCounter.toString(36)}`;
|
|
1295
1393
|
}
|
|
1296
1394
|
var Editor = class {
|
|
1297
1395
|
store = new DocumentStore();
|
|
@@ -1307,9 +1405,11 @@ var Editor = class {
|
|
|
1307
1405
|
size: "m"
|
|
1308
1406
|
};
|
|
1309
1407
|
toolStateContext;
|
|
1408
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1310
1409
|
// Creates a new editor instance with the given options (with defaults if not provided)
|
|
1311
1410
|
constructor(opts = {}) {
|
|
1312
1411
|
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED };
|
|
1412
|
+
this.store.listen(() => this.emitChange());
|
|
1313
1413
|
this.toolStateContext = {
|
|
1314
1414
|
transition: (id, info) => this.tools.transition(id, info)
|
|
1315
1415
|
};
|
|
@@ -1319,7 +1419,7 @@ var Editor = class {
|
|
|
1319
1419
|
for (const customTool of opts.toolDefinitions ?? []) {
|
|
1320
1420
|
this.registerToolDefinition(customTool);
|
|
1321
1421
|
}
|
|
1322
|
-
this.
|
|
1422
|
+
this.setCurrentTool(opts.initialToolId ?? "pen");
|
|
1323
1423
|
}
|
|
1324
1424
|
registerToolDefinition(toolDefinition) {
|
|
1325
1425
|
for (const stateConstructor of toolDefinition.stateConstructors) {
|
|
@@ -1380,6 +1480,7 @@ var Editor = class {
|
|
|
1380
1480
|
}
|
|
1381
1481
|
setCurrentTool(id) {
|
|
1382
1482
|
this.tools.setCurrentTool(id);
|
|
1483
|
+
this.emitChange();
|
|
1383
1484
|
}
|
|
1384
1485
|
getCurrentToolId() {
|
|
1385
1486
|
return this.tools.getCurrentToolId();
|
|
@@ -1389,10 +1490,73 @@ var Editor = class {
|
|
|
1389
1490
|
}
|
|
1390
1491
|
setCurrentDrawStyle(partial) {
|
|
1391
1492
|
this.drawStyle = { ...this.drawStyle, ...partial };
|
|
1493
|
+
this.emitChange();
|
|
1494
|
+
}
|
|
1495
|
+
setViewport(partial) {
|
|
1496
|
+
this.viewport = {
|
|
1497
|
+
x: partial.x ?? this.viewport.x,
|
|
1498
|
+
y: partial.y ?? this.viewport.y,
|
|
1499
|
+
zoom: partial.zoom ?? this.viewport.zoom
|
|
1500
|
+
};
|
|
1501
|
+
this.emitChange();
|
|
1392
1502
|
}
|
|
1393
1503
|
panBy(dx, dy) {
|
|
1394
|
-
this.
|
|
1395
|
-
|
|
1504
|
+
this.setViewport({
|
|
1505
|
+
x: this.viewport.x + dx,
|
|
1506
|
+
y: this.viewport.y + dy
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
getDocumentSnapshot() {
|
|
1510
|
+
return {
|
|
1511
|
+
records: documentSnapshotToRecords(this.store.getSnapshot())
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
loadDocumentSnapshot(snapshot) {
|
|
1515
|
+
const documentSnapshot = recordsToDocumentSnapshot(snapshot.records);
|
|
1516
|
+
if (!documentSnapshot) return;
|
|
1517
|
+
this.store.loadSnapshot(documentSnapshot);
|
|
1518
|
+
}
|
|
1519
|
+
getSessionStateSnapshot(args) {
|
|
1520
|
+
return {
|
|
1521
|
+
version: 1,
|
|
1522
|
+
viewport: {
|
|
1523
|
+
x: this.viewport.x,
|
|
1524
|
+
y: this.viewport.y,
|
|
1525
|
+
zoom: this.viewport.zoom
|
|
1526
|
+
},
|
|
1527
|
+
currentToolId: this.getCurrentToolId(),
|
|
1528
|
+
drawStyle: this.getCurrentDrawStyle(),
|
|
1529
|
+
selectedShapeIds: [...args?.selectedShapeIds ?? []]
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
loadSessionStateSnapshot(snapshot) {
|
|
1533
|
+
this.setViewport(snapshot.viewport);
|
|
1534
|
+
this.setCurrentDrawStyle(snapshot.drawStyle);
|
|
1535
|
+
if (this.tools.hasTool(snapshot.currentToolId)) {
|
|
1536
|
+
this.setCurrentTool(snapshot.currentToolId);
|
|
1537
|
+
}
|
|
1538
|
+
return [...snapshot.selectedShapeIds];
|
|
1539
|
+
}
|
|
1540
|
+
getPersistenceSnapshot(args) {
|
|
1541
|
+
return {
|
|
1542
|
+
document: this.getDocumentSnapshot(),
|
|
1543
|
+
state: this.getSessionStateSnapshot(args)
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
loadPersistenceSnapshot(snapshot) {
|
|
1547
|
+
if (snapshot.document) {
|
|
1548
|
+
this.loadDocumentSnapshot(snapshot.document);
|
|
1549
|
+
}
|
|
1550
|
+
if (snapshot.state) {
|
|
1551
|
+
return this.loadSessionStateSnapshot(snapshot.state);
|
|
1552
|
+
}
|
|
1553
|
+
return [];
|
|
1554
|
+
}
|
|
1555
|
+
listen(listener) {
|
|
1556
|
+
this.listeners.add(listener);
|
|
1557
|
+
return () => {
|
|
1558
|
+
this.listeners.delete(listener);
|
|
1559
|
+
};
|
|
1396
1560
|
}
|
|
1397
1561
|
// Convert screen coords to page coords
|
|
1398
1562
|
screenToPage(screenX, screenY) {
|
|
@@ -1405,6 +1569,11 @@ var Editor = class {
|
|
|
1405
1569
|
const visible = shapes.filter((s) => !erasingIds.has(s.id));
|
|
1406
1570
|
this.renderer.render(ctx, this.viewport, visible);
|
|
1407
1571
|
}
|
|
1572
|
+
emitChange() {
|
|
1573
|
+
for (const listener of this.listeners) {
|
|
1574
|
+
listener();
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1408
1577
|
};
|
|
1409
1578
|
|
|
1410
1579
|
// src/tools/select/selectHelpers.ts
|
|
@@ -1648,6 +1817,6 @@ function applyResize(editor, handle, startBounds, startShapes, pointer, lockAspe
|
|
|
1648
1817
|
}
|
|
1649
1818
|
}
|
|
1650
1819
|
|
|
1651
|
-
export { CanvasRenderer, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, DocumentStore, ERASER_MARGIN, Editor, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, InputManager, MAX_POINTS_PER_SHAPE, PenDrawingState, PenIdleState, STROKE_WIDTHS, SelectIdleState, StateNode, ToolManager, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, encodePoints, getSelectionBoundsPage, getShapeBounds2 as getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
1820
|
+
export { CanvasRenderer, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, DocumentStore, ERASER_MARGIN, Editor, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, InputManager, MAX_POINTS_PER_SHAPE, PenDrawingState, PenIdleState, STROKE_WIDTHS, SelectIdleState, StateNode, ToolManager, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, documentSnapshotToRecords, encodePoints, getSelectionBoundsPage, getShapeBounds2 as getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, recordsToDocumentSnapshot, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
1652
1821
|
//# sourceMappingURL=index.js.map
|
|
1653
1822
|
//# sourceMappingURL=index.js.map
|