feat(BlockEditor): add inline formatting with rich content model

- migrate block content from plain strings to InlineNode[] structure
- add inline toolbar (bold, italic, code, color, link) on text selection
- add checklist block type with toggle support
- add image block type (URL-based, phase 2)
- add inline serialization helpers (inlineToDom, domToInline)
- add inline types and length utilities
- extend caret utils with range get/set support
- update block registry and all existing block types for new content model
- update demo blocks in ComponentsPage to use rich inline content
- update README to reflect new architecture
This commit is contained in:
2026-04-25 18:27:20 -04:00
parent 3eeaebfa68
commit 5a8d2ad02f
19 changed files with 1244 additions and 126 deletions
@@ -218,11 +218,20 @@ export default function ComponentsPage() {
function BlockEditorDemo() {
const [blocks, setBlocks] = useState([
{ id: 'demo-1', type: 'heading_1', content: 'Bienvenue dans BlockEditor' },
{ id: 'demo-2', type: 'paragraph', content: "Tapez '/' pour ouvrir le menu de commandes." },
{ id: 'demo-3', type: 'bullet_item', content: 'Glissez la poignée ⋮⋮ pour réordonner' },
{ id: 'demo-4', type: 'bullet_item', content: 'Tapez `# ` au début pour un titre, `- ` pour une puce' },
{ id: 'demo-5', type: 'paragraph', content: '' },
{ id: 'demo-1', type: 'heading_1', content: [{ type: 'text', text: 'Bienvenue dans BlockEditor' }] },
{ id: 'demo-2', type: 'paragraph', content: [
{ type: 'text', text: "Tapez " },
{ type: 'text', text: "'/'", marks: [{ type: 'code' }] },
{ type: 'text', text: ' pour ouvrir le menu, ou ' },
{ type: 'text', text: 'sélectionnez', marks: [{ type: 'bold' }] },
{ type: 'text', text: ' pour ' },
{ type: 'text', text: 'mettre en forme', marks: [{ type: 'italic' }, { type: 'color', color: 'blue' }] },
{ type: 'text', text: '.' },
] },
{ id: 'demo-3', type: 'checklist', checked: true, content: [{ type: 'text', text: 'Format inline (gras, italique, couleur, lien)' }] },
{ id: 'demo-4', type: 'checklist', checked: false, content: [{ type: 'text', text: 'Bloc image (URL uniquement en Phase 2)' }] },
{ id: 'demo-5', type: 'bullet_item', content: [{ type: 'text', text: 'Glissez la poignée ⋮⋮ pour réordonner' }] },
{ id: 'demo-6', type: 'paragraph', content: [] },
]);
return (
<div className="w-full flex flex-col gap-4">