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

[Question] Could it be used with Tiptap (prosemirror based editor)? #4

Open
devgeni opened this issue Nov 3, 2021 · 8 comments
Open

Comments

@devgeni
Copy link

devgeni commented Nov 3, 2021

Hey!
This plugin looks nice and I would like to use it with Tiptap editor.
There is a page on how to use prosemirror plugins with Tiptap. But I can't figure out how should I set up your plugin in a similar way.
Could you please help me out with this? Thanks!

@rowanc1
Copy link
Member

rowanc1 commented Nov 3, 2021

It should be possible to use with tiptap, I would love to document this for other people as well with your help!

This shouldn't be an extension to the editor in the tip-tap sense, so much as an export using the editor.state which is the prosemirror EditorState (doc, schema are all in there) when you press a button or something.

You need access to the EditorState

const state = editor.state;

// Need some way to pass the buffer into the word serializer (e.g. base64 conversion)
const opts = {
  getImageBuffer(src: string) {
    return anImageBuffer;
  },
};

const wordDocument = defaultDocxSerializer.serialize(state.doc, opts);

I think that should be it?

You could also console.log the schema.nodes and marks, which you will need if you are doing anything non-standard or named differently than the standard prosemirror world. I think the errors should guide you there.

You can extend that:

import { DocxSerializer, defaultNodes, defaultMarks } from 'prosemirror-docx';

const nodeSerializer = {
  ...defaultNodes,
  my_paragraph(state, node) {
    state.renderInline(node);
    state.closeBlock(node);
  },
};

export const myDocxSerializer = new DocxSerializer(nodeSerializer, defaultMarks);

Where you have your paragraph etc. as custom nodes, these would need to match what ever customizations that you do in tiptap.


Let me know if that gives some hints on approach -- excited to document this in the readme, and would love your help with that!

@devgeni
Copy link
Author

devgeni commented Nov 4, 2021

OK, thanks! I'll try my best!

@devgeni
Copy link
Author

devgeni commented Nov 4, 2021

@rowanc1
OK, so I managed that to work. The only problem I have is with:

const opts = {
  getImageBuffer(src: string) {
    return anImageBuffer;
  },
};

Can't render image. I think that getImageBuffer should return Promise<Buffer> instead of just Buffer. I can't think of any synchronous operation that would get buffer data from image source.
Would be great if I could do something like that:

const opts = {
  async getImageBuffer(src: string) {
    const imgBuffer = await fetchImageBuffer(src);
    return imgBuffer;
  }
}

Other than that, awesome work! 👍

@rowanc1
Copy link
Member

rowanc1 commented Nov 4, 2021

Do you think you would be willing to write a paragraph in the readme under a heading like Integrating with TipTap showing a quick description and a code snippet? If it is easier to post it in this issue that would be fine to! :)

Agree on the promise -- I went that way because docx doesn't support promises in the doc creation. I think that we can abstract over it though. Opened issue #5.

@devgeni
Copy link
Author

devgeni commented Nov 4, 2021

I just followed your instructions. 🙂
Something like that:

import { Editor } from "@tiptap/react";
import { writeDocx, DocxSerializer, defaultNodes, defaultMarks } from 'prosemirror-docx';

// tiptap has these camelCased
const nodeSerializer = {
  ...defaultNodes,
  hardBreak: defaultNodes.hard_break,
  codeBlock: defaultNodes.code_block,
  orderedList: defaultNodes.ordered_list,
  listItem: defaultNodes.list_item,
  bulletList: defaultNodes.bullet_list,
  horizontalRule: defaultNodes.horizontal_rule,
  image(state, node) {
    // no image
    state.renderInline(node);
    state.closeBlock(node);
  }
};

const myDocxSerializer = new DocxSerializer(nodeSerializer, defaultMarks);

// somewhere in the app
const editor = new Editor({
  // options
});

export const ButtonExportDOCX = (props) => {
  return (
    <button onClick={async () => {
      const opts = {
        getImageBuffer(src: string) {
          return Buffer.from("real buffer here");
        },
      };

      const wordDocument = myDocxSerializer.serialize(editor.state.doc, opts);
      await writeDocx(wordDocument, (buffer) => {
        // use buffer
      });
    }}>
      export to docx
    </button>
  )
}

@xiangshu233
Copy link

How can I export custom nodes in tiptap? I have encapsulated some of them and inserted them into vueNodeView components.
image
The DOM structure I get through editor.getHTML() is returned as is in the custom Vue component. I think the <question-item> tag may not be recognized when using the export tool.

My English is very poor so I can only use Google Translate to express my meaning, please forgive me

@xiangshu233
Copy link

@devgeni Hello, I would like to ask how to use the custom node export

@Nlarou
Copy link

Nlarou commented May 16, 2024

image
@xiangshu233 I'm using TipTap with the mentions extension. In my case for a custom node like mention you can do like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants