Guías paso a paso
Definiendo Elementos Personalizados
4 min
en nuestro ejemplo anterior, comenzamos con un párrafo, pero nunca le dijimos a slate nada sobre el párrafo tipo de bloque simplemente dejamos que usara su renderizador predeterminado interno, que utiliza un antiguo \<div> pero eso no es todo lo que puedes hacer slate te permite definir cualquier tipo de bloques personalizados que desees, como citas en bloque, bloques de código, elementos de lista, etc te mostraremos cómo comencemos con nuestra aplicación de antes const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const \[value, setvalue] = usestate(\[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ]) return ( \<slate editor={editor} value={value} onchange={value => setvalue(value)}> \<editable onkeydown={event => { if (event key === '&') { event preventdefault() editor inserttext('and') } }} /> \</slate> ) } ahora agreguemos "bloques de código" a nuestro editor el problema es que los bloques de código no se renderizarán simplemente como un párrafo plano, necesitarán ser renderizados de manera diferente para que eso suceda, necesitamos definir un "renderizador" para código nodos de elemento los renderizadores de elementos son solo componentes simples de react, así // define a react component renderer for our code blocks const codeelement = props => { return ( \<pre { props attributes}> \<code>{props children}\</code> \</pre> ) } suficientemente fácil ¿ves la props attributes referencia? slate pasa atributos que deben ser renderizados en el elemento más alto de tus bloques, para que no tengas que construirlos tú mismo tú debes mezclar los atributos en tu componente y ¿ves esa props children referencia? slate renderizará automáticamente todos los hijos de un bloque para ti, y luego te los pasará como lo haría cualquier otro componente de react, a través de props children de esa manera no tienes que preocuparte por renderizar los nodos de texto adecuados ni nada por el estilo tú debes renderizar los hijos como la hoja más baja en tu componente y aquí hay un componente para los elementos "predeterminados" const defaultelement = props => { return \<p { props attributes}>{props children}\</p> } ahora, agreguemos ese renderizador a nuestro editor const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const \[value, setvalue] = usestate(\[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ]) // 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={value} onchange={value => setvalue(value)}> \<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> } está bien, pero ahora necesitaremos una forma para que el usuario realmente convierta un bloque en un bloque de código así que cambiemos nuestra onkeydown función para agregar un atajo ``ctrl ``` que haga precisamente eso // import the `editor` and `transforms` helpers from slate import { editor, transforms } from 'slate' const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const \[value, setvalue] = usestate(\[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ]) const renderelement = usecallback(props => { switch (props element type) { case 'code' return \<codeelement { props} /> default return \<defaultelement { props} /> } }, \[]) return ( \<slate editor={editor} value={value} onchange={value => setvalue(value)}> \<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> } ahora, si presionas ``ctrl ``` el bloque en el que está tu cursor debería convertirse en un bloque de código! ¡magia! pero olvidamos una cosa cuando presiones ``ctrl ``` de nuevo, debería cambiar el bloque de código de vuelta a un párrafo para hacer eso, necesitaremos agregar un poco de lógica para cambiar el tipo que establecemos según si alguno de los bloques seleccionados actualmente ya es un bloque de código const app = () => { const editor = usememo(() => withreact(createeditor()), \[]) const \[value, setvalue] = usestate(\[ { type 'paragraph', children \[{ text 'a line of text in a paragraph ' }], }, ]) const renderelement = usecallback(props => { switch (props element type) { case 'code' return \<codeelement { props} /> default return \<defaultelement { props} /> } }, \[]) return ( \<slate editor={editor} value={value} onchange={value => setvalue(value)}> \<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> ) } ¡y ahí lo tienes! si presionas ``ctrl ``` mientras estás dentro de un bloque de código, debería volver a convertirse en un párrafo!
