@pooder/core 0.1.0 → 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/dist/index.js CHANGED
@@ -20,25 +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
- Circle: () => import_fabric4.Circle,
24
- Ellipse: () => import_fabric4.Ellipse,
25
- Group: () => import_fabric4.Group,
26
- Image: () => import_fabric4.FabricImage,
27
- Line: () => import_fabric4.Line,
28
- Path: () => import_fabric4.Path,
29
- Pattern: () => import_fabric4.Pattern,
30
- Point: () => import_fabric4.Point,
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,
38
- util: () => import_fabric4.util
23
+ CommandService: () => CommandService,
24
+ ConfigurationService: () => ConfigurationService,
25
+ ContributionPointIds: () => ContributionPointIds,
26
+ ContributionRegistry: () => ContributionRegistry,
27
+ ExtensionManager: () => ExtensionManager,
28
+ ExtensionRegistry: () => ExtensionRegistry,
29
+ Pooder: () => Pooder,
30
+ ServiceRegistry: () => ServiceRegistry
39
31
  });
40
32
  module.exports = __toCommonJS(index_exports);
41
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
+
42
54
  // src/event.ts
43
55
  var EventBus = class {
44
56
  constructor() {
@@ -75,440 +87,500 @@ var EventBus = class {
75
87
  return (_b = (_a = this.events.get(event)) == null ? void 0 : _a.length) != null ? _b : 0;
76
88
  }
77
89
  };
90
+ var event_default = EventBus;
78
91
 
79
- // src/command.ts
80
- var DefaultCommandManager = class {
81
- constructor(editor) {
82
- this.editor = editor;
83
- }
84
- register(name, command) {
85
- if (this.editor.commands.has(name)) {
86
- console.warn(`Command "${name}" already exists. It will be overwritten.`);
87
- }
88
- this.editor.commands.set(name, command);
89
- }
90
- unregister(name) {
91
- this.editor.commands.delete(name);
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
+ };
92
109
  }
93
- execute(name, ...args) {
94
- const command = this.editor.commands.get(name);
95
- if (!command) {
96
- console.warn(`Command "${name}" not found`);
97
- return false;
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
+ );
98
118
  }
99
- try {
100
- return command.execute(...args);
101
- } catch (e) {
102
- console.error(`Error executing command "${name}":`, e);
103
- return false;
119
+ this.points.set(point.id, point);
120
+ if (!this.contributions.byPointId.has(point.id)) {
121
+ this.contributions.byPointId.set(point.id, []);
104
122
  }
105
123
  }
106
- get(name) {
107
- return this.editor.commands.get(name);
108
- }
109
- has(name) {
110
- return this.editor.commands.has(name);
111
- }
112
- count() {
113
- return this.editor.commands.size;
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
+ };
114
173
  }
115
- list() {
116
- return Array.from(this.editor.commands.keys());
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
+ );
117
182
  }
118
- clear() {
119
- this.editor.commands.clear();
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);
120
205
  }
121
206
  };
122
207
 
123
208
  // src/extension.ts
124
- var DefaultExtensionManager = class {
125
- constructor(editor) {
126
- this.mounted = false;
127
- this.editor = editor;
128
- }
129
- _registerCommands(extension) {
130
- if (extension.commands) {
131
- Object.entries(extension.commands).forEach(([name, command]) => {
132
- const commandName = `${extension.name}.${name}`;
133
- this.editor.registerCommand(commandName, command);
134
- });
135
- }
136
- }
137
- _unregisterCommands(extension) {
138
- if (extension.commands) {
139
- Object.keys(extension.commands).forEach((name) => {
140
- const commandName = `${extension.name}.${name}`;
141
- this.editor.unregisterCommand(commandName);
142
- });
143
- }
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;
144
216
  }
145
217
  register(extension) {
146
- var _a, _b;
147
- if (this.editor.extensions.has(extension.name)) {
218
+ if (this.extensionRegistry.has(extension.id)) {
148
219
  console.warn(
149
- `Plugin "${extension.name}" already registered. It will be overwritten.`
220
+ `Plugin "${extension.id}" already registered. It will be overwritten.`
150
221
  );
151
222
  }
152
- try {
153
- if (extension.enabled === void 0) {
154
- extension.enabled = true;
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
+ }
155
249
  }
156
- this.editor.extensions.set(extension.name, extension);
157
- (_a = extension.onCreate) == null ? void 0 : _a.call(extension, this.editor);
250
+ }
251
+ try {
252
+ this.extensionRegistry.set(extension.id, extension);
253
+ this.context.eventBus.emit("extension:register", extension);
158
254
  } catch (error) {
159
255
  console.error(
160
- `Error in onCreate hook for plugin "${extension.name}":`,
256
+ `Error in onCreate hook for plugin "${extension.id}":`,
161
257
  error
162
258
  );
163
259
  }
164
- if (extension.enabled) {
165
- this._registerCommands(extension);
166
- if (this.mounted) {
167
- try {
168
- (_b = extension.onMount) == null ? void 0 : _b.call(extension, this.editor);
169
- } catch (error) {
170
- console.error(
171
- `Error in onMount hook for plugin "${extension.name}":`,
172
- error
173
- );
174
- }
175
- }
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);
176
280
  }
177
- console.log(`Plugin "${extension.name}" registered successfully`);
178
281
  }
