├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── dependabot.yml
├── .gitignore
├── LICENSE
├── LICENSE.md
├── README.md
├── _config.yml
├── package-lock.json
├── package.json
├── src
├── component
│ └── ImageResizeComponent.tsx
├── image.tsx
└── index.ts
└── tiptap-imagresize.iml
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | litters-backend/node_modules/
4 | build/
5 | tmp/
6 | temp/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Bram Hammer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021, überdosis GbR
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @breakerh/tiptap-image-resize
2 | [](https://github.com/breakerh/tiptap-image-resize)
3 | [](https://github.com/breakerh/tiptap-image-resize)
4 |
5 | ## Introduction
6 | tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
7 | I am not affiliated with TipTap in any way. I build this module for myself and thought maybe I can help other with it.. Please [let me know](https://github.com/breakerh/tiptap-image-resize/issues) if you experience any problems whatsoever!
8 |
9 | ## Installation
10 | Install the package through NPM ( `` npm i tiptap-imagresize `` ) or yarn ( `` yarn add tiptap-imagresize `` ), and don't forget to include it in the use editor explained [here](https://tiptap.dev/guide/configuration#nodes-marks-and-extensions).
11 |
12 | ### Configuration
13 | While adding Image Resizer to your TipTap editor you can set a few options.
14 |
15 | | Key | Description | Default |
16 | |----------------|-------------------------------------------------|---------|
17 | | inline | Is the image inline? | `false` |
18 | | allowBase64 | Can you insert Base64 encoded images? | `false` |
19 | | HTMLAttributes | Do you want to add custom attributes? | empty |
20 | | resizeIcon | What type if resize icon would you want to see? | `⊙` |
21 | | useFigure | Do you want to wrap your image in a figure tag? | `false` |
22 |
23 | #### Example:
24 | ```js
25 | const editor = useEditor({
26 | extensions: [
27 | StarterKit, ImageResize.configure({resizeIcon: <>ResizeMe>})
28 | ],
29 | content: '
Hello World!
',
30 | })
31 | ```
32 |
33 | ## Styling
34 | I didn't include any styling since a assume you have your reasons you will use TipTap instead of other editors.
35 | Do you still want a quick result or just want some starter css?
36 | Add this to your (s)css or convert it to react styles markup.
37 | ### Scss
38 | ```css
39 | .image-resizer {
40 | display: inline-flex;
41 | position: relative;
42 | flex-grow: 0;
43 | .resize-trigger {
44 | position: absolute;
45 | right: -6px;
46 | bottom: -9px;
47 | opacity: 0;
48 | transition: opacity .3s ease;
49 | color: #3259a5;
50 | }
51 | &:hover .resize-trigger {
52 | opacity: 1;
53 | }
54 | }
55 | ```
56 | ### Css
57 | ```css
58 | .image-resizer {
59 | display: inline-flex;
60 | position: relative;
61 | flex-grow: 0;
62 | }
63 | .image-resizer .resize-trigger {
64 | position: absolute;
65 | right: -6px;
66 | bottom: -9px;
67 | opacity: 0;
68 | transition: opacity .3s ease;
69 | color: #3259a5;
70 | }
71 | .image-resizer:hover .resize-trigger {
72 | opacity: 1;
73 | }
74 | ```
75 |
76 | ## Official Documentation
77 | Documentation can be found on the [tiptap website](https://tiptap.dev).
78 |
79 | ## License
80 | tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
81 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-midnight
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tiptap-imagresize",
3 | "version": "1.1.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "tiptap-imagresize",
9 | "version": "1.1.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@types/react": "^18.0.38"
13 | },
14 | "peerDependencies": {
15 | "@tiptap/core": "^2.0.0-beta.1",
16 | "@tiptap/extension-image": "^2.0.0-beta.27",
17 | "@tiptap/react": "^2.0.0-beta.109",
18 | "react": "^17.0.2 || ^18"
19 | }
20 | },
21 | "node_modules/@popperjs/core": {
22 | "version": "2.11.8",
23 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
24 | "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
25 | "peer": true,
26 | "funding": {
27 | "type": "opencollective",
28 | "url": "https://opencollective.com/popperjs"
29 | }
30 | },
31 | "node_modules/@remirror/core-constants": {
32 | "version": "2.0.2",
33 | "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz",
34 | "integrity": "sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==",
35 | "peer": true
36 | },
37 | "node_modules/@tiptap/core": {
38 | "version": "2.3.1",
39 | "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.3.1.tgz",
40 | "integrity": "sha512-ycpQlmczAOc05TgB5sc3RUTEEBXAVmS8MR9PqQzg96qidaRfVkgE+2w4k7t83PMHl2duC0MGqOCy96pLYwSpeg==",
41 | "peer": true,
42 | "funding": {
43 | "type": "github",
44 | "url": "https://github.com/sponsors/ueberdosis"
45 | },
46 | "peerDependencies": {
47 | "@tiptap/pm": "^2.0.0"
48 | }
49 | },
50 | "node_modules/@tiptap/extension-bubble-menu": {
51 | "version": "2.3.1",
52 | "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.3.1.tgz",
53 | "integrity": "sha512-6PGrk65f0eXHcCEe6A2/GpooMsD6RPZY1kWSSWUNfklJO54R/8uAtsSVIBr7wQ34pvrYkNaluRUrDWUokWyBOQ==",
54 | "peer": true,
55 | "dependencies": {
56 | "tippy.js": "^6.3.7"
57 | },
58 | "funding": {
59 | "type": "github",
60 | "url": "https://github.com/sponsors/ueberdosis"
61 | },
62 | "peerDependencies": {
63 | "@tiptap/core": "^2.0.0",
64 | "@tiptap/pm": "^2.0.0"
65 | }
66 | },
67 | "node_modules/@tiptap/extension-floating-menu": {
68 | "version": "2.3.1",
69 | "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.3.1.tgz",
70 | "integrity": "sha512-3+dONthHRMFzJjLF9JtRbm9u4XJs8txCoChsZjwD0wBf8XfPtUGZQn9W5xNJG+5pozrOQhj9KC1UZL4tuvSRkg==",
71 | "peer": true,
72 | "dependencies": {
73 | "tippy.js": "^6.3.7"
74 | },
75 | "funding": {
76 | "type": "github",
77 | "url": "https://github.com/sponsors/ueberdosis"
78 | },
79 | "peerDependencies": {
80 | "@tiptap/core": "^2.0.0",
81 | "@tiptap/pm": "^2.0.0"
82 | }
83 | },
84 | "node_modules/@tiptap/extension-image": {
85 | "version": "2.3.1",
86 | "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.3.1.tgz",
87 | "integrity": "sha512-3RhVBySQA2LbftWhtZ0p2Mqf9lihNAYs3uQ3iyaB+BYViQiHyVpui09Wny0BwNy0oV6ryUWjBifko2Z1AZgANw==",
88 | "peer": true,
89 | "funding": {
90 | "type": "github",
91 | "url": "https://github.com/sponsors/ueberdosis"
92 | },
93 | "peerDependencies": {
94 | "@tiptap/core": "^2.0.0"
95 | }
96 | },
97 | "node_modules/@tiptap/pm": {
98 | "version": "2.3.1",
99 | "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.3.1.tgz",
100 | "integrity": "sha512-jdd1PFAFeewcu1rWsiqoCc04u5NCplHVjsGPN4jxUmqKdU0YN/9sp7h8gRG6YN1GZRoC1Y6KD+WPLMdzkwizZQ==",
101 | "peer": true,
102 | "dependencies": {
103 | "prosemirror-changeset": "^2.2.1",
104 | "prosemirror-collab": "^1.3.1",
105 | "prosemirror-commands": "^1.5.2",
106 | "prosemirror-dropcursor": "^1.8.1",
107 | "prosemirror-gapcursor": "^1.3.2",
108 | "prosemirror-history": "^1.3.2",
109 | "prosemirror-inputrules": "^1.3.0",
110 | "prosemirror-keymap": "^1.2.2",
111 | "prosemirror-markdown": "^1.12.0",
112 | "prosemirror-menu": "^1.2.4",
113 | "prosemirror-model": "^1.19.4",
114 | "prosemirror-schema-basic": "^1.2.2",
115 | "prosemirror-schema-list": "^1.3.0",
116 | "prosemirror-state": "^1.4.3",
117 | "prosemirror-tables": "^1.3.5",
118 | "prosemirror-trailing-node": "^2.0.7",
119 | "prosemirror-transform": "^1.8.0",
120 | "prosemirror-view": "^1.32.7"
121 | },
122 | "funding": {
123 | "type": "github",
124 | "url": "https://github.com/sponsors/ueberdosis"
125 | }
126 | },
127 | "node_modules/@tiptap/react": {
128 | "version": "2.3.1",
129 | "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.3.1.tgz",
130 | "integrity": "sha512-MM6UOi5nmdM/dZXYtbBYHJEsVtyyFFnOCXlXmhTlhz0WYI8VkEAY7XWLB96KrqsbRk9PUWwdev7iT1q40zxVeg==",
131 | "peer": true,
132 | "dependencies": {
133 | "@tiptap/extension-bubble-menu": "^2.3.1",
134 | "@tiptap/extension-floating-menu": "^2.3.1"
135 | },
136 | "funding": {
137 | "type": "github",
138 | "url": "https://github.com/sponsors/ueberdosis"
139 | },
140 | "peerDependencies": {
141 | "@tiptap/core": "^2.0.0",
142 | "@tiptap/pm": "^2.0.0",
143 | "react": "^17.0.0 || ^18.0.0",
144 | "react-dom": "^17.0.0 || ^18.0.0"
145 | }
146 | },
147 | "node_modules/@types/prop-types": {
148 | "version": "15.7.12",
149 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
150 | "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
151 | },
152 | "node_modules/@types/react": {
153 | "version": "18.3.3",
154 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
155 | "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
156 | "dependencies": {
157 | "@types/prop-types": "*",
158 | "csstype": "^3.0.2"
159 | }
160 | },
161 | "node_modules/argparse": {
162 | "version": "2.0.1",
163 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
164 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
165 | "peer": true
166 | },
167 | "node_modules/crelt": {
168 | "version": "1.0.6",
169 | "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
170 | "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
171 | "peer": true
172 | },
173 | "node_modules/csstype": {
174 | "version": "3.1.3",
175 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
176 | "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
177 | },
178 | "node_modules/entities": {
179 | "version": "4.5.0",
180 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
181 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
182 | "peer": true,
183 | "engines": {
184 | "node": ">=0.12"
185 | },
186 | "funding": {
187 | "url": "https://github.com/fb55/entities?sponsor=1"
188 | }
189 | },
190 | "node_modules/escape-string-regexp": {
191 | "version": "4.0.0",
192 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
193 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
194 | "peer": true,
195 | "engines": {
196 | "node": ">=10"
197 | },
198 | "funding": {
199 | "url": "https://github.com/sponsors/sindresorhus"
200 | }
201 | },
202 | "node_modules/js-tokens": {
203 | "version": "4.0.0",
204 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
205 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
206 | "peer": true
207 | },
208 | "node_modules/linkify-it": {
209 | "version": "5.0.0",
210 | "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
211 | "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
212 | "peer": true,
213 | "dependencies": {
214 | "uc.micro": "^2.0.0"
215 | }
216 | },
217 | "node_modules/loose-envify": {
218 | "version": "1.4.0",
219 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
220 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
221 | "peer": true,
222 | "dependencies": {
223 | "js-tokens": "^3.0.0 || ^4.0.0"
224 | },
225 | "bin": {
226 | "loose-envify": "cli.js"
227 | }
228 | },
229 | "node_modules/markdown-it": {
230 | "version": "14.1.0",
231 | "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
232 | "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
233 | "peer": true,
234 | "dependencies": {
235 | "argparse": "^2.0.1",
236 | "entities": "^4.4.0",
237 | "linkify-it": "^5.0.0",
238 | "mdurl": "^2.0.0",
239 | "punycode.js": "^2.3.1",
240 | "uc.micro": "^2.1.0"
241 | },
242 | "bin": {
243 | "markdown-it": "bin/markdown-it.mjs"
244 | }
245 | },
246 | "node_modules/mdurl": {
247 | "version": "2.0.0",
248 | "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
249 | "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
250 | "peer": true
251 | },
252 | "node_modules/orderedmap": {
253 | "version": "2.1.1",
254 | "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
255 | "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
256 | "peer": true
257 | },
258 | "node_modules/prosemirror-changeset": {
259 | "version": "2.2.1",
260 | "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
261 | "integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
262 | "peer": true,
263 | "dependencies": {
264 | "prosemirror-transform": "^1.0.0"
265 | }
266 | },
267 | "node_modules/prosemirror-collab": {
268 | "version": "1.3.1",
269 | "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
270 | "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
271 | "peer": true,
272 | "dependencies": {
273 | "prosemirror-state": "^1.0.0"
274 | }
275 | },
276 | "node_modules/prosemirror-commands": {
277 | "version": "1.5.2",
278 | "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz",
279 | "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==",
280 | "peer": true,
281 | "dependencies": {
282 | "prosemirror-model": "^1.0.0",
283 | "prosemirror-state": "^1.0.0",
284 | "prosemirror-transform": "^1.0.0"
285 | }
286 | },
287 | "node_modules/prosemirror-dropcursor": {
288 | "version": "1.8.1",
289 | "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
290 | "integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
291 | "peer": true,
292 | "dependencies": {
293 | "prosemirror-state": "^1.0.0",
294 | "prosemirror-transform": "^1.1.0",
295 | "prosemirror-view": "^1.1.0"
296 | }
297 | },
298 | "node_modules/prosemirror-gapcursor": {
299 | "version": "1.3.2",
300 | "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz",
301 | "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==",
302 | "peer": true,
303 | "dependencies": {
304 | "prosemirror-keymap": "^1.0.0",
305 | "prosemirror-model": "^1.0.0",
306 | "prosemirror-state": "^1.0.0",
307 | "prosemirror-view": "^1.0.0"
308 | }
309 | },
310 | "node_modules/prosemirror-history": {
311 | "version": "1.4.0",
312 | "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.0.tgz",
313 | "integrity": "sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==",
314 | "peer": true,
315 | "dependencies": {
316 | "prosemirror-state": "^1.2.2",
317 | "prosemirror-transform": "^1.0.0",
318 | "prosemirror-view": "^1.31.0",
319 | "rope-sequence": "^1.3.0"
320 | }
321 | },
322 | "node_modules/prosemirror-inputrules": {
323 | "version": "1.4.0",
324 | "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz",
325 | "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==",
326 | "peer": true,
327 | "dependencies": {
328 | "prosemirror-state": "^1.0.0",
329 | "prosemirror-transform": "^1.0.0"
330 | }
331 | },
332 | "node_modules/prosemirror-keymap": {
333 | "version": "1.2.2",
334 | "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz",
335 | "integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==",
336 | "peer": true,
337 | "dependencies": {
338 | "prosemirror-state": "^1.0.0",
339 | "w3c-keyname": "^2.2.0"
340 | }
341 | },
342 | "node_modules/prosemirror-markdown": {
343 | "version": "1.12.0",
344 | "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.12.0.tgz",
345 | "integrity": "sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==",
346 | "peer": true,
347 | "dependencies": {
348 | "markdown-it": "^14.0.0",
349 | "prosemirror-model": "^1.0.0"
350 | }
351 | },
352 | "node_modules/prosemirror-menu": {
353 | "version": "1.2.4",
354 | "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz",
355 | "integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==",
356 | "peer": true,
357 | "dependencies": {
358 | "crelt": "^1.0.0",
359 | "prosemirror-commands": "^1.0.0",
360 | "prosemirror-history": "^1.0.0",
361 | "prosemirror-state": "^1.0.0"
362 | }
363 | },
364 | "node_modules/prosemirror-model": {
365 | "version": "1.20.0",
366 | "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.20.0.tgz",
367 | "integrity": "sha512-q7AY7vMjKYqDCeoedgUiAgrLabliXxndJuuFmcmc2+YU1SblvnOiG2WEACF2lwAZsMlfLpiAilA3L+TWlDqIsQ==",
368 | "peer": true,
369 | "dependencies": {
370 | "orderedmap": "^2.0.0"
371 | }
372 | },
373 | "node_modules/prosemirror-schema-basic": {
374 | "version": "1.2.2",
375 | "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz",
376 | "integrity": "sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==",
377 | "peer": true,
378 | "dependencies": {
379 | "prosemirror-model": "^1.19.0"
380 | }
381 | },
382 | "node_modules/prosemirror-schema-list": {
383 | "version": "1.3.0",
384 | "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz",
385 | "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==",
386 | "peer": true,
387 | "dependencies": {
388 | "prosemirror-model": "^1.0.0",
389 | "prosemirror-state": "^1.0.0",
390 | "prosemirror-transform": "^1.7.3"
391 | }
392 | },
393 | "node_modules/prosemirror-state": {
394 | "version": "1.4.3",
395 | "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz",
396 | "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==",
397 | "peer": true,
398 | "dependencies": {
399 | "prosemirror-model": "^1.0.0",
400 | "prosemirror-transform": "^1.0.0",
401 | "prosemirror-view": "^1.27.0"
402 | }
403 | },
404 | "node_modules/prosemirror-tables": {
405 | "version": "1.3.7",
406 | "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz",
407 | "integrity": "sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==",
408 | "peer": true,
409 | "dependencies": {
410 | "prosemirror-keymap": "^1.1.2",
411 | "prosemirror-model": "^1.8.1",
412 | "prosemirror-state": "^1.3.1",
413 | "prosemirror-transform": "^1.2.1",
414 | "prosemirror-view": "^1.13.3"
415 | }
416 | },
417 | "node_modules/prosemirror-trailing-node": {
418 | "version": "2.0.8",
419 | "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz",
420 | "integrity": "sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==",
421 | "peer": true,
422 | "dependencies": {
423 | "@remirror/core-constants": "^2.0.2",
424 | "escape-string-regexp": "^4.0.0"
425 | },
426 | "peerDependencies": {
427 | "prosemirror-model": "^1.19.0",
428 | "prosemirror-state": "^1.4.2",
429 | "prosemirror-view": "^1.31.2"
430 | }
431 | },
432 | "node_modules/prosemirror-transform": {
433 | "version": "1.8.0",
434 | "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.8.0.tgz",
435 | "integrity": "sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A==",
436 | "peer": true,
437 | "dependencies": {
438 | "prosemirror-model": "^1.0.0"
439 | }
440 | },
441 | "node_modules/prosemirror-view": {
442 | "version": "1.33.6",
443 | "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.6.tgz",
444 | "integrity": "sha512-zRLUNgLIQfd8IfGprsXxWTjdA8xEAFJe8cDNrOptj6Mop9sj+BMeVbJvceyAYCm5G2dOdT2prctH7K9dfnpIMw==",
445 | "peer": true,
446 | "dependencies": {
447 | "prosemirror-model": "^1.20.0",
448 | "prosemirror-state": "^1.0.0",
449 | "prosemirror-transform": "^1.1.0"
450 | }
451 | },
452 | "node_modules/punycode.js": {
453 | "version": "2.3.1",
454 | "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
455 | "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
456 | "peer": true,
457 | "engines": {
458 | "node": ">=6"
459 | }
460 | },
461 | "node_modules/react": {
462 | "version": "18.3.1",
463 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
464 | "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
465 | "peer": true,
466 | "dependencies": {
467 | "loose-envify": "^1.1.0"
468 | },
469 | "engines": {
470 | "node": ">=0.10.0"
471 | }
472 | },
473 | "node_modules/react-dom": {
474 | "version": "18.3.1",
475 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
476 | "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
477 | "peer": true,
478 | "dependencies": {
479 | "loose-envify": "^1.1.0",
480 | "scheduler": "^0.23.2"
481 | },
482 | "peerDependencies": {
483 | "react": "^18.3.1"
484 | }
485 | },
486 | "node_modules/rope-sequence": {
487 | "version": "1.3.4",
488 | "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
489 | "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
490 | "peer": true
491 | },
492 | "node_modules/scheduler": {
493 | "version": "0.23.2",
494 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
495 | "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
496 | "peer": true,
497 | "dependencies": {
498 | "loose-envify": "^1.1.0"
499 | }
500 | },
501 | "node_modules/tippy.js": {
502 | "version": "6.3.7",
503 | "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
504 | "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
505 | "peer": true,
506 | "dependencies": {
507 | "@popperjs/core": "^2.9.0"
508 | }
509 | },
510 | "node_modules/uc.micro": {
511 | "version": "2.1.0",
512 | "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
513 | "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
514 | "peer": true
515 | },
516 | "node_modules/w3c-keyname": {
517 | "version": "2.2.8",
518 | "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
519 | "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
520 | "peer": true
521 | }
522 | }
523 | }
524 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tiptap-imagresize",
3 | "description": "image extension + resize function for tiptap",
4 | "version": "1.1.0",
5 | "homepage": "https://github.com/breakerh/ ",
6 | "license": "MIT",
7 | "keywords": [
8 | "tiptap",
9 | "tiptap extension"
10 | ],
11 | "peerDependencies": {
12 | "@tiptap/core": "^2.0.0-beta.1",
13 | "@tiptap/extension-image": "^2.0.0-beta.27",
14 | "@tiptap/react": "^2.0.0-beta.109",
15 | "react": "^17.0.2 || ^18"
16 | },
17 | "main": "src/index.ts",
18 | "files": [
19 | "src"
20 | ],
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/breakerh/tiptap-image-resize"
24 | },
25 | "dependencies": {
26 | "@types/react": "^18.0.38"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/component/ImageResizeComponent.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/anchor-is-valid */
2 | import React from 'react'
3 | import { NodeViewWrapper } from '@tiptap/react'
4 |
5 | export default (props:any) => {
6 | const handler = (mouseDownEvent: React.MouseEvent) => {
7 | const parent = (mouseDownEvent.target as HTMLElement).closest('.image-resizer')
8 | const image = parent?.querySelector('img.postimage') ?? null
9 | if(image===null)
10 | return
11 | const startSize = { x: image.clientWidth, y: image.clientHeight }
12 | const startPosition = { x: mouseDownEvent.pageX, y: mouseDownEvent.pageY }
13 |
14 | function onMouseMove(mouseMoveEvent:MouseEvent) {
15 | props.updateAttributes({
16 | width: startSize.x - startPosition.x + mouseMoveEvent.pageX,
17 | height: startSize.y - startPosition.y + mouseMoveEvent.pageY
18 | })
19 | }
20 | function onMouseUp() {
21 | document.body.removeEventListener("mousemove", onMouseMove);
22 | }
23 |
24 | document.body.addEventListener("mousemove", onMouseMove);
25 | document.body.addEventListener("mouseup", onMouseUp, { once: true });
26 | };
27 | return (
28 |
29 | {props.extension.options.useFigure? (
30 |
31 |
32 |
33 | ) : ( )}
34 |
35 | {props.extension.options.resizeIcon}
36 |
37 |
38 | )
39 | }
--------------------------------------------------------------------------------
/src/image.tsx:
--------------------------------------------------------------------------------
1 | import React, {Component, FC, ReactElement} from "react";
2 | import {mergeAttributes, nodeInputRule, Node} from "@tiptap/core";
3 | import {ReactNodeViewRenderer} from "@tiptap/react";
4 | import ImageResizeComponent from "./component/ImageResizeComponent";
5 | import Image from '@tiptap/extension-image'
6 |
7 | export interface ImageOptions {
8 | inline: boolean,
9 | allowBase64: boolean,
10 | HTMLAttributes: Record,
11 | resizeIcon: FC|Component|ReactElement,
12 | useFigure: boolean
13 | }
14 | declare module '@tiptap/core' {
15 | interface Commands {
16 | imageResize: {
17 | setImage: (options: { src: string, alt?: string, title?: string, width?: string|number, height?: string|number, isDraggable?: boolean }) => ReturnType,
18 | }
19 | }
20 | }
21 | export const inputRegex = /(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/
22 | export const ImageResize = Image.extend({
23 | name: "imageResize",
24 | addOptions() {
25 | return {
26 | inline: false,
27 | allowBase64: false,
28 | HTMLAttributes: {},
29 | resizeIcon: <>⊙>,
30 | useFigure: false
31 | }
32 | },
33 | addAttributes() {
34 | return {
35 | ...this.parent?.(),
36 | width: {
37 | default: '100%',
38 | renderHTML: (attributes) => {
39 | return {
40 | width: attributes.width
41 | };
42 | }
43 | },
44 | height: {
45 | default: 'auto',
46 | renderHTML: (attributes) => {
47 | return {
48 | height: attributes.height
49 | };
50 | }
51 | },
52 | };
53 | },
54 |
55 | addNodeView() {
56 | return ReactNodeViewRenderer(ImageResizeComponent)
57 | },
58 | addInputRules() {
59 | return [
60 | nodeInputRule({
61 | find: inputRegex,
62 | type: this.type,
63 | getAttributes: match => {
64 | const [,, alt, src, title, height, width, isDraggable] = match
65 | return { src, alt, title, height, width, isDraggable }
66 | },
67 | }),
68 | ]
69 | },
70 | })
71 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { ImageResize } from './image'
2 |
3 | export * from './image'
4 |
5 | export default ImageResize
6 |
--------------------------------------------------------------------------------
/tiptap-imagresize.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------