Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Community Extensions #819

Open
2 of 6 tasks
hanspagel opened this issue Sep 1, 2020 · 67 comments
Open
2 of 6 tasks

Community Extensions #819

hanspagel opened this issue Sep 1, 2020 · 67 comments
Labels
Type: Feature The issue or pullrequest is a new feature

Comments

@hanspagel
Copy link
Contributor

hanspagel commented Sep 1, 2020

Hi everyone!

I’ve seen a ton of helpful Gists with custom extensions for Tiptap. It’s amazing what you all come up with! 🥰

Unfortunately, we don’t have the capabilities to maintain all of them in the core packages, but it’s sad to see those gems hidden in some Gists. What if you - the community - could easily provide those as separate npm packages?

Advantages of packages

  • New extensions can be added without a need for approval
  • Extensions can be updated and improved by everyone
  • You can come up with extensions we don’t even understand
  • There is more room for “experimental” extensions, that aren’t stable enough for the core package
  • We can have multiple flavors of extensions (e. g. an Image node including the Upload to S3 mechanic)

Proof of Concept

I built a tiny proof of concept for superscript and subscript, see here:
https://github.com/hanspagel/tiptap-extension-superscript
https://github.com/hanspagel/tiptap-extension-subscript

Usage:

$ yarn add tiptap-extension-superscript
import { Superscript } from 'tiptap-extension-superscript'

new Editor({
  extensions: [
    new Superscript(),
  ],
})

Examples of community Gists, code snippets, PRs and ideas

Tiptap v2

Tiptap v1

Not needed with Tiptap v2

Roadmap

I think we’d need to do a few things to make that easier for everyone:

  • Build a proof of concept
  • Ask for feedback
  • Figure out testing
  • Publish an extension boilerplate
  • Write a guide
  • Add a list of community extensions to the README

Your feedback

What do you all think? Would you be up to contribute a community extension?

Feel free to post links to Gists of others you’d love to see published as a package.

@hanspagel hanspagel added the Type: Feature The issue or pullrequest is a new feature label Sep 1, 2020
@hanspagel hanspagel pinned this issue Sep 1, 2020
@ramsane
Copy link

ramsane commented Sep 5, 2020

I would love to. I am working for a project that involves rich content editor. I am trying to bring each feature one by one. Till now, I was able to get inline math and block level math integrations without any errors. There were few minor issues. But I was able to correct them.

I am more than happy to share it. But I am not writing any unit tests. Is it okay ?

@ramsane

This comment has been minimized.

@andreasvirkus
Copy link

Increasing the collection with

export class CustomLink extends Link {
  get schema() {
    return {
      attrs: {
        href: {
          default: null,
        },
        'data-link-type': {
          default: 'link',
        },
        target: {
          default: null,
        },
        rel: {
          default: null,
        },
        class: {
          default: 'oct-a',
        },
      },
      inclusive: false,
      parseDOM: [
        {
          tag: 'a[href]',
          getAttrs: (dom) => {
            return {
              href: dom.getAttribute('href'),
              target: dom.getAttribute('target'),
              rel: dom.getAttribute('rel'),
              'data-link-type': dom.getAttribute('data-link-type'),
            }
          },
        },
      ],
      toDOM: (node) => {
        return [
          'a',
          {
            ...node.attrs,
            target: '__blank',
            class: 'content-link',
            rel: 'noopener noreferrer nofollow',
          },
          0,
        ]
      },
    }
  }

@hanspagel hanspagel mentioned this issue Oct 19, 2020
@andreasvirkus
Copy link

andreasvirkus commented Oct 28, 2020

Found a plugin that supports pasting images under #686 (comment) 👇

https://gist.github.com/slava-vishnyakov/16076dff1a77ddaca93c4bccd4ec4521
and/or: #508

@andreasvirkus
Copy link

andreasvirkus commented Nov 6, 2020

Leaving this here as a request: heading anchor links extension #662

@andreasvirkus
Copy link

Resizable image plugin: #740 (comment) (links to this gist)

@Aymkdn
Copy link

Aymkdn commented Mar 3, 2021

I created a gist with a TextColor extension file as well as an example with a .vue file to see how to use it: https://gist.github.com/Aymkdn/9f993c5cfe8476f718c4fd2fd7bda1f0

@jelleroorda
Copy link

I've ported the TrailingNode extension for TipTap 2: https://gist.github.com/jelleroorda/2a3085f45ef75b9fdd9f76a4444d6bd6

@hanspagel
Copy link
Contributor Author

Oh, thanks! Great work! I’ve added it as a (more or less hidden) experiment to the documentation. I think we’ll add this as an official extension:

https://www.tiptap.dev/experiments/trailing-node

@joevallender
Copy link
Contributor

One approach for resizable images for v2 #1283

Just doing my reading before trying to create an iframe video embed for v2...

@joevallender
Copy link
Contributor

I got video (as) working (as I need to for now) in my project :)

