add basic image extension
This commit is contained in:
45
docs/src/demos/Extensions/Image/index.vue
Normal file
45
docs/src/demos/Extensions/Image/index.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="editor">
|
||||||
|
<editor-content :editor="editor" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Editor } from '@tiptap/core'
|
||||||
|
import { EditorContent } from '@tiptap/vue'
|
||||||
|
import Document from '@tiptap/extension-document'
|
||||||
|
import Paragraph from '@tiptap/extension-paragraph'
|
||||||
|
import Text from '@tiptap/extension-text'
|
||||||
|
import Image from '@tiptap/extension-image'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EditorContent,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
extensions: [
|
||||||
|
Document(),
|
||||||
|
Paragraph(),
|
||||||
|
Text(),
|
||||||
|
Image(),
|
||||||
|
],
|
||||||
|
content: `
|
||||||
|
<p>This is basic example of implementing images. Try to drop new images here. Reordering also works.</p>
|
||||||
|
<img src="https://66.media.tumblr.com/dcd3d24b79d78a3ee0f9192246e727f1/tumblr_o00xgqMhPM1qak053o1_400.gif" />
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
16
docs/src/docPages/api/extensions/image.md
Normal file
16
docs/src/docPages/api/extensions/image.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Image
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```bash
|
||||||
|
# With npm
|
||||||
|
npm install @tiptap/extension-image
|
||||||
|
|
||||||
|
# Or: With Yarn
|
||||||
|
yarn add @tiptap/extension-image
|
||||||
|
```
|
||||||
|
|
||||||
|
## Source code
|
||||||
|
[packages/extension-image/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-image/)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
<demo name="Extensions/Image" highlight="12,30" />
|
||||||
@@ -132,6 +132,9 @@
|
|||||||
link: /api/extensions/history
|
link: /api/extensions/history
|
||||||
- title: HorizontalRule
|
- title: HorizontalRule
|
||||||
link: /api/extensions/horizontal-rule
|
link: /api/extensions/horizontal-rule
|
||||||
|
- title: Image
|
||||||
|
link: /api/extensions/image
|
||||||
|
draft: true
|
||||||
- title: Italic
|
- title: Italic
|
||||||
link: /api/extensions/italic
|
link: /api/extensions/italic
|
||||||
- title: Link
|
- title: Link
|
||||||
@@ -163,6 +166,7 @@
|
|||||||
link: /api/extensions/text
|
link: /api/extensions/text
|
||||||
- title: Text Align
|
- title: Text Align
|
||||||
link: /api/extensions/text-align
|
link: /api/extensions/text-align
|
||||||
|
draft: true
|
||||||
# - title: TodoItem
|
# - title: TodoItem
|
||||||
# link: /api/extensions/todo-item
|
# link: /api/extensions/todo-item
|
||||||
# draft: true
|
# draft: true
|
||||||
|
|||||||
125
packages/extension-image/index.ts
Normal file
125
packages/extension-image/index.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import { Command, createNode, nodeInputRule } from '@tiptap/core'
|
||||||
|
import { Plugin } from 'prosemirror-state'
|
||||||
|
|
||||||
|
const IMAGE_INPUT_REGEX = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/
|
||||||
|
|
||||||
|
const Image = createNode({
|
||||||
|
name: 'image',
|
||||||
|
|
||||||
|
inline: true,
|
||||||
|
|
||||||
|
group: 'inline',
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
src: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
alt: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: 'img[src]',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ attributes }) {
|
||||||
|
return ['img', attributes]
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
image: (attrs: any): Command => ({ tr }) => {
|
||||||
|
const { selection } = tr
|
||||||
|
console.log({ selection })
|
||||||
|
// const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos
|
||||||
|
const position = selection.$anchor ? selection.$anchor.pos : selection.$to.pos
|
||||||
|
const node = this.type.create(attrs)
|
||||||
|
tr.insert(position, node)
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
nodeInputRule(IMAGE_INPUT_REGEX, this.type, match => {
|
||||||
|
const [, alt, src, title] = match
|
||||||
|
return {
|
||||||
|
src,
|
||||||
|
alt,
|
||||||
|
title,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [
|
||||||
|
new Plugin({
|
||||||
|
props: {
|
||||||
|
handleDOMEvents: {
|
||||||
|
drop(view, event) {
|
||||||
|
const hasFiles = event.dataTransfer
|
||||||
|
&& event.dataTransfer.files
|
||||||
|
&& event.dataTransfer.files.length
|
||||||
|
|
||||||
|
if (!hasFiles) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const images = Array
|
||||||
|
// @ts-ignore
|
||||||
|
.from(event.dataTransfer.files)
|
||||||
|
.filter(file => (/image/i).test(file.type))
|
||||||
|
|
||||||
|
if (images.length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
const { schema } = view.state
|
||||||
|
const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY })
|
||||||
|
|
||||||
|
images.forEach(image => {
|
||||||
|
const reader = new FileReader()
|
||||||
|
|
||||||
|
reader.onload = readerEvent => {
|
||||||
|
const node = schema.nodes.image.create({
|
||||||
|
// @ts-ignore
|
||||||
|
src: readerEvent.target.result,
|
||||||
|
})
|
||||||
|
// @ts-ignore
|
||||||
|
const transaction = view.state.tr.insert(coordinates.pos, node)
|
||||||
|
view.dispatch(transaction)
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(image)
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Image
|
||||||
|
|
||||||
|
declare module '@tiptap/core/src/Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
Image: typeof Image,
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/extension-image/package.json
Normal file
17
packages/extension-image/package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "@tiptap/extension-image",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": "index.ts",
|
||||||
|
"main": "dist/tiptap-extension-image.js",
|
||||||
|
"umd:main": "dist/tiptap-extension-image.umd.js",
|
||||||
|
"module": "dist/tiptap-extension-image.mjs",
|
||||||
|
"unpkg": "dist/tiptap-extension-image.js",
|
||||||
|
"jsdelivr": "dist/tiptap-extension-image.js",
|
||||||
|
"files": [
|
||||||
|
"src",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/core": "2.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user