{
onFocus?.(event)
if (!event.defaultPrevented && event.target === event.currentTarget) {
editor?.commands.focus()
}
}}
onBlur={(event) => {
const nextTarget = event.relatedTarget
const movedWithinEditor =
event.currentTarget.contains(nextTarget) ||
(nextTarget instanceof HTMLElement &&
Boolean(nextTarget.closest("[data-rich-text-editor-popover]")))
if (!movedWithinEditor) onBlur?.(event)
}}
className={cn(
"overflow-hidden rounded-md border border-control-3 bg-background text-foreground transition-[border-color,box-shadow]",
"focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50",
"data-[invalid]:border-destructive data-[invalid]:ring-3 data-[invalid]:ring-destructive/20",
"data-[disabled]:cursor-not-allowed data-[disabled]:bg-muted data-[disabled]:text-muted-foreground",
"data-[readonly]:bg-muted/40",
"[&_.tiptap_p]:my-2 [&_.tiptap_p:first-child]:mt-0 [&_.tiptap_p:last-child]:mb-0",
"[&_.tiptap_h2]:my-3 [&_.tiptap_h2]:text-lg [&_.tiptap_h2]:font-semibold",
"[&_.tiptap_h3]:my-2 [&_.tiptap_h3]:text-base [&_.tiptap_h3]:font-semibold",
"[&_.tiptap_ul]:my-2 [&_.tiptap_ul]:list-disc [&_.tiptap_ul]:ps-6",
"[&_.tiptap_ol]:my-2 [&_.tiptap_ol]:list-decimal [&_.tiptap_ol]:ps-6",
"[&_.tiptap_blockquote]:my-3 [&_.tiptap_blockquote]:border-s-2 [&_.tiptap_blockquote]:border-brand [&_.tiptap_blockquote]:ps-3 [&_.tiptap_blockquote]:text-muted-foreground",
"[&_.tiptap_a]:text-brand [&_.tiptap_a]:underline [&_.tiptap_a]:underline-offset-4",
"[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none [&_.tiptap_p.is-editor-empty:first-child::before]:float-left [&_.tiptap_p.is-editor-empty:first-child::before]:h-0 [&_.tiptap_p.is-editor-empty:first-child::before]:text-muted-foreground [&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]",
className,
)}
{...props}
>
{canEdit ? (
{blockCommands.map((command) => (
))}
{markCommands.map((command) => (
))}
{editor ? (
) : null}
) : null}
{editor && canEdit
? createPortal(
from !== to &&
currentEditor.isEditable &&
currentEditor.state.doc
.textBetween(from, to)
.trim().length > 0
}
options={{
placement: "top",
offset: 8,
strategy: "fixed",
}}
>
{markCommands.map((command) => (
))}
,
document.body,
)
: null}
{name ? (
) : null}
)
},
)
RichTextEditor.displayName = "RichTextEditor"
export { RichTextEditor }
export type { RichTextEditorProps }