Estoy trabajando en un clon de Google Docs basado en React como proyecto paralelo. Estoy usando TipTap como base.
Quería intentar imitar la funcionalidad en Google Docs donde el campo de selección se actualizaría con el valor apropiado según el texto que el usuario seleccione (por ejemplo, "título 1" aparecería en el campo de selección si un usuario resalta el texto con < estilo h1></h1>).
Aquí hay un pequeño video de la funcionalidad que quiero imitar: https://i.gyazo.com/18cc57f0285c8c5cd80d5dd6051f0ee7.mp4
Este es el código que tengo hasta ahora con el React Hook usado para los campos de selección:
const [font, setFont] = useState('sans-serif') const handleFontChange = (e) => { setFont(e.target.value) editor.chain().focus().setFontFamily(e.target.value).run() } return ( <select value={font} onChange={handleFontChange}> {fontFamilies.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)} </select> )He intentado entender los React Hooks y la API de selección, pero estoy atascado. ¿Es esto posible en Javascript/React?
EDITAR:
Encontré una función de la API de Tiptap que hace exactamente lo que estoy buscando. Supongo que ahora el problema es ¿cómo actualizo ese valor en la selección? Aquí está mi nuevo código:
const font = [ { value: 'sans-serif', label: 'Sans-serif' }, ... ] const [selectedFont, setSelectedFont] = useState([]) const handleFontChange = (obj) => { setSelectedFont(obj) editor.chain().focus().setFontFamily(obj.value).run() console.log(editor.isActive('textStyle', {fontFamily: selectedFont.value})) // prints true if the user clicked on text with the property active, otherwise prints false } return ( <Select name="fontFamily" options={font} isClearable="true" isSearchable="true" value={selectedFont} onChange={(option) => handleFontChange(option)} /> )Parece que la solución es realmente simple, pero lo estoy pensando demasiado.
Así que finalmente descubrí qué hacer. Necesitaba pasar una función en valor que itera sobre la matriz:
const fontList = [ { label: 'Sans-serif', value: 'sans-serif' }, ... ] <Select name="fontFamily" placeholder="Select font..." value={ editor.isActive('textStyle', {fontFamily: font}) ? ( selectedFont.find(index => fontList[index]) ) : '' } options={fontList} onChange={({value: fontSel}) => { setFont(fontSel) editor.chain().focus().setFontFamily(fontSel).run() }} />Solo me llevó una semana entera arrancarme el pelo... Me alegro de haberlo hecho finalmente.
Solo para agregar a esto, pude hacer lo siguiente en Vue para seleccionar encabezados con un menú desplegable.
<select :value="editor.isActive('heading') ? editor.getAttributes('heading').level : 0" @input="setSelectedHeading" > <option v-for="heading in headings" :key="heading.value" :label="heading.label" :value="heading.value" /> </select> headings: [ { value: 0, label: 'Normal text' }, { value: 1, label: 'Heading 1' }, { value: 2, label: 'Heading 2' }, { value: 3, label: 'Heading 3' }, { value: 4, label: 'Heading 4' }, { value: 5, label: 'Heading 5' }, { value: 6, label: 'Heading 6' } ] setSelectedHeading (selected) { if (selected === 0) { const selectedLevel = this.editor.getAttributes('heading').level return this.editor.chain().focus().toggleHeading({ level: selectedLevel }).run() } return this.editor.chain().focus().setHeading({ level: selected }).run() }En caso de que alguien quiera crear un menú desplegable simple con vue y tiptap , ya que esto no parece funcionar:
<select class="font-type"> <option @click="editor.chain().focus().setParagraph().run()" selected>Paragraph</option> <option @click="editor.chain().focus().toggleHeading({level: 1}).run()">Heading 1</option> <option @click="editor.chain().focus().toggleHeading({level: 2}).run()">Heading 2</option> <option @click="editor.chain().focus().toggleHeading({level: 3}).run()">Heading 3</option> </select>Puedes hacerlo:
<select class="font-type" @change="toggleType(editor, $event)"> <option value="p" selected>Paragraph</option> <option value="1">Heading 1</option> <option value="2">Heading 2</option> <option value="3">Heading 3</option> </select> y agrega esto a tu <script> :
const toggleType = (editor, event) => { if (event.target.value == 'p') { editor.chain().focus().setParagraph().run() } else { editor.chain().focus().toggleHeading({level: Number(event.target.value)}).run() } }