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

Textalign doesnt work as expected #1877

Closed
rezaffm opened this issue Sep 10, 2021 · 9 comments
Closed

Textalign doesnt work as expected #1877

rezaffm opened this issue Sep 10, 2021 · 9 comments
Labels
Type: Bug The issue or pullrequest is related to a bug

Comments

@rezaffm
Copy link

rezaffm commented Sep 10, 2021

Description

Working on Vue 2.

I have a Custom Paragraph, like:

  const CustomParagraph = Paragraph.extend({
    addAttributes() {
        return {
          ...this.parent?.(),
          class: {
            default: null
          },
          style: {
            default: null
          }
      }
    }
  })

I initially noticed that when I don't add the style attribute Tiptap (Prosemirror) will throw away my text alignment on initial render.

Now, the text alignment stays after rendering, but it is not possible anymore to change the alignment. I noticed while debugging that while the text-alignment changes, it doesn't do anything in the editor.

Also, it is possible to change to center, right and justify but not back to left.

The same is true for Headings and Images.

Steps to reproduce the bug
Steps to reproduce the behavior:

  1. Take a Paragraph and align it center
  2. Reload Editor/Page
  3. It is not possible to change alignment anymore

If you come back to the text, the node looks like:

<p style="text-align: center; "><strong>Test</strong></p>

If you then try to align, e.g. to the right, it becomes:

<p style="text-align: right; text-align: center; "><strong>Test</strong></p>

Expected behavior
Quite obvious, after a text alignment is set, should be possible after re-rendering the text to change/adjust it.

@rezaffm rezaffm added Type: Bug The issue or pullrequest is related to a bug v2 labels Sep 10, 2021
@philippkuehn
Copy link
Contributor

Please provide a codesandbox.

@rezaffm
Copy link
Author

rezaffm commented Sep 10, 2021

Hi Philipp, not very experienced with codesandboxes to be honest.

As described in my report, first I had to add the 'style' attribute to the Custom Paragraph to make it work (expected), but then for some reason when i try to change the alignment, a new css style is added.

It works perfect initially, only after reloading (re-rendering the editor) it doesnt work anymore.

@philippkuehn
Copy link
Contributor

Do you use the TextAlign extension?

@rezaffm
Copy link
Author

rezaffm commented Sep 10, 2021

Yes, basically thats what I do:

  import Vue from 'vue'
  import store from '@/admin/store'
  import { mapGetters } from 'vuex'
  import { Editor, EditorContent, BubbleMenu, FloatingMenu } from '@tiptap/vue-2'
  import MenuBar from '@/admin/editor/MenuBar'

  // Starterkit extensions
  import Blockquote from '@tiptap/extension-blockquote'
  import Bold from '@tiptap/extension-bold'
  import BulletList from '@tiptap/extension-bullet-list'
  import Code from '@tiptap/extension-code'
  import CodeBlock from '@tiptap/extension-code-block'
  import Document from '@tiptap/extension-document'
  import Dropcursor from '@tiptap/extension-dropcursor'
  import Gapcursor from '@tiptap/extension-gapcursor'
  import HardBreak from '@tiptap/extension-hard-break'
  import Heading from '@tiptap/extension-heading'
  import Highlight from '@tiptap/extension-highlight'
  import History from '@tiptap/extension-history'
  import HorizontalRule from '@tiptap/extension-horizontal-rule'
  import Italic from '@tiptap/extension-italic'
  import ListItem from '@tiptap/extension-list-item'
  import OrderedList from '@tiptap/extension-ordered-list'
  import Paragraph from '@tiptap/extension-paragraph'
  import Strike from '@tiptap/extension-strike'
  import Text from '@tiptap/extension-text'
  import TextAlign from '@tiptap/extension-text-align'
  import Link from '@tiptap/extension-link'

.... and some more extensions

Then my CustomParagraph (to have classes):

  const CustomParagraph = Paragraph.extend({
    addAttributes() {
        return {
          ...this.parent?.(),
          class: {
            default: null
          }
      }
    }
  })

and in the MenuBar I call:

          {
            icon: 'align-left',
            title: 'Align Left',
            action: () => this.editor.chain().focus().setTextAlign('left').run(),
          },
          {
            icon: 'align-center',
            title: 'Align Center',
            action: () => this.editor.chain().focus().setTextAlign('center').run(),
          },
          {
            icon: 'align-right',
            title: 'Align Right',
            action: () => this.editor.chain().focus().setTextAlign('right').run(),
          },
          {
            icon: 'align-justify',
            title: 'Align Justify',
            action: () => this.editor.chain().focus().setTextAlign('justify').run(),
          },

On initial load it works great, only when I reload the text the style attributes are gone (that's why I then added the style attribute, but that is apparently not the solution).

For some reason the editor doesnt want to render the "textAlign" attribute.

@rezaffm
Copy link
Author

rezaffm commented Sep 10, 2021

Well, I set up a sandbox for you, it show's the same bug:

https://codesandbox.io/s/tiptap-issue-template-forked-0rwv3?file=/src/components/Tiptap.vue

The result is actually interesting, because I can see on the website that with vue 3 seems to be fine?

https://www.tiptap.dev/api/extensions/text-align/

@rezaffm
Copy link
Author

rezaffm commented Sep 10, 2021

I kept debugging the parseHTML and renderHTMl functions and I noticed, that while the parseHTML function delivers the correct value, e.g. 'left', 'center', 'right' or 'justify (or 'left' in case there is nothing), the renderHTML function always delivered:

{ textAlign: 'left', class: null }

So I came to the point where I thought there must something with the value returned by the parseHTML function.

So I copied the TextAlign Extension created a new one "CustomTextAlign.js" and this seems to work:

import { Extension } from '@tiptap/core';

const TextAlign = Extension.create({
  name: 'textAlign',
  defaultOptions: {
    types: [],
    alignments: ['left', 'center', 'right', 'justify'],
    defaultAlignment: 'left',
  },
  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          textAlign: {
            default: this.options.defaultAlignment,
            //parseHTML: element => element.style.textAlign || this.options.defaultAlignment,
            parseHTML: element => {
              return {
                textAlign: element.style.textAlign || this.options.defaultAlignment,
              };
            },
            renderHTML: attributes => {
              if (attributes.textAlign === this.options.defaultAlignment) {
                return {};
              }
              return { style: `text-align: ${attributes.textAlign}` };
            },
          },
        },
      },
    ];
  },
  addCommands() {
    return {
      setTextAlign: (alignment) => ({ commands }) => {
        if (!this.options.alignments.includes(alignment)) {
          return false;
        }
        return this.options.types.every(type => commands.updateAttributes(type, { textAlign: alignment }));
      },
      unsetTextAlign: () => ({ commands }) => {
        return this.options.types.every(type => commands.resetAttributes(type, 'textAlign'));
      },
    };
  },
  addKeyboardShortcuts() {
    return {
      'Mod-Shift-l': () => this.editor.commands.setTextAlign('left'),
      'Mod-Shift-e': () => this.editor.commands.setTextAlign('center'),
      'Mod-Shift-r': () => this.editor.commands.setTextAlign('right'),
      'Mod-Shift-j': () => this.editor.commands.setTextAlign('justify'),
    };
  },
});

export { TextAlign, TextAlign as default };
//# sourceMappingURL=tiptap-extension-text-align.esm.js.map

To make long story short, instead of returning a String, we return an object:

        attributes: {
          textAlign: {
            default: this.options.defaultAlignment,
            //parseHTML: element => element.style.textAlign || this.options.defaultAlignment,
            parseHTML: element => {
              return {
                textAlign: element.style.textAlign || this.options.defaultAlignment,
              };
            },
            ...
        },

It now it works as expected (not tested, of course).

So, if you think that's a solution - please explain why it works Philipp. ;-)

@philippkuehn
Copy link
Contributor

Hey, the solution is simple: just update all of your tiptap dependencies to the latest versions. Because of this change. Update and everything should work fine :)

@rezaffm
Copy link
Author

rezaffm commented Sep 10, 2021

Oh no, so simple...! But still, I found a solution, not too bad?

@philippkuehn
Copy link
Contributor

philippkuehn commented Sep 10, 2021

Haha yeah, you found the old syntax :D

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

No branches or pull requests

2 participants