Skip to content

Instantly share code, notes, and snippets.

@gregveres
Created May 3, 2022 23:26
Show Gist options
  • Save gregveres/973e8d545ab40dc375b47ebc63f92846 to your computer and use it in GitHub Desktop.
Save gregveres/973e8d545ab40dc375b47ebc63f92846 to your computer and use it in GitHub Desktop.
background-color for tiptap 2
import { Extension } from "@tiptap/core";
import "@tiptap/extension-text-style";
export type ColorOptions = {
types: string[];
};
declare module "@tiptap/core" {
interface Commands<ReturnType> {
backColor: {
/**
* Set the text color
*/
setBackColor: (color: string) => ReturnType;
/**
* Unset the text color
*/
unsetBackColor: () => ReturnType;
};
}
}
export const BackColor = Extension.create<ColorOptions>({
name: "backColor",
addOptions() {
return {
types: ["textStyle"],
};
},
addGlobalAttributes() {
return [
{
types: this.options.types,
attributes: {
backgroundColor: {
default: null,
parseHTML: (element) =>
element.style.backgroundColor.replace(/['"]+/g, ""),
renderHTML: (attributes) => {
if (!attributes.backgroundColor) {
return {};
}
return {
style: `background-color: ${attributes.backgroundColor}`,
};
},
},
},
},
];
},
addCommands() {
return {
setBackColor:
(color) =>
({ chain }) => {
return chain().setMark("textStyle", { backgroundColor: color }).run();
},
unsetBackColor:
() =>
({ chain }) => {
return chain()
.setMark("textStyle", { backgroundColor: null })
.removeEmptyTextStyle()
.run();
},
};
},
});
@gregveres
Copy link
Author

I can not. I am still on Vue 2 and Vuetify. What UI toolkit are you using? Have you got the tiptap editor showing and editing text yet?

@Muhammetmyrat
Copy link

Yes. Can you in vue 2 or nuxt becouse I do not understant and I can not use this?

@gregveres
Copy link
Author

When setting up the editor, you first have to install this extension like this:

import { BackColor } from "./Extensions/back-color";

    const editor = ref<Editor>(
      new Editor({
        content: content.value,
        extensions: [
          ...
          BackColor,
        ],
        onUpdate: () => {
          emit("input", editor.value.getHTML());
        },
      })

I have a button that I put on the toolbar that is implemented like this:

TextColorButton.vue

<script lang="ts">
import { defineComponent, ref, PropType } from 'vue';
import { Editor } from '@tiptap/vue-2';
import EditorMenuButton from './EditorMenuButton.vue';
import ColorPopover from '../utilities/ColorPopover.vue';

export default defineComponent({
  name: 'TextColorButton',
  components: { EditorMenuButton, ColorPopover },
  props: {
    editor: {
      type: Object as PropType<Editor>,
      required: true
    },
    background: {
      type: Boolean,
      default: false
    },
    tooltip: {
      type: String,
      required: false
    }
  },
  setup(props) {
    const selected = ref(props.editor.getAttributes('textStyle').color);
    const popoverVisible = ref(false);

    const confirmColor = (color: string | undefined): void => {
      popoverVisible.value = false;
      if (color) {
        const newColor = color[0] === '#' ? color : `#${color}`;
        if (props.background) {
          props.editor.chain().focus().setBackColor(newColor).run();
        } else {
          props.editor.chain().focus().setColor(newColor).run();
        }
      } else {
        if (props.background) {
          props.editor.chain().focus().unsetBackColor().run();
        } else {
          props.editor.chain().focus().unsetColor().run();
        }
      }
    };
    const close = () => {
      popoverVisible.value = false;
    };
    return { selected, popoverVisible, confirmColor, close };
  }
});
</script>

<template>
  <v-menu :close-on-content-click="false" bottom offset-y v-model="popoverVisible">
    <template v-slot:activator="{ on, attrs }">
      <EditorMenuButton
        :icon="background ? '$fontBGColor' : '$fontColor'"
        v-bind="attrs"
        v-on="on"
        :tooltip="tooltip"
      />
    </template>
    <ColorPopover :color="selected" @close="close" @selected="confirmColor" />
  </v-menu>
</template>

And then in my toolbar I use the TextColorButton like this:

    <TextColorButton :editor="editor" tooltip="Set text foreground color" />
    <TextColorButton :editor="editor" tooltip="Set text background color" background />

@Muhammetmyrat
Copy link

Uncaught Error: There is no mark type named 'textStyle'. Maybe you forgot to add the extension?

@Muhammetmyrat
Copy link

Muhammetmyrat commented Sep 11, 2023

Thank you worked for me I do not import "@tiptap/extension-text-style";

@namlh023
Copy link

namlh023 commented Feb 2, 2024

Thanks, it's work. Save me a lot of time.

@xumengmvp
Copy link

amazing

@thienbd203
Copy link

thienbd203 commented Jul 31, 2024

This is the background color I implemented like color, hope it is useful :))

import { Extension } from '@tiptap/core'

export type BackgroundColorOptions = {
  /**
   * The types where the color can be applied
   * @default ['textStyle']
   * @example ['heading', 'paragraph']
   */
  types: string[]
}

declare module '@tiptap/core' {
  interface Commands<ReturnType> {
    backgroundColor: {
      /**
       * Set the background color
       */
      setBackgroundColor: (color: string) => ReturnType
      /**
       * Unset the background color
       */
      unsetBackgroundColor: () => ReturnType
    }
  }
}

export const BackgroundColor = Extension.create<BackgroundColorOptions>({
  name: 'backgroundColor',

  addOptions() {
    return {
      types: ['textStyle']
    }
  },

  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          backgroundColor: {
            default: null,
            parseHTML: (element) => element.style.backgroundColor?.replace(/['"]+/g, ''),
            renderHTML: (attributes) => {
              if (!attributes.backgroundColor) {
                return {}
              }

              return {
                style: `background-color: ${attributes.backgroundColor}`
              }
            }
          }
        }
      }
    ]
  },

  addCommands() {
    return {
      setBackgroundColor:
        (color) =>
        ({ chain }) => {
          return chain().setMark('textStyle', { backgroundColor: color }).run()
        },
      unsetBackgroundColor:
        () =>
        ({ chain }) => {
          return chain()
            .setMark('textStyle', { backgroundColor: null })
            .removeEmptyTextStyle()
            .run()
        }
    }
  }
})

@lushangkan
Copy link

This is the background color I implemented like color, hope it is useful :))

import { Extension } from '@tiptap/core'

export type BackgroundColorOptions = {
  /**
   * The types where the color can be applied
   * @default ['textStyle']
   * @example ['heading', 'paragraph']
   */
  types: string[]
}

declare module '@tiptap/core' {
  interface Commands<ReturnType> {
    backgroundColor: {
      /**
       * Set the background color
       */
      setBackgroundColor: (color: string) => ReturnType
      /**
       * Unset the background color
       */
      unsetBackgroundColor: () => ReturnType
    }
  }
}

export const BackgroundColor = Extension.create<BackgroundColorOptions>({
  name: 'backgroundColor',

  addOptions() {
    return {
      types: ['textStyle']
    }
  },

  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          backgroundColor: {
            default: null,
            parseHTML: (element) => element.style.backgroundColor?.replace(/['"]+/g, ''),
            renderHTML: (attributes) => {
              if (!attributes.backgroundColor) {
                return {}
              }

              return {
                style: `background-color: ${attributes.backgroundColor}`
              }
            }
          }
        }
      }
    ]
  },

  addCommands() {
    return {
      setBackgroundColor:
        (color) =>
        ({ chain }) => {
          return chain().setMark('textStyle', { backgroundColor: color }).run()
        },
      unsetBackgroundColor:
        () =>
        ({ chain }) => {
          return chain()
            .setMark('textStyle', { backgroundColor: null })
            .removeEmptyTextStyle()
            .run()
        }
    }
  }
})

Very good code! But be aware that need to import @tiptap/extension-text-style, otherwise you will get an error removeEmptyTextStyle not found!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment