Files
OSIT-AE-App-Svelte/src/lib/element_tiptap_editor.svelte

425 lines
17 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { Color } from '@tiptap/extension-color'
import ListItem from '@tiptap/extension-list-item'
import TextStyle from '@tiptap/extension-text-style'
import StarterKit from "@tiptap/starter-kit";
import { Editor } from "@tiptap/core";
// import Highlight from '@tiptap/extension-highlight';
// import Highlight from '@tiptap/extension-highlight' ????
// import Typography from '@tiptap/extension-typography' ????
import "./element_tiptap_editor.scss";
// https://tiptap.dev/docs/examples/basics/default-text-editor
// https://tiptap.dev/docs/examples/basics/formatting
// <code class="language-css">
export let html_text: string = '';
export let default_minimal: boolean = false;
export let show_menu: boolean = true;
if (default_minimal) {
show_menu = false;
}
// export let html_text: string = `
// <h2>
// Hi there,
// </h2>
// <p>
// this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles youd probably expect from a text editor. But wait until you see the lists:
// </p>
// <ul>
// <li>
// Thats a bullet list with one …
// </li>
// <li>
// … or two list items.
// </li>
// </ul>
// <p>
// Isnt that great? And all of that is editable. But wait, theres more. Lets try a code block:
// </p>
// <pre><code class="language-css">body {
// display: none;
// }</code></pre>
// <p>
// I know, I know, this is impressive. Its only the tip of the iceberg though. Give it a try and click a little bit around. Dont forget to check the other examples too.
// </p>
// <blockquote>
// Wow, thats amazing. Good work, boy! 👏
// <br />
// — Mom
// </blockquote>
// `;
let element: HTMLDivElement;
let editor: any;
let show_button_kv_defaults: any = {
bold: true,
italic: true,
strike: true,
code: true,
paragraph: true,
heading__h1: true,
heading__h2: true,
heading__h3: true,
unsetAllMarks: true,
bulletList: true,
orderedList: true,
hardBreak: true,
undo: true,
redo: true,
};
export let show_button_kv: any;
if (show_button_kv) {
show_button_kv = { ...show_button_kv_defaults, ...show_button_kv };
} else {
show_button_kv = show_button_kv_defaults;
}
// export let new_json = editor?.getJSON();
export let new_html: string = '';
onMount(() => {
editor = new Editor({
element: element,
extensions: [
Color.configure({ types: [TextStyle.name, ListItem.name] }),
TextStyle.configure({ types: [ListItem.name] }),
StarterKit,
],
content: html_text,
onTransaction: () => {
// force re-render so `editor.isActive` works as expected
editor = editor;
let updated_html = editor.getHTML();
if (updated_html == '<p></p>') {
new_html = '';
} else {
new_html = updated_html;
}
},
onUpdate: ({ editor }) => {
let updated_html = editor.getHTML();
if (updated_html == '<p></p>') {
new_html = '';
} else {
new_html = updated_html;
}
}
});
});
onDestroy(() => {
if (editor) {
editor.destroy();
}
});
function getContent() {
if (editor) {
return editor.getHTML();
}
return '';
}
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
on:click={() => {
if (default_minimal) {
editor.chain().focus().setParagraph().run();
show_menu = true;
}
}}
on:mouseleave={() => {
if (default_minimal) {
show_menu = false;
}
}}
class="editor border border-gray-300 rounded p-1 pb-2 bg-gray-200"
>
{#if editor && show_menu}
<div class="control-group bg-gray-200 border-b border-gray-400 p-1">
<div class="button-group flex flex-row flex-wrap gap-4 items-center justify-between">
<span>
<button
type="button"
on:click={() => console.log(editor?.getHTML()) && editor.chain().toggleBold().run()}
disabled={!editor.can().chain().focus().toggleBold().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md font-bold"
class:variant-ghost-secondary={editor.isActive("bold") ?? false}
class:hidden={!show_button_kv.bold}
>
<span class="fas fa-bold mx-1"></span>
<!-- Bold -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleItalic().run()}
disabled={!editor.can().chain().focus().toggleItalic().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md italic"
class:variant-ghost-secondary={editor.isActive("italic") ?? false}
class:hidden={!show_button_kv.italic}
>
<span class="fas fa-italic mx-1"></span>
<!-- Italic -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleStrike().run()}
disabled={!editor.can().chain().focus().toggleStrike().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md line-through"
class:variant-ghost-secondary={editor.isActive("strike") ?? false}
class:hidden={!show_button_kv.strike}
>
<span class="fas fa-strikethrough mx-1"></span>
<!-- Strike -->
</button>
</span>
<span>
<button
type="button"
on:click={() => editor.chain().focus().toggleCode().run()}
disabled={!editor.can().chain().focus().toggleCode().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("code") ?? false}
class:hidden={!show_button_kv.code}
>
<span class="fas fa-code mx-1"></span>
<!-- Code -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().unsetAllMarks().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.unsetAllMarks}
>
<!-- <span class="fas fa-broom mx-1"></span> -->
<span class="fas fa-remove-format mx-1"></span>
<!-- Clear marks -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().clearNodes().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.clearNodes}
>
<!-- <span class="fas fa-broom mx-1"></span> -->
<span class="fas fa-remove-format mx-1"></span>
Clear nodes
</button>
</span>
<span>
<button
type="button"
on:click={() => editor.chain().focus().setParagraph().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("paragraph") ? "is-active" : ""}
class:hidden={!show_button_kv.paragraph}
title="Paragraph"
>
<span class="fas fa-paragraph mx-1"></span>
<!-- Paragraph -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md text-xs"
class:variant-ghost-secondary={editor.isActive("heading", { level: 1 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h1}
title="Heading 1 <h1>"
>
<span class="fas fa-heading mx-1"></span>1
<!-- H1 -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md text-xs"
class:variant-ghost-secondary={editor.isActive("heading", { level: 2 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h2}
title="Heading 2 <h2>"
>
<span class="fas fa-heading mx-1"></span>2
<!-- <span class="text-xs">2</span> -->
<!-- 2 -->
<!-- H2 -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md text-xs"
class:variant-ghost-secondary={editor.isActive("heading", { level: 3 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h3}
title="Heading 3 <h3>"
>
<span class="fas fa-heading mx-1"></span>3
<!-- H3 -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("heading", { level: 4 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h4}
title="Heading 4 <h4>"
>
H4
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("heading", { level: 5 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h5}
title="Heading 5 <h5>"
>
H5
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("heading", { level: 6 }) ? "is-active" : ""}
class:hidden={!show_button_kv.heading__h6}
title="Heading 6 <h6>"
>
H6
</button>
</span>
<span>
<button
type="button"
on:click={() => editor.chain().focus().toggleBulletList().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("bulletList") ? "is-active" : ""}
class:hidden={!show_button_kv.bulletList}
title="Bullet list"
>
<span class="fas fa-list-ul mx-1"></span>
<!-- Bullet -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleOrderedList().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("orderedList") ? "is-active" : ""}
class:hidden={!show_button_kv.orderedList}
title="Ordered list"
>
<span class="fas fa-list-ol mx-1"></span>
<!-- Ordered -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleCodeBlock().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("codeBlock") ? "is-active" : ""}
class:hidden={!show_button_kv.codeBlock}
title="Code block"
>
Code block
</button>
<button
type="button"
on:click={() => editor.chain().focus().toggleBlockquote().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive("blockquote") ? "is-active" : ""}
class:hidden={!show_button_kv.blockquote}
title="Blockquote"
>
Blockquote
</button>
<button
type="button"
on:click={() => editor.chain().focus().setHorizontalRule().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.horizontalRule}
title="Horizontal rule"
>
Horizontal rule
</button>
<button
type="button"
on:click={() => editor.chain().focus().setHardBreak().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.hardBreak}
title="Hard break"
>
<span class="fas fa-level-down-alt mx-1"></span>
<!-- Hard break -->
</button>
</span>
<span
class="justify-self-end"
>
<button
type="button"
on:click={() => editor.chain().focus().undo().run()}
disabled={!editor.can().chain().focus().undo().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.undo}
title="Undo"
>
<span class="fas fa-undo mx-1"></span>
<!-- Undo -->
</button>
<button
type="button"
on:click={() => editor.chain().focus().redo().run()}
disabled={!editor.can().chain().focus().redo().run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:hidden={!show_button_kv.redo}
title="Redo"
>
<span class="fas fa-redo mx-1"></span>
<!-- Redo -->
</button>
</span>
<!-- <span>
<button
type="button"
on:click={() => editor.chain().focus().setColor('#958DF1').run()}
class="btn btn-sm variant-glass-secondary hover:variant-filled-secondary rounded-md"
class:variant-ghost-secondary={editor.isActive('textStyle', { color: '#958DF1' }) ? 'is-active' : ''}
class:hidden={!show_button_kv.color__purple}
>
Purple
</button>
</span> -->
</div>
</div>
{/if}
<div
bind:this={element}
class="tiptap bg-slate-100 px-1 py-2"
/>
</div>
<style lang="scss">
</style>