Files
docmost/apps/client/src/features/editor/components/code-block/code-block-view.tsx
Philip Okugbe 33ddd92198 * fix codeblock tab-size (#703)
* hide codeblock menu group during printing
2025-02-06 17:43:31 +00:00

104 lines
3.1 KiB
TypeScript

import { NodeViewContent, NodeViewProps, NodeViewWrapper } from "@tiptap/react";
import { ActionIcon, CopyButton, Group, Select, Tooltip } from "@mantine/core";
import { useEffect, useState } from "react";
import { IconCheck, IconCopy } from "@tabler/icons-react";
import classes from "./code-block.module.css";
import React from "react";
import { Suspense } from "react";
import { useTranslation } from "react-i18next";
const MermaidView = React.lazy(
() => import("@/features/editor/components/code-block/mermaid-view.tsx"),
);
export default function CodeBlockView(props: NodeViewProps) {
const { t } = useTranslation();
const { node, updateAttributes, extension, editor, getPos } = props;
const { language } = node.attrs;
const [languageValue, setLanguageValue] = useState<string | null>(
language || null,
);
const [isSelected, setIsSelected] = useState(false);
useEffect(() => {
const updateSelection = () => {
const { state } = editor;
const { from, to } = state.selection;
// Check if the selection intersects with the node's range
const isNodeSelected =
(from >= getPos() && from < getPos() + node.nodeSize) ||
(to > getPos() && to <= getPos() + node.nodeSize);
setIsSelected(isNodeSelected);
};
editor.on("selectionUpdate", updateSelection);
return () => {
editor.off("selectionUpdate", updateSelection);
};
}, [editor, getPos(), node.nodeSize]);
function changeLanguage(language: string) {
setLanguageValue(language);
updateAttributes({
language: language,
});
}
return (
<NodeViewWrapper className="codeBlock">
<Group
justify="flex-end"
contentEditable={false}
className={classes.menuGroup}
>
<Select
placeholder="auto"
checkIconPosition="right"
data={extension.options.lowlight.listLanguages().sort()}
value={languageValue}
onChange={changeLanguage}
searchable
style={{ maxWidth: "130px" }}
classNames={{ input: classes.selectInput }}
disabled={!editor.isEditable}
/>
<CopyButton value={node?.textContent} timeout={2000}>
{({ copied, copy }) => (
<Tooltip
label={copied ? t("Copied") : t("Copy")}
withArrow
position="right"
>
<ActionIcon
color={copied ? "teal" : "gray"}
variant="subtle"
onClick={copy}
>
{copied ? <IconCheck size={16} /> : <IconCopy size={16} />}
</ActionIcon>
</Tooltip>
)}
</CopyButton>
</Group>
<pre
spellCheck="false"
hidden={
((language === "mermaid" && !editor.isEditable) ||
(language === "mermaid" && !isSelected)) &&
node.textContent.length > 0
}
>
<NodeViewContent as="code" className={`language-${language}`} />
</pre>
{language === "mermaid" && (
<Suspense fallback={null}>
<MermaidView props={props} />
</Suspense>
)}
</NodeViewWrapper>
);
}