Qortal-Hub/src/components/Group/Forum/ReadOnlySlate.tsx
2025-04-23 20:49:30 +02:00

131 lines
2.7 KiB
TypeScript

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { createEditor } from 'slate';
import {
withReact,
Slate,
Editable,
RenderElementProps,
RenderLeafProps,
} from 'slate-react';
type ExtendedRenderElementProps = RenderElementProps & { mode?: string };
export const renderElement = ({
attributes,
children,
element,
mode,
}: ExtendedRenderElementProps) => {
switch (element.type) {
case 'block-quote':
return <blockquote {...attributes}>{children}</blockquote>;
case 'heading-2':
return (
<h2
className="h2"
{...attributes}
style={{ textAlign: element.textAlign }}
>
{children}
</h2>
);
case 'heading-3':
return (
<h3
className="h3"
{...attributes}
style={{ textAlign: element.textAlign }}
>
{children}
</h3>
);
case 'code-block':
return (
<pre {...attributes} className="code-block">
<code>{children}</code>
</pre>
);
case 'code-line':
return <div {...attributes}>{children}</div>;
case 'link':
return (
<a href={element.url} {...attributes}>
{children}
</a>
);
default:
return (
<p
className={`paragraph${mode ? `-${mode}` : ''}`}
{...attributes}
style={{ textAlign: element.textAlign }}
>
{children}
</p>
);
}
};
export const renderLeaf = ({ attributes, children, leaf }: RenderLeafProps) => {
let el = children;
if (leaf.bold) {
el = <strong>{el}</strong>;
}
if (leaf.italic) {
el = <em>{el}</em>;
}
if (leaf.underline) {
el = <u>{el}</u>;
}
if (leaf.link) {
el = (
<a href={leaf.link} {...attributes}>
{el}
</a>
);
}
return <span {...attributes}>{el}</span>;
};
interface ReadOnlySlateProps {
content: any;
mode?: string;
}
const ReadOnlySlate: React.FC<ReadOnlySlateProps> = ({ content, mode }) => {
const [load, setLoad] = useState(false);
const editor = useMemo(() => withReact(createEditor()), []);
const value = useMemo(() => content, [content]);
const performUpdate = useCallback(async () => {
setLoad(true);
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 250);
});
setLoad(false);
}, []);
useEffect(() => {
performUpdate();
}, [value]);
if (load) return null;
return (
<Slate editor={editor} value={value} onChange={() => {}}>
<Editable
readOnly
renderElement={(props) => renderElement({ ...props, mode })}
renderLeaf={renderLeaf}
/>
</Slate>
);
};
export default ReadOnlySlate;