analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
399 lines (396 loc) • 14.2 kB
JavaScript
import {
ImageDialog
} from "./chunk-LVDGCRQI.mjs";
import {
MathNode
} from "./chunk-NVNYYFHH.mjs";
import {
FormulaDialog,
processLatexInHtml
} from "./chunk-FTQMDLZ5.mjs";
import "./chunk-IPVIZIHN.mjs";
import "./chunk-GKY77WVA.mjs";
import {
normalizeLineBreaksInHtml
} from "./chunk-QV5SUP4T.mjs";
import "./chunk-LI2FS7M2.mjs";
import "./chunk-WI3GQX74.mjs";
import "./chunk-EXVVHZOO.mjs";
import "./chunk-TNLGS7SB.mjs";
import "./chunk-Z2G5TBXF.mjs";
import {
Button_default
} from "./chunk-LAYB7IKW.mjs";
import {
Text_default
} from "./chunk-IMCIR6TJ.mjs";
import "./chunk-53ICLDGS.mjs";
import "./chunk-YG7W6JE3.mjs";
import "./chunk-AYI25BJ2.mjs";
import "./chunk-DG76FRXG.mjs";
import "./chunk-G7IP4VLI.mjs";
import "./chunk-RB5U4DHU.mjs";
// src/components/RichEditor/RichEditorCore.tsx
import { EditorContent, useEditor } from "@tiptap/react";
// src/components/RichEditor/components/extensions.ts
import StarterKit from "@tiptap/starter-kit";
import Underline from "@tiptap/extension-underline";
import TextAlign from "@tiptap/extension-text-align";
import { Color } from "@tiptap/extension-color";
import { TextStyle } from "@tiptap/extension-text-style";
import Highlight from "@tiptap/extension-highlight";
import Subscript from "@tiptap/extension-subscript";
import Superscript from "@tiptap/extension-superscript";
import Link from "@tiptap/extension-link";
import Placeholder from "@tiptap/extension-placeholder";
import Image from "@tiptap/extension-image";
function createRichEditorExtensions(placeholder) {
return [
StarterKit,
Underline,
TextStyle,
Color,
Highlight.configure({ multicolor: true }),
Subscript,
Superscript,
TextAlign.configure({ types: ["heading", "paragraph"] }),
Link.configure({ openOnClick: false }),
Placeholder.configure({ placeholder }),
Image.configure({ inline: false, allowBase64: false }),
MathNode
];
}
// src/components/RichEditor/RichEditorCore.tsx
import "katex/dist/katex.min.css";
import { TextBolderIcon } from "@phosphor-icons/react/dist/csr/TextB";
import { TextItalicIcon } from "@phosphor-icons/react/dist/csr/TextItalic";
import { TextUnderlineIcon } from "@phosphor-icons/react/dist/csr/TextUnderline";
import { TextStrikethroughIcon } from "@phosphor-icons/react/dist/csr/TextStrikethrough";
import { TextAlignLeftIcon } from "@phosphor-icons/react/dist/csr/TextAlignLeft";
import { TextAlignCenterIcon } from "@phosphor-icons/react/dist/csr/TextAlignCenter";
import { TextAlignRightIcon } from "@phosphor-icons/react/dist/csr/TextAlignRight";
import { TextAlignJustifyIcon } from "@phosphor-icons/react/dist/csr/TextAlignJustify";
import { LinkIcon } from "@phosphor-icons/react/dist/csr/Link";
import { ListBulletsIcon } from "@phosphor-icons/react/dist/csr/ListBullets";
import { ListNumbersIcon } from "@phosphor-icons/react/dist/csr/ListNumbers";
import { QuotesIcon } from "@phosphor-icons/react/dist/csr/Quotes";
import { MinusIcon } from "@phosphor-icons/react/dist/csr/Minus";
import { CodeIcon } from "@phosphor-icons/react/dist/csr/Code";
import { TextHOneIcon } from "@phosphor-icons/react/dist/csr/TextHOne";
import { TextHTwoIcon } from "@phosphor-icons/react/dist/csr/TextHTwo";
import { TextHThreeIcon } from "@phosphor-icons/react/dist/csr/TextHThree";
import { MathOperationsIcon } from "@phosphor-icons/react/dist/csr/MathOperations";
import { ImageIcon } from "@phosphor-icons/react/dist/csr/Image";
import { useState, useRef, useEffect } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
var ToolbarBtn = ({ onClick, active, title, children }) => /* @__PURE__ */ jsx(
Button_default,
{
type: "button",
onClick,
title,
size: "small",
className: `bg-transparent border-transparent h-7 w-7 p-0 flex items-center justify-center rounded hover:bg-background-100 ${active ? "bg-background-200 text-primary-700" : "text-text-700"}`,
children
}
);
var Divider = () => /* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-border-200 mx-0.5" });
var prepareContent = (content) => processLatexInHtml(normalizeLineBreaksInHtml(content || ""));
function RichEditor({
content,
onChange,
placeholder = "Digite aqui...",
onGenerateLatexWithAI,
onUploadImage
}) {
const [formulaOpen, setFormulaOpen] = useState(false);
const [imageOpen, setImageOpen] = useState(false);
const lastContentRef = useRef(content);
const editor = useEditor({
extensions: createRichEditorExtensions(placeholder),
content: prepareContent(content),
// External updates do not reach this callback: the sync effect below calls
// setContent with `emitUpdate: false`.
onUpdate: ({ editor: editor2 }) => {
const html = editor2.getHTML();
lastContentRef.current = html;
onChange?.({
json: editor2.getJSON(),
html
});
},
editorProps: {
attributes: {
class: "min-h-[120px] outline-none prose prose-sm max-w-none px-4 py-3 focus:outline-none"
}
}
});
useEffect(() => {
if (editor && content !== void 0 && content !== lastContentRef.current) {
editor.commands.setContent(prepareContent(content), {
emitUpdate: false
});
lastContentRef.current = content;
}
}, [content, editor]);
const insertFormula = (latex) => {
if (!latex || !editor) return;
editor.chain().focus().insertContent({
type: "mathInline",
attrs: { latex }
}).run();
setFormulaOpen(false);
};
const insertImage = (src, alt) => {
if (!src || !editor) return;
editor.chain().focus().setImage({ src, alt }).run();
setImageOpen(false);
};
const setLink = () => {
const url = globalThis.window.prompt("URL do link:");
if (url === null || !editor) return;
if (url === "") {
editor.chain().focus().extendMarkRange("link").unsetLink().run();
return;
}
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
};
if (!editor) return null;
return /* @__PURE__ */ jsxs("div", { className: "border border-border-200 rounded-xl overflow-hidden bg-background-0", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 border-b border-border-200 bg-background-50 px-2 py-1.5 flex-wrap", children: [
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(),
active: editor.isActive("heading", { level: 1 }),
title: "T\xEDtulo 1",
children: /* @__PURE__ */ jsx(TextHOneIcon, { size: 16, weight: "bold" })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(),
active: editor.isActive("heading", { level: 2 }),
title: "T\xEDtulo 2",
children: /* @__PURE__ */ jsx(TextHTwoIcon, { size: 16, weight: "bold" })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
active: editor.isActive("heading", { level: 3 }),
title: "T\xEDtulo 3",
children: /* @__PURE__ */ jsx(TextHThreeIcon, { size: 16, weight: "bold" })
}
),
/* @__PURE__ */ jsx(Divider, {}),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleBold().run(),
active: editor.isActive("bold"),
title: "Negrito (Ctrl+B)",
children: /* @__PURE__ */ jsx(TextBolderIcon, { size: 16, weight: "bold" })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleItalic().run(),
active: editor.isActive("italic"),
title: "It\xE1lico (Ctrl+I)",
children: /* @__PURE__ */ jsx(TextItalicIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleUnderline().run(),
active: editor.isActive("underline"),
title: "Sublinhado (Ctrl+U)",
children: /* @__PURE__ */ jsx(TextUnderlineIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleStrike().run(),
active: editor.isActive("strike"),
title: "Tachado",
children: /* @__PURE__ */ jsx(TextStrikethroughIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleSubscript().run(),
active: editor.isActive("subscript"),
title: "Subscrito",
children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
"X",
/* @__PURE__ */ jsx("sub", { className: "text-[8px]", children: "2" })
] })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleSuperscript().run(),
active: editor.isActive("superscript"),
title: "Sobrescrito",
children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
"X",
/* @__PURE__ */ jsx("sup", { className: "text-[8px]", children: "2" })
] })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleCode().run(),
active: editor.isActive("code"),
title: "C\xF3digo inline",
children: /* @__PURE__ */ jsx(CodeIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(Divider, {}),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().setTextAlign("left").run(),
active: editor.isActive({ textAlign: "left" }),
title: "Alinhar \xE0 esquerda",
children: /* @__PURE__ */ jsx(TextAlignLeftIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().setTextAlign("center").run(),
active: editor.isActive({ textAlign: "center" }),
title: "Centralizar",
children: /* @__PURE__ */ jsx(TextAlignCenterIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().setTextAlign("right").run(),
active: editor.isActive({ textAlign: "right" }),
title: "Alinhar \xE0 direita",
children: /* @__PURE__ */ jsx(TextAlignRightIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().setTextAlign("justify").run(),
active: editor.isActive({ textAlign: "justify" }),
title: "Justificar",
children: /* @__PURE__ */ jsx(TextAlignJustifyIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(Divider, {}),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleBulletList().run(),
active: editor.isActive("bulletList"),
title: "Lista com marcadores",
children: /* @__PURE__ */ jsx(ListBulletsIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleOrderedList().run(),
active: editor.isActive("orderedList"),
title: "Lista numerada",
children: /* @__PURE__ */ jsx(ListNumbersIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().toggleBlockquote().run(),
active: editor.isActive("blockquote"),
title: "Cita\xE7\xE3o",
children: /* @__PURE__ */ jsx(QuotesIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => editor.chain().focus().setHorizontalRule().run(),
active: false,
title: "Linha horizontal",
children: /* @__PURE__ */ jsx(MinusIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(Divider, {}),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: setLink,
active: editor.isActive("link"),
title: "Inserir link",
children: /* @__PURE__ */ jsx(LinkIcon, { size: 16 })
}
),
/* @__PURE__ */ jsx(
ToolbarBtn,
{
onClick: () => setImageOpen(true),
active: editor.isActive("image"),
title: "Inserir imagem",
children: /* @__PURE__ */ jsx(ImageIcon, { size: 16 })
}
),
/* @__PURE__ */ jsxs(
Button_default,
{
type: "button",
onClick: () => setFormulaOpen(true),
title: "Inserir f\xF3rmula LaTeX",
size: "extra-small",
variant: "link",
children: [
/* @__PURE__ */ jsx(MathOperationsIcon, { size: 16 }),
"LaTeX"
]
}
)
] }),
/* @__PURE__ */ jsx(EditorContent, { editor }),
/* @__PURE__ */ jsx("div", { className: "border-t border-border-200 px-4 py-2 bg-background-50", children: /* @__PURE__ */ jsxs(Text_default, { size: "xs", color: "text-text-400", children: [
"Dica: use",
" ",
/* @__PURE__ */ jsx("code", { className: "bg-background-200 px-1 rounded", children: "$f\xF3rmula$" }),
" para inserir LaTeX inline diretamente."
] }) }),
/* @__PURE__ */ jsx(
FormulaDialog,
{
open: formulaOpen,
onClose: () => setFormulaOpen(false),
onInsert: insertFormula,
onGenerateWithAI: onGenerateLatexWithAI
}
),
/* @__PURE__ */ jsx(
ImageDialog,
{
open: imageOpen,
onClose: () => setImageOpen(false),
onInsert: insertImage,
onUploadImage
}
)
] });
}
export {
RichEditor
};
//# sourceMappingURL=RichEditorCore-ZGHPGZXZ.mjs.map