diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 0aa3a92..be2bc1f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -16,5 +16,6 @@ module.exports = { rules: { "vue/multi-word-component-names": 0, "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/no-explicit-any": "off", }, }; diff --git a/packages/editor/package.json b/packages/editor/package.json index 6df445d..4a8897c 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -83,6 +83,7 @@ "@tiptap/extension-underline": "2.0.0-beta.202", "@tiptap/suggestion": "2.0.0-beta.202", "@tiptap/vue-3": "2.0.0-beta.202", + "@vueuse/core": "^9.6.0", "floating-vue": "2.0.0-beta.20", "katex": "^0.16.3", "lowlight": "^2.7.0", diff --git a/packages/editor/src/components/Editor.vue b/packages/editor/src/components/Editor.vue index 43b5bfc..e22ed9a 100644 --- a/packages/editor/src/components/Editor.vue +++ b/packages/editor/src/components/Editor.vue @@ -34,7 +34,7 @@ defineProps({
diff --git a/packages/editor/src/extensions/code-block/CodeBlockViewRenderer.vue b/packages/editor/src/extensions/code-block/CodeBlockViewRenderer.vue index ad36351..eaa47ca 100644 --- a/packages/editor/src/extensions/code-block/CodeBlockViewRenderer.vue +++ b/packages/editor/src/extensions/code-block/CodeBlockViewRenderer.vue @@ -1,9 +1,20 @@ + + diff --git a/packages/editor/src/extensions/image/index.ts b/packages/editor/src/extensions/image/index.ts new file mode 100644 index 0000000..145dc70 --- /dev/null +++ b/packages/editor/src/extensions/image/index.ts @@ -0,0 +1,59 @@ +import TiptapImage from "@tiptap/extension-image"; +import { VueNodeViewRenderer } from "@tiptap/vue-3"; +import ImageView from "./ImageView.vue"; + +const Image = TiptapImage.extend({ + inline() { + return true; + }, + + group() { + return "inline"; + }, + + addAttributes() { + return { + ...this.parent?.(), + width: { + default: null, + parseHTML: (element) => { + const width = + element.style.width || element.getAttribute("width") || null; + return width == null ? null : parseInt(width, 10); + }, + renderHTML: (attributes) => { + return { + width: attributes.width, + }; + }, + }, + height: { + default: null, + parseHTML: (element) => { + const height = + element.style.height || element.getAttribute("height") || null; + return height == null ? null : parseInt(height, 10); + }, + renderHTML: (attributes) => { + return { + height: attributes.height, + }; + }, + }, + }; + }, + + addNodeView() { + return VueNodeViewRenderer(ImageView); + }, + + parseHTML() { + return [ + { + tag: "img[src]", + }, + ]; + }, +}); + +export default Image; diff --git a/packages/editor/src/extensions/index.ts b/packages/editor/src/extensions/index.ts index 4ce515f..01afe0f 100644 --- a/packages/editor/src/extensions/index.ts +++ b/packages/editor/src/extensions/index.ts @@ -16,7 +16,7 @@ import ExtensionOrderedList from "@tiptap/extension-ordered-list"; import ExtensionParagraph from "@tiptap/extension-paragraph"; import ExtensionStrike from "@tiptap/extension-strike"; import ExtensionText from "@tiptap/extension-text"; -import ExtensionImage from "@tiptap/extension-image"; +import ExtensionImage from "./image"; import ExtensionTaskList from "@tiptap/extension-task-list"; import ExtensionTaskItem from "@tiptap/extension-task-item"; import ExtensionLink from "@tiptap/extension-link"; @@ -55,12 +55,7 @@ const allExtensions = [ ExtensionParagraph, ExtensionStrike, ExtensionText, - ExtensionImage.configure({ - inline: true, - HTMLAttributes: { - loading: "lazy", - }, - }), + ExtensionImage, ExtensionTaskList, ExtensionTaskItem, ExtensionLink.configure({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e57010..7cb1974 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,6 +105,7 @@ importers: '@tiptap/vue-3': 2.0.0-beta.202 '@types/katex': ^0.14.0 '@vue/compiler-sfc': ^3.2.45 + '@vueuse/core': ^9.6.0 autoprefixer: ^10.4.13 floating-vue: 2.0.0-beta.20 katex: ^0.16.3 @@ -152,6 +153,7 @@ importers: '@tiptap/extension-underline': 2.0.0-beta.202_fosglmwb3u6jhi6bbjmnlbdsbu '@tiptap/suggestion': 2.0.0-beta.202_fosglmwb3u6jhi6bbjmnlbdsbu '@tiptap/vue-3': 2.0.0-beta.202_fosglmwb3u6jhi6bbjmnlbdsbu + '@vueuse/core': 9.6.0 floating-vue: 2.0.0-beta.20 katex: 0.16.3 lowlight: 2.7.0 @@ -1309,6 +1311,10 @@ packages: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: false + /@types/web-bluetooth/0.0.16: + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + dev: false + /@typescript-eslint/eslint-plugin/5.33.0_4ef6l6rno4vditvp6wd3bmzmmy: resolution: {integrity: sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1686,6 +1692,31 @@ packages: '@types/node': 18.11.9 dev: true + /@vueuse/core/9.6.0: + resolution: {integrity: sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==} + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.6.0 + '@vueuse/shared': 9.6.0 + vue-demi: 0.13.6 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/metadata/9.6.0: + resolution: {integrity: sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==} + dev: false + + /@vueuse/shared/9.6.0: + resolution: {integrity: sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==} + dependencies: + vue-demi: 0.13.6 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + /abab/2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true @@ -6011,6 +6042,19 @@ packages: acorn-walk: 8.2.0 dev: true + /vue-demi/0.13.6: + resolution: {integrity: sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dev: false + /vue-demi/0.13.6_vue@3.2.45: resolution: {integrity: sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==} engines: {node: '>=12'}