My use case is embedding YouTube, Vimeo or Loom video (the URLs of which have already been created/sanitised outside of tiptap). I pulled some example code out of my project and put it in my example

I'd hacked the helper class for the parent div

return ['div', {class: 'video-wrapper'}, ['iframe', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]]

Which would be better retrieved from the .configure({HTMLAttributes ... set when instantiating the editor and extensions - but you get the idea. Then set some 'classic' responsive iframe CSS yourself

I guess to make these draggable we'd need to add a handle since all clicks on the iframe belong to the iframe. How does tiptap handle dragging, is it explicitly the node itself, or can we set a handle element somehow? I'm happy with deleting/re-adding in my project tbh.

@jelleroorda
Copy link

Oh, thanks! Great work! I’ve added it as a (more or less hidden) experiment to the documentation. I think we’ll add this as an official extension:

https://www.tiptap.dev/experiments/trailing-node

I've updated the gist, by adding a TypeScript variant for trailing node as well.

@hanspagel I have also ported your Subscript extension and your Superscript extension for v2 with TypeScript. Thanks again for those 😄.

@andon94
Copy link

andon94 commented May 24, 2021

@jelleroorda Could you give me a couple of tips on how to implement this Subscript/Superscript extensions to an existing Vue project, where changing the file extensions to .ts is not an option?

@joevallender
Copy link
Contributor

@andon94 it should be almost exactly the same, it doesn't require TS. See a quick (untested) example here https://gist.github.com/joevallender/47e957298d7fbf4c41f5a1ba462d1d59

@martinstoeckli
Copy link

martinstoeckli commented Jul 26, 2022

@sereneinserenade Thanks for the tip, I'm aware of this method, but I have the requirement that it must work on a disabled editor, when the editor cannot get the focus. For some reason after calling setContent() with large documents, the page is not always on the top.

@puopg
Copy link

puopg commented Aug 10, 2022

Super tiny, simple file paste handler extension:

import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "prosemirror-state";

const extensionName = "pasteFileHandler";

export type PasteFileHandlerOptions = {
  onFilePasted: (file: File) => boolean;
};

const handleFilePaste = (event: ClipboardEvent, onPasteEvent?: (file: File) => void): void => {
  const { items } = event.clipboardData || event.originalEvent.clipboardData;

  const keys = Object.keys(items);

  keys.some((key) => {
    const item = items[key];

    if (item.kind === "file") {
      const file = item.getAsFile();

      if (onPasteEvent) {
        onPasteEvent(file);
      }

      return true;
    }

    return false;
  });
};

const PasteFileHandler = Extension.create<PasteFileHandlerOptions>({
  name: extensionName,

  addOptions() {
    return {
      onFilePasted: () => false,
    };
  },

  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: new PluginKey(extensionName),
        props: {
          handlePaste: (view, event) => {
            return handleFilePaste(event, this.options.onFilePasted);
          },
        },
      }),
    ];
  },
});

export default PasteFileHandler;

@fantasticit
Copy link

image

I've made an open source project called think, which relies on tiptap to develop a lot of extensions, maybe it can help you.

https://github.com/fantasticit/think/tree/main/packages/client/src/tiptap/core/extensions

@tabdon
Copy link

tabdon commented Aug 23, 2022 via email

@lzxlzxlzxl
Copy link

Has anybody done table expansion? For example, table border color

@chenyuncai
Copy link

Track Changes like Microsoft Office Word. I have implemented this feature, but the code is just in my project. I will publish one day. mark it

@tslater
Copy link

tslater commented Sep 30, 2022

image

I've made an open source project called think, which relies on tiptap to develop a lot of extensions, maybe it can help you.

