Introduction
¿Qué es un widget?
¿Qué es un widget en React?
Un arcWidget es un componente configurable para una aplicación de negocio: por ejemplo una tabla, un calendario o un tablero Kanban. Pasas la representación como data y conectas los eventos con tu aplicación mediante callback props.
Un ejemplo completo
import {
ArcWidgetBadge,
ArcWidgetTable,
type ArcWidgetTableRow,
} from '@arcrider/arcwidgets-react';
import { useState } from 'react';
const lang = document.documentElement.lang.startsWith('en') ? 'en' : document.documentElement.lang.startsWith('es') ? 'es' : 'de'; const requested = new URLSearchParams(location.search).get('data'); const pack = requested === 'empty' || requested === 'busy' ? requested : 'demo'; const t = (de: string, en: string, es: string) => lang === 'en' ? en : lang === 'es' ? es : de;
const statusTone = { open: { color: '#d97706', label: t('Offen', 'Open', 'Abierto') }, work: { color: '#0f766e', label: t('In Arbeit', 'In progress', 'En curso') }, done: { color: '#15803d', label: t('Erledigt', 'Done', 'Hecho') }, wait: { color: '#be123c', label: t('Wartet', 'Waiting', 'En espera') }, };
type Status = keyof typeof statusTone; type Order = { id: string; title: string; amount: number; status: Status; items?: Order[]; };
const demoOrders: Order[] = [ { id: 'a', title: t('Auftrag Nordhafen', 'North Harbor order', 'Pedido Puerto Norte'), amount: 240, status: 'work', items: [ { id: 'a-1', title: t('Vorbereitung', 'Preparation', 'Preparación'), amount: 80, status: 'done', }, { id: 'a-2', title: t('Umsetzung', 'Delivery', 'Entrega'), amount: 160, status: 'work', }, ], }, { id: 'b', title: t('Auftrag Westpark', 'Westpark order', 'Pedido Westpark'), amount: 80, status: 'open', }, { id: 'c', title: t('Auftrag Innenstadt', 'Downtown order', 'Pedido centro'), amount: 420, status: 'wait', }, { id: 'd', title: t('Auftrag Werkstatt', 'Workshop order', 'Pedido taller'), amount: 150, status: 'done', }, ];
const SITES = [ 'Nordhafen', 'Westpark', 'Innenstadt', 'Werkstatt', 'Messe', 'Logistik', 'Campus', 'Hafen Süd', ]; const STATUSES: Status[] = ['open', 'work', 'done', 'wait'];
const busyOrders: Order[] = Array.from({ length: 800 }, (_, index) => ({ id: busy-${index + 1}, title: ${t('Auftrag', 'Order', 'Pedido')} ${SITES[index % SITES.length]} ${String(index + 1).padStart(3, '0')}, amount: 50 + ((index * 47) % 9950), status: STATUSES[index % STATUSES.length], }));
const orders = pack === 'empty' ? [] : pack === 'busy' ? busyOrders : demoOrders;
export default function Example() { const [selected, setSelected] = useState( t('Keine Auswahl', 'Nothing selected', 'Sin selección'), ); const statusMark = (status: Status) => pack === 'busy' ? ( <span style={{ display: 'inline-block', borderRadius: 6, padding: '3px 8px', fontSize: 12, fontWeight: 600, color: statusTone[status].color, backgroundColor: '#f4f4f5', }} > {statusTone[status].label} </span> ) : ( <ArcWidgetBadge data={{ value: statusTone[status].label, singleColor: statusTone[status].color, borderRadius: '6px', paddingX: '8px', paddingY: '3px', }} /> ); const row = (order: Order): ArcWidgetTableRow => ({ id: order.id, clickable: true, columns: [ { value: order.title, width: 'fraction' }, { value: statusMark(order.status), width: '130px', }, { value: order.amount, width: '90px', sort: { value: order.amount }, }, ], items: (order.items ?? []).map(row), }); return ( <> <ArcWidgetTable id="orders" data={{ height: pack === 'busy' ? '520px' : '320px', styles: { borders: { outer: true, rows: true, columns: false, color: '#e4e4e7', }, }, rowHoverAction: { hoverActive: true, backgroundColor: '#fafafa' }, header: { columns: [ { title: t('Auftrag', 'Order', 'Pedido'), width: 'fraction', sort: { enabled: true, type: 'text' }, }, { title: t('Status', 'Status', 'Estado'), width: '130px' }, { title: t('Betrag', 'Amount', 'Importe'), width: '90px', sort: { enabled: true, type: 'number' }, }, ], }, table: orders.map(row), emptyTable: { title: t('Keine Aufträge', 'No orders', 'Sin pedidos'), value: ( <div style={{ padding: 24, textAlign: 'center' }}> <strong> {t('Keine Aufträge', 'No orders', 'Sin pedidos')} </strong> <p> {t( 'Leerer Zustand — über Daten auf Voll oder Demo wechseln.', 'Empty state — switch Data to Full or Demo.', 'Estado vacío — cambia Datos a Completo o Demo.', )} </p> </div> ), }, }} onCellClick={(_event, { row_index }) => { setSelected( row_index == null ? t('Keine Auswahl', 'Nothing selected', 'Sin selección') : ${t('Zeile', 'Row', 'Fila')} ${row_index + 1}, ); }} /> <p aria-live="polite">{selected}</p> </> ); }</code></pre>
La lista se genera a partir de datos de React. Un clic actualiza el state local. Para el acceso a datos, el almacenamiento y la navegación usas tu propia API y los componentes de tu aplicación.
Las piezas
data contiene la configuración específica del widget.id identifica opcionalmente la instancia.- Los callback props como
onCellClick informan las interacciones. - Los slots de contenido permiten elementos de React propios y otros widgets.
<a href="/docs/react/intro/setup-react">Configurar React</a> · <a href="/docs/react/intro/react-components">Todos los componentes</a> · <a href="/docs/react/patterns/nested-widget-descriptors">Combinar componentes</a>.