innoboxrr-react-form-elements
v3.8.0
Published
Gemelo React de innoboxrr-form-elements: los mismos componentes, los mismos nombres y el mismo contrato, con diálogos, drawers, menús, avisos y paleta de comandos.
Maintainers
Readme
innoboxrr-react-form-elements
Gemelo React de innoboxrr-form-elements. Los mismos 37
componentes, con los mismos nombres: los controles de formulario y las piezas de
escritorio (DialogComponent, DrawerComponent, MenuComponent,
CommandPaletteComponent, ToastRegionComponent, ConfirmHostComponent y
SkeletonComponent).
Los nombres coinciden a propósito: larapack-generator emite el mismo
form_component del laraimport.json para Vue y para React, así que un nombre
distinto rompería esa simetría. Hay un test de paridad en cada repositorio que
falla si un paquete exporta algo que el otro no.
Instalación
npm i innoboxrr-react-form-elementsLos estilos van una vez por aplicación:
import 'innoboxrr-react-form-elements/src/css/form-elements.css'
import '@yaireo/tagify/dist/tagify.css' // si usas TagsInputComponent
import 'react-phone-number-input/style.css' // si usas CountrySelectInputComponentUso
import { TextInputComponent, SelectInputComponent } from 'innoboxrr-react-form-elements'
<TextInputComponent
type="text"
name="title"
label="Título"
validators="required"
value={form.title}
onChange={(value) => setField('title', value)} />
<SelectInputComponent name="status" label="Estado" value={form.status} onChange={...}>
<option value="">Selecciona</option>
<option value="draft">Borrador</option>
</SelectInputComponent>Equivalencias con la versión Vue
| Vue | React |
|---|---|
| v-model | value + onChange(valor) |
| :custom-class | customClass |
| min_length / max_length | minLength / maxLength (se aceptan también los de guion bajo) |
| slot por defecto de SelectInputComponent | children |
| v-format | prop maskFormat |
| @change de CountrySelectInputComponent | onCountryChange({ phone, country, callingCode, national, isValid }) |
| @submit / @selected de ModelSearchInputComponent | onSubmit / onSelected |
| install(app) | no existe: React no tiene plugin de aplicación |
onChange recibe el valor, no el evento, igual que update:modelValue
recibe el valor y no el $event. Para el evento del DOM están onInput,
onFocus, onBlur, onEnter y onPaste.
Todos los controles funcionan también sin value: se gobiernan solos. Eso
permite montarlos en una prueba o en un formulario no controlado sin escribir
estado alrededor.
Piezas de escritorio
Sobre <dialog>, el atributo popover y Floating UI, con el mismo
comportamiento que la rama Vue. Lo que cambia es la forma de pasar las cosas:
| Vue | React |
|---|---|
| v-model:open | open + onOpenChange(abierto) |
| slot footer / header con { close } | prop footer / header: un nodo o una función ({ close }) => … |
| slot trigger de MenuComponent | renderTrigger({ toggle, open, loading, triggerProps }) |
| @select | onSelect(item) |
| :save de ClickToEditComponent | onSave(valor) |
import { DrawerComponent, ToastRegionComponent, ConfirmHostComponent } from 'innoboxrr-react-form-elements'
import { notifySuccess } from 'innoboxrr-form-core'
<DrawerComponent open={abierto} onOpenChange={setAbierto} title="Nuevo producto"
footer={({ close }) => <button type="button" onClick={close}>Cancelar</button>}>
<CreateForm onSubmit={(producto) => { notifySuccess('Producto creado'); setAbierto(false) }} />
</DrawerComponent>
// una vez, en la raíz
<ToastRegionComponent />
<ConfirmHostComponent />React no escribe el atributo autofocus en el DOM, así que lo que tiene que
recibir el foco al abrir un diálogo se marca con data-autofocus.
Las librerías de debajo
Cada componente envuelve el equivalente React de la librería que envuelve su gemelo Vue. Donde la librería es agnóstica, es literalmente la misma:
| Componente | Vue | React |
|---|---|---|
| TextInputComponent (máscara) | innoboxrr-maskjs/vue | innoboxrr-maskjs — el mismo motor |
| TagsInputComponent | @yaireo/tagify | @yaireo/tagify/react — la misma librería |
| EditorInputComponent | @tinymce/tinymce-vue | @tinymce/tinymce-react — el envoltorio oficial hermano |
| CodeMirrorComponent | vue-codemirror | @uiw/react-codemirror — el mismo CodeMirror 6 |
| SelectSearchInputComponent | vue-select | react-select |
| CountrySelectInputComponent | vue-tel-input | react-phone-number-input — el mismo libphonenumber-js |
| DynamicGroupInputComponent | vuedraggable | @dnd-kit/sortable |
| ColorPickerInputComponent | lightvue (opcional) | react-colorful |
Tres notas sobre esas elecciones:
@dnd-kites el sucesor dereact-beautiful-dnd, que está archivado. A diferencia de SortableJS trae reordenación por teclado, así que el asa de arrastre es un<button>alcanzable con tabulador. Un formulario que solo se reordena con el ratón no es accesible.react-phone-number-inputvalida conlibphonenumber-js, igual quevue-tel-input. Sabe cuántos dígitos tiene un número de cada país.react-colorfulpesa 2,8 kB y no tiene dependencias. La versión Vue cae a<input type="color">cuandolightvueno está, que abre el diálogo del sistema operativo y no se puede estilar ni probar.
Máscaras
<TextInputComponent
type="text"
name="phone"
label="Teléfono"
maskFormat={{ mask: '(___) ___-____', format: '(***) ***-****' }}
value={phone}
onChange={setPhone} />En format: * es un dígito, a una letra, A letra o dígito. Todo lo demás
es un literal. Ver innoboxrr-maskjs.
Editor de código
CodeMirrorComponent carga el lenguaje bajo demanda. language (javascript
por defecto, json, html o css) llega con import(), así que una
aplicación solo descarga el que usa: un editor de JSON ya no se lleva html, css
y javascript. Mientras llega, el editor funciona como texto plano. Un lenguaje
fuera de esa lista lo deja en texto plano.
theme es dark (por defecto) o light. one-dark va siempre en el bundle
porque lo importa @uiw/react-codemirror, no este paquete.
Diferencias deliberadas
MultiCheckboxInputComponentderiva la selección del valor. La versión Vue la recalculaba condocument.querySelectorAll, así que dos grupos con el mismoidse pisaban.SelectSearchInputComponent,ColorPickerInputComponent,CodeMirrorComponentyEditorInputComponentpublican su valor en un<input type="hidden">con elnamey eldata-validators. Sus librerías no exponen un input donde ponerlos, y el validador del proyecto los lee del DOM.- Todos aceptan
id. Sin eso, pasar unidcambiaba el del control pero no elforde la etiqueta, y la etiqueta quedaba apuntando a la nada.
Pruebas
npm test