Files
OSIT-AE-App-Svelte/src/lib/components/shad-editor/shad-editor.svelte

177 lines
4.8 KiB
Svelte

<script lang="ts">
import './editor.css';
import { Editor, type Content } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import { onDestroy, onMount } from 'svelte';
import EditorToolbar from './editor-toolbar.svelte';
import { cn } from '$lib/utils.js';
import { Subscript } from '@tiptap/extension-subscript';
import { Superscript } from '@tiptap/extension-superscript';
import { Underline } from '@tiptap/extension-underline';
import { Link } from '@tiptap/extension-link';
import TaskList from '@tiptap/extension-task-list';
import TaskItem from '@tiptap/extension-task-item';
import TextStyle from '@tiptap/extension-text-style';
import Color from '@tiptap/extension-color';
import Highlight from '@tiptap/extension-highlight';
import Text from '@tiptap/extension-text';
import Typography from '@tiptap/extension-typography';
import TextAlign from '@tiptap/extension-text-align';
import { SmilieReplacer } from './custom/Extentions/SmilieReplacer.js';
import { ColorHighlighter } from './custom/Extentions/ColorHighlighter.js';
import Table from '@tiptap/extension-table';
import TableRow from '@tiptap/extension-table-row';
import TableHeader from '@tiptap/extension-table-header';
import TableCell from '@tiptap/extension-table-cell';
import { ImageExtension } from './custom/Extentions/ImageExtention.js';
import { SvelteNodeViewRenderer } from 'svelte-tiptap';
import CodeExtended from './custom/code-extended.svelte';
// Lowlight
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
import { all, createLowlight } from 'lowlight';
import './onedark.css';
import SearchAndReplace from './custom/Extentions/SearchAndReplace.js';
const lowlight = createLowlight(all);
interface Props {
class?: string;
content?: Content;
showToolbar?: boolean;
// html_text?: string;
new_html?: string;
placeholder?: string;
}
let { class:
className = '',
content = $bindable(''),
showToolbar = true,
// html_text = '',
new_html = $bindable(''),
placeholder = $bindable('Start typing...')
}: Props = $props();
let editor = $state<Editor>();
let element = $state<HTMLElement>();
onMount(() => {
editor = new Editor({
element,
content,
editorProps: {
attributes: {
class:
'm-auto p-2 focus:outline-none flex-1 prose text-foreground min-w-full max-h-full overflow-auto dark:prose-invert *:my-2'
}
},
extensions: [
StarterKit.configure({
orderedList: {
HTMLAttributes: {
class: 'list-decimal'
}
},
bulletList: {
HTMLAttributes: {
class: 'list-disc'
}
},
heading: {
levels: [1, 2, 3, 4],
HTMLAttributes: {
class: 'tiptap-heading'
}
}
}),
Typography,
Text,
TextStyle,
TextAlign.configure({
types: ['heading', 'paragraph']
}),
Color,
Highlight.configure({ multicolor: true }),
Underline,
Superscript,
Subscript,
Link.configure({
openOnClick: false,
autolink: true,
defaultProtocol: 'https',
HTMLAttributes: {
target: '_blank',
rel: 'noopener noreferrer'
}
}),
TaskList,
TaskItem.configure({
nested: true
}),
SearchAndReplace,
CodeBlockLowlight.configure({
lowlight
}).extend({
addNodeView() {
return SvelteNodeViewRenderer(CodeExtended);
}
}),
SmilieReplacer,
ColorHighlighter,
Table.configure({
allowTableNodeSelection: true,
resizable: true
}),
TableRow,
TableHeader,
TableCell,
ImageExtension
],
autofocus: true,
onTransaction: (transaction) => {
/**
* Weird behavior of editor.
* If we do not make it undefined, then it looses it's reactivity
* this is because assigning editor directly to `transaction.editor`
* the original object is not mutated.
*/
editor = undefined;
editor = transaction.editor;
console.log(editor.isActive('bold'));
content = editor.getHTML();
// console.log(content);
let html = editor.getHTML();
if (html == '<p></p>') {
new_html = '';
} else {
new_html = html ?? '';
}
}
});
});
onDestroy(() => {
if (editor) editor.destroy();
});
</script>
<div class={cn('flex flex-col rounded border', className)}>
{#if editor && showToolbar}
<EditorToolbar {editor} />
{/if}
<div
bind:this={element}
spellcheck="false"
class="tiptap h-full w-full overflow-auto relative">
<span
class="placeholder text-sm text-gray-400 italic absolute p-3"
contenteditable="false"
hidden={editor?.getHTML() !== '<p></p>'}
>{placeholder}</span>
</div>
</div>