https://github.com/fantasticit/think/tree/main/packages/client/src/tiptap/core/extensions

Very cool. What does the app (think) do?

@hansmei
Copy link

hansmei commented Oct 11, 2022

Track Changes like Microsoft Office Word. I have implemented this feature, but the code is just in my project. I will publish one day. mark it

@chenyuncai
I'm looking for this functionality these days. Please do share:)

@SalahAdDin
Copy link

image

I've made an open-source project called to think, which relies on tiptap to develop a lot of extensions, maybe it can help you.

https://github.com/fantasticit/think/tree/main/packages/client/src/tiptap/core/extensions

Man, you have very interesting tools, but your documentation is in Chinese :').

@fantasticit
Copy link

image I've made an open-source project called to think, which relies on tiptap to develop a lot of extensions, maybe it can help you. https://github.com/fantasticit/think/tree/main/packages/client/src/tiptap/core/extensions

Man, you have very interesting tools, but your documentation is in Chinese :').

google translate may help. ^_^

@SalahAdDin
Copy link

image I've made an open-source project called to think, which relies on tiptap to develop a lot of extensions, maybe it can help you. https://github.com/fantasticit/think/tree/main/packages/client/src/tiptap/core/extensions

Man, you have very interesting tools, but your documentation is in Chinese :').

google translate may help. ^_^

I think it is not enough hahahahah

@rfgamaral
Copy link
Contributor

Hey folks, I've been meaning to post this there, but I always end up forgetting about it 😅

This is not an extension per se, but we open-source our Typist editor built on top of Tiptap. It includes a few custom/extended extensions with new and improved features, and it also comes with support for Markdown input/output.

@chenyuncai
Copy link

Track Changes like Microsoft Office Word. I have implemented this feature, but the code is just in my project. I will publish one day. mark it

@chenyuncai I'm looking for this functionality these days. Please do share:)

code here

https://github.com/chenyuncai/tiptap-track-change-extension

@antoniormrzz
Copy link

Is there a way to limit html size? I read the other thread as well, but I think the custom extensions were for tiptap 1.
It's easy to abuse char limit otherwise. What's stoping a user from bolding and italicizing every other char in a 500 long text?

@radans
Copy link

radans commented Jun 7, 2023

Hello everyone, I created two extensions for tiptap, here they are. Hope that it will help out someone

https://www.npmjs.com/package/@rcode-link/tiptap-drawio
https://www.npmjs.com/package/@rcode-link/tiptap-comments

@linspw
Copy link

linspw commented Jun 19, 2023

@chenyuncai Your idea looks amazing, can you share?
Case with, the link seems to be broken

@chenyuncai
Copy link

chenyuncai commented Jun 30, 2023

@chenyuncai Your idea looks amazing, can you share? Case with, the link seems to be broken

yes, take a look here https://github.com/chenyuncai/tiptap-track-change-extension

@sjdemartini
Copy link
Contributor

I've released a package called mui-tiptap https://github.com/sjdemartini/mui-tiptap, which adds built-in styling using Material UI, and includes a suite of additional components and extensions. I've been using this code in a production app successfully for months and have incorporated several things that I think add value beyond vanilla Tiptap. For instance:

  • ResizableImage extension for interactively resizing images within the editor with a drag handle
  • TableImproved extension (which resolves some reported Tiptap Table extension issues related to column-resizing, when used in conjunction with the mui-tiptap styles)
  • HeadingWithAnchor extension for dynamic GitHub-like clickable anchor links for every heading that's added (allowing users to share links and jump to specific headings within your rendered editor content)
  • LinkBubbleMenu component so adding and editing links is easy (with a Slack-like link-editing UI)
  • TableBubbleMenu for interactively editing rich text tables (add or delete columns or rows, merge cells, etc.)
  • General-purpose ControlledBubbleMenu for building your own custom menus, solving some shortcomings of the Tiptap BubbleMenu
  • Composable/extendable menu buttons and controls for the standard Tiptap extensions
  • Built-in styles for Tiptap's extensions (text formatting, lists, tables, Google Docs-like collaboration cursors, etc), including support for light and dark mode

Here's a quick demo of some of the UI/functionality (check out the README for a CodeSandbox link and more details):
mui-tiptap demo

The package is still fairly new—I plan to add more functionality soon—but I figured folks here may be interested. I welcome feedback and/or contributions!

