@rollstack/rscanvas 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -23,6 +23,7 @@ const state: RSCanvasStateConfig = {
23
23
  y: 50,
24
24
  width: 200,
25
25
  height: 40,
26
+ rotation: 0,
26
27
  options: { text: "Hello world" },
27
28
  },
28
29
  image1: {
@@ -31,6 +32,7 @@ const state: RSCanvasStateConfig = {
31
32
  y: 120,
32
33
  width: 150,
33
34
  height: 100,
35
+ rotation: 0,
34
36
  options: { type: "url", url: "https://example.com/image.png" },
35
37
  },
36
38
  },
@@ -253,7 +255,7 @@ RSCanvas uses a `requestAnimationFrame`-based paint loop. Mutations never touch
253
255
 
254
256
  ![Paint loop sequence diagram](paint_loop.png)
255
257
 
256
- `setState` is deferred: the incoming state is stored as `_pendingState` and applied at the start of the next paint. If the canvas mutated its own state between the `setState` call and the paint (e.g. the user dragged an object), the pending state is stale and is dropped. This prevents echoed state from the host from overwriting newer internal changes.
258
+ `setState` is deferred: the incoming state is stored as `_pendingState` and applied at the start of the next paint. If the canvas mutated its own state between the `setState` call and the paint (e.g. the user dragged an object), the pending state is stale and is dropped.
257
259
 
258
260
  ### Events
259
261
 
package/dist/index.d.mts CHANGED
@@ -14,59 +14,18 @@ interface RSObjectConfig {
14
14
  options: RSObjectOptionsConfig;
15
15
  }
16
16
  /**
17
- * State configuration for the canvas.
17
+ * A single slide containing objects.
18
18
  */