179
282
  unregister(name) {
180
- var _a, _b;
181
- const extension = this.editor.extensions.get(name);
283
+ const extension = this.extensionRegistry.get(name);
182
284
  if (!extension) {
183
285
  console.warn(`Plugin "${name}" not found.`);
184
286
  return;
185
287
  }
186
- if (this.mounted && extension.enabled) {
187
- try {
188
- (_a = extension.onUnmount) == null ? void 0 : _a.call(extension, this.editor);
189
- } catch (error) {
190
- console.error(`Error in onUnmount hook for plugin "${name}":`, error);
191
- }
192
- }
193
288
  try {
194
- (_b = extension.onDestroy) == null ? void 0 : _b.call(extension, this.editor);
289
+ extension.deactivate(this.context);
195
290
  } catch (error) {
196
- console.error(`Error in onDestroy hook for plugin "${name}":`, error);
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);
197
297
  }
198
- this._unregisterCommands(extension);
199
- this.editor.extensions.delete(name);
298
+ this.extensionRegistry.delete(name);
200
299
  console.log(`Plugin "${name}" unregistered`);
201
300
  return true;
202
301
  }
203
302
  enable(name) {
204
- var _a;
205
- const extension = this.get(name);
303
+ const extension = this.extensionRegistry.get(name);
206
304
  if (!extension) {
207
305
  console.warn(`Plugin "${name}" not found.`);
208
306
  return;
209
307
  }
210
- if (extension.enabled) return;
211
- extension.enabled = true;
212
- this._registerCommands(extension);
213
- if (this.mounted) {
214
- try {
215
- (_a = extension.onMount) == null ? void 0 : _a.call(extension, this.editor);
216
- } catch (error) {
217
- console.error(`Error in onMount hook for plugin "${name}":`, error);
218
- }
219
- }
220
308
  }
221
309
  disable(name) {
222
- var _a;
223
- const extension = this.get(name);
310
+ const extension = this.extensionRegistry.get(name);
224
311
  if (!extension) {
225
312
  console.warn(`Plugin "${name}" not found.`);
226
313
  return;
227
314
  }
228
- if (!extension.enabled) return;
229
- extension.enabled = false;
230
- this._unregisterCommands(extension);
231
- if (this.mounted) {
232
- try {
233
- (_a = extension.onUnmount) == null ? void 0 : _a.call(extension, this.editor);
234
- } catch (error) {
235
- console.error(`Error in onUnmount hook for plugin "${name}":`, error);
236
- }
237
- }
238
- }
239
- get(name) {
240
- return this.editor.extensions.get(name);
241
- }
242
- has(name) {
243
- return this.editor.extensions.has(name);
244
- }
245
- count() {
246
- return this.editor.extensions.size;
247
- }
248
- list() {
249
- return Array.from(this.editor.extensions.values());
250
- }
251
- mount() {
252
- if (this.mounted) return;
253
- this.editor.extensions.forEach((extension) => {
254
- var _a;
255
- if (extension.enabled) {
256
- try {
257
- console.log(`Mounting plugin "${extension.name}"`);
258
- (_a = extension.onMount) == null ? void 0 : _a.call(extension, this.editor);
259
- } catch (e) {
260
- console.error(
261
- `Error in onMount hook for plugin "${extension.name}":`,
262
- e
263
- );
264
- }
265
- }
266
- });
267
- console.log(`Plugins mounted`);
268
- this.mounted = true;
269
- }
270
- unmount() {
271
- if (!this.mounted) return;
272
- this.editor.extensions.forEach((extension) => {
273
- var _a;
274
- if (extension.enabled) {
275
- try {
276
- (_a = extension.onUnmount) == null ? void 0 : _a.call(extension, this.editor);
277
- } catch (e) {
278
- console.error(
279
- `Error in onUnmount hook for plugin "${extension.name}":`,
280
- e
281
- );
282
- }
283
- }
284
- });
285
- console.log(`Plugins unmounted`);
286
- this.mounted = false;
287
315
  }
