@pooder/kit 2.0.0 → 3.0.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/src/mirror.ts CHANGED
@@ -1,39 +1,99 @@
1
- import { Command, Editor, Extension, OptionSchema } from "@pooder/core";
1
+ import {
2
+ Extension,
3
+ ExtensionContext,
4
+ ContributionPointIds,
5
+ CommandContribution,
6
+ ConfigurationContribution,
7
+ } from "@pooder/core";
8
+ import CanvasService from "./CanvasService";
2
9
 
3
- export interface MirrorToolOptions {
4
- enabled: boolean;
5
- }
10
+ export class MirrorTool implements Extension {
11
+ id = "pooder.kit.mirror";
6
12
 
7
- export class MirrorTool implements Extension<MirrorToolOptions> {
8
- public name = "MirrorTool";
9
- public options: MirrorToolOptions = {
10
- enabled: false,
13
+ public metadata = {
14
+ name: "MirrorTool",
11
15
  };
16
+ private enabled = false;
12
17
 
13
- public schema: Record<keyof MirrorToolOptions, OptionSchema> = {
14
- enabled: {
15
- type: "boolean",
16
- label: "Mirror View",
17
- },
18
- };
18
+ private canvasService?: CanvasService;
19
19
 
20
- onMount(editor: Editor) {
21
- if (this.options.enabled) {
22
- this.applyMirror(editor, true);
20
+ constructor(
21
+ options?: Partial<{
22
+ enabled: boolean;
23
+ }>,
24
+ ) {
25
+ if (options) {
26
+ Object.assign(this, options);
23
27
  }
24
28
  }
25
29
 
26
- onUpdate(editor: Editor) {
27
- this.applyMirror(editor, this.options.enabled);
30
+ toJSON() {
31
+ return {
32
+ enabled: this.enabled,
33
+ };
28
34
  }
29
35
 
30
- onUnmount(editor: Editor) {
31
- // Force disable on unmount to restore view
32
- this.applyMirror(editor, false);
36
+ loadFromJSON(json: any) {
37
+ this.enabled = json.enabled;
33
38
  }
34
39
 
35
- private applyMirror(editor: Editor, enabled: boolean) {
36
- const canvas = editor.canvas;
40
+ activate(context: ExtensionContext) {
41
+ this.canvasService = context.services.get<CanvasService>("CanvasService");
42
+ if (!this.canvasService) {
43
+ console.warn("CanvasService not found for MirrorTool");
44
+ return;
45
+ }
46
+
47
+ const configService = context.services.get<any>("ConfigurationService");
48
+ if (configService) {
49
+ // Load initial config
50
+ this.enabled = configService.get("mirror.enabled", this.enabled);
51
+
52
+ // Listen for changes
53
+ configService.onAnyChange((e: { key: string; value: any }) => {
54
+ if (e.key === "mirror.enabled") {
55
+ this.applyMirror(e.value);
56
+ }
57
+ });
58
+ }
59
+
60
+ // Initialize with current state (if enabled was persisted)
61
+ if (this.enabled) {
62
+ this.applyMirror(true);
63
+ }
64
+ }
65
+
66
+ deactivate(context: ExtensionContext) {
67
+ this.applyMirror(false);
68
+ this.canvasService = undefined;
69
+ }
70
+
71
+ contribute() {
72
+ return {
73
+ [ContributionPointIds.CONFIGURATIONS]: [
74
+ {
75
+ id: "mirror.enabled",
76
+ type: "boolean",
77
+ label: "Enable Mirror",
78
+ default: false,
79
+ },
80
+ ] as ConfigurationContribution[],
81
+ [ContributionPointIds.COMMANDS]: [
82
+ {
83
+ command: "setMirror",
84
+ title: "Set Mirror",
85
+ handler: (enabled: boolean) => {
86
+ this.applyMirror(enabled);
87
+ return true;
88
+ },
89
+ },
90
+ ] as CommandContribution[],
91
+ };
92
+ }
93
+
94
+ private applyMirror(enabled: boolean) {
95
+ if (!this.canvasService) return;
96
+ const canvas = this.canvasService.canvas;
37
97
  if (!canvas) return;
38
98
 
39
99
  const width = canvas.width || 800;
@@ -54,6 +114,7 @@ export class MirrorTool implements Extension<MirrorToolOptions> {
54
114
 
55
115
  canvas.setViewportTransform(vpt as any);
56
116
  canvas.requestRenderAll();
117
+ this.enabled = true;
57
118
  } else if (!enabled && isFlipped) {
58
119
  // Restore
59
120
  vpt[0] = -vpt[0]; // Unflip scale
@@ -61,31 +122,7 @@ export class MirrorTool implements Extension<MirrorToolOptions> {
61
122
 
62
123
  canvas.setViewportTransform(vpt as any);
63
124
  canvas.requestRenderAll();
125
+ this.enabled = false;
64
126
  }
65
127
  }
66
-
67
- commands: Record<string, Command> = {
68
- toggleMirror: {
69
- execute: (editor: Editor) => {
70
- this.options.enabled = !this.options.enabled;
71
- this.applyMirror(editor, this.options.enabled);
72
- return true;
73
- },
74
- },
75
- setMirror: {
76
- execute: (editor: Editor, enabled: boolean) => {
77
- if (this.options.enabled === enabled) return true;
78
- this.options.enabled = enabled;
79
- this.applyMirror(editor, enabled);
80
- return true;
81
- },
82
- schema: {
83
- enabled: {
84
- type: "boolean",
85
- label: "Enabled",
86
- required: true,
87
- },
88
- },
89
- },
90
- };
91
128
  }
package/src/ruler.ts CHANGED
@@ -1,111 +1,216 @@
1
1
  import {
2
- Command,
3
- Editor,
4
- EditorState,
5
2
  Extension,
6
- OptionSchema,
7
- PooderLayer,
8
- Rect,
9
- Line,
10
- Text,
3
+ ExtensionContext,
4
+ ContributionPointIds,
5
+ CommandContribution,
6
+ ConfigurationContribution,
11
7
  } from "@pooder/core";
8
+ import { Rect, Line, Text } from "fabric";
9
+ import CanvasService from "./CanvasService";
12
10
 
13
- export interface RulerToolOptions {
14
- unit: "px" | "mm" | "cm" | "in";
15
- thickness: number;
16
- backgroundColor: string;
17
- textColor: string;
18
- lineColor: string;
19
- fontSize: number;
20
- }
21
-
22
- export class RulerTool implements Extension<RulerToolOptions> {
23
- public name = "RulerTool";
24
- public options: RulerToolOptions = {
25
- unit: "px",
26
- thickness: 20,
27
- backgroundColor: "#f0f0f0",
28
- textColor: "#333333",
29
- lineColor: "#999999",
30
- fontSize: 10,
31
- };
11
+ export class RulerTool implements Extension {
12
+ id = "pooder.kit.ruler";
32
13
 
33
- public schema: Record<keyof RulerToolOptions, OptionSchema> = {
34
- unit: {
35
- type: "select",
36
- options: ["px", "mm", "cm", "in"],
37
- label: "Unit",
38
- },
39
- thickness: { type: "number", min: 10, max: 100, label: "Thickness" },
40
- backgroundColor: { type: "color", label: "Background Color" },
41
- textColor: { type: "color", label: "Text Color" },
42
- lineColor: { type: "color", label: "Line Color" },
43
- fontSize: { type: "number", min: 8, max: 24, label: "Font Size" },
14
+ public metadata = {
15
+ name: "RulerTool",
44
16
  };
45
17
 
46
- onMount(editor: Editor) {
47
- this.createLayer(editor);
48
- this.updateRuler(editor);
18
+ private unit: "px" | "mm" | "cm" | "in" = "px";
19
+ private thickness: number = 20;
20
+ private backgroundColor: string = "#f0f0f0";
21
+ private textColor: string = "#333333";
22
+ private lineColor: string = "#999999";
23
+ private fontSize: number = 10;
24
+
25
+ private canvasService?: CanvasService;
26
+
27
+ constructor(
28
+ options?: Partial<{
29
+ unit: "px" | "mm" | "cm" | "in";
30
+ thickness: number;
31
+ backgroundColor: string;
32
+ textColor: string;
33
+ lineColor: string;
34
+ fontSize: number;
35
+ }>,
36
+ ) {
37
+ if (options) {
38
+ Object.assign(this, options);
39
+ }
49
40
  }
50
41
 
51
- onUnmount(editor: Editor) {
52
- this.destroyLayer(editor);
53
- }
42
+ activate(context: ExtensionContext) {
43
+ this.canvasService = context.services.get<CanvasService>("CanvasService");
44
+ if (!this.canvasService) {
45
+ console.warn("CanvasService not found for RulerTool");
46
+ return;
47
+ }
48
+
49
+ const configService = context.services.get<any>("ConfigurationService");
50
+ if (configService) {
51
+ // Load initial config
52
+ this.unit = configService.get("ruler.unit", this.unit);
53
+ this.thickness = configService.get("ruler.thickness", this.thickness);
54
+ this.backgroundColor = configService.get(
55
+ "ruler.backgroundColor",
56
+ this.backgroundColor,
57
+ );
58
+ this.textColor = configService.get("ruler.textColor", this.textColor);
59
+ this.lineColor = configService.get("ruler.lineColor", this.lineColor);
60
+ this.fontSize = configService.get("ruler.fontSize", this.fontSize);
61
+
62
+ // Listen for changes
63
+ configService.onAnyChange((e: { key: string; value: any }) => {
64
+ if (e.key.startsWith("ruler.")) {
65
+ const prop = e.key.split(".")[1];
66
+ if (prop && prop in this) {
67
+ (this as any)[prop] = e.value;
68
+ this.updateRuler();
69
+ }
70
+ }
71
+ });
72
+ }
54
73
 
55
- onUpdate(editor: Editor, state: EditorState) {
56
- this.updateRuler(editor);
74
+ this.createLayer();
75
+ this.updateRuler();
57
76
  }
58
77
 
59
- onDestroy(editor: Editor) {
60
- this.destroyLayer(editor);
78
+ deactivate(context: ExtensionContext) {
79
+ this.destroyLayer();
80
+ this.canvasService = undefined;
61
81
  }
62
82
 
63
- private getLayer(editor: Editor) {
64
- return editor.canvas
65
- .getObjects()
66
- .find((obj: any) => obj.data?.id === "ruler-overlay") as
67
- | PooderLayer
68
- | undefined;
83
+ contribute() {
84
+ return {
85
+ [ContributionPointIds.CONFIGURATIONS]: [
86
+ {
87
+ id: "ruler.unit",
88
+ type: "select",
89
+ label: "Unit",
90
+ options: ["px", "mm", "cm", "in"],
91
+ default: "px",
92
+ },
93
+ {
94
+ id: "ruler.thickness",
95
+ type: "number",
96
+ label: "Thickness",
97
+ min: 10,
98
+ max: 100,
99
+ default: 20,
100
+ },
101
+ {
102
+ id: "ruler.backgroundColor",
103
+ type: "color",
104
+ label: "Background Color",
105
+ default: "#f0f0f0",
106
+ },
107
+ {
108
+ id: "ruler.textColor",
109
+ type: "color",
110
+ label: "Text Color",
111
+ default: "#333333",
112
+ },
113
+ {
114
+ id: "ruler.lineColor",
115
+ type: "color",
116
+ label: "Line Color",
117
+ default: "#999999",
118
+ },
119
+ {
120
+ id: "ruler.fontSize",
121
+ type: "number",
122
+ label: "Font Size",
123
+ min: 8,
124
+ max: 24,
125
+ default: 10,
126
+ },
127
+ ] as ConfigurationContribution[],
128
+ [ContributionPointIds.COMMANDS]: [
129
+ {
130
+ command: "setUnit",
131
+ title: "Set Ruler Unit",
132
+ handler: (unit: "px" | "mm" | "cm" | "in") => {
133
+ if (this.unit === unit) return true;
134
+ this.unit = unit;
135
+ this.updateRuler();
136
+ return true;
137
+ },
138
+ },
139
+ {
140
+ command: "setTheme",
141
+ title: "Set Ruler Theme",
142
+ handler: (
143
+ theme: Partial<{
144
+ backgroundColor: string;
145
+ textColor: string;
146
+ lineColor: string;
147
+ fontSize: number;
148
+ thickness: number;
149
+ }>,
150
+ ) => {
151
+ const oldState = {
152
+ backgroundColor: this.backgroundColor,
153
+ textColor: this.textColor,
154
+ lineColor: this.lineColor,
155
+ fontSize: this.fontSize,
156
+ thickness: this.thickness,
157
+ };
158
+ const newState = { ...oldState, ...theme };
159
+ if (JSON.stringify(newState) === JSON.stringify(oldState))
160
+ return true;
161
+
162
+ Object.assign(this, newState);
163
+ this.updateRuler();
164
+ return true;
165
+ },
166
+ },
167
+ ] as CommandContribution[],
168
+ };
69
169
  }
70
170
 
71
- private createLayer(editor: Editor) {
72
- let layer = this.getLayer(editor);
171
+ private getLayer() {
172
+ return this.canvasService?.getLayer("ruler-overlay");
173
+ }
73
174
 
74
- if (!layer) {
75
- const width = editor.canvas.width || 800;
76
- const height = editor.canvas.height || 600;
175
+ private createLayer() {
176
+ if (!this.canvasService) return;
77
177
 
78
- layer = new PooderLayer([], {
79
- width,
80
- height,
81
- selectable: false,
82
- evented: false,
83
- data: { id: "ruler-overlay" },
84
- } as any);
178
+ const canvas = this.canvasService.canvas;
179
+ const width = canvas.width || 800;
180
+ const height = canvas.height || 600;
85
181
 
86
- editor.canvas.add(layer);
87
- }
182
+ const layer = this.canvasService.createLayer("ruler-overlay", {
183
+ width,
184
+ height,
185
+ selectable: false,
186
+ evented: false,
187
+ left: 0,
188
+ top: 0,
189
+ originX: "left",
190
+ originY: "top",
191
+ });
88
192
 
89
- editor.canvas.bringObjectToFront(layer);
193
+ canvas.bringObjectToFront(layer);
90
194
  }
91
195
 
92
- private destroyLayer(editor: Editor) {
93
- const layer = this.getLayer(editor);
196
+ private destroyLayer() {
197
+ if (!this.canvasService) return;
198
+ const layer = this.getLayer();
94
199
  if (layer) {
95
- editor.canvas.remove(layer);
200
+ this.canvasService.canvas.remove(layer);
96
201
  }
97
202
  }
98
203
 
99
- private updateRuler(editor: Editor) {
100
- const layer = this.getLayer(editor);
204
+ private updateRuler() {
205
+ if (!this.canvasService) return;
206
+ const layer = this.getLayer();
101
207
  if (!layer) return;
102
208
 
103
209
  layer.remove(...layer.getObjects());
104
210
 
105
- const { thickness, backgroundColor, lineColor, textColor, fontSize } =
106
- this.options;
107
- const width = editor.canvas.width || 800;
108
- const height = editor.canvas.height || 600;
211
+ const { thickness, backgroundColor, lineColor, textColor, fontSize } = this;
212
+ const width = this.canvasService.canvas.width || 800;
213
+ const height = this.canvasService.canvas.height || 600;
109
214
 
110
215
  // Backgrounds
111
216
  const topBg = new Rect({
@@ -140,7 +245,9 @@ export class RulerTool implements Extension<RulerToolOptions> {
140
245
  evented: false,
141
246
  });
142
247
 
143
- layer.add(topBg, leftBg, cornerBg);
248
+ layer.add(topBg);
249
+ layer.add(leftBg);
250
+ layer.add(cornerBg);
144
251
 
145
252
  // Drawing Constants (Pixel based for now)
146
253
  const step = 100; // Major tick
@@ -212,44 +319,7 @@ export class RulerTool implements Extension<RulerToolOptions> {
212
319
  }
213
320
 
214
321
  // Always bring ruler to front
215
- editor.canvas.bringObjectToFront(layer);
216
- editor.canvas.requestRenderAll();
322
+ this.canvasService.canvas.bringObjectToFront(layer);
323
+ this.canvasService.canvas.requestRenderAll();
217
324
  }
218
-
219
- commands: Record<string, Command> = {
220
- setUnit: {
221
- execute: (editor: Editor, unit: "px" | "mm" | "cm" | "in") => {
222
- if (this.options.unit === unit) return true;
223
- this.options.unit = unit;
224
- this.updateRuler(editor);
225
- return true;
226
- },
227
- schema: {
228
- unit: {
229
- type: "string",
230
- label: "Unit",
231
- options: ["px", "mm", "cm", "in"],
232
- required: true,
233
- },
234
- },
235
- },
236
- setTheme: {
237
- execute: (editor: Editor, theme: Partial<RulerToolOptions>) => {
238
- const newOptions = { ...this.options, ...theme };
239
- if (JSON.stringify(newOptions) === JSON.stringify(this.options))
240
- return true;
241
-
242
- this.options = newOptions;
243
- this.updateRuler(editor);
244
- return true;
245
- },
246
- schema: {
247
- theme: {
248
- type: "object",
249
- label: "Theme",
250
- required: true,
251
- },
252
- },
253
- },
254
- };
255
325
  }