19
- interface RSCanvasStateConfig {
20
- /**
21
- * Objects configuration for the canvas as key-value pairs of object id and object config.
22
- *
23
- * @example
24
- /**
25
- * Example (!!! claude-generated :| !!!!)
26
- *
27
- * ```ts
28
- * const canvasState: RSCanvasStateConfig = {
29
- * objects: {
30
- * "text1": {
31
- * type: "text",
32
- * x: 100,
33
- * y: 80,
34
- * width: 200,
35
- * height: 60,
36
- * options: {
37
- * text: "Hello world!",
38
- * fontSize: 20,
39
- * color: "#222"
40
- * }
41
- * },
42
- * "image1": {
43
- * type: "image",
44
- * x: 250,
45
- * y: 170,
46
- * width: 120,
47
- * height: 90,
48
- * options: {
49
- * url: "https://placekitten.com/200/300"
50
- * }
51
- * },
52
- * "richtext1": {
53
- * type: "richtext",
54
- * x: 400,
55
- * y: 230,
56
- * width: 300,
57
- * height: 120,
58
- * options: {
59
- * content: [
60
- * { type: "paragraph", children: [{ text: "Supports " }, { text: "rich", bold: true }, { text: " text." }] }
61
- * ]
62
- * }
63
- * }
64
- * }
65
- * }
66
- * ```
67
- */
19
+ interface RSSlideConfig {
20
+ id: string;
68
21
  objects: Record<string, RSObjectConfig>;
69
22
  }
23
+ /**
24
+ * State configuration for the canvas — an array of slides.
25
+ */
26
+ interface RSCanvasStateConfig {
27
+ slides: RSSlideConfig[];
28
+ }
70
29
  interface RSObject<T> {
71
30
  isStateEqual(state: T): boolean;
72
31
  updateState(state: T): void;
@@ -119,9 +78,19 @@ interface RSControl {
119
78
  render(node: HTMLElement): void;
120
79
  destroy(): void;
121
80
  }
81
+ /** Minimal interface for an object node (position + size). */
82
+ interface RSObjectNodeLike {
83
+ getX(): number;
84
+ getY(): number;
85
+ getWidth(): number;
86
+ getHeight(): number;
87
+ getId(): string;
88
+ getType(): string;
89
+ }
122
90
  interface RSCanvasLike {
123
91
  changeCursor(cursor: string): void;
124
92
  getScale(): number;
93
+ toWorldSize(viewSize: number): number;
125
94
  toWorldX(viewX: number): number;
126
95
  toWorldY(viewY: number): number;
127
96
  objectIdAtXY(viewX: number, viewY: number): string | null;
@@ -130,12 +99,7 @@ interface RSCanvasLike {
130
99
  getCornerWorldXYSFCT(objectId: string, corner: RSCanvasCorner, out: RSWorldXY): boolean;
131
100
  getCanvasWidth(): number;
132
101
  getCanvasHeight(): number;
133
- getObjectNode(objectId: string): {
134
- getX(): number;
135
- getY(): number;
136
- getWidth(): number;
137
- getHeight(): number;
138
- } | null;
102
+ getObjectNode(objectId: string): RSObjectNodeLike | null;
139
103
  resizeObject(objectId: string, dw: number, dh: number): void;
140
104
  rotateObject(objectId: string, dAngle: number): void;
141
105
  translateObject(objectId: string, dx: number, dy: number): void;
@@ -149,6 +113,7 @@ interface RSCanvasLike {
149
113
  startEditSession(objectId: string, handle: RSObjectEditingSessionHandle): boolean;
150
114
  deleteObject(objectId: string): void;
151
115
  addControlToFront(ControlCtor: new (canvas: RSCanvasLike) => RSControl): RSControl;
116
+ forEachObject(fn: (node: RSObjectNodeLike) => void): void;
152
117
  }
153
118
 
154
119
  type RSCanvasOptions = {
@@ -165,6 +130,8 @@ declare class RSCanvas implements RSCanvasLike {
165
130
  private _translateX;
166
131
  private _translateY;
167
132
  private _objects;
133
+ private _slides;
134
+ private _selectedSlideId;
168
135
  private _objectConstructors;
169
136
  private _objectEditorConstructors;
170
137
  private _editingObjectId;
@@ -182,15 +149,14 @@ declare class RSCanvas implements RSCanvasLike {
182
149
  private _resizeObserver;
183
150
  private _boundingClientRect;
184
151
  private readonly _controls;
185
- private readonly _onPaint;
186
152
  private readonly _localInvalidate;
187
153
  constructor(container: HTMLDivElement, options?: RSCanvasOptions);
154
+ private readonly _onPaint;
188
155
  private _setupEventListeners;
189
156
  private _updateBoundingClientRect;
190
157
  private _viewXFromEvent;
191
158
  private _viewYFromEvent;
192
159
  private _emit;
193
- private _paint;
194
160
  private _invalidate;
195
161
  private _cornerWorldPosSFCT;
196
162
  private _emitStateChanged;
@@ -208,6 +174,7 @@ declare class RSCanvas implements RSCanvasLike {
208
174
  private _onKeyUp;
209
175
  private _on;
210
176
  private _getObjectEditorConstructor;
177
+ private _findSlideIndexById;
211
178
  private _updateObjectTree;
212
179
  onHighlight(fn: RSCanvasHighlightHandler): void;
213
180
  onStateChanged(fn: RSCanvasStateChangedHandler<RSCanvas>): void;
@@ -215,9 +182,12 @@ declare class RSCanvas implements RSCanvasLike {
215
182
  registerObjectTypeEditor(objectType: string, constructor: RSObjectEditorConstructor<RSObjectOptionsConfig>): void;
216
183
  setState(state: RSCanvasStateConfig): void;
217
184
  getStateSFCT(state: RSCanvasStateConfig): void;
185
+ getSelectedSlideId(): string | null;
186
+ setSelectedSlide(slideId: string): void;
218
187
  changeCursor(cursor: string): void;
219
188
  addControlToFront(ControlCtor: new (canvas: RSCanvasLike) => RSControl): RSControl;
220
189
  getScale(): number;
190
+ toWorldSize(viewSize: number): number;
221
191
  toWorldX(viewX: number): number;
222
192
  toWorldY(viewY: number): number;
223
193
  toViewX(worldX: number): number;
@@ -228,12 +198,7 @@ declare class RSCanvas implements RSCanvasLike {
228
198
  getCornerWorldXYSFCT(objectId: string, corner: RSCanvasCorner, out: RSWorldXY): boolean;
229
199
  getCanvasWidth(): number;
230
200
  getCanvasHeight(): number;
231
- getObjectNode(objectId: string): {
232
- getX(): number;
233
- getY(): number;
234
- getWidth(): number;
235
- getHeight(): number;
236
- } | null;
201
+ getObjectNode(objectId: string): RSObjectNodeLike | null;
237
202
  resizeObject(objectId: string, dw: number, dh: number): void;
238
203
  rotateObject(objectId: string, dAngle: number): void;
239
204
  translateObject(objectId: string, dx: number, dy: number): void;
@@ -247,6 +212,7 @@ declare class RSCanvas implements RSCanvasLike {
247
212
  canEditObject(objectId: string): boolean;
248
213
  startEditSession(objectId: string, hostHandle: RSObjectEditingSessionHandle): boolean;
249
214
  deleteObject(objectId: string): void;
215
+ forEachObject(fn: (node: RSObjectNodeLike) => void): void;
250
216
  saveToImage(callback: (blob: Blob) => void): Promise<void>;
251
217
  destroy(): void;
252
218
  }
@@ -266,4 +232,4 @@ interface RSImageObjectOptionsConfig extends RSObjectOptionsConfig {
266
232
  key?: string;
267
233
  }
268
234
 
269
- export { RSCanvas, type RSCanvasCorner, type RSCanvasEvent, type RSCanvasEventType, type RSCanvasHighlightHandler, type RSCanvasLike, type RSCanvasOptions, type RSCanvasStateChangedHandler, type RSCanvasStateConfig, type RSControl, type RSEditorHandle, type RSImageObjectOptionsConfig, type RSObject, type RSObjectConfig, type RSObjectConstructor, type RSObjectEditingSessionHandle, type RSObjectEditor, type RSObjectEditorConstructor, type RSObjectOptionsConfig, type RSRichTextObjectOptionsConfig, type RSTextObjectOptionsConfig, type RSViewXY, type RSWorldXY, richTextSchema };
235
+ export { RSCanvas, type RSCanvasCorner, type RSCanvasEvent, type RSCanvasEventType, type RSCanvasHighlightHandler, type RSCanvasLike, type RSCanvasOptions, type RSCanvasStateChangedHandler, type RSCanvasStateConfig, type RSControl, type RSEditorHandle, type RSImageObjectOptionsConfig, type RSObject, type RSObjectConfig, type RSObjectConstructor, type RSObjectEditingSessionHandle, type RSObjectEditor, type RSObjectEditorConstructor, type RSObjectNodeLike, type RSObjectOptionsConfig, type RSRichTextObjectOptionsConfig, type RSSlideConfig, type RSTextObjectOptionsConfig, type RSViewXY, type RSWorldXY, richTextSchema };
package/dist/index.d.ts CHANGED
@@ -14,59 +14,18 @@ interface RSObjectConfig {
14
14
  options: RSObjectOptionsConfig;
15
15
  }
16
16
  /**
17
- * State configuration for the canvas.
17
+ * A single slide containing objects.
18
18
  */
19
- interface RSCanvasStateConfig {
20
- /**
21
- * Objects configuration for the canvas as key-value pairs of object id and object config.
22
- *
23
- * @example
24
- /**
25
- * Example (!!! claude-generated :| !!!!)
26
- *
27
- * ```ts
28
- * const canvasState: RSCanvasStateConfig = {
29
- * objects: {
30
- * "text1": {
31
- * type: "text",
32
- * x: 100,
33
- * y: 80,
34
- * width: 200,
35
- * height: 60,
36
- * options: {
37
- * text: "Hello world!",
38
- * fontSize: 20,
39
- * color: "#222"
40
- * }
41
- * },
42
- * "image1": {
43
- * type: "image",
44
- * x: 250,
45
- * y: 170,
46
- * width: 120,
47
- * height: 90,
48
- * options: {
49
- * url: "https://placekitten.com/200/300"
50
- * }
51
- * },
52
- * "richtext1": {
53
- * type: "richtext",
54
- * x: 400,
55
- * y: 230,
56
- * width: 300,
57
- * height: 120,
58
- * options: {
59
- * content: [
60
- * { type: "paragraph", children: [{ text: "Supports " }, { text: "rich", bold: true }, { text: " text." }] }
61
- * ]
62
- * }
63
- * }
64
- * }
65
- * }
66
- * ```
67
- */
19
+ interface RSSlideConfig {
20
+ id: string;
68
21
  objects: Record<string, RSObjectConfig>;
69
22
  }
23
+ /**
24
+ * State configuration for the canvas — an array of slides.
25
+ */
26
+ interface RSCanvasStateConfig {
27
+ slides: RSSlideConfig[];
28
+ }
70
29
  interface RSObject<T> {
71
30
  isStateEqual(state: T): boolean;
72
31
  updateState(state: T): void;
@@ -119,9 +78,19 @@ interface RSControl {
119
78
  render(node: HTMLElement): void;
120
79
  destroy(): void;
121
80
  }
81
+ /** Minimal interface for an object node (position + size). */
82
+ interface RSObjectNodeLike {
83
+ getX(): number;
84
+ getY(): number;
85
+ getWidth(): number;
86
+ getHeight(): number;
87
+ getId(): string;
88
+ getType(): string;
89
+ }
122
90
  interface RSCanvasLike {
123
91
  changeCursor(cursor: string): void;
124
92
  getScale(): number;
93
+ toWorldSize(viewSize: number): number;
125
94
  toWorldX(viewX: number): number;
126
95
  toWorldY(viewY: number): number;
127
96
  objectIdAtXY(viewX: number, viewY: number): string | null;
@@ -130,12 +99,7 @@ interface RSCanvasLike {
130
99
  getCornerWorldXYSFCT(objectId: string, corner: RSCanvasCorner, out: RSWorldXY): boolean;
131
100
  getCanvasWidth(): number;
132
101
  getCanvasHeight(): number;
133
- getObjectNode(objectId: string): {
134
- getX(): number;
135
- getY(): number;
136
- getWidth(): number;
137
- getHeight(): number;
138
- } | null;
102
+ getObjectNode(objectId: string): RSObjectNodeLike | null;
139
103
  resizeObject(objectId: string, dw: number, dh: number): void;
140
104
  rotateObject(objectId: string, dAngle: number): void;
141
105
  translateObject(objectId: string, dx: number, dy: number): void;
@@ -149,6 +113,7 @@ interface RSCanvasLike {
149
113
  startEditSession(objectId: string, handle: RSObjectEditingSessionHandle): boolean;
150
114
  deleteObject(objectId: string): void;
151
115
  addControlToFront(ControlCtor: new (canvas: RSCanvasLike) => RSControl): RSControl;
116
+ forEachObject(fn: (node: RSObjectNodeLike) => void): void;
152
117
  }
153
118
 
154
119
  type RSCanvasOptions = {
@@ -165,6 +130,8 @@ declare class RSCanvas implements RSCanvasLike {
165
130
  private _translateX;
166
131
  private _translateY;
167
132
  private _objects;
133
+ private _slides;
134
+ private _selectedSlideId;
168
135
  private _objectConstructors;
169
136
  private _objectEditorConstructors;
170
137
  private _editingObjectId;
@@ -182,15 +149,14 @@ declare class RSCanvas implements RSCanvasLike {
182
149
  private _resizeObserver;
183
150
  private _boundingClientRect;
184
151
  private readonly _controls;
185
- private readonly _onPaint;
186
152
  private readonly _localInvalidate;
187
153
  constructor(container: HTMLDivElement, options?: RSCanvasOptions);
154
+ private readonly _onPaint;
188
155
  private _setupEventListeners;
189
156
  private _updateBoundingClientRect;
190
157
  private _viewXFromEvent;
191
158
  private _viewYFromEvent;
192
159
  private _emit;
193
- private _paint;
194
160
  private _invalidate;
195
161
  private _cornerWorldPosSFCT;
196
162
  private _emitStateChanged;
@@ -208,6 +174,7 @@ declare class RSCanvas implements RSCanvasLike {
208
174
  private _onKeyUp;
209
175
  private _on;
210
176
  private _getObjectEditorConstructor;
177
+ private _findSlideIndexById;
211
178
  private _updateObjectTree;
212
179
  onHighlight(fn: RSCanvasHighlightHandler): void;
213
180
  onStateChanged(fn: RSCanvasStateChangedHandler<RSCanvas>): void;
@@ -215,9 +182,12 @@ declare class RSCanvas implements RSCanvasLike {
215
182
  registerObjectTypeEditor(objectType: string, constructor: RSObjectEditorConstructor<RSObjectOptionsConfig>): void;
216
183
  setState(state: RSCanvasStateConfig): void;
217
184
  getStateSFCT(state: RSCanvasStateConfig): void;
185
+ getSelectedSlideId(): string | null;
186
+ setSelectedSlide(slideId: string): void;
218
187
  changeCursor(cursor: string): void;
219
188
  addControlToFront(ControlCtor: new (canvas: RSCanvasLike) => RSControl): RSControl;
220
189
  getScale(): number;
190
+ toWorldSize(viewSize: number): number;
221
191
  toWorldX(viewX: number): number;
222
192
  toWorldY(viewY: number): number;
223
193
  toViewX(worldX: number): number;
@@ -228,12 +198,7 @@ declare class RSCanvas implements RSCanvasLike {
228
198
  getCornerWorldXYSFCT(objectId: string, corner: RSCanvasCorner, out: RSWorldXY): boolean;
229
199
  getCanvasWidth(): number;
230
200
  getCanvasHeight(): number;
231
- getObjectNode(objectId: string): {
232
- getX(): number;
233
- getY(): number;
234
- getWidth(): number;
235
- getHeight(): number;
236
- } | null;
201
+ getObjectNode(objectId: string): RSObjectNodeLike | null;
237
202
  resizeObject(objectId: string, dw: number, dh: number): void;
238
203
  rotateObject(objectId: string, dAngle: number): void;
239
204
  translateObject(objectId: string, dx: number, dy: number): void;
@@ -247,6 +212,7 @@ declare class RSCanvas implements RSCanvasLike {
247
212
  canEditObject(objectId: string): boolean;
248
213
  startEditSession(objectId: string, hostHandle: RSObjectEditingSessionHandle): boolean;
249
214
  deleteObject(objectId: string): void;
215
+ forEachObject(fn: (node: RSObjectNodeLike) => void): void;
250
216
  saveToImage(callback: (blob: Blob) => void): Promise<void>;
251
217
  destroy(): void;
252
218
  }
@@ -266,4 +232,4 @@ interface RSImageObjectOptionsConfig extends RSObjectOptionsConfig {
266
232
  key?: string;
267
233
  }
268
234
 
269
- export { RSCanvas, type RSCanvasCorner, type RSCanvasEvent, type RSCanvasEventType, type RSCanvasHighlightHandler, type RSCanvasLike, type RSCanvasOptions, type RSCanvasStateChangedHandler, type RSCanvasStateConfig, type RSControl, type RSEditorHandle, type RSImageObjectOptionsConfig, type RSObject, type RSObjectConfig, type RSObjectConstructor, type RSObjectEditingSessionHandle, type RSObjectEditor, type RSObjectEditorConstructor, type RSObjectOptionsConfig, type RSRichTextObjectOptionsConfig, type RSTextObjectOptionsConfig, type RSViewXY, type RSWorldXY, richTextSchema };
235
+ export { RSCanvas, type RSCanvasCorner, type RSCanvasEvent, type RSCanvasEventType, type RSCanvasHighlightHandler, type RSCanvasLike, type RSCanvasOptions, type RSCanvasStateChangedHandler, type RSCanvasStateConfig, type RSControl, type RSEditorHandle, type RSImageObjectOptionsConfig, type RSObject, type RSObjectConfig, type RSObjectConstructor, type RSObjectEditingSessionHandle, type RSObjectEditor, type RSObjectEditorConstructor, type RSObjectNodeLike, type RSObjectOptionsConfig, type RSRichTextObjectOptionsConfig, type RSSlideConfig, type RSTextObjectOptionsConfig, type RSViewXY, type RSWorldXY, richTextSchema };