288
316
  update() {
289
- const state = this.editor.getState();
290
- this.editor.extensions.forEach((extension) => {
291
- var _a;
292
- if (extension.enabled) {
293
- try {
294
- (_a = extension.onUpdate) == null ? void 0 : _a.call(extension, this.editor, state);
295
- } catch (e) {
296
- console.error(
297
- `Error in onUpdate hook for plugin "${extension.name}":`,
298
- e
299
- );
300
- }
301
- }
302
- });
303
317
  }
304
318
  destroy() {
305
- const extensionNames = Array.from(this.editor.extensions.keys());
319
+ const extensionNames = Array.from(this.extensionRegistry.keys());
306
320
  extensionNames.forEach((name) => this.unregister(name));
307
- this.mounted = false;
308
321
  }
309
322
  };
310
323
 
311
- // src/canvas.ts
312
- var import_fabric = require("fabric");
313
-
314
- // src/editor.ts
315
- var PooderEditor = class {
316
- constructor(el, options = {}) {
317
- this.extensions = /* @__PURE__ */ new Map();
324
+ // src/services/CommandService.ts
325
+ var CommandService = class {
326
+ constructor() {
318
327
  this.commands = /* @__PURE__ */ new Map();
319
- this.destroyed = false;
320
- this.state = {
321
- width: options.width || 800,
322
- height: options.height || 600
323
- };
324
- this.canvas = new import_fabric.Canvas(el, {
325
- width: this.state.width,
326
- height: this.state.height,
327
- preserveObjectStacking: true
328
- });
329
- this.eventBus = new EventBus();
330
- this.commandManager = new DefaultCommandManager(this);
331
- this.extensionManager = new DefaultExtensionManager(this);
332
- if (options.extensions && options.extensions.length > 0) {
333
- options.extensions.forEach(this.extensionManager.register);
334
- }
335
- this.extensionManager.mount();
336
- console.log(
337
- "Editor initialized with",
338
- this.extensionManager.count(),
339
- "plugins"
340
- );
341
328
  }
342
- use(extension) {
343
- if (this.destroyed) {
344
- throw new Error("Cannot register plugin: Editor is destroyed");
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
+ );
345
341
  }
346
- this.extensionManager.register(extension);
347
- this.emit("update", this.state);
348
- }
349
- unuse(name) {
350
- return this.extensionManager.unregister(name);
351
- }
352
- getExtension(name) {
353
- return this.extensionManager.get(name);
354
- }
355
- getExtensions() {
356
- return this.extensionManager.list();
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
+ };
357
354
  }
358
- enableExtension(name) {
359
- this.extensionManager.enable(name);
360
- this.emit("update", this.state);
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
+ }
361
372
  }
362
- disableExtension(name) {
363
- this.extensionManager.disable(name);
364
- this.emit("update", this.state);
373
+ /**
374
+ * Get all registered commands
375
+ */
376
+ getCommands() {
377
+ return this.commands;
365
378
  }
366
- registerCommand(name, command) {
367
- this.commandManager.register(name, command);
379
+ /**
380
+ * Get a specific command
381
+ */
382
+ getCommand(commandId) {
383
+ return this.commands.get(commandId);
368
384
  }
369
- unregisterCommand(name) {
370
- this.commandManager.unregister(name);
385
+ dispose() {
386
+ this.commands.clear();
371
387
  }
372
- executeCommand(name, ...args) {
373
- if (this.destroyed) {
374
- console.warn("Cannot execute command: Editor is destroyed");
375
- return false;
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 });
376
415
  }
377
- this.emit("beforeCommand", name, ...args);
378
- const result = this.commandManager.execute(name, ...args);
379
- this.emit("afterCommand", name, args, result);
380
- return result;
381
- }
382
- on(event, handler, priority) {
383
- this.eventBus.on(event, handler, priority);
384
416
  }
385
- off(event, handler) {
386
- this.eventBus.off(event, handler);
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
+ };
387
425
  }
388
- emit(event, ...args) {
389
- this.eventBus.emit(event, ...args);
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
+ };
390
434
  }
391
- getObjects() {
392
- if (this.destroyed) {
393
- throw new Error("Cannot get objects: Editor is destroyed");
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;
394
443
  }
395
- return this.canvas.getObjects();
396
- }
397
- getObject(id, layerId) {
398
- var _a;
399
- let objs;
400
- if (layerId) {
401
- objs = (_a = this.getLayer(layerId)) == null ? void 0 : _a.getObjects();
402
- } else {
403
- objs = this.getObjects();
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;
404
455
  }
405
- return objs == null ? void 0 : objs.find((obj) => {
406
- var _a2;
407
- return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.id) === id;
456
+ Object.entries(data).forEach(([key, value]) => {
457
+ this.update(key, value);
408
458
  });
409
459
  }
410
- getLayers() {
411
- return this.getObjects().filter(
412
- (obj) => obj.type === "group"
413
- );
414
- }
415
- getLayer(id) {
416
- return this.getLayers().find((obj) => {
417
- var _a;
418
- return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.id) === id;
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
+ }
419
476
  });
420
477
  }
421
- updateState(updater) {
422
- if (this.destroyed) {
423
- console.warn("Cannot update state: Editor is destroyed");
424
- return;
425
- }
426
- this.state = updater(this.state);
427
- this.extensionManager.update();
428
- this.emit("update", this.state);
429
- }
430
- toJSON() {
431
- const extensions = {};
432
- this.extensionManager.list().forEach((ext) => {
433
- if (ext.toJSON) {
434
- extensions[ext.name] = ext.toJSON();
435
- } else if (ext.options) {
436
- extensions[ext.name] = ext.options;
478
+ dispose() {
479
+ this.configValues.clear();
480
+ }
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)
437
502
  }
438
- });
439
- return {
440
- width: this.state.width,
441
- height: this.state.height,
442
- metadata: this.state.metadata,
443
- extensions
444
503
  };
504
+ this.extensionManager = new ExtensionManager(context);
445
505
  }
446
- async loadFromJSON(json) {
447
- if (!json) return;
448
- this.extensionManager.unmount();
449
- this.canvas.clear();
450
- this.extensionManager.mount();
451
- if (json.extensions) {
452
- for (const [name, data] of Object.entries(json.extensions)) {
453
- const ext = this.extensionManager.get(name);
454
- if (ext) {
455
- if (ext.loadFromJSON) {
456
- await ext.loadFromJSON(data);
457
- } else if (data) {
458
- ext.options = data;
459
- }
460
- }
461
- }
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
+ });
527
+ }
528
+ // --- Service Management ---
529
+ registerService(service) {
530
+ var _a;
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;
537
+ }
538
+ this.services.register(serviceId, service);
539
+ this.eventBus.emit("service:register", service);
540
+ return true;
541
+ }
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;
462
554
  }
463
- this.updateState((state) => ({
464
- ...state,
465
- width: json.width,
466
- height: json.height,
467
- metadata: json.metadata
468
- }));
555
+ this.services.delete(serviceId);
556
+ this.eventBus.emit("service:unregister", service);
557
+ return true;
469
558
  }
470
- getState() {
471
- return { ...this.state };
559
+ getService(id) {
560
+ return this.services.get(id);
472
561
  }
473
- destroy() {
474
- if (this.destroyed) return;
475
- this.emit("beforeDestroy");
476
- this.canvas.dispose();
477
- this.extensionManager.destroy();
478
- this.eventBus.clear();
479
- this.commandManager.clear();
480
- this.destroyed = true;
481
- console.log("Editor destroyed");
482
- }
483
- isDestroyed() {
484
- return this.destroyed;
562
+ // --- Contribution Management ---
563
+ registerContributionPoint(point) {
564
+ this.contributions.registerPoint(point);
565
+ this.eventBus.emit("contribution:point:register", point);
566
+ }
567
+ registerContribution(pointId, contribution) {
568
+ const disposable = this.contributions.register(pointId, contribution);
569
+ this.eventBus.emit("contribution:register", { ...contribution, pointId });
570
+ return disposable;
571
+ }
572
+ getContributions(pointId) {
573
+ return this.contributions.get(pointId);
485
574
  }
486
575
  };
487
-
488
- // src/layer.ts
489
- var import_fabric2 = require("fabric");
490
-
491
- // src/obj.ts
492
- var import_fabric3 = require("fabric");
493
-
494
- // src/index.ts
495
- var import_fabric4 = require("fabric");
496
576
  // Annotate the CommonJS export names for ESM import in node:
497
577
  0 && (module.exports = {
498
- Circle,
499
- Ellipse,
500
- Group,
501
- Image,
502
- Line,
503
- Path,
504
- Pattern,
505
- Point,
506
- PooderCanvas,
507
- PooderEditor,
508
- PooderLayer,
509
- PooderObject,
510
- Rect,
511
- Text,
512
- filters,
513
- util
578
+ CommandService,
579
+ ConfigurationService,
580
+ ContributionPointIds,
581
+ ContributionRegistry,
582
+ ExtensionManager,
583
+ ExtensionRegistry,
584
+ Pooder,
585
+ ServiceRegistry
514
586
  });