tiptap-extension-izzy-resizable-image 0.1.13 → 0.1.15
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/README.md +210 -203
- package/npm/index.js +843 -649
- package/package.json +38 -38
package/README.md
CHANGED
|
@@ -1,203 +1,210 @@
|
|
|
1
|
-
# TipTap Izzy Extension: Resizable Image
|
|
2
|
-
|
|
3
|
-
Resizable inline image node for TipTap v2 with eight resize handles, optional alignment menu, drag-and-drop, and sensible defaults via `.extend()`.
|
|
4
|
-
|
|
5
|
-
Demo: https://startinn.github.io/TipTap-Extension-Izzy-Resizable-Image/
|
|
6
|
-
|
|
7
|
-
Download: https://www.npmjs.com/package/tiptap-extension-izzy-resizable-image
|
|
8
|
-
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
- Inline resizable image with 8 handles (nw, n, ne, e, se, s, sw, w)
|
|
12
|
-
- Drag-and-drop repositioning using browser native drag
|
|
13
|
-
- Optional inline alignment menu (left, center, right, clear)
|
|
14
|
-
- Menu position configurable (`above` or `below`)
|
|
15
|
-
- Keeps aspect ratio while resizing
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
import {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
- `
|
|
115
|
-
- `
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- `
|
|
137
|
-
- `
|
|
138
|
-
- `
|
|
139
|
-
- `
|
|
140
|
-
- `
|
|
141
|
-
- `
|
|
142
|
-
- `
|
|
143
|
-
- `
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
- `
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
```
|
|
1
|
+
# TipTap Izzy Extension: Resizable Image
|
|
2
|
+
|
|
3
|
+
Resizable inline image node for TipTap v2 with eight resize handles, optional alignment menu, drag-and-drop, and sensible defaults via `.extend()`.
|
|
4
|
+
|
|
5
|
+
Demo: https://startinn.github.io/TipTap-Extension-Izzy-Resizable-Image/
|
|
6
|
+
|
|
7
|
+
Download: https://www.npmjs.com/package/tiptap-extension-izzy-resizable-image
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Inline resizable image with 8 handles (nw, n, ne, e, se, s, sw, w)
|
|
12
|
+
- Drag-and-drop repositioning using browser native drag
|
|
13
|
+
- Optional inline alignment menu (left, center, right, clear)
|
|
14
|
+
- Menu position configurable (`above` or `below`)
|
|
15
|
+
- Keeps aspect ratio while resizing
|
|
16
|
+
- Preview modal supports mouse-wheel zoom from 0.25x to 4x
|
|
17
|
+
- Copies the image as PNG or copies its URL from the alignment menu
|
|
18
|
+
- Menu icons accept HTML strings (e.g., `<i class="...">`)
|
|
19
|
+
- Deselects image and hides UI when clicking outside
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
This demo loads TipTap and the extension via ESM in the browser. Include `resizable-image.js` next to your HTML file and import it.
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<script type="module">
|
|
27
|
+
import { Editor } from 'https://esm.sh/@tiptap/core@2';
|
|
28
|
+
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2';
|
|
29
|
+
import { TiptapIzzyExtensionResizableImage } from './resizable-image.js';
|
|
30
|
+
// ...
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
const editor = new Editor({
|
|
38
|
+
element: document.querySelector('#editor'),
|
|
39
|
+
extensions: [StarterKit, TiptapIzzyExtensionResizableImage],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Insert an image
|
|
43
|
+
editor.commands.insertResizableImage({ src: 'https://picsum.photos/300/200', width: 300, height: 200 });
|
|
44
|
+
|
|
45
|
+
// Align the selected image
|
|
46
|
+
editor.commands.setResizableImageAlignment('center');
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Using from npm (bundler)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install tiptap-extension-izzy-resizable-image @tiptap/core@^3 prosemirror-state
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import { Editor } from '@tiptap/core';
|
|
57
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
58
|
+
import { TiptapIzzyExtensionResizableImage } from 'tiptap-extension-izzy-resizable-image';
|
|
59
|
+
|
|
60
|
+
const editor = new Editor({
|
|
61
|
+
element: document.querySelector('#editor'),
|
|
62
|
+
extensions: [StarterKit, TiptapIzzyExtensionResizableImage],
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Defaults via `.extend()`
|
|
67
|
+
|
|
68
|
+
You can set extension-wide defaults using `.extend()` to override `addOptions()`.
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
const editor = new Editor({
|
|
72
|
+
element: document.querySelector('#editor'),
|
|
73
|
+
extensions: [
|
|
74
|
+
StarterKit,
|
|
75
|
+
TiptapIzzyExtensionResizableImage.extend({
|
|
76
|
+
addOptions() {
|
|
77
|
+
return {
|
|
78
|
+
height: 200,
|
|
79
|
+
showAlignMenu: true,
|
|
80
|
+
alignMenuPosition: 'below',
|
|
81
|
+
alignMenuIcons: {
|
|
82
|
+
left: '⟸',
|
|
83
|
+
center: '⇔',
|
|
84
|
+
right: '⟹',
|
|
85
|
+
clear: 'x',
|
|
86
|
+
preview: '🔍',
|
|
87
|
+
},
|
|
88
|
+
alignMenuOrder: ['left', 'center', 'right', 'clear', 'preview', 'size50', 'size100', 'copy', 'copyUrl'],
|
|
89
|
+
alignMenuButtonsHide: {
|
|
90
|
+
// hide specific buttons if true
|
|
91
|
+
// left: true,
|
|
92
|
+
// right: true,
|
|
93
|
+
// center: true,
|
|
94
|
+
// clear: true,
|
|
95
|
+
// preview: true,
|
|
96
|
+
// size50: true,
|
|
97
|
+
// size100: true,
|
|
98
|
+
},
|
|
99
|
+
fitToContainerSelector: '.tiptap',
|
|
100
|
+
autoFitWhenOversized: true,
|
|
101
|
+
maxAllowedWidth: null,
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// With defaults set, you can omit height/menu attrs in insert:
|
|
109
|
+
editor.commands.insertResizableImage({ src: 'https://picsum.photos/300/200', width: 300 });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Options (via `.extend()`)
|
|
113
|
+
|
|
114
|
+
- `height: number | null` — default height in pixels when node `height` attr is missing.
|
|
115
|
+
- `showAlignMenu: boolean` — whether the inline alignment menu is shown by default.
|
|
116
|
+
- `alignMenuPosition: 'above' | 'below'` — where the menu appears relative to the image.
|
|
117
|
+
- `alignMenuIcons: { left: string, center: string, right: string, clear: string, preview: string, copy: string, copyUrl: string, copied: string, copyError: string }` — HTML strings for menu buttons. `copied` and `copyError` are shown for 3 seconds after a copy succeeds or fails.
|
|
118
|
+
- `alignMenuLabels: Record<string, string>` — overrides the English tooltip and `aria-label` texts, merged over the defaults (supports `left`, `center`, `right`, `clear`, `preview`, `size50`, `size100`, `copy`, `copyUrl`, `copied`, `copyFailed`, `urlCopied`, `urlCopyFailed`).
|
|
119
|
+
- `alignMenuOrder: string[]` — order of buttons in the alignment menu (default: `['left', 'center', 'right', 'clear', 'preview', 'size50', 'size100', 'copy', 'copyUrl']`). Buttons are displayed in the order specified.
|
|
120
|
+
- `alignMenuButtonsHide: Record<string, boolean>` — hide specific buttons when `true` (supports `left`, `center`, `right`, `clear`, `preview`, `size50`, `size100`, `copy`, `copyUrl`).
|
|
121
|
+
- `fitToContainerSelector: string` — CSS selector used as width reference for the initial image fit (default: `.tiptap`).
|
|
122
|
+
- `autoFitWhenOversized: boolean` — when `true`, oversized images inserted without explicit width are automatically set to `width: 100%` and `height: auto` (default: `true`).
|
|
123
|
+
- `maxAllowedWidth: number | null` — maximum allowed width in pixels. If image width exceeds this value, it is forced to `width: 100%` and `height: auto`.
|
|
124
|
+
|
|
125
|
+
Clipboard operations require a secure context. Copying an image writes PNG and requires its host to allow cross-origin fetches (CORS).
|
|
126
|
+
|
|
127
|
+
Reference:
|
|
128
|
+
- Defined in `resizable-image.js:387-394`
|
|
129
|
+
- Passed into the NodeView in `resizable-image.js:383-385`
|
|
130
|
+
- Used for insertion defaults in `resizable-image.js:402-414`
|
|
131
|
+
|
|
132
|
+
## Node Attributes
|
|
133
|
+
|
|
134
|
+
These can be set per-node, overriding options.
|
|
135
|
+
|
|
136
|
+
- `src: string` — image URL.
|
|
137
|
+
- `alt: string | null`
|
|
138
|
+
- `title: string | null`
|
|
139
|
+
- `width: number | null` — width in px.
|
|
140
|
+
- `height: number | null` — height in px.
|
|
141
|
+
- `id: string | null` — applied to the `<img>` element.
|
|
142
|
+
- `class: string | null` — applied to the `<img>` element.
|
|
143
|
+
- `align: 'left' | 'center' | 'right' | null` — alignment.
|
|
144
|
+
- `showAlignMenu: boolean | null` — show/hide menu per node.
|
|
145
|
+
- `alignMenuPosition: 'above' | 'below' | null`
|
|
146
|
+
- `iconLeft: string | null` — HTML or text for the left button.
|
|
147
|
+
- `iconCenter: string | null`
|
|
148
|
+
- `iconRight: string | null`
|
|
149
|
+
- `iconClear: string | null`
|
|
150
|
+
- `iconView: string | null` — HTML or text for the preview (lightbox) button.
|
|
151
|
+
|
|
152
|
+
Reference: `resizable-image.js:358-372`
|
|
153
|
+
|
|
154
|
+
## Commands
|
|
155
|
+
|
|
156
|
+
- `insertResizableImage({ src, alt, title, width, height, id, class })`
|
|
157
|
+
- Inserts the resizable image node. Missing attrs fall back to options (e.g., `height`).
|
|
158
|
+
- Reference: `resizable-image.js:398-416`
|
|
159
|
+
|
|
160
|
+
- `setResizableImageAlignment(align)`
|
|
161
|
+
- Sets `align` on the currently selected image node.
|
|
162
|
+
- Reference: `resizable-image.js:417-433`
|
|
163
|
+
|
|
164
|
+
## Keyboard Shortcuts
|
|
165
|
+
|
|
166
|
+
- `Enter` when an image is selected inserts a paragraph after it and moves the cursor there.
|
|
167
|
+
- Reference: `resizable-image.js:412-431`
|
|
168
|
+
|
|
169
|
+
## Alignment Behavior
|
|
170
|
+
|
|
171
|
+
- Alignment is applied via `text-align` on the wrapper and toggling wrapper display.
|
|
172
|
+
- `left | center | right` set `text-align` accordingly; unaligned flows inline.
|
|
173
|
+
- Reference: `resizable-image.js:172-193`
|
|
174
|
+
|
|
175
|
+
## Resizing Behavior
|
|
176
|
+
|
|
177
|
+
- Eight handles adjust width/height; aspect ratio is preserved by default.
|
|
178
|
+
- Live preview updates `style.width`/`style.height`; final size is persisted to node attrs on pointerup.
|
|
179
|
+
- Reference: `resizable-image.js:195-271`
|
|
180
|
+
|
|
181
|
+
## Selection and Focus
|
|
182
|
+
|
|
183
|
+
- Menu and handles overlay appear only when the image node is selected.
|
|
184
|
+
- Clicking outside the image deselects it and hides menu/overlay.
|
|
185
|
+
- Reference: show/hide logic `resizable-image.js:302-321`, `resizable-image.js:324-334`; outside-click handling `resizable-image.js:456-483`.
|
|
186
|
+
|
|
187
|
+
## HTML Icons
|
|
188
|
+
|
|
189
|
+
- Menu buttons render using `innerHTML`, allowing HTML strings for icons or rich content.
|
|
190
|
+
- Use trusted sources; avoid unsanitized user input to prevent XSS.
|
|
191
|
+
- Reference: `resizable-image.js:120-123` and `resizable-image.js:291-294`.
|
|
192
|
+
|
|
193
|
+
## Demo Hooks
|
|
194
|
+
|
|
195
|
+
- Example toolbar integration in the demo (`index.html:37-73`) shows inserting images and alignment controls.
|
|
196
|
+
|
|
197
|
+
## Notes
|
|
198
|
+
|
|
199
|
+
- The extension is inline and draggable; selection toggles menu/handles.
|
|
200
|
+
- Deselecting removes the overlay/menu from the DOM to keep markup clean.
|
|
201
|
+
### Example with `id` and `class`
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
editor.commands.insertResizableImage({
|
|
205
|
+
src: 'https://picsum.photos/300/200',
|
|
206
|
+
width: 300,
|
|
207
|
+
id: 'hero-image',
|
|
208
|
+
class: 'rounded shadow'
|
|
209
|
+
});
|
|
210
|
+
```
|