feat: sélection texte → Toggle/Callout dans le BubbleMenu
Quand l'utilisateur sélectionne du texte (1 ou plusieurs paragraphes), la barre flottante affiche deux boutons: - ChevronsRightLeft → enveloppe dans un Toggle - MessageSquareWarning → enveloppe dans un Callout Le contenu sélectionné devient le contenu du bloc.
This commit is contained in:
@@ -1350,6 +1350,28 @@ function BubbleToolbar({ editor, onSuggestCharts }: { editor: Editor | null; onS
|
||||
toast.error(msg && msg !== AI_REFORMULATE_FALLBACK ? msg : t('richTextEditor.aiReformulateFailed'))
|
||||
}
|
||||
|
||||
// Wrap the current text selection in a container block (toggle or callout)
|
||||
const wrapSelectionInBlock = useCallback((blockType: string) => {
|
||||
if (!editor) return
|
||||
const { from, to } = editor.state.selection
|
||||
if (from === to) return
|
||||
|
||||
// Get the selected slice (all blocks in the range)
|
||||
const slice = editor.state.doc.slice(from, to)
|
||||
const content = slice.content
|
||||
|
||||
// Create the container node with the selected content inside
|
||||
const containerNode = editor.state.schema.nodes[blockType].create(
|
||||
blockType === 'calloutBlock' ? { type: 'info' } : { opened: true },
|
||||
content,
|
||||
)
|
||||
|
||||
// Replace the selection with the container
|
||||
const tr = editor.state.tr
|
||||
tr.replaceRangeWith(from, to, containerNode)
|
||||
editor.view.dispatch(tr)
|
||||
}, [editor])
|
||||
|
||||
const [aiOpen, setAiOpen] = useState(false)
|
||||
const [aiLoading, setAiLoading] = useState(false)
|
||||
const [linkOpen, setLinkOpen] = useState(false)
|
||||
@@ -1477,6 +1499,13 @@ function BubbleToolbar({ editor, onSuggestCharts }: { editor: Editor | null; onS
|
||||
<div className="w-px h-4 bg-gray-300 dark:bg-gray-600 mx-0.5" />
|
||||
<button onClick={openLinkEditor} className={cn('notion-bubble-btn rounded-md', editorState.isLink && 'notion-bubble-btn-active')}><LinkIcon className="w-3.5 h-3.5" /></button>
|
||||
<button onClick={() => setAiOpen(!aiOpen)} className={cn('notion-bubble-btn rounded-md', aiLoading && 'animate-pulse')}><Sparkles className="w-3.5 h-3.5" /></button>
|
||||
<div className="w-px h-4 bg-gray-300 dark:bg-gray-600 mx-0.5" />
|
||||
<button onClick={() => wrapSelectionInBlock('toggleBlock')} title="Section repliable" className="notion-bubble-btn rounded-md">
|
||||
<ChevronsRightLeft className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button onClick={() => wrapSelectionInBlock('calloutBlock')} title="Encadré" className="notion-bubble-btn rounded-md">
|
||||
<MessageSquareWarning className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
{editorState.isImage && (
|
||||
<>
|
||||
<div className="w-px h-4 bg-gray-300 dark:bg-gray-600 mx-0.5" />
|
||||
|
||||
@@ -296,8 +296,6 @@ export const MathEquationExtension = Node.create({
|
||||
]
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
// Inline math mark — detects $...$ in text
|
||||
export const InlineMathExtension = Node.create({
|
||||
|
||||
Reference in New Issue
Block a user