@pooder/core 0.0.2

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.
@@ -0,0 +1,189 @@
1
+ import {Editor, Extension} from "./types";
2
+
3
+ export { ExtensionManager, DefaultExtensionManager, ExtensionMap }
4
+
5
+ interface ExtensionManager{
6
+ register(extension: Extension):void
7
+ unregister(name:string):void
8
+ enable(name:string):void
9
+ disable(name:string):void
10
+ get(name:string):Extension | undefined
11
+ has(name:string):boolean
12
+ count():number
13
+ list():Extension[]
14
+ mount():void
15
+ update():void
16
+ destroy():void
17
+ }
18
+ class ExtensionMap extends Map<string, Extension> {}
19
+ class DefaultExtensionManager implements ExtensionManager{
20
+ private readonly editor: Editor;
21
+ private mounted: boolean = false;
22
+
23
+ constructor(editor: Editor) {
24
+ this.editor = editor
25
+ }
26
+
27
+ private _registerCommands(extension: Extension) {
28
+ if(extension.commands){
29
+ Object.entries(extension.commands).forEach(([name, command]) => {
30
+ const commandName = `${extension.name}.${name}`;
31
+ this.editor.registerCommand(commandName, command);
32
+ })
33
+ }
34
+ }
35
+
36
+ private _unregisterCommands(extension: Extension) {
37
+ if(extension.commands){
38
+ Object.keys(extension.commands).forEach((name) => {
39
+ const commandName = `${extension.name}.${name}`;
40
+ this.editor.unregisterCommand(commandName);
41
+ })
42
+ }
43
+ }
44
+
45
+ register(extension: Extension){
46
+ if (this.editor.extensions.has(extension.name)) {
47
+ console.warn(`Plugin "${extension.name}" already registered. It will be overwritten.`);
48
+ }
49
+
50
+ try {
51
+ if(extension.enabled === undefined) {
52
+ extension.enabled = true;
53
+ }
54
+ this.editor.extensions.set(extension.name, extension);
55
+ extension.onCreate?.(this.editor)
56
+ } catch (error) {
57
+ console.error(`Error in onCreate hook for plugin "${extension.name}":`, error);
58
+ }
59
+
60
+ if (extension.enabled) {
61
+ this._registerCommands(extension);
62
+
63
+ if(this.mounted) {
64
+ try {
65
+ extension.onMount?.(this.editor);
66
+ } catch (error) {
67
+ console.error(`Error in onMount hook for plugin "${extension.name}":`, error);
68
+ }
69
+ }
70
+ }
71
+
72
+ console.log(`Plugin "${extension.name}" registered successfully`);
73
+ }
74
+
75
+ unregister(name: string){
76
+ const extension = this.editor.extensions.get(name);
77
+ if (!extension) {
78
+ console.warn(`Plugin "${name}" not found.`);
79
+ return;
80
+ }
81
+
82
+ if (this.mounted && extension.enabled) {
83
+ try {
84
+ extension.onUnmount?.(this.editor);
85
+ } catch (error) {
86
+ console.error(`Error in onUnmount hook for plugin "${name}":`, error);
87
+ }
88
+ }
89
+
90
+ try {
91
+ extension.onDestroy?.(this.editor);
92
+ } catch (error) {
93
+ console.error(`Error in onDestroy hook for plugin "${name}":`, error);
94
+ }
95
+
96
+ this._unregisterCommands(extension);
97
+
98
+ this.editor.extensions.delete(name);
99
+ console.log(`Plugin "${name}" unregistered`);
100
+ return true;
101
+ }
102
+
103
+ enable(name: string) {
104
+ const extension = this.get(name);
105
+ if (!extension) {
106
+ console.warn(`Plugin "${name}" not found.`);
107
+ return;
108
+ }
109
+ if (extension.enabled) return;
110
+
111
+ extension.enabled = true;
112
+ this._registerCommands(extension);
113
+
114
+ if (this.mounted) {
115
+ try {
116
+ extension.onMount?.(this.editor);
117
+ } catch (error) {
118
+ console.error(`Error in onMount hook for plugin "${name}":`, error);
119
+ }
120
+ }
121
+ }
122
+
123
+ disable(name: string) {
124
+ const extension = this.get(name);
125
+ if (!extension) {
126
+ console.warn(`Plugin "${name}" not found.`);
127
+ return;
128
+ }
129
+ if (!extension.enabled) return;
130
+
131
+ extension.enabled = false;
132
+ this._unregisterCommands(extension);
133
+
134
+ if (this.mounted) {
135
+ try {
136
+ extension.onUnmount?.(this.editor);
137
+ } catch (error) {
138
+ console.error(`Error in onUnmount hook for plugin "${name}":`, error);
139
+ }
140
+ }
141
+ }
142
+
143
+ get(name:string){
144
+ return this.editor.extensions.get( name)
145
+ }
146
+ has(name:string){
147
+ return this.editor.extensions.has(name)
148
+ }
149
+ count(){
150
+ return this.editor.extensions.size
151
+ }
152
+ list(){
153
+ return Array.from(this.editor.extensions.values())
154
+ }
155
+ mount(){
156
+ if(this.mounted)return
157
+
158
+ this.editor.extensions.forEach((extension) => {
159
+ if (extension.enabled) {
160
+ try {
161
+ extension.onMount?.(this.editor);
162
+ }catch (e){
163
+ console.error(`Error in onMount hook for plugin "${extension.name}":`, e);
164
+ }
165
+ }
166
+ })
167
+
168
+ this.mounted=true
169
+ }
170
+ update(){
171
+ const state = this.editor.getState();
172
+
173
+ this.editor.extensions.forEach((extension) => {
174
+ if (extension.enabled) {
175
+ try {
176
+ extension.onUpdate?.(this.editor, state);
177
+ }catch (e){
178
+ console.error(`Error in onUpdate hook for plugin "${extension.name}":`, e);
179
+ }
180
+ }
181
+ })
182
+ }
183
+
184
+ destroy(){
185
+ const extensionNames = Array.from(this.editor.extensions.keys());
186
+ extensionNames.forEach(name => this.unregister(name))
187
+ this.mounted=false
188
+ }
189
+ }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export {PooderEditor} from "./editor"
2
+
3
+ export {PooderCanvas }from "./canvas"
4
+ export {PooderLayer} from "./layer"
5
+ export {PooderObject} from "./obj"
6
+
7
+ export type {Editor, EditorState, Command, Event, EventHandler, Extension, ExtensionOptions, OptionSchema} from "./types"
8
+
9
+ export { FabricImage as Image, Ellipse, Rect, Circle, Line, Text, Group, Path, Point, Pattern, filters } from "fabric"
package/src/layer.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { Group } from "fabric";
2
+ declare module "fabric" {
3
+ interface Group {
4
+ data?: any;
5
+ }
6
+ interface GroupProps {
7
+ data?: any;
8
+ }
9
+ interface SerializedGroupProps {
10
+ data?: any;
11
+ }
12
+ }
13
+ export { Group as PooderLayer }
package/src/obj.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { FabricObject } from "fabric";
2
+ declare module "fabric" {
3
+ interface FabricObject {
4
+ data?: any;
5
+ }
6
+ }
7
+ export { FabricObject as PooderObject }
package/src/types.ts ADDED
@@ -0,0 +1,102 @@
1
+ import {PooderCanvas} from "./canvas";
2
+ import {PooderObject} from "./obj";
3
+ import {PooderLayer} from "./layer";
4
+ import {ExtensionMap} from "./extension";
5
+ import {CommandMap} from "./command";
6
+
7
+ export interface CommandArgSchema {
8
+ type: 'string' | 'number' | 'boolean' | 'object' | 'any';
9
+ label?: string;
10
+ description?: string;
11
+ required?: boolean;
12
+ default?: any;
13
+ // Type-specific constraints
14
+ options?: string[] | { label: string; value: any }[];
15
+ min?: number;
16
+ max?: number;
17
+ }
18
+
19
+ export interface CommandSchema {
20
+ [argName: string]: CommandArgSchema;
21
+ }
22
+
23
+ export interface Command {
24
+ execute(...args: any[]): boolean;
25
+ schema?: CommandSchema;
26
+ }
27
+
28
+ export interface Event{
29
+ name:string;
30
+ data:any;
31
+ }
32
+
33
+ export type EventHandler = (...args: any[]) => void|boolean;
34
+
35
+ export interface ExtensionOptions {
36
+ [key: string]: any;
37
+ }
38
+ export interface OptionSchema {
39
+ type: 'string' | 'number' | 'boolean' | 'color' | 'select';
40
+ options?: string[] | { label: string; value: any }[];
41
+ min?: number;
42
+ max?: number;
43
+ step?: number;
44
+ label?: string;
45
+ }
46
+
47
+ export interface Extension<T extends ExtensionOptions=ExtensionOptions>{
48
+ name: string
49
+ priority?: number
50
+ options?: T
51
+ schema?: Record<keyof T, OptionSchema>
52
+ enabled?: boolean
53
+
54
+ onCreate?(editor: Editor):void
55
+ onMount?(editor: Editor):void
56
+ onUpdate?(editor: Editor, state: EditorState):void
57
+ onUnmount?(editor: Editor):void
58
+ onDestroy?(editor: Editor):void
59
+
60
+ commands?: Record<string, Command>
61
+ }
62
+
63
+ export interface EditorState{
64
+ width: number
65
+ height: number
66
+ metadata?: Record<string, any>
67
+ }
68
+
69
+ export interface Editor{
70
+ state: EditorState
71
+ canvas: PooderCanvas
72
+ extensions: ExtensionMap
73
+ commands: CommandMap
74
+
75
+ use(extension: Extension):void
76
+ unuse(name:string):void
77
+ getExtension(name:string):Extension | undefined
78
+ getExtensions():Extension[]
79
+ enableExtension(name:string):void
80
+ disableExtension(name:string):void
81
+
82
+ registerCommand(name:string,command:Command):void
83
+ unregisterCommand(name:string):void
84
+ executeCommand(name:string,...args:any[]):void
85
+
86
+ on(event:string, handler:EventHandler,priority?:number):void
87
+ off(event:string, handler:EventHandler):void
88
+ emit(event:string, ...args:any[]):void
89
+
90
+ getObjects():PooderObject[]
91
+ getObject(id:string,layerId?:string):PooderObject | undefined
92
+ getLayers():PooderLayer[]
93
+ getLayer(id:string):PooderLayer | undefined
94
+
95
+ updateState(updater:(state:EditorState)=>EditorState):void
96
+ getState():EditorState
97
+
98
+ toJSON(): any;
99
+ loadFromJSON(json: any): Promise<void>;
100
+
101
+ destroy():void
102
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2018",
4
+ "module": "esnext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["esnext", "dom"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "declaration": true
11
+ },
12
+ "include": ["src"]
13
+ }