@pooder/core 0.0.2 → 1.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/CHANGELOG.md +19 -7
- package/dist/index.d.mts +243 -131
- package/dist/index.d.ts +243 -131
- package/dist/index.js +447 -298
- package/dist/index.mjs +439 -283
- package/package.json +2 -4
- package/src/command.ts +10 -61
- package/src/context.ts +17 -0
- package/src/contribution/index.ts +12 -0
- package/src/contribution/points.ts +63 -0
- package/src/contribution/registry.ts +118 -0
- package/src/disposable.ts +3 -0
- package/src/event.ts +53 -48
- package/src/extension.ts +164 -189
- package/src/index.ts +140 -9
- package/src/run-test-full.ts +98 -0
- package/src/service.ts +25 -0
- package/src/services/CommandService.ts +79 -0
- package/src/services/ConfigurationService.ts +107 -0
- package/src/services/index.ts +4 -0
- package/src/test-extension-full.ts +79 -0
- package/tsconfig.json +13 -13
- package/tsconfig.test.json +7 -0
- package/src/canvas.ts +0 -3
- package/src/editor.ts +0 -171
- package/src/layer.ts +0 -13
- package/src/obj.ts +0 -7
- package/src/types.ts +0 -102
package/dist/index.js
CHANGED
|
@@ -20,24 +20,37 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
PooderCanvas: () => import_fabric.Canvas,
|
|
32
|
-
PooderEditor: () => PooderEditor,
|
|
33
|
-
PooderLayer: () => import_fabric2.Group,
|
|
34
|
-
PooderObject: () => import_fabric3.FabricObject,
|
|
35
|
-
Rect: () => import_fabric4.Rect,
|
|
36
|
-
Text: () => import_fabric4.Text,
|
|
37
|
-
filters: () => import_fabric4.filters
|
|
23
|
+
CommandService: () => CommandService,
|
|
24
|
+
ConfigurationService: () => ConfigurationService,
|
|
25
|
+
ContributionPointIds: () => ContributionPointIds,
|
|
26
|
+
ContributionRegistry: () => ContributionRegistry,
|
|
27
|
+
ExtensionManager: () => ExtensionManager,
|
|
28
|
+
ExtensionRegistry: () => ExtensionRegistry,
|
|
29
|
+
Pooder: () => Pooder,
|
|
30
|
+
ServiceRegistry: () => ServiceRegistry
|
|
38
31
|
});
|
|
39
32
|
module.exports = __toCommonJS(index_exports);
|
|
40
33
|
|
|
34
|
+
// src/service.ts
|
|
35
|
+
var ServiceRegistry = class {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.services = /* @__PURE__ */ new Map();
|
|
38
|
+
}
|
|
39
|
+
register(name, service) {
|
|
40
|
+
this.services.set(name, service);
|
|
41
|
+
return service;
|
|
42
|
+
}
|
|
43
|
+
get(serviceName) {
|
|
44
|
+
return this.services.get(serviceName);
|
|
45
|
+
}
|
|
46
|
+
has(serviceName) {
|
|
47
|
+
return this.services.has(serviceName);
|
|
48
|
+
}
|
|
49
|
+
delete(serviceName) {
|
|
50
|
+
this.services.delete(serviceName);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
41
54
|
// src/event.ts
|
|
42
55
|
var EventBus = class {
|
|
43
56
|
constructor() {
|
|
@@ -74,364 +87,500 @@ var EventBus = class {
|
|
|
74
87
|
return (_b = (_a = this.events.get(event)) == null ? void 0 : _a.length) != null ? _b : 0;
|
|
75
88
|
}
|
|
76
89
|
};
|
|
90
|
+
var event_default = EventBus;
|
|
77
91
|
|
|
78
|
-
// src/
|
|
79
|
-
var
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.
|
|
92
|
+
// src/contribution/points.ts
|
|
93
|
+
var ContributionPointIds = {
|
|
94
|
+
CONTRIBUTIONS: "contribution.point.contributions",
|
|
95
|
+
COMMANDS: "contribution.point.commands",
|
|
96
|
+
TOOLS: "contribution.point.tools",
|
|
97
|
+
VIEWS: "contribution.point.views",
|
|
98
|
+
CONFIGURATIONS: "contribution.point.configurations"
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/contribution/registry.ts
|
|
102
|
+
var ContributionRegistry = class {
|
|
103
|
+
constructor() {
|
|
104
|
+
this.points = /* @__PURE__ */ new Map();
|
|
105
|
+
this.contributions = {
|
|
106
|
+
byId: /* @__PURE__ */ new Map(),
|
|
107
|
+
byPointId: /* @__PURE__ */ new Map()
|
|
108
|
+
};
|
|
91
109
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Register a new contribution point
|
|
112
|
+
*/
|
|
113
|
+
registerPoint(point) {
|
|
114
|
+
if (this.points.has(point.id)) {
|
|
115
|
+
console.warn(
|
|
116
|
+
`Contribution point ${point.id} already exists. Overwriting definitions may cause issues.`
|
|
117
|
+
);
|
|
97
118
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
console.error(`Error executing command "${name}":`, e);
|
|
102
|
-
return false;
|
|
119
|
+
this.points.set(point.id, point);
|
|
120
|
+
if (!this.contributions.byPointId.has(point.id)) {
|
|
121
|
+
this.contributions.byPointId.set(point.id, []);
|
|
103
122
|
}
|
|
104
123
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Register a contribution to a specific point
|
|
126
|
+
* @returns Disposable to unregister the contribution
|
|
127
|
+
*/
|
|
128
|
+
register(pointId, contribution) {
|
|
129
|
+
if (this.contributions.byId.has(contribution.id)) {
|
|
130
|
+
console.warn(
|
|
131
|
+
`Contribution with ID "${contribution.id}" is already registered. Overwriting.`
|
|
132
|
+
);
|
|
133
|
+
this.unregister(pointId, contribution.id);
|
|
134
|
+
}
|
|
135
|
+
if (!this.points.has(pointId)) {
|
|
136
|
+
console.warn(
|
|
137
|
+
`Contribution point ${pointId} does not exist. The contribution ${contribution.id} will be queued but may not be valid.`
|
|
138
|
+
);
|
|
139
|
+
if (!this.contributions.byPointId.has(pointId)) {
|
|
140
|
+
this.contributions.byPointId.set(pointId, []);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const point = this.points.get(pointId);
|
|
144
|
+
if (point == null ? void 0 : point.validate) {
|
|
145
|
+
try {
|
|
146
|
+
if (!point.validate(contribution.data)) {
|
|
147
|
+
console.error(
|
|
148
|
+
`Contribution ${contribution.id} failed validation for point ${pointId}.`
|
|
149
|
+
);
|
|
150
|
+
return { dispose: () => {
|
|
151
|
+
} };
|
|
152
|
+
}
|
|
153
|
+
} catch (e) {
|
|
154
|
+
console.error(
|
|
155
|
+
`Validation error for contribution ${contribution.id}:`,
|
|
156
|
+
e
|
|
157
|
+
);
|
|
158
|
+
return { dispose: () => {
|
|
159
|
+
} };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const arr = this.contributions.byPointId.get(pointId);
|
|
163
|
+
arr.push(contribution);
|
|
164
|
+
this.contributions.byId.set(contribution.id, contribution);
|
|
165
|
+
if (pointId === ContributionPointIds.CONTRIBUTIONS) {
|
|
166
|
+
this.registerPoint(contribution.data);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
dispose: () => {
|
|
170
|
+
this.unregister(pointId, contribution.id);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
116
173
|
}
|
|
117
|
-
|
|
118
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Get all contributions for a given point
|
|
176
|
+
*/
|
|
177
|
+
get(pointId) {
|
|
178
|
+
var _a;
|
|
179
|
+
return Array.from(
|
|
180
|
+
((_a = this.contributions.byPointId.get(pointId)) == null ? void 0 : _a.values()) || []
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get a specific contribution by ID
|
|
185
|
+
*/
|
|
186
|
+
getById(id) {
|
|
187
|
+
return this.contributions.byId.get(id);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the contribution point definition
|
|
191
|
+
*/
|
|
192
|
+
getPoint(pointId) {
|
|
193
|
+
return this.points.get(pointId);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Unregister a contribution
|
|
197
|
+
*/
|
|
198
|
+
unregister(pointId, contributionId) {
|
|
199
|
+
const arr = this.contributions.byPointId.get(pointId);
|
|
200
|
+
arr == null ? void 0 : arr.splice(
|
|
201
|
+
arr.findIndex((c) => c.id === contributionId),
|
|
202
|
+
1
|
|
203
|
+
);
|
|
204
|
+
this.contributions.byId.delete(contributionId);
|
|
119
205
|
}
|
|
120
206
|
};
|
|
121
207
|
|
|
122
208
|
// src/extension.ts
|
|
123
|
-
var
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Object.entries(extension.commands).forEach(([name, command]) => {
|
|
131
|
-
const commandName = `${extension.name}.${name}`;
|
|
132
|
-
this.editor.registerCommand(commandName, command);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
_unregisterCommands(extension) {
|
|
137
|
-
if (extension.commands) {
|
|
138
|
-
Object.keys(extension.commands).forEach((name) => {
|
|
139
|
-
const commandName = `${extension.name}.${name}`;
|
|
140
|
-
this.editor.unregisterCommand(commandName);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
209
|
+
var ExtensionRegistry = class extends Map {
|
|
210
|
+
};
|
|
211
|
+
var ExtensionManager = class {
|
|
212
|
+
constructor(context) {
|
|
213
|
+
this.extensionRegistry = new ExtensionRegistry();
|
|
214
|
+
this.extensionDisposables = /* @__PURE__ */ new Map();
|
|
215
|
+
this.context = context;
|
|
143
216
|
}
|
|
144
217
|
register(extension) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
218
|
+
if (this.extensionRegistry.has(extension.id)) {
|
|
219
|
+
console.warn(
|
|
220
|
+
`Plugin "${extension.id}" already registered. It will be overwritten.`
|
|
221
|
+
);
|
|
148
222
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
223
|
+
this.extensionDisposables.set(extension.id, []);
|
|
224
|
+
const disposables = this.extensionDisposables.get(extension.id);
|
|
225
|
+
if (extension.contribute) {
|
|
226
|
+
for (const [pointId, items] of Object.entries(extension.contribute())) {
|
|
227
|
+
if (Array.isArray(items)) {
|
|
228
|
+
items.forEach((item, index) => {
|
|
229
|
+
const contributionId = item.id || (item.command ? item.command : `${extension.id}.${pointId}.${index}`);
|
|
230
|
+
const contribution = {
|
|
231
|
+
id: contributionId,
|
|
232
|
+
metadata: {
|
|
233
|
+
extensionId: extension.id,
|
|
234
|
+
...item == null ? void 0 : item.metadata
|
|
235
|
+
},
|
|
236
|
+
data: item
|
|
237
|
+
};
|
|
238
|
+
const disposable = this.context.contributions.register(
|
|
239
|
+
pointId,
|
|
240
|
+
contribution
|
|
241
|
+
);
|
|
242
|
+
disposables.push(disposable);
|
|
243
|
+
const dispose = this.collectContribution(pointId, contribution);
|
|
244
|
+
if (dispose) {
|
|
245
|
+
disposables.push(dispose);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
152
249
|
}
|
|
153
|
-
|
|
154
|
-
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
this.extensionRegistry.set(extension.id, extension);
|
|
253
|
+
this.context.eventBus.emit("extension:register", extension);
|
|
155
254
|
} catch (error) {
|
|
156
|
-
console.error(
|
|
255
|
+
console.error(
|
|
256
|
+
`Error in onCreate hook for plugin "${extension.id}":`,
|
|
257
|
+
error
|
|
258
|
+
);
|
|
157
259
|
}
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
260
|
+
try {
|
|
261
|
+
extension.activate(this.context);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error(
|
|
264
|
+
`Error in onActivate hook for plugin "${extension.id}":`,
|
|
265
|
+
error
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
console.log(`Plugin "${extension.id}" registered successfully`);
|
|
269
|
+
}
|
|
270
|
+
collectContribution(pointId, item) {
|
|
271
|
+
if (pointId === ContributionPointIds.CONFIGURATIONS) {
|
|
272
|
+
const configService = this.context.services.get(
|
|
273
|
+
"ConfigurationService"
|
|
274
|
+
);
|
|
275
|
+
configService == null ? void 0 : configService.initializeDefaults([item.data]);
|
|
276
|
+
}
|
|
277
|
+
if (pointId === ContributionPointIds.COMMANDS && item.data.handler) {
|
|
278
|
+
const commandService = this.context.services.get("CommandService");
|
|
279
|
+
return commandService.registerCommand(item.id, item.data.handler);
|
|
167
280
|
}
|
|
168
|
-
console.log(`Plugin "${extension.name}" registered successfully`);
|
|
169
281
|
}
|
|
170
282
|
unregister(name) {
|
|
171
|
-
|
|
172
|
-
const extension = this.editor.extensions.get(name);
|
|
283
|
+
const extension = this.extensionRegistry.get(name);
|
|
173
284
|
if (!extension) {
|
|
174
285
|
console.warn(`Plugin "${name}" not found.`);
|
|
175
286
|
return;
|
|
176
287
|
}
|
|
177
|
-
if (this.mounted && extension.enabled) {
|
|
178
|
-
try {
|
|
179
|
-
(_a = extension.onUnmount) == null ? void 0 : _a.call(extension, this.editor);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error(`Error in onUnmount hook for plugin "${name}":`, error);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
288
|
try {
|
|
185
|
-
|
|
289
|
+
extension.deactivate(this.context);
|
|
186
290
|
} catch (error) {
|
|
187
|
-
console.error(`Error in
|
|
291
|
+
console.error(`Error in deactivate for plugin "${name}":`, error);
|
|
292
|
+
}
|
|
293
|
+
const disposables = this.extensionDisposables.get(name);
|
|
294
|
+
if (disposables) {
|
|
295
|
+
disposables.forEach((d) => d.dispose());
|
|
296
|
+
this.extensionDisposables.delete(name);
|
|
188
297
|
}
|
|
189
|
-
this.
|
|
190
|
-
this.editor.extensions.delete(name);
|
|
298
|
+
this.extensionRegistry.delete(name);
|
|
191
299
|
console.log(`Plugin "${name}" unregistered`);
|
|
192
300
|
return true;
|
|
193
301
|
}
|
|
194
302
|
enable(name) {
|
|
195
|
-
|
|
196
|
-
const extension = this.get(name);
|
|
303
|
+
const extension = this.extensionRegistry.get(name);
|
|
197
304
|
if (!extension) {
|
|
198
305
|
console.warn(`Plugin "${name}" not found.`);
|
|
199
306
|
return;
|
|
200
307
|
}
|
|
201
|
-
if (extension.enabled) return;
|
|
202
|
-
extension.enabled = true;
|
|
203
|
-
this._registerCommands(extension);
|
|
204
|
-
if (this.mounted) {
|
|
205
|
-
try {
|
|
206
|
-
(_a = extension.onMount) == null ? void 0 : _a.call(extension, this.editor);
|
|
207
|
-
} catch (error) {
|
|
208
|
-
console.error(`Error in onMount hook for plugin "${name}":`, error);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
308
|
}
|
|
212
309
|
disable(name) {
|
|
213
|
-
|
|
214
|
-
const extension = this.get(name);
|
|
310
|
+
const extension = this.extensionRegistry.get(name);
|
|
215
311
|
if (!extension) {
|
|
216
312
|
console.warn(`Plugin "${name}" not found.`);
|
|
217
313
|
return;
|
|
218
314
|
}
|
|
219
|
-
if (!extension.enabled) return;
|
|
220
|
-
extension.enabled = false;
|
|
221
|
-
this._unregisterCommands(extension);
|
|
222
|
-
if (this.mounted) {
|
|
223
|
-
try {
|
|
224
|
-
(_a = extension.onUnmount) == null ? void 0 : _a.call(extension, this.editor);
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error(`Error in onUnmount hook for plugin "${name}":`, error);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
get(name) {
|
|
231
|
-
return this.editor.extensions.get(name);
|
|
232
|
-
}
|
|
233
|
-
has(name) {
|
|
234
|
-
return this.editor.extensions.has(name);
|
|
235
|
-
}
|
|
236
|
-
count() {
|
|
237
|
-
return this.editor.extensions.size;
|
|
238
|
-
}
|
|
239
|
-
list() {
|
|
240
|
-
return Array.from(this.editor.extensions.values());
|
|
241
|
-
}
|
|
242
|
-
mount() {
|
|
243
|
-
if (this.mounted) return;
|
|
244
|
-
this.editor.extensions.forEach((extension) => {
|
|
245
|
-
var _a;
|
|
246
|
-
if (extension.enabled) {
|
|
247
|
-
try {
|
|
248
|
-
(_a = extension.onMount) == null ? void 0 : _a.call(extension, this.editor);
|
|
249
|
-
} catch (e) {
|
|
250
|
-
console.error(`Error in onMount hook for plugin "${extension.name}":`, e);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
this.mounted = true;
|
|
255
315
|
}
|
|
256
316
|
update() {
|
|
257
|
-
const state = this.editor.getState();
|
|
258
|
-
this.editor.extensions.forEach((extension) => {
|
|
259
|
-
var _a;
|
|
260
|
-
if (extension.enabled) {
|
|
261
|
-
try {
|
|
262
|
-
(_a = extension.onUpdate) == null ? void 0 : _a.call(extension, this.editor, state);
|
|
263
|
-
} catch (e) {
|
|
264
|
-
console.error(`Error in onUpdate hook for plugin "${extension.name}":`, e);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
317
|
}
|
|
269
318
|
destroy() {
|
|
270
|
-
const extensionNames = Array.from(this.
|
|
319
|
+
const extensionNames = Array.from(this.extensionRegistry.keys());
|
|
271
320
|
extensionNames.forEach((name) => this.unregister(name));
|
|
272
|
-
this.mounted = false;
|
|
273
321
|
}
|
|
274
322
|
};
|
|
275
323
|
|
|
276
|
-
// src/
|
|
277
|
-
var
|
|
278
|
-
|
|
279
|
-
// src/editor.ts
|
|
280
|
-
var PooderEditor = class {
|
|
281
|
-
constructor(el, options = {}) {
|
|
282
|
-
this.extensions = /* @__PURE__ */ new Map();
|
|
324
|
+
// src/services/CommandService.ts
|
|
325
|
+
var CommandService = class {
|
|
326
|
+
constructor() {
|
|
283
327
|
this.commands = /* @__PURE__ */ new Map();
|
|
284
|
-
this.destroyed = false;
|
|
285
|
-
this.state = {
|
|
286
|
-
width: options.width || 800,
|
|
287
|
-
height: options.height || 600
|
|
288
|
-
};
|
|
289
|
-
this.canvas = new import_fabric.Canvas(el, { width: this.state.width, height: this.state.height });
|
|
290
|
-
this.eventBus = new EventBus();
|
|
291
|
-
this.commandManager = new DefaultCommandManager(this);
|
|
292
|
-
this.extensionManager = new DefaultExtensionManager(this);
|
|
293
|
-
if (options.extensions && options.extensions.length > 0) {
|
|
294
|
-
options.extensions.forEach(this.extensionManager.register);
|
|
295
|
-
}
|
|
296
|
-
this.extensionManager.mount();
|
|
297
|
-
console.log("Editor initialized with", this.extensionManager.count(), "plugins");
|
|
298
328
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Register a command
|
|
331
|
+
* @param commandId Command Name (ID)
|
|
332
|
+
* @param handler Command handler function
|
|
333
|
+
* @param thisArg The `this` context for the handler
|
|
334
|
+
* @returns Disposable to unregister the command
|
|
335
|
+
*/
|
|
336
|
+
registerCommand(commandId, handler, thisArg) {
|
|
337
|
+
if (this.commands.has(commandId)) {
|
|
338
|
+
console.warn(
|
|
339
|
+
`Command "${commandId}" is already registered. Overwriting.`
|
|
340
|
+
);
|
|
302
341
|
}
|
|
303
|
-
|
|
304
|
-
|
|
342
|
+
const command = {
|
|
343
|
+
id: commandId,
|
|
344
|
+
handler: thisArg ? handler.bind(thisArg) : handler
|
|
345
|
+
};
|
|
346
|
+
this.commands.set(commandId, command);
|
|
347
|
+
return {
|
|
348
|
+
dispose: () => {
|
|
349
|
+
if (this.commands.get(commandId) === command) {
|
|
350
|
+
this.commands.delete(commandId);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
};
|
|
305
354
|
}
|
|
306
|
-
|
|
307
|
-
|
|
355
|
+
/**
|
|
356
|
+
* Execute a command
|
|
357
|
+
* @param commandId Command Name (ID)
|
|
358
|
+
* @param args Arguments to pass to the handler
|
|
359
|
+
* @returns The result of the command handler
|
|
360
|
+
*/
|
|
361
|
+
async executeCommand(commandId, ...args) {
|
|
362
|
+
const command = this.commands.get(commandId);
|
|
363
|
+
if (!command) {
|
|
364
|
+
throw new Error(`Command "${commandId}" not found.`);
|
|
365
|
+
}
|
|
366
|
+
try {
|
|
367
|
+
return await command.handler(...args);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.error(`Error executing command "${commandId}":`, error);
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
308
372
|
}
|
|
309
|
-
|
|
310
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Get all registered commands
|
|
375
|
+
*/
|
|
376
|
+
getCommands() {
|
|
377
|
+
return this.commands;
|
|
311
378
|
}
|
|
312
|
-
|
|
313
|
-
|
|
379
|
+
/**
|
|
380
|
+
* Get a specific command
|
|
381
|
+
*/
|
|
382
|
+
getCommand(commandId) {
|
|
383
|
+
return this.commands.get(commandId);
|
|
314
384
|
}
|
|
315
|
-
|
|
316
|
-
this.
|
|
317
|
-
this.emit("update", this.state);
|
|
385
|
+
dispose() {
|
|
386
|
+
this.commands.clear();
|
|
318
387
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// src/services/ConfigurationService.ts
|
|
391
|
+
var ConfigurationService = class {
|
|
392
|
+
constructor() {
|
|
393
|
+
this.configValues = /* @__PURE__ */ new Map();
|
|
394
|
+
this.eventBus = new event_default();
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Get a configuration value.
|
|
398
|
+
*/
|
|
399
|
+
get(key, defaultValue) {
|
|
400
|
+
if (this.configValues.has(key)) {
|
|
401
|
+
return this.configValues.get(key);
|
|
402
|
+
}
|
|
403
|
+
return defaultValue;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Update a configuration value.
|
|
407
|
+
* Emits 'change' event.
|
|
408
|
+
*/
|
|
409
|
+
update(key, value) {
|
|
410
|
+
const oldValue = this.configValues.get(key);
|
|
411
|
+
if (oldValue !== value) {
|
|
412
|
+
this.configValues.set(key, value);
|
|
413
|
+
this.eventBus.emit(`change:${key}`, { key, value, oldValue });
|
|
414
|
+
this.eventBus.emit("change", { key, value, oldValue });
|
|
415
|
+
}
|
|
322
416
|
}
|
|
323
|
-
|
|
324
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Listen for changes to a specific configuration key.
|
|
419
|
+
*/
|
|
420
|
+
onDidChange(key, callback) {
|
|
421
|
+
this.eventBus.on(`change:${key}`, callback);
|
|
422
|
+
return {
|
|
423
|
+
dispose: () => this.eventBus.off(`change:${key}`, callback)
|
|
424
|
+
};
|
|
325
425
|
}
|
|
326
|
-
|
|
327
|
-
|
|
426
|
+
/**
|
|
427
|
+
* Listen for any configuration change.
|
|
428
|
+
*/
|
|
429
|
+
onAnyChange(callback) {
|
|
430
|
+
this.eventBus.on("change", callback);
|
|
431
|
+
return {
|
|
432
|
+
dispose: () => this.eventBus.off("change", callback)
|
|
433
|
+
};
|
|
328
434
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
435
|
+
/**
|
|
436
|
+
* Export current configuration state as a JSON-serializable object.
|
|
437
|
+
* Useful for saving configuration templates.
|
|
438
|
+
*/
|
|
439
|
+
export() {
|
|
440
|
+
const exportData = {};
|
|
441
|
+
for (const [key, value] of this.configValues) {
|
|
442
|
+
exportData[key] = value;
|
|
443
|
+
}
|
|
444
|
+
return exportData;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Import configuration from a JSON object.
|
|
448
|
+
* This will merge the provided configuration with the current state,
|
|
449
|
+
* overwriting existing keys and triggering change events.
|
|
450
|
+
*/
|
|
451
|
+
import(data) {
|
|
452
|
+
if (!data || typeof data !== "object") {
|
|
453
|
+
console.warn("ConfigurationService: Import data must be an object.");
|
|
454
|
+
return;
|
|
333
455
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return result;
|
|
456
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
457
|
+
this.update(key, value);
|
|
458
|
+
});
|
|
338
459
|
}
|
|
339
|
-
|
|
340
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Initialize configuration with defaults from contributions.
|
|
462
|
+
* This should be called when a contribution is registered.
|
|
463
|
+
*/
|
|
464
|
+
initializeDefaults(contributions) {
|
|
465
|
+
contributions.forEach((contrib) => {
|
|
466
|
+
if (!contrib.id) {
|
|
467
|
+
console.warn(
|
|
468
|
+
"Configuration contribution missing 'id'. Skipping default initialization.",
|
|
469
|
+
contrib
|
|
470
|
+
);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (!this.configValues.has(contrib.id) && contrib.default !== void 0) {
|
|
474
|
+
this.configValues.set(contrib.id, contrib.default);
|
|
475
|
+
}
|
|
476
|
+
});
|
|
341
477
|
}
|
|
342
|
-
|
|
343
|
-
this.
|
|
478
|
+
dispose() {
|
|
479
|
+
this.configValues.clear();
|
|
344
480
|
}
|
|
345
|
-
|
|
346
|
-
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// src/index.ts
|
|
484
|
+
var Pooder = class {
|
|
485
|
+
constructor() {
|
|
486
|
+
this.eventBus = new event_default();
|
|
487
|
+
this.services = new ServiceRegistry();
|
|
488
|
+
this.contributions = new ContributionRegistry();
|
|
489
|
+
this.initDefaultContributionPoints();
|
|
490
|
+
const commandService = new CommandService();
|
|
491
|
+
this.registerService(commandService);
|
|
492
|
+
const configurationService = new ConfigurationService();
|
|
493
|
+
this.registerService(configurationService);
|
|
494
|
+
const context = {
|
|
495
|
+
eventBus: this.eventBus,
|
|
496
|
+
services: {
|
|
497
|
+
get: (serviceName) => this.services.get(serviceName)
|
|
498
|
+
},
|
|
499
|
+
contributions: {
|
|
500
|
+
get: (pointId) => this.getContributions(pointId),
|
|
501
|
+
register: (pointId, contribution) => this.registerContribution(pointId, contribution)
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
this.extensionManager = new ExtensionManager(context);
|
|
347
505
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
506
|
+
initDefaultContributionPoints() {
|
|
507
|
+
this.registerContributionPoint({
|
|
508
|
+
id: ContributionPointIds.CONTRIBUTIONS,
|
|
509
|
+
description: "Contribution point for contribution points"
|
|
510
|
+
});
|
|
511
|
+
this.registerContributionPoint({
|
|
512
|
+
id: ContributionPointIds.COMMANDS,
|
|
513
|
+
description: "Contribution point for commands"
|
|
514
|
+
});
|
|
515
|
+
this.registerContributionPoint({
|
|
516
|
+
id: ContributionPointIds.TOOLS,
|
|
517
|
+
description: "Contribution point for tools"
|
|
518
|
+
});
|
|
519
|
+
this.registerContributionPoint({
|
|
520
|
+
id: ContributionPointIds.VIEWS,
|
|
521
|
+
description: "Contribution point for UI views"
|
|
522
|
+
});
|
|
523
|
+
this.registerContributionPoint({
|
|
524
|
+
id: ContributionPointIds.CONFIGURATIONS,
|
|
525
|
+
description: "Contribution point for configurations"
|
|
526
|
+
});
|
|
353
527
|
}
|
|
354
|
-
|
|
528
|
+
// --- Service Management ---
|
|
529
|
+
registerService(service) {
|
|
355
530
|
var _a;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
|
|
531
|
+
const serviceId = service.constructor.name;
|
|
532
|
+
try {
|
|
533
|
+
(_a = service == null ? void 0 : service.init) == null ? void 0 : _a.call(service);
|
|
534
|
+
} catch (e) {
|
|
535
|
+
console.error(`Error initializing service ${serviceId}:`, e);
|
|
536
|
+
return false;
|
|
361
537
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
getLayers() {
|
|
368
|
-
return this.getObjects().filter((obj) => obj.type === "group");
|
|
369
|
-
}
|
|
370
|
-
getLayer(id) {
|
|
371
|
-
return this.getLayers().find((obj) => {
|
|
372
|
-
var _a;
|
|
373
|
-
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.id) === id;
|
|
374
|
-
});
|
|
538
|
+
this.services.register(serviceId, service);
|
|
539
|
+
this.eventBus.emit("service:register", service);
|
|
540
|
+
return true;
|
|
375
541
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
542
|
+
unregisterService(service) {
|
|
543
|
+
var _a;
|
|
544
|
+
const serviceId = service.constructor.name;
|
|
545
|
+
if (!this.services.has(serviceId)) {
|
|
546
|
+
console.warn(`Service ${serviceId} is not registered.`);
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
try {
|
|
550
|
+
(_a = service == null ? void 0 : service.dispose) == null ? void 0 : _a.call(service);
|
|
551
|
+
} catch (e) {
|
|
552
|
+
console.error(`Error disposing service ${serviceId}:`, e);
|
|
553
|
+
return false;
|
|
380
554
|
}
|
|
381
|
-
this.
|
|
382
|
-
this.
|
|
383
|
-
|
|
555
|
+
this.services.delete(serviceId);
|
|
556
|
+
this.eventBus.emit("service:unregister", service);
|
|
557
|
+
return true;
|
|
384
558
|
}
|
|
385
|
-
|
|
386
|
-
return
|
|
387
|
-
width: this.state.width,
|
|
388
|
-
height: this.state.height,
|
|
389
|
-
metadata: this.state.metadata
|
|
390
|
-
};
|
|
559
|
+
getService(id) {
|
|
560
|
+
return this.services.get(id);
|
|
391
561
|
}
|
|
392
|
-
|
|
562
|
+
// --- Contribution Management ---
|
|
563
|
+
registerContributionPoint(point) {
|
|
564
|
+
this.contributions.registerPoint(point);
|
|
565
|
+
this.eventBus.emit("contribution:point:register", point);
|
|
393
566
|
}
|
|
394
|
-
|
|
395
|
-
|
|
567
|
+
registerContribution(pointId, contribution) {
|
|
568
|
+
const disposable = this.contributions.register(pointId, contribution);
|
|
569
|
+
this.eventBus.emit("contribution:register", { ...contribution, pointId });
|
|
570
|
+
return disposable;
|
|
396
571
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
this.emit("beforeDestroy");
|
|
400
|
-
this.canvas.dispose();
|
|
401
|
-
this.extensionManager.destroy();
|
|
402
|
-
this.eventBus.clear();
|
|
403
|
-
this.commandManager.clear();
|
|
404
|
-
this.destroyed = true;
|
|
405
|
-
console.log("Editor destroyed");
|
|
406
|
-
}
|
|
407
|
-
isDestroyed() {
|
|
408
|
-
return this.destroyed;
|
|
572
|
+
getContributions(pointId) {
|
|
573
|
+
return this.contributions.get(pointId);
|
|
409
574
|
}
|
|
410
575
|
};
|
|
411
|
-
|
|
412
|
-
// src/layer.ts
|
|
413
|
-
var import_fabric2 = require("fabric");
|
|
414
|
-
|
|
415
|
-
// src/obj.ts
|
|
416
|
-
var import_fabric3 = require("fabric");
|
|
417
|
-
|
|
418
|
-
// src/index.ts
|
|
419
|
-
var import_fabric4 = require("fabric");
|
|
420
576
|
// Annotate the CommonJS export names for ESM import in node:
|
|
421
577
|
0 && (module.exports = {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
PooderCanvas,
|
|
431
|
-
PooderEditor,
|
|
432
|
-
PooderLayer,
|
|
433
|
-
PooderObject,
|
|
434
|
-
Rect,
|
|
435
|
-
Text,
|
|
436
|
-
filters
|
|
578
|
+
CommandService,
|
|
579
|
+
ConfigurationService,
|
|
580
|
+
ContributionPointIds,
|
|
581
|
+
ContributionRegistry,
|
|
582
|
+
ExtensionManager,
|
|
583
|
+
ExtensionRegistry,
|
|
584
|
+
Pooder,
|
|
585
|
+
ServiceRegistry
|
|
437
586
|
});
|