{"version":3,"file":"RichTextEditor.cjs","names":[],"sources":["../../src/editor/RichTextEditor.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — the body builds the tiptap editor,\n * its toolbar state and the change plumbing: every toolbar button reads\n * `editor.isActive`, so the toolbar cannot be lifted out without passing the editor\n * instance back down.\n */\nimport { useEffect } from \"react\";\nimport { EditorContent, useEditor, useEditorState } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport {\n    Bold,\n    Code,\n    Heading1,\n    Heading2,\n    Italic,\n    List,\n    ListOrdered,\n    Quote,\n    Redo2,\n    Strikethrough,\n    Undo2,\n} from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RichTextEditor.module.css\";\n\nexport interface RichTextEditorProps {\n    /** Current editor content as an HTML string (controlled). */\n    value: string;\n    /** Called with the updated HTML whenever the document changes. */\n    onChange: (html: string) => void;\n    /** Placeholder text shown when the editor is empty. */\n    placeholder?: string;\n    /** Whether the content is editable. Defaults to `true`. */\n    editable?: boolean;\n    /** Whether to render the formatting toolbar. Defaults to `true`. */\n    toolbar?: boolean;\n    /** Extra class names applied to the wrapper element. */\n    className?: string;\n}\n\n/**\n * RichTextEditor — a controlled WYSIWYG editor built on tiptap v3.\n *\n * Renders an optional formatting toolbar (bold, italic, strike, code, headings,\n * lists, blockquote, undo/redo) above a ProseMirror-backed editable area. The\n * document is controlled via the `value` (HTML) / `onChange` pair: external\n * changes to `value` are synced into the editor without re-emitting updates.\n *\n * The toolbar's pressed states and the undo/redo `disabled` flags come from\n * `useEditorState`, which subscribes to exactly those values. `useEditor` does\n * not re-render on transactions (the tiptap v3 default), so reading `isActive`\n * and `can()` directly in the render body left every button stale — toggling\n * bold with a collapsed cursor arms the mark without changing the document, so no\n * update event ever brought React back to recompute the state. Subscribing\n * re-renders only when one of the tracked values actually flips, which is also\n * cheaper than re-rendering on every keystroke.\n *\n * Two effects keep the instance aligned with the props: one pushes an external\n * `value` change into the document with `emitUpdate: false` (so syncing never\n * re-emits `onChange`), the other mirrors the `editable` flag.\n */\nexport function RichTextEditor({\n    value,\n    onChange,\n    placeholder,\n    editable = true,\n    toolbar = true,\n    className,\n}: RichTextEditorProps) {\n    const editor = useEditor({\n        extensions: [StarterKit],\n        content: value,\n        editable,\n        onUpdate: ({ editor: instance }) => onChange(instance.getHTML()),\n    });\n\n    useEffect(() => {\n        if (!editor) return;\n        if (value !== editor.getHTML()) {\n            editor.commands.setContent(value, { emitUpdate: false });\n        }\n    }, [editor, value]);\n\n    useEffect(() => {\n        if (!editor) return;\n        editor.setEditable(editable);\n    }, [editor, editable]);\n\n    const toolbarState = useEditorState({\n        editor,\n        selector: ({ editor: instance }) => ({\n            bold: instance.isActive(\"bold\"),\n            italic: instance.isActive(\"italic\"),\n            strike: instance.isActive(\"strike\"),\n            code: instance.isActive(\"code\"),\n            heading1: instance.isActive(\"heading\", { level: 1 }),\n            heading2: instance.isActive(\"heading\", { level: 2 }),\n            bulletList: instance.isActive(\"bulletList\"),\n            orderedList: instance.isActive(\"orderedList\"),\n            blockquote: instance.isActive(\"blockquote\"),\n            canUndo: instance.can().chain().focus().undo().run(),\n            canRedo: instance.can().chain().focus().redo().run(),\n        }),\n    });\n\n    if (!editor || !toolbarState) return null;\n\n    const canUndo = toolbarState.canUndo;\n    const canRedo = toolbarState.canRedo;\n\n    return (\n        <div className={cn(styles.wrapper, className)}>\n            {toolbar && (\n                <div className={styles.toolbar} role=\"toolbar\" aria-label=\"Formatação de texto\">\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.bold && styles.active)}\n                        aria-label=\"Negrito\"\n                        aria-pressed={toolbarState.bold}\n                        onClick={() => editor.chain().focus().toggleBold().run()}\n                    >\n                        <Bold size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.italic && styles.active)}\n                        aria-label=\"Itálico\"\n                        aria-pressed={toolbarState.italic}\n                        onClick={() => editor.chain().focus().toggleItalic().run()}\n                    >\n                        <Italic size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.strike && styles.active)}\n                        aria-label=\"Tachado\"\n                        aria-pressed={toolbarState.strike}\n                        onClick={() => editor.chain().focus().toggleStrike().run()}\n                    >\n                        <Strikethrough size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.code && styles.active)}\n                        aria-label=\"Código\"\n                        aria-pressed={toolbarState.code}\n                        onClick={() => editor.chain().focus().toggleCode().run()}\n                    >\n                        <Code size={16} aria-hidden />\n                    </button>\n                    <span className={styles.separator} aria-hidden />\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.heading1 && styles.active)}\n                        aria-label=\"Título 1\"\n                        aria-pressed={toolbarState.heading1}\n                        onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}\n                    >\n                        <Heading1 size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.heading2 && styles.active)}\n                        aria-label=\"Título 2\"\n                        aria-pressed={toolbarState.heading2}\n                        onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}\n                    >\n                        <Heading2 size={16} aria-hidden />\n                    </button>\n                    <span className={styles.separator} aria-hidden />\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.bulletList && styles.active)}\n                        aria-label=\"Lista com marcadores\"\n                        aria-pressed={toolbarState.bulletList}\n                        onClick={() => editor.chain().focus().toggleBulletList().run()}\n                    >\n                        <List size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.orderedList && styles.active)}\n                        aria-label=\"Lista numerada\"\n                        aria-pressed={toolbarState.orderedList}\n                        onClick={() => editor.chain().focus().toggleOrderedList().run()}\n                    >\n                        <ListOrdered size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.button, toolbarState.blockquote && styles.active)}\n                        aria-label=\"Citação\"\n                        aria-pressed={toolbarState.blockquote}\n                        onClick={() => editor.chain().focus().toggleBlockquote().run()}\n                    >\n                        <Quote size={16} aria-hidden />\n                    </button>\n                    <span className={styles.separator} aria-hidden />\n                    <button\n                        type=\"button\"\n                        className={styles.button}\n                        aria-label=\"Desfazer\"\n                        disabled={!canUndo}\n                        onClick={() => editor.chain().focus().undo().run()}\n                    >\n                        <Undo2 size={16} aria-hidden />\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={styles.button}\n                        aria-label=\"Refazer\"\n                        disabled={!canRedo}\n                        onClick={() => editor.chain().focus().redo().run()}\n                    >\n                        <Redo2 size={16} aria-hidden />\n                    </button>\n                </div>\n            )}\n            <EditorContent\n                editor={editor}\n                className={styles.content}\n                data-placeholder={placeholder}\n            />\n        </div>\n    );\n}\n"],"mappings":"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"}