Définition d’éléments personnalisés
4 min
dans notre exemple précédent, nous avons commencé avec un paragraphe, mais nous n’avons en réalité jamais indiqué à slate quoi que ce soit concernant le type de bloc paragraphe nous avons simplement laissé slate utiliser son moteur de rendu interne par défaut, qui utilise un simple \<div> mais ce n’est pas tout ce que vous pouvez faire slate vous permet de définir n’importe quel type de blocs personnalisés, comme des citations de bloc, des blocs de code, des éléments de liste, etc nous allons vous montrer comment commençons avec notre application précédente const initialvalue = \[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ] const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) return ( \<slate editor={editor} value={initialvalue}> \<editable onkeydown={event => { if (event key === '&') { event preventdefault() editor inserttext('and') } }} /> \</slate> ) } ajoutons maintenant des « blocs de code » à notre éditeur le problème est que les blocs de code ne doivent pas être rendus comme un simple paragraphe, ils doivent être rendus différemment pour cela, nous devons définir un « renderer » pour les nœuds d’élément de type code les renderers d’éléments sont simplement des composants react simples, comme ceci // define a react component renderer for our code blocks const codeelement = props => { return ( \<pre { props attributes}> \<code>{props children}\</code> \</pre> ) } simple vous voyez la référence à props attributes ? slate transmet des attributs qui doivent être rendus sur l’élément le plus haut de vos blocs, afin que vous n’ayez pas à les construire vous même vous devez impérativement intégrer ces attributs dans votre composant et vous voyez la référence à props children ? slate rend automatiquement tous les enfants d’un bloc pour vous, puis vous les transmet comme n’importe quel autre composant react, via props children ainsi, vous n’avez pas à vous occuper du rendu des nœuds de texte ou quoi que ce soit de ce genre vous devez impérativement rendre les enfants comme la feuille la plus basse de votre composant voici un composant pour les éléments « par défaut » const defaultelement = props => { return \<p { props attributes}>{props children}\</p> } maintenant, ajoutons ce renderer à notre éditeur const initialvalue = \[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ] const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) // define a rendering function based on the element passed to `props` we use // `usecallback` here to memoize the function for subsequent renders const renderelement = usecallback(props => { switch (props element type) { case 'code' return \<codeelement { props} /> default return \<defaultelement { props} /> } }, \[]) return ( \<slate editor={editor} value={initialvalue}> \<editable // pass in the `renderelement` function renderelement={renderelement} onkeydown={event => { if (event key === '&') { event preventdefault() editor inserttext('and') } }} /> \</slate> ) } const codeelement = props => { return ( \<pre { props attributes}> \<code>{props children}\</code> \</pre> ) } const defaultelement = props => { return \<p { props attributes}>{props children}\</p> } très bien, mais nous avons maintenant besoin d’un moyen permettant à l’utilisateur de transformer effectivement un bloc en bloc de code pour cela, modifions notre fonction onkeydown pour ajouter un raccourci ``ctrl ``` qui fait exactement cela // import the `editor` and `transforms` helpers from slate import { editor, transforms } from 'slate' const initialvalue = \[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ] const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const renderelement = usecallback(props => { switch (props element type) { case 'code' return \<codeelement { props} /> default return \<defaultelement { props} /> } }, \[]) return ( \<slate editor={editor} value={initialvalue}> \<editable renderelement={renderelement} onkeydown={event => { if (event key === '`' && event ctrlkey) { // prevent the "`" from being inserted by default event preventdefault() // otherwise, set the currently selected blocks type to "code" transforms setnodes( editor, { type 'code' }, { match n => editor isblock(editor, n) } ) } }} /> \</slate> ) } const codeelement = props => { return ( \<pre { props attributes}> \<code>{props children}\</code> \</pre> ) } const defaultelement = props => { return \<p { props attributes}>{props children}\</p> } maintenant, si vous appuyez sur ``ctrl ``` le bloc dans lequel se trouve votre curseur devrait devenir un bloc de code ! magique ! mais nous avons oublié une chose lorsque vous appuyez à nouveau sur ``ctrl ``` cela devrait retransformer le bloc de code en paragraphe pour cela, nous devons ajouter un peu de logique afin de changer le type que nous définissons selon que l’un des blocs actuellement sélectionnés est déjà un bloc de code const initialvalue = \[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ] const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const renderelement = usecallback(props => { switch (props element type) { case 'code' return \<codeelement { props} /> default return \<defaultelement { props} /> } }, \[]) return ( \<slate editor={editor} value={initialvalue}> \<editable renderelement={renderelement} onkeydown={event => { if (event key === '`' && event ctrlkey) { event preventdefault() // determine whether any of the currently selected blocks are code blocks const \[match] = editor nodes(editor, { match n => n type === 'code', }) // toggle the block type depending on whether there's already a match transforms setnodes( editor, { type match ? 'paragraph' 'code' }, { match n => editor isblock(editor, n) } ) } }} /> \</slate> ) } et voilà ! si vous appuyez sur "ctrl `" lorsque vous êtes dans un bloc de code, celui ci devrait redevenir un paragraphe !