@carlosvaldesweb
Copy link

Hello, I want to share an extension I created for uploading images with a loading placeholder. I have based it on the ProseMirror example at "https://prosemirror.net/examples/upload/". I hope you can add it and find it useful.

I'm a backend developer, and this is my first npm package. I hope everything is alright configured.

https://github.com/carlosvaldesweb/tiptap-extension-upload-image

Grabacion.de.pantalla.2023-08-25.a.la.s.20.54.49.mov

@HMarzban
Copy link

HMarzban commented Nov 1, 2023

New Extensions: Hyperlink & HyperMultimedia 🚀

Hello TipTappers!

We're excited to introduce two new extensions to enhance your Tiptap editing experience: @docs.plus/extension-hyperlink and @docs.plus/extension-hypermultimedia.

Hyperlink Extension 🎩🪄

Inspired by Tiptap's extension-link, our hyperlink extension adds a touch of Google Docs magic, streamlining hyperlinking with customizable protocols, auto-linking, and interactive dialog boxes for a user-friendly touch.

NPM | Github | Demo

HyperMultimedia Extension 🎥🎶

Enhance Tiptap with our HyperMultimedia extension, facilitating the embedding of Image, YouTube, Vimeo, SoundCloud, and Twitter posts directly within the editor. Each media type comes with a snazzy modal—use ours or craft your own!

NPM | Github | Demo

We value your feedback. Share your thoughts to help us refine these extensions! 💫💬

Hyperlink Demo | HyperMultimedia Demo

hypermultimedia-github.mp4

hyperlink-demo (g)

@peihk2
Copy link

peihk2 commented Nov 10, 2023

Hi, has anyone ever written a hashtag extension (like on Facebook) or a similar extension? I need such an extension but don't know how to customize it

@puopg
Copy link

puopg commented Nov 11, 2023

Hi, has anyone ever written a hashtag extension (like on Facebook) or a similar extension? I need such an extension but don't know how to customize it

You can likely extend the mention plugin. The idea is pretty similar right? You trigger with the #, display a set of suggestions, each hashtag is colored in some way with a class.

@victorfunes
Copy link

Hi, I needed to support div tags in the html editor, and I kind of get a solution. It is not perfect, but at least it allows you to add div to your code using editor.chain().insertContent().

I hope it will help to other people, and if you can help me to improve this extensiion would be great.

DivExtension.ts:

import { getNodeContent } from "./extensionUtils";

export interface DivOptions {
  HTMLAttributes: Record<string, any>;
}

export interface DivStyleAttributes {
  class?: string;
  style?: string;
}

// declare module "@tiptap/core" {
//   interface Commands<ReturnType> {
//     div: {
//       /**
//        * Set the div
//        */
//       setDiv: (options?: DivStyleAttributes) => ReturnType;
//     };
//   }
// }

export const Div = Node.create<DivOptions>({
  name: "div",
  group: "block",
  atom: true,
  draggable: true,
  content: "block*",
  selectable: true,
  isolating: false,
  allowGapCursor: true,
  defining: true,

  addAttributes() {
    return {
      class: {
        default: this.options.HTMLAttributes.class,
      },
      style: {
        default: this.options.HTMLAttributes.style,
      },
    };
  },

  parseHTML: () => {
    return [
      {
        tag: "div",
      },
    ];
  },

  renderHTML({ node, HTMLAttributes }) {
    const content = getNodeContent(node);
    return ["div", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), ...content];
  },

  parseDOM: [{ tag: "div" }],

  toDOM: () => ["div", 0],

  // addCommands: () => {
  //   return {
  //     setDiv:
  //       (options) =>
  //       ({ tr, dispatch, editor }) => {
  //         const divNode = editor.schema.nodes.div.createChecked(options, null);
  //         if (dispatch) {
  //           const offset = tr.selection.anchor + 1;

  //           tr.replaceSelectionWith(divNode)
  //             .scrollIntoView()
  //             .setSelection(TextSelection.near(tr.doc.resolve(offset)));
  //         }
  //         return true;
  //       },
  //   };
  // },

  addOptions: () => {
    return {
      HTMLAttributes: {},
    };
  },
});

extensionUtils.ts:

import { DOMOutputSpec, Fragment, Node } from "@tiptap/pm/model";

export const getNodeContent = (node: Node | Fragment) => {
  const childNodes: DOMOutputSpec[] = [];
  for (let i = 0; i < node.childCount; i++) {
    const currentChild = node.child(i);
    if (currentChild.type.spec.toDOM) {
      const nodeDOMOutputSpec = currentChild.type.spec.toDOM(currentChild);
      const htmlTag = (nodeDOMOutputSpec as any)[0] as string;
      const content = getNodeContent(currentChild.content);
      childNodes.push([htmlTag, currentChild.attrs, ...content]);
    } else {
      if (currentChild.text) {
        childNodes.push(currentChild.text);
      }
    }
  }
  return childNodes;
};

@victorfunes
Copy link

I am also trying to support icons in the editor, and it seems easy, but for any reason it is not rendering the svg even when it is inserted in the html. Somebody could help me to guess why?

SvgExtension.ts:

import { mergeAttributes, Node } from "@tiptap/core";
import { getNodeContent } from "./extensionUtils";

export interface SvgOptions {
  HTMLAttributes: Record<string, any>;
}

export interface SvgAttributes {
  class?: string;
  style?: string;
  fill?: string;
  height?: string;
  stroke?: string;
  "stroke-width"?: string;
  version?: string;
  viewBox?: string;
  width?: string;
  xmlns?: string;
  "aria-hidden"?: string;
}

export const Svg = Node.create<SvgOptions>({
  name: "svg",
  group: "block",
  // atom: false,
  draggable: true,
  content: "path*",
  selectable: true,
  // isolating: true,
  // allowGapCursor: true,
  // defining: true,

  addAttributes() {
    return {
      class: {
        default: null,
        renderHTML: (attributes) => {
          return attributes.class
            ? {
                style: attributes.class,
              }
            : undefined;
        },
      },
      style: {
        default: this.options.HTMLAttributes.style,
      },
      fill: {
        default: this.options.HTMLAttributes.fill,
      },
      height: {
        default: this.options.HTMLAttributes.height,
      },
      stroke: {
        default: this.options.HTMLAttributes.stroke,
      },
      "stroke-width": {
        default: this.options.HTMLAttributes["stroke-width"],
      },
      "aria-hidden": {
        default: this.options.HTMLAttributes["aria-hidden"],
      },
      version: {
        default: this.options.HTMLAttributes.version,
      },
      viewBox: {
        default: this.options.HTMLAttributes.viewBox,
      },
      width: {
        default: this.options.HTMLAttributes.width,
      },
      xmlns: {
        default: this.options.HTMLAttributes.xmlns,
      },
    };
  },

  parseHTML: () => {
    return [
      {
        tag: "svg",
      },
    ];
  },

  renderHTML({ node, HTMLAttributes }) {
    const content = getNodeContent(node);
    return ["svg", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), ...content];
  },

  parseDOM: [{ tag: "svg" }],

  toDOM: () => ["svg", 0],

  addOptions: () => {
    return {
      HTMLAttributes: {},
    };
  },
});

PathExtension.ts:

import { mergeAttributes, Node } from "@tiptap/core";

export interface PathOptions {
  HTMLAttributes: Record<string, any>;
}

export interface PathAttributes {
  d?: string;
  "stroke-linecap"?: string;
  "stroke-linejoin"?: string;
}

export const Path = Node.create<PathOptions>({
  name: "path",
  group: "path",
  draggable: false,
  selectable: false,

  addAttributes() {
    return {
      d: {
        default: this.options.HTMLAttributes.d,
      },
      "stroke-linecap": {
        default: this.options.HTMLAttributes["stroke-linecap"],
      },
      "stroke-linejoin": {
        default: this.options.HTMLAttributes["stroke-linejoin"],
      },
    };
  },

  parseHTML: () => {
    return [
      {
        tag: "path",
      },
    ];
  },

  renderHTML({ HTMLAttributes }) {
    return ["path", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
  },

  parseDOM: [{ tag: "path" }],

  toDOM: () => ["path", 0],

  addOptions: () => {
    return {
      HTMLAttributes: {},
    };
  },
});

I insert this icon in the editor, but for any reason it is not being displayed. If I add this in a plane html file, it works... Can somebody help me? Thank you!

<svg class="h-6 w-6 m-0.5 rounded-sm text-red-700 dark:text-red-700 dark:bg-gray-200" style="color:rgb(185,28,28);height:1.5rem;width:1.5rem;margin:0.125rem;border-radius:0.125rem" fill="currentColor" height="1em" stroke="currentColor" stroke-width="0" version="1.1" viewbox="0 0 16 16" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M13.156 9.211c-0.213-0.21-0.686-0.321-1.406-0.331-0.487-0.005-1.073 0.038-1.69 0.124-0.276-0.159-0.561-0.333-0.784-0.542-0.601-0.561-1.103-1.34-1.415-2.197 0.020-0.080 0.038-0.15 0.054-0.222 0 0 0.339-1.923 0.249-2.573-0.012-0.089-0.020-0.115-0.044-0.184l-0.029-0.076c-0.092-0.212-0.273-0.437-0.556-0.425l-0.171-0.005c-0.316 0-0.573 0.161-0.64 0.403-0.205 0.757 0.007 1.889 0.39 3.355l-0.098 0.239c-0.275 0.67-0.619 1.345-0.923 1.94l-0.040 0.077c-0.32 0.626-0.61 1.157-0.873 1.607l-0.271 0.144c-0.020 0.010-0.485 0.257-0.594 0.323-0.926 0.553-1.539 1.18-1.641 1.678-0.032 0.159-0.008 0.362 0.156 0.456l0.263 0.132c0.114 0.057 0.234 0.086 0.357 0.086 0.659 0 1.425-0.821 2.48-2.662 1.218-0.396 2.604-0.726 3.819-0.908 0.926 0.521 2.065 0.883 2.783 0.883 0.128 0 0.238-0.012 0.327-0.036 0.138-0.037 0.254-0.115 0.325-0.222 0.139-0.21 0.168-0.499 0.13-0.795-0.011-0.088-0.081-0.196-0.157-0.271zM3.307 12.72c0.12-0.329 0.596-0.979 1.3-1.556 0.044-0.036 0.153-0.138 0.253-0.233-0.736 1.174-1.229 1.642-1.553 1.788zM7.476 3.12c0.212 0 0.333 0.534 0.343 1.035s-0.107 0.853-0.252 1.113c-0.12-0.385-0.179-0.992-0.179-1.389 0 0-0.009-0.759 0.088-0.759v0zM6.232 9.961c0.148-0.264 0.301-0.543 0.458-0.839 0.383-0.724 0.624-1.29 0.804-1.755 0.358 0.651 0.804 1.205 1.328 1.649 0.065 0.055 0.135 0.111 0.207 0.166-1.066 0.211-1.987 0.467-2.798 0.779v0zM12.952 9.901c-0.065 0.041-0.251 0.064-0.37 0.064-0.386 0-0.864-0.176-1.533-0.464 0.257-0.019 0.493-0.029 0.705-0.029 0.387 0 0.502-0.002 0.88 0.095s0.383 0.293 0.318 0.333v0z"></path><path d="M14.341 3.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-7.75c-0.689 0-1.25 0.561-1.25 1.25v13.5c0 0.689 0.561 1.25 1.25 1.25h11.5c0.689 0 1.25-0.561 1.25-1.25v-9.75c0-0.224-0.068-0.615-0.659-1.421v0zM12.271 2.729c0.48 0.48 0.856 0.912 1.134 1.271h-2.406v-2.405c0.359 0.278 0.792 0.654 1.271 1.134v0zM14 14.75c0 0.136-0.114 0.25-0.25 0.25h-11.5c-0.135 0-0.25-0.114-0.25-0.25v-13.5c0-0.135 0.115-0.25 0.25-0.25 0 0 7.749-0 7.75 0v3.5c0 0.276 0.224 0.5 0.5 0.5h3.5v9.75z">
</path>
</svg>

@NiclasDev63
Copy link

NiclasDev63 commented Mar 26, 2024

Even though I am still quite new to tiptap/prosemirror, I have managed to develope a working drag handle based on the drag handle from https://github.com/steven-tey/novel. However, unlike with the drag handle in novel, it is possible to drag single list items or whole lists through the editor as expected. Furthermore, it is also possible to select several nodes of different types and drag them as well. I look forward to your feedback and any suggestions for improvement.
I have uploaded the drag handle as an extension to npm and of course opensourced it on github.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature The issue or pullrequest is a new feature
Projects
None yet
Development

No branches or pull requests