This commit is contained in:
Philipp Kühn
2021-06-01 17:44:42 +02:00
6 changed files with 211 additions and 31 deletions

View File

@@ -0,0 +1,104 @@
import {
Command,
Node,
nodeInputRule,
} from '@tiptap/core'
export interface FigureOptions {
HTMLAttributes: Record<string, any>,
}
declare module '@tiptap/core' {
interface Commands {
figure: {
/**
* Add a figure element
*/
setFigure: (options: { src: string, alt?: string, title?: string }) => Command,
}
}
}
export const inputRegex = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/
export const Figure = Node.create<FigureOptions>({
name: 'figure',
defaultOptions: {
// inline: false,
HTMLAttributes: {},
},
group: 'block',
content: 'inline*',
draggable: true,
addAttributes() {
return {
src: {
default: null,
parseHTML: element => {
return {
src: element.querySelector('img')?.getAttribute('src'),
}
},
},
alt: {
default: null,
parseHTML: element => {
return {
alt: element.querySelector('img')?.getAttribute('alt'),
}
},
},
title: {
default: null,
parseHTML: element => {
return {
title: element.querySelector('img')?.getAttribute('title'),
}
},
},
}
},
parseHTML() {
return [
{
tag: 'figure',
contentELement: 'figcaption',
},
]
},
renderHTML({ HTMLAttributes }) {
return [
'figure', this.options.HTMLAttributes,
['img', HTMLAttributes],
['figcaption', 0],
]
},
addCommands() {
return {
setFigure: options => ({ commands }) => {
return commands.insertContent({
type: this.name,
attrs: options,
})
},
}
},
addInputRules() {
return [
nodeInputRule(inputRegex, this.type, match => {
const [, alt, src, title] = match
return { src, alt, title }
}),
]
},
})

View File

@@ -0,0 +1,81 @@
<template>
<div v-if="editor">
<editor-content :editor="editor" />
<h2>HTML</h2>
{{ editor.getHTML() }}
</div>
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-2'
import StarterKit from '@tiptap/starter-kit'
import { Figure } from './figure'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
StarterKit,
Figure,
],
content: `
<p>Figure + Figcaption</p>
<figure>
<img src="https://source.unsplash.com/8xznAGy4HcY/800x400" alt="Random photo of something" title="Whos dat?">
<figcaption>
<p>Amazing caption</p>
</figcaption>
</figure>
<p>Thats it.</p>
`,
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss" scoped>
::v-deep {
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
figure {
max-width: 25rem;
border: 3px solid #0D0D0D;
border-radius: 0.5rem;
margin: 1rem 0;
padding: 0.5rem;
}
figcaption {
margin-top: 0.25rem;
text-align: center;
padding: 0.5rem;
border: 2px dashed #0D0D0D20;
border-radius: 0.5rem;
}
img {
max-width: 100%;
height: auto;
border-radius: 0.5rem;
}
}
}
</style>

View File

@@ -11,3 +11,4 @@ Congratulations! Youve found our playground with a list of experiments. Be aw
* [@tiptap/extension-collaboration-annotation](/experiments/collaboration-annotation) * [@tiptap/extension-collaboration-annotation](/experiments/collaboration-annotation)
* [@tiptap/extension-word-break](/experiments/word-break) * [@tiptap/extension-word-break](/experiments/word-break)
* [@tiptap/extension-trailing-node](/experiments/trailing-node) * [@tiptap/extension-trailing-node](/experiments/trailing-node)
* [@tiptap/extension-figure](/experiments/figure)

View File

@@ -0,0 +1,17 @@
# Figure
⚠️ Experiment
## Known issues
* Dragging should move the image, but duplicates it
## Tasks
* Add the caption as an optional parameter to the command
* Build commands to wrap an image into a figure + figcaption?
* Build commands to unrwap figure + figcaption to an image?
## Related links
* https://github.com/ueberdosis/tiptap/issues/573#issuecomment-730122427
* https://discuss.prosemirror.net/t/figure-and-editable-caption/462/5
<demo name="Experiments/Figure" />

View File

@@ -1,8 +1,8 @@
--- # Introduction
title: Headless WYSIWYG Text Editor
---
# tiptap a headless text editor ## toc
## Whats tiptap?
[![Version](https://img.shields.io/npm/v/@tiptap/core.svg?label=version)](https://www.npmjs.com/package/@tiptap/core) [![Version](https://img.shields.io/npm/v/@tiptap/core.svg?label=version)](https://www.npmjs.com/package/@tiptap/core)
[![Downloads](https://img.shields.io/npm/dm/@tiptap/core.svg)](https://npmcharts.com/compare/@tiptap/core?minimal=true) [![Downloads](https://img.shields.io/npm/dm/@tiptap/core.svg)](https://npmcharts.com/compare/@tiptap/core?minimal=true)
[![License](https://img.shields.io/npm/l/@tiptap/core.svg)](https://www.npmjs.com/package/@tiptap/core) [![License](https://img.shields.io/npm/l/@tiptap/core.svg)](https://www.npmjs.com/package/@tiptap/core)
@@ -12,31 +12,6 @@ tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) a
Create exactly the rich text editor you want out of customizable building blocks. tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. Its backed by a welcoming community, open source, and free. Create exactly the rich text editor you want out of customizable building blocks. tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. Its backed by a welcoming community, open source, and free.
## Example ## What does “headless” mean?
<demo name="Examples/CollaborativeEditing" hide-source inline /> There is no provided user interface, you are absolutely free to build whatever interface you want. No need to overwrite any class, to use `!important` or other hacks, just write whatever you like in the setup you are used to.
## Features
**Headless.** We dont tell you what a menu should look like or where it should be rendered in the DOM. Thats why tiptap is headless and comes without any CSS. You are in full control over markup, styling and behaviour.
**Framework-agnostic.** No matter what framework you use, youll enjoy tiptap. Out of the box, it works with Vanilla JavaScript and Vue.js, but its also possible to use it in [React](/installation/react), Svelte and others.
**TypeScript.** tiptap is written in TypeScript. That helps us to find bugs early and gives you a nice autocomplete for the API (if your IDE supports that) on top of the extensive human written documentation.
**Collaborative.** Real-time collaboration, syncing between different devices and working offline used to be hard. We provide everything you need to keep everything in sync, conflict-free with the power of [Y.js](https://github.com/yjs/yjs). Our production-grade setup requires less than 20 lines of code.
**Community.** Over the years, a lovely community has grown around tiptap. Theres so much content shared, so many people helping out in issues and a ton of community extensions, youll be surprised how much that can help.
## Who uses tiptap?
- [GitLab](https://gitlab.com)
- [Statamic CMS](https://statamic.com)
- [Twill CMS](https://twill.io)
- [ApostropheCMS](https://apostrophecms.com)
- [Directus CMS](https://directus.io)
- [Nextcloud](https://apps.nextcloud.com/apps/text)
- [DocIQ](https://www.dociq.io)
- [ycode](https://www.ycode.com/)
- [Scrumpy](https://www.scrumpy.io)
- … and [many more](https://github.com/ueberdosis/tiptap/network/dependents?package_id=UGFja2FnZS0xMzE5OTg0ODc%3D)
## License
tiptap is licensed under [MIT](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md), so youre free to do whatever you want. If youre using it in production, do the right thing and [become one of our wonderful sponsors](/sponsor) to fund the development, maintenance and support of tiptap and the whole ecosystem.

View File

@@ -10,6 +10,8 @@
- title: Overview - title: Overview
items: items:
- title: Introduction
link: /introduction
- title: Installation - title: Installation
link: /installation link: /installation
items: items: