'use client' import { Node, mergeAttributes } from '@tiptap/core' import { ReactNodeViewRenderer, NodeViewWrapper, NodeViewContent } from '@tiptap/react' import { ChevronRight, X, Trash2 } from 'lucide-react' import { useState } from 'react' import { cn } from '@/lib/utils' import { useLanguage } from '@/lib/i18n' const ToggleView = ({ node, updateAttributes, deleteNode, getPos, editor }: any) => { const [opened, setOpened] = useState(node.attrs.opened !== false) const { t } = useLanguage() const toggle = () => { const next = !opened setOpened(next) updateAttributes({ opened: next }) } const unwrap = () => { const pos = getPos() if (typeof pos !== 'number') return const { state, view } = editor const toggleNode = state.doc.nodeAt(pos) if (!toggleNode) return const children: any[] = [] toggleNode.forEach((child: any) => { children.push(child.toJSON()) }) if (children.length === 0) children.push({ type: 'paragraph' }) editor.chain().focus().deleteRange({ from: pos, to: pos + toggleNode.nodeSize }).run() editor.chain().focus().insertContentAt(pos, children).run() } return (
{opened ? t('richTextEditor.toggleOpened') : t('richTextEditor.toggleClosed')}
) } export const ToggleExtension = Node.create({ name: 'toggleBlock', group: 'block', content: 'block+', defining: true, addAttributes() { return { opened: { default: true, parseHTML: (element) => element.getAttribute('data-opened') !== 'false', renderHTML: (attributes) => ({ 'data-opened': attributes.opened, }), }, } }, parseHTML() { return [ { tag: 'div[data-type="toggle-block"]', }, { tag: 'details', getAttrs: (element) => { if (typeof element === 'string') return false return { opened: !(element as HTMLElement).hasAttribute('closed') } }, }, ] }, renderHTML({ HTMLAttributes }) { return [ 'div', mergeAttributes(HTMLAttributes, { 'data-type': 'toggle-block', class: 'toggle-block', }), 0, ] }, addNodeView() { return ReactNodeViewRenderer(ToggleView) }, }) export function insertToggleBlock(editor: any) { editor.chain().focus().insertContent({ type: 'toggleBlock', attrs: { opened: true }, content: [ { type: 'paragraph' }, ], }).run() } /** * Transforme un bloc existant en section repliable. * Le contenu du bloc original est déplacé dans le toggle. */ export function turnIntoToggleBlock(editor: any, blockPos: number, blockNode: any) { if (!blockNode || blockPos < 0) return const nodeJson = blockNode.toJSON() editor.chain().focus().deleteRange({ from: blockPos, to: blockPos + blockNode.nodeSize, }).insertContentAt(blockPos, { type: 'toggleBlock', attrs: { opened: true }, content: [nodeJson], }).setTextSelection(blockPos + 2).run() }