From 87611d812ae1974e993b18a7930a886219480711 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Tue, 1 Jun 2021 16:58:50 +0200 Subject: [PATCH] experiments: add a figure + figcaption node --- docs/src/demos/Experiments/Figure/figure.ts | 104 ++++++++++++++++++++ docs/src/demos/Experiments/Figure/index.vue | 81 +++++++++++++++ docs/src/docPages/experiments.md | 1 + docs/src/docPages/experiments/figure.md | 17 ++++ 4 files changed, 203 insertions(+) create mode 100644 docs/src/demos/Experiments/Figure/figure.ts create mode 100644 docs/src/demos/Experiments/Figure/index.vue create mode 100644 docs/src/docPages/experiments/figure.md diff --git a/docs/src/demos/Experiments/Figure/figure.ts b/docs/src/demos/Experiments/Figure/figure.ts new file mode 100644 index 00000000..9da3107e --- /dev/null +++ b/docs/src/demos/Experiments/Figure/figure.ts @@ -0,0 +1,104 @@ +import { + Command, + Node, + nodeInputRule, +} from '@tiptap/core' + +export interface FigureOptions { + HTMLAttributes: Record, +} + +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({ + 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 } + }), + ] + }, +}) diff --git a/docs/src/demos/Experiments/Figure/index.vue b/docs/src/demos/Experiments/Figure/index.vue new file mode 100644 index 00000000..6e593e84 --- /dev/null +++ b/docs/src/demos/Experiments/Figure/index.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md index 41e29d5d..c86656de 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -11,3 +11,4 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw * [@tiptap/extension-collaboration-annotation](/experiments/collaboration-annotation) * [@tiptap/extension-word-break](/experiments/word-break) * [@tiptap/extension-trailing-node](/experiments/trailing-node) +* [@tiptap/extension-figure](/experiments/figure) diff --git a/docs/src/docPages/experiments/figure.md b/docs/src/docPages/experiments/figure.md new file mode 100644 index 00000000..db2790d0 --- /dev/null +++ b/docs/src/docPages/experiments/figure.md @@ -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 + +