@kerebron/extension-basic-editor 0.5.0 → 0.5.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.
@@ -1,8 +1,11 @@
1
1
  import { type NodeSpec } from 'prosemirror-model';
2
+ import type { NodeViewConstructor } from 'prosemirror-view';
2
3
  import { Node } from '@kerebron/editor';
4
+ import type { CoreEditor } from '@kerebron/editor';
3
5
  export declare class NodeImage extends Node {
4
6
  name: string;
5
7
  requires: string[];
6
8
  getNodeSpec(): NodeSpec;
9
+ getNodeView(editor: CoreEditor): NodeViewConstructor;
7
10
  }
8
11
  //# sourceMappingURL=NodeImage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeImage.d.ts","sourceRoot":"","sources":["../src/NodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,qBAAa,SAAU,SAAQ,IAAI;IACxB,IAAI,SAAW;IACxB,QAAQ,WAAW;IAEV,WAAW,IAAI,QAAQ;CA4BjC"}
1
+ {"version":3,"file":"NodeImage.d.ts","sourceRoot":"","sources":["../src/NodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAc,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qBAAa,SAAU,SAAQ,IAAI;IACxB,IAAI,SAAW;IACxB,QAAQ,WAAW;IAEV,WAAW,IAAI,QAAQ;IAsCvB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,mBAAmB;CAkM9D"}
package/esm/NodeImage.js CHANGED
@@ -9,6 +9,8 @@ export class NodeImage extends Node {
9
9
  src: {},
10
10
  alt: { default: null },
11
11
  title: { default: null },
12
+ width: { default: null },
13
+ height: { default: null },
12
14
  },
13
15
  group: 'inline',
14
16
  draggable: true,
@@ -20,15 +22,201 @@ export class NodeImage extends Node {
20
22
  src: dom.getAttribute('src'),
21
23
  title: dom.getAttribute('title'),
22
24
  alt: dom.getAttribute('alt'),
25
+ width: dom.getAttribute('width') || dom.style.width || null,
26
+ height: dom.getAttribute('height') || dom.style.height || null,
23
27
  };
24
28
  },
25
29
  },
26
30
  ],
27
31
  toDOM(node) {
28
- const { src, alt, title } = node.attrs;
29
- return ['img', { src, alt, title }];
32
+ const { src, alt, title, width, height } = node.attrs;
33
+ const attrs = { src };
34
+ if (alt)
35
+ attrs.alt = alt;
36
+ if (title)
37
+ attrs.title = title;
38
+ if (width)
39
+ attrs.width = width;
40
+ if (height)
41
+ attrs.height = height;
42
+ return ['img', attrs];
30
43
  },
31
44
  };
32
45
  }
46
+ getNodeView(editor) {
47
+ return (node, view, getPos) => {
48
+ // Create wrapper div for the image with resize handles
49
+ const wrapper = document.createElement('span');
50
+ wrapper.className = 'kb-image-wrapper';
51
+ wrapper.contentEditable = 'false';
52
+ // Create the image element
53
+ const img = document.createElement('img');
54
+ img.src = node.attrs.src;
55
+ if (node.attrs.alt)
56
+ img.alt = node.attrs.alt;
57
+ if (node.attrs.title)
58
+ img.title = node.attrs.title;
59
+ if (node.attrs.width) {
60
+ img.style.width = typeof node.attrs.width === 'number'
61
+ ? `${node.attrs.width}px`
62
+ : node.attrs.width;
63
+ }
64
+ if (node.attrs.height) {
65
+ img.style.height = typeof node.attrs.height === 'number'
66
+ ? `${node.attrs.height}px`
67
+ : node.attrs.height;
68
+ }
69
+ img.draggable = false;
70
+ wrapper.appendChild(img);
71
+ // Create resize handles
72
+ const positions = ['nw', 'ne', 'sw', 'se'];
73
+ const handles = [];
74
+ for (const pos of positions) {
75
+ const handle = document.createElement('span');
76
+ handle.className =
77
+ `kb-image-resize-handle kb-image-resize-handle-${pos}`;
78
+ handle.dataset.position = pos;
79
+ handles.push(handle);
80
+ wrapper.appendChild(handle);
81
+ }
82
+ let isResizing = false;
83
+ let startX = 0;
84
+ let startY = 0;
85
+ let startWidth = 0;
86
+ let startHeight = 0;
87
+ let aspectRatio = 1;
88
+ let activeHandle = null;
89
+ const onMouseDown = (e) => {
90
+ const target = e.target;
91
+ if (!target.classList.contains('kb-image-resize-handle'))
92
+ return;
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+ isResizing = true;
96
+ activeHandle = target.dataset.position || null;
97
+ startX = e.clientX;
98
+ startY = e.clientY;
99
+ const rect = img.getBoundingClientRect();
100
+ startWidth = rect.width;
101
+ startHeight = rect.height;
102
+ aspectRatio = startWidth / startHeight;
103
+ wrapper.classList.add('kb-image-resizing');
104
+ document.addEventListener('mousemove', onMouseMove);
105
+ document.addEventListener('mouseup', onMouseUp);
106
+ };
107
+ const onMouseMove = (e) => {
108
+ if (!isResizing)
109
+ return;
110
+ const deltaX = e.clientX - startX;
111
+ const deltaY = e.clientY - startY;
112
+ let newWidth = startWidth;
113
+ let newHeight = startHeight;
114
+ // Calculate new dimensions based on which handle is being dragged
115
+ switch (activeHandle) {
116
+ case 'se':
117
+ newWidth = startWidth + deltaX;
118
+ newHeight = e.shiftKey
119
+ ? startHeight + deltaY
120
+ : newWidth / aspectRatio;
121
+ break;
122
+ case 'sw':
123
+ newWidth = startWidth - deltaX;
124
+ newHeight = e.shiftKey
125
+ ? startHeight + deltaY
126
+ : newWidth / aspectRatio;
127
+ break;
128
+ case 'ne':
129
+ newWidth = startWidth + deltaX;
130
+ newHeight = e.shiftKey
131
+ ? startHeight - deltaY
132
+ : newWidth / aspectRatio;
133
+ break;
134
+ case 'nw':
135
+ newWidth = startWidth - deltaX;
136
+ newHeight = e.shiftKey
137
+ ? startHeight - deltaY
138
+ : newWidth / aspectRatio;
139
+ break;
140
+ }
141
+ // Ensure minimum size
142
+ newWidth = Math.max(50, newWidth);
143
+ newHeight = Math.max(50, newHeight);
144
+ img.style.width = `${Math.round(newWidth)}px`;
145
+ img.style.height = `${Math.round(newHeight)}px`;
146
+ };
147
+ const onMouseUp = () => {
148
+ if (!isResizing)
149
+ return;
150
+ isResizing = false;
151
+ activeHandle = null;
152
+ wrapper.classList.remove('kb-image-resizing');
153
+ document.removeEventListener('mousemove', onMouseMove);
154
+ document.removeEventListener('mouseup', onMouseUp);
155
+ // Get the new dimensions and update the node
156
+ const newWidth = Math.round(img.getBoundingClientRect().width);
157
+ const newHeight = Math.round(img.getBoundingClientRect().height);
158
+ const pos = getPos();
159
+ if (typeof pos === 'number') {
160
+ const tr = view.state.tr.setNodeMarkup(pos, undefined, {
161
+ ...node.attrs,
162
+ width: `${newWidth}px`,
163
+ height: `${newHeight}px`,
164
+ });
165
+ view.dispatch(tr);
166
+ }
167
+ };
168
+ wrapper.addEventListener('mousedown', onMouseDown);
169
+ // Add click handler to select the image
170
+ wrapper.addEventListener('click', (e) => {
171
+ e.preventDefault();
172
+ const pos = getPos();
173
+ if (typeof pos === 'number') {
174
+ const $pos = view.state.doc.resolve(pos);
175
+ const selection = view.state.selection.constructor.near($pos);
176
+ view.dispatch(view.state.tr.setSelection(selection));
177
+ }
178
+ });
179
+ return {
180
+ dom: wrapper,
181
+ update: (updatedNode) => {
182
+ if (updatedNode.type.name !== 'image')
183
+ return false;
184
+ img.src = updatedNode.attrs.src;
185
+ if (updatedNode.attrs.alt)
186
+ img.alt = updatedNode.attrs.alt;
187
+ if (updatedNode.attrs.title)
188
+ img.title = updatedNode.attrs.title;
189
+ if (updatedNode.attrs.width) {
190
+ img.style.width = typeof updatedNode.attrs.width === 'number'
191
+ ? `${updatedNode.attrs.width}px`
192
+ : updatedNode.attrs.width;
193
+ }
194
+ else {
195
+ img.style.width = '';
196
+ }
197
+ if (updatedNode.attrs.height) {
198
+ img.style.height = typeof updatedNode.attrs.height === 'number'
199
+ ? `${updatedNode.attrs.height}px`
200
+ : updatedNode.attrs.height;
201
+ }
202
+ else {
203
+ img.style.height = '';
204
+ }
205
+ return true;
206
+ },
207
+ destroy: () => {
208
+ wrapper.removeEventListener('mousedown', onMouseDown);
209
+ document.removeEventListener('mousemove', onMouseMove);
210
+ document.removeEventListener('mouseup', onMouseUp);
211
+ },
212
+ stopEvent: (event) => {
213
+ // Allow selection events to pass through
214
+ return event.type === 'mousedown' &&
215
+ event.target.classList.contains('kb-image-resize-handle');
216
+ },
217
+ ignoreMutation: () => true,
218
+ };
219
+ };
220
+ }
33
221
  }
34
222
  //# sourceMappingURL=NodeImage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeImage.js","sourceRoot":"","sources":["../src/NodeImage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,MAAM,OAAO,SAAU,SAAQ,IAAI;IACxB,IAAI,GAAG,OAAO,CAAC;IACxB,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC;IAEV,WAAW;QAClB,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE;gBACL,GAAG,EAAE,EAAE;gBACP,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBACtB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aACzB;YACD,KAAK,EAAE,QAAQ;YACf,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,UAAU;oBACf,QAAQ,CAAC,GAAgB;wBACvB,OAAO;4BACL,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC;4BAC5B,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC;4BAChC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC;yBAC7B,CAAC;oBACJ,CAAC;iBACF;aACF;YACD,KAAK,CAAC,IAAI;gBACR,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;gBACvC,OAAO,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;YACtC,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"NodeImage.js","sourceRoot":"","sources":["../src/NodeImage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerebron/extension-basic-editor",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "license": "MIT",
5
5
  "module": "./esm/BasicEditorKit.js",
6
6
  "exports": {
@@ -37,6 +37,9 @@
37
37
  "./ExtensionHtml": {
38
38
  "import": "./esm/ExtensionHtml.js"
39
39
  },
40
+ "./ExtensionTextAlign": {
41
+ "import": "./esm/ExtensionTextAlign.js"
42
+ },
40
43
  "./NodeDocument": {
41
44
  "import": "./esm/NodeDocument.js"
42
45
  },
@@ -109,8 +112,8 @@
109
112
  "./MarkSubscript": {
110
113
  "import": "./esm/MarkSubscript.js"
111
114
  },
112
- "./ExtensionTextAlign": {
113
- "import": "./esm/ExtensionTextAlign.js"
115
+ "./assets/*.css": {
116
+ "import": "./assets/*.css"
114
117
  }
115
118
  },
116
119
  "scripts": {},
@@ -119,7 +122,7 @@
119
122
  "src"
120
123
  ],
121
124
  "dependencies": {
122
- "@kerebron/editor": "0.5.0",
125
+ "@kerebron/editor": "0.5.1",
123
126
  "prosemirror-history": "1.4.1",
124
127
  "prosemirror-model": "1.25.3",
125
128
  "prosemirror-state": "1.4.3",
package/src/NodeImage.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { type NodeSpec } from 'prosemirror-model';
2
+ import type { Node as PmNode } from 'prosemirror-model';
3
+ import type { EditorView, NodeViewConstructor } from 'prosemirror-view';
2
4
  import { Node } from '@kerebron/editor';
5
+ import type { CoreEditor } from '@kerebron/editor';
3
6
 
4
7
  export class NodeImage extends Node {
5
8
  override name = 'image';
@@ -12,6 +15,8 @@ export class NodeImage extends Node {
12
15
  src: {},
13
16
  alt: { default: null },
14
17
  title: { default: null },
18
+ width: { default: null },
19
+ height: { default: null },
15
20
  },
16
21
  group: 'inline',
17
22
  draggable: true,
@@ -23,14 +28,216 @@ export class NodeImage extends Node {
23
28
  src: dom.getAttribute('src'),
24
29
  title: dom.getAttribute('title'),
25
30
  alt: dom.getAttribute('alt'),
31
+ width: dom.getAttribute('width') || dom.style.width || null,
32
+ height: dom.getAttribute('height') || dom.style.height || null,
26
33
  };
27
34
  },
28
35
  },
29
36
  ],
30
37
  toDOM(node) {
31
- const { src, alt, title } = node.attrs;
32
- return ['img', { src, alt, title }];
38
+ const { src, alt, title, width, height } = node.attrs;
39
+ const attrs: Record<string, string> = { src };
40
+ if (alt) attrs.alt = alt;
41
+ if (title) attrs.title = title;
42
+ if (width) attrs.width = width;
43
+ if (height) attrs.height = height;
44
+ return ['img', attrs];
33
45
  },
34
46
  };
35
47
  }
48
+
49
+ override getNodeView(editor: CoreEditor): NodeViewConstructor {
50
+ return (node: PmNode, view: EditorView, getPos) => {
51
+ // Create wrapper div for the image with resize handles
52
+ const wrapper = document.createElement('span');
53
+ wrapper.className = 'kb-image-wrapper';
54
+ wrapper.contentEditable = 'false';
55
+
56
+ // Create the image element
57
+ const img = document.createElement('img');
58
+ img.src = node.attrs.src;
59
+ if (node.attrs.alt) img.alt = node.attrs.alt;
60
+ if (node.attrs.title) img.title = node.attrs.title;
61
+ if (node.attrs.width) {
62
+ img.style.width = typeof node.attrs.width === 'number'
63
+ ? `${node.attrs.width}px`
64
+ : node.attrs.width;
65
+ }
66
+ if (node.attrs.height) {
67
+ img.style.height = typeof node.attrs.height === 'number'
68
+ ? `${node.attrs.height}px`
69
+ : node.attrs.height;
70
+ }
71
+ img.draggable = false;
72
+
73
+ wrapper.appendChild(img);
74
+
75
+ // Create resize handles
76
+ const positions = ['nw', 'ne', 'sw', 'se'] as const;
77
+ const handles: HTMLElement[] = [];
78
+
79
+ for (const pos of positions) {
80
+ const handle = document.createElement('span');
81
+ handle.className =
82
+ `kb-image-resize-handle kb-image-resize-handle-${pos}`;
83
+ handle.dataset.position = pos;
84
+ handles.push(handle);
85
+ wrapper.appendChild(handle);
86
+ }
87
+
88
+ let isResizing = false;
89
+ let startX = 0;
90
+ let startY = 0;
91
+ let startWidth = 0;
92
+ let startHeight = 0;
93
+ let aspectRatio = 1;
94
+ let activeHandle: string | null = null;
95
+
96
+ const onMouseDown = (e: MouseEvent) => {
97
+ const target = e.target as HTMLElement;
98
+ if (!target.classList.contains('kb-image-resize-handle')) return;
99
+
100
+ e.preventDefault();
101
+ e.stopPropagation();
102
+
103
+ isResizing = true;
104
+ activeHandle = target.dataset.position || null;
105
+ startX = e.clientX;
106
+ startY = e.clientY;
107
+
108
+ const rect = img.getBoundingClientRect();
109
+ startWidth = rect.width;
110
+ startHeight = rect.height;
111
+ aspectRatio = startWidth / startHeight;
112
+
113
+ wrapper.classList.add('kb-image-resizing');
114
+
115
+ document.addEventListener('mousemove', onMouseMove);
116
+ document.addEventListener('mouseup', onMouseUp);
117
+ };
118
+
119
+ const onMouseMove = (e: MouseEvent) => {
120
+ if (!isResizing) return;
121
+
122
+ const deltaX = e.clientX - startX;
123
+ const deltaY = e.clientY - startY;
124
+
125
+ let newWidth = startWidth;
126
+ let newHeight = startHeight;
127
+
128
+ // Calculate new dimensions based on which handle is being dragged
129
+ switch (activeHandle) {
130
+ case 'se':
131
+ newWidth = startWidth + deltaX;
132
+ newHeight = e.shiftKey
133
+ ? startHeight + deltaY
134
+ : newWidth / aspectRatio;
135
+ break;
136
+ case 'sw':
137
+ newWidth = startWidth - deltaX;
138
+ newHeight = e.shiftKey
139
+ ? startHeight + deltaY
140
+ : newWidth / aspectRatio;
141
+ break;
142
+ case 'ne':
143
+ newWidth = startWidth + deltaX;
144
+ newHeight = e.shiftKey
145
+ ? startHeight - deltaY
146
+ : newWidth / aspectRatio;
147
+ break;
148
+ case 'nw':
149
+ newWidth = startWidth - deltaX;
150
+ newHeight = e.shiftKey
151
+ ? startHeight - deltaY
152
+ : newWidth / aspectRatio;
153
+ break;
154
+ }
155
+
156
+ // Ensure minimum size
157
+ newWidth = Math.max(50, newWidth);
158
+ newHeight = Math.max(50, newHeight);
159
+
160
+ img.style.width = `${Math.round(newWidth)}px`;
161
+ img.style.height = `${Math.round(newHeight)}px`;
162
+ };
163
+
164
+ const onMouseUp = () => {
165
+ if (!isResizing) return;
166
+
167
+ isResizing = false;
168
+ activeHandle = null;
169
+ wrapper.classList.remove('kb-image-resizing');
170
+
171
+ document.removeEventListener('mousemove', onMouseMove);
172
+ document.removeEventListener('mouseup', onMouseUp);
173
+
174
+ // Get the new dimensions and update the node
175
+ const newWidth = Math.round(img.getBoundingClientRect().width);
176
+ const newHeight = Math.round(img.getBoundingClientRect().height);
177
+
178
+ const pos = getPos();
179
+ if (typeof pos === 'number') {
180
+ const tr = view.state.tr.setNodeMarkup(pos, undefined, {
181
+ ...node.attrs,
182
+ width: `${newWidth}px`,
183
+ height: `${newHeight}px`,
184
+ });
185
+ view.dispatch(tr);
186
+ }
187
+ };
188
+
189
+ wrapper.addEventListener('mousedown', onMouseDown);
190
+
191
+ // Add click handler to select the image
192
+ wrapper.addEventListener('click', (e) => {
193
+ e.preventDefault();
194
+ const pos = getPos();
195
+ if (typeof pos === 'number') {
196
+ const $pos = view.state.doc.resolve(pos);
197
+ const selection = view.state.selection.constructor.near($pos);
198
+ view.dispatch(view.state.tr.setSelection(selection));
199
+ }
200
+ });
201
+
202
+ return {
203
+ dom: wrapper,
204
+ update: (updatedNode: PmNode) => {
205
+ if (updatedNode.type.name !== 'image') return false;
206
+
207
+ img.src = updatedNode.attrs.src;
208
+ if (updatedNode.attrs.alt) img.alt = updatedNode.attrs.alt;
209
+ if (updatedNode.attrs.title) img.title = updatedNode.attrs.title;
210
+ if (updatedNode.attrs.width) {
211
+ img.style.width = typeof updatedNode.attrs.width === 'number'
212
+ ? `${updatedNode.attrs.width}px`
213
+ : updatedNode.attrs.width;
214
+ } else {
215
+ img.style.width = '';
216
+ }
217
+ if (updatedNode.attrs.height) {
218
+ img.style.height = typeof updatedNode.attrs.height === 'number'
219
+ ? `${updatedNode.attrs.height}px`
220
+ : updatedNode.attrs.height;
221
+ } else {
222
+ img.style.height = '';
223
+ }
224
+
225
+ return true;
226
+ },
227
+ destroy: () => {
228
+ wrapper.removeEventListener('mousedown', onMouseDown);
229
+ document.removeEventListener('mousemove', onMouseMove);
230
+ document.removeEventListener('mouseup', onMouseUp);
231
+ },
232
+ stopEvent: (event: Event) => {
233
+ // Allow selection events to pass through
234
+ return event.type === 'mousedown' &&
235
+ (event.target as HTMLElement).classList.contains(
236
+ 'kb-image-resize-handle',
237
+ );
238
+ },
239
+ ignoreMutation: () => true,
240
+ };
241
+ };
242
+ }
36
243
  }