Premium Widgets
Custom Calendar Timeline
CalendarTimeline en React
Muestra periodos de tiempo por recurso u objeto en un eje de tiempo compartido.
Referencia para @arcrider/arcwidgets-react@0.1.0-alpha.5. <a href="/docs/react/intro/setup-react">Instalación</a> · <a href="/docs/react/intro/react-components">Todos los componentes</a>.
Ejemplo completo
import { ArcWidgetCalendarTimeline } 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 day = (value: number) => new Date(2026, 8, value).getTime();
const chrome = { backgroundColor: '#ffffff', fontColor: '#18181b', mutedColor: '#52525b', subtleColor: '#71717a', headerBackgroundColor: '#fafafa', groupBackgroundColor: '#f4f4f5', rowBackgroundColor: '#ffffff', borders: { outer: true, rows: true, columns: false, color: '#e4e4e7' }, dayStripes: { odd: '#ffffff', even: '#f4f4f5' }, };
const look = (backgroundColor: string, color: string) => ({ backgroundColor, color, fontColor: color, });
type Bar = { id: string; title: string; dateFrom: number; dateTo: number; clickable: true; draggable: true; styles: ReturnType<typeof look>; };
type Row = { id: string; title: string; timeEntries: Bar[]; };
const bar = ( id: string, title: string, from: number, to: number, backgroundColor: string, color: string, ): Bar => ({ id, title, dateFrom: day(from), dateTo: day(to), clickable: true, draggable: true, styles: look(backgroundColor, color), });
const demoRows: Row[] = [ { id: 'team-a', title: t('Team Montage', 'Install team', 'Equipo montaje'), timeEntries: [ bar( 'job-a', t('Installation', 'Installation', 'Instalación'), 16, 18, '#d1fae5', '#065f46', ), ], }, { id: 'team-b', title: t('Kundentermin', 'Site visit', 'Visita'), timeEntries: [ bar( 'job-b-out', t('Anfahrt', 'Travel there', 'Ida'), 16, 16, '#99f6e4', '#115e59', ), bar( 'job-b', t('Hauptarbeit', 'On site', 'Trabajo principal'), 17, 17, '#ccfbf1', '#115e59', ), bar( 'job-b-back', t('Abfahrt', 'Travel back', 'Vuelta'), 18, 18, '#99f6e4', '#115e59', ), ], }, ];
const busyRows: Row[] = [ ...demoRows, { id: 'team-c', title: t('Team Messe', 'Fair team', 'Equipo feria'), timeEntries: [ bar( 'job-c', t('Aufbau', 'Setup', 'Montaje'), 15, 17, '#ede9fe', '#5b21b6', ), bar( 'job-d', t('Abbau', 'Teardown', 'Desmontaje'), 22, 24, '#ffe4e6', '#9f1239', ), ], }, ];
const emptyRows: Row[] = demoRows.map((row) => ({ ...row, timeEntries: [] }));
export default function Example() { const [rows, setRows] = useState( pack === 'empty' ? emptyRows : pack === 'busy' ? busyRows : demoRows, ); const [selected, setSelected] = useState( t( 'Balken ziehen oder zoomen', 'Drag bars or zoom days', 'Arrastra barras o haz zoom', ), ); return ( <> <ArcWidgetCalendarTimeline id="resources" data={{ timeZoneBalance: 0, height: '360px', lang, styles: chrome, dateSettings: { startDate: day(14), duration: 14, }, columns: [{ title: t('Team', 'Team', 'Equipo'), width: '180px' }], zoomSettings: { enabled: true, defaultDayWidth: '64px', minDayWidth: '20px', maxDayWidth: '160px', persist: false, }, items: rows.map((row) => ({ id: row.id, columns: [{ title: row.title, clickable: true }], timeEntries: row.timeEntries, })), }} onEntryClick={(rowIndex, entryIndex) => setSelected( rows[rowIndex]?.timeEntries[entryIndex]?.title ?? selected, ) } onLabelClick={(rowIndex) => setSelected(rows[rowIndex]?.title ?? selected) } onEntryDragSave={(rowIndex, entryIndex, start, rowChange) => { setRows((previous) => { const next = previous.map((row) => ({ ...row, timeEntries: [...row.timeEntries], })); const [item] = next[rowIndex].timeEntries.splice(entryIndex, 1); next[rowChange.row_index ?? rowIndex].timeEntries.push({ ...item, dateFrom: Number(start.dateFrom ?? item.dateFrom), dateTo: Number(start.dateTo ?? item.dateTo), }); return next; }); setSelected(t('Balken verschoben', 'Bar moved', 'Barra movida')); }} /> <p aria-live="polite">{selected}</p> </> ); }</code></pre>
Props del componente
id
ID opcional y estable de la instancia del widget. Sin especificarlo, React genera un ID.
data
Configuración de tipo ArcWidgetCalendarTimelineData. Pasa los cambios como objetos nuevos; gestiona los datos de negocio y la selección en el estado de React.
onAction
Fallback opcional (type: string, ...args: unknown[]) => unknown. El callback concreto tiene prioridad. Detalles: <a href="/docs/react/patterns/react-state-events">Estado y eventos</a>.
onEntryClick
Índice de la cita, y en Timeline también la fila del recurso.
onEntryClick?: (row_index: number, entry_index: number) => void;
onEntryDragSave
Fin del arrastre con los datos originales. No hay horas de destino completas nuevas; consulta las notas sobre persistencia.
onEntryDragSave?: (
row_index: number,
entry_index: number,
start_data: ArcWidgetCalendarTimelineDragStart,
row_change: ArcWidgetCalendarTimelineRowChange
) => void;
onLabelClick
Índices de la fila de recurso y la columna de etiqueta clicadas.
onLabelClick?: (row_index: number, column_index: number) => void;
onGhostClick
Posición del área libre clicada.
onGhostClick?: (row_index: number, column_value: number) => void;
Configuración
Los siguientes campos pertenecen a data. Los tamaños se indican como strings, los números y valores de tiempo según su tipo respectivo.
height
Altura del widget, p. ej. "320px". Los valores porcentuales necesitan un contenedor padre con altura definida.
Tipo: string.
timeZoneBalance
Corrección en horas; los ejemplos usan 0 y valores de día generados localmente.
Tipo: number | string.
dateSettings
Rango de fechas, cabeceras y marcados.
El tipo y los campos anidados están en ArcWidgetCalendarTimelineData, bajo tipos de datos.
columns
Columnas de etiqueta izquierdas de los recursos.
Tipo: ArcWidgetCalendarTimelineColumn[].
items
Entradas de la selección o de la representación; consulta el tipo de datos correspondiente.
Tipo: ArcWidgetCalendarTimelineItem[].
dayWidth
Ancho de un día en el eje de tiempo.
Tipo: string.
zoomSettings
Límites de zoom y controles.
El tipo y los campos anidados están en ArcWidgetCalendarTimelineData, bajo tipos de datos.
timeSettings
Rango horario y cuadrícula; las unidades son milisegundos.
Tipo: Record<string, unknown>.
columnWidth
Ancho del área de columna izquierda.
Tipo: string.
lang
Idioma de las etiquetas del calendario.
Tipo: string.
styles
Colores, espaciados y bordes comunes; los campos ofrecidos son específicos del widget.
Tipo: ArcWidgetCalendarTimelineStyles | string.
borders
Configuración histórica de bordes. Prefiere styles.borders, si el widget lo ofrece.
Tipo: ArcWidgetCalendarTimelineBorders.
borderRadius
Redondeo de esquinas.
Tipo: string.
Comportamiento y límites
- Para JSX en citas usa
customLayout. Los campos estándar title, subtitle y value se procesan como texto o HTML.
- Los valores de fecha son marcas de tiempo en milisegundos; las horas son milisegundos desde el inicio del día. Consulta <a href="/docs/react/patterns/react-dates">Fecha y hora</a>.
clickable: true activa la selección. Un índice de callback no es un ID de registro; resuélvelo mediante tu lista actual de entradas.
- Los callbacks de arrastre actuales contienen el estado original (
start_data), pero no horas de destino completas nuevas. Por eso el ejemplo establece draggable: false. Edita las citas mediante el estado de React hasta que exista un contrato de persistencia completo para arrastrar y soltar.
items contiene filas de recurso, dentro de las cuales están los timeEntries. columns define las columnas de etiqueta izquierdas.
onEntryClick(rowIndex, entryIndex) usa dos índices. dayWidth y zoomSettings controlan la escala.
Los campos ArcWidgetSlot admitidos permiten elementos JSX individuales, texto o descriptores de widget. Pasa texto externo como texto JSX; los strings HTML se interpretan como HTML. <a href="/docs/react/patterns/nested-widget-descriptors">Combinar contenidos</a>.
Tipos de datos
Estos tipos relacionados con el widget se exportan desde el paquete. También están disponibles tipos comunes como ArcWidgetSlot, ArcWidgetStyles y ArcReactWidgetProps. Las firmas de índice permiten extensiones; no garantizan que el widget evalúe campos arbitrarios.
export type ArcWidgetCalendarTimelineBorderLine = boolean | {
color?: string;
width?: string;
borderColor?: string;
borderWidth?: string;
borderSize?: string;
enabled?: boolean;
};
export interface ArcWidgetCalendarTimelineBorders { color?: string; width?: string; outer?: ArcWidgetCalendarTimelineBorderLine; columns?: ArcWidgetCalendarTimelineBorderLine; rows?: ArcWidgetCalendarTimelineBorderLine; }
export interface ArcWidgetCalendarTimelineStyles extends ArcWidgetStyles { borders?: ArcWidgetCalendarTimelineBorders; headerBackgroundColor?: string; groupBackgroundColor?: string; rowBackgroundColor?: string; mutedColor?: string; subtleColor?: string; dayStripes?: boolean | { enabled?: boolean; odd?: string; even?: string; oddColor?: string; evenColor?: string; }; }
export interface ArcWidgetCalendarTimelineColumn { title?: ArcWidgetSlot; width?: string; backgroundColor?: string; fontColor?: string; fontSize?: string; fontWeight?: string | number; [key: string]: unknown; }
export interface ArcWidgetCalendarTimelineItemColumn { title?: ArcWidgetSlot; subtitle?: ArcWidgetSlot; clickable?: boolean; alignX?: string; alignY?: string; fontSize?: string; fontWeight?: string | number; [key: string]: unknown; }
export interface ArcWidgetCalendarTimelineGhost { title?: ArcWidgetSlot; clickable?: boolean; position?: 'bottomRight' | 'timeEntry' | string; styles?: ArcWidgetStyles | string; [key: string]: unknown; }
export interface ArcWidgetCalendarTimelineEntryLabel { value?: string | number; width?: string | number; }
export interface ArcWidgetCalendarTimelineTimeEntry { id?: string | number; title?: string | ArcWidgetCalendarTimelineEntryLabel; subtitle?: string | ArcWidgetCalendarTimelineEntryLabel; value?: string; customLayout?: ArcWidgetSlot; dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; styles?: ArcWidgetStyles | string; clickable?: boolean; draggable?: boolean; tooltip?: { value?: ArcWidgetSlot; width?: string; maxWidth?: string; maxHeight?: string; position?: string; styles?: ArcWidgetStyles | string; [key: string]: unknown; }; [key: string]: unknown; }
export interface ArcWidgetCalendarTimelineItem { id: string | number; title?: ArcWidgetSlot; subtitle?: ArcWidgetSlot; columns?: ArcWidgetCalendarTimelineItemColumn[]; timeEntries?: ArcWidgetCalendarTimelineTimeEntry[]; items?: ArcWidgetCalendarTimelineItem[]; highlights?: Array<{ date?: unknown; dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; color?: string; [key: string]: unknown; }>; ghost?: ArcWidgetCalendarTimelineGhost; [key: string]: unknown; }
export interface ArcWidgetCalendarTimelineDragStart { dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; }
export interface ArcWidgetCalendarTimelineRowChange { start_row_index: number; row_index: number; }
export interface ArcWidgetCalendarTimelineData extends Omit<ArcWidgetBaseData, 'actions'> { height?: string; timeZoneBalance?: number | string; dateSettings?: { header?: { title?: ArcWidgetSlot | { value?: ArcWidgetSlot; customLayout?: unknown; alignX?: string; fontSize?: string; fontColor?: string; fontWeight?: string | number; backgroundColor?: string; [key: string]: unknown; }; days?: { compactRanges?: boolean; monthCompactBelow?: number; [key: string]: unknown; }; months?: unknown; weeks?: unknown; alignX?: string; sticky?: string; stickyPadding?: string; [key: string]: unknown; }; highlights?: Array<{ date?: unknown; weekday?: number; color?: string; applyToRows?: boolean; styles?: ArcWidgetCalendarTimelineStyles | string; [key: string]: unknown; }>; [key: string]: unknown; }; columns?: ArcWidgetCalendarTimelineColumn[]; items?: ArcWidgetCalendarTimelineItem[]; dayWidth?: string; zoomSettings?: { enabled?: boolean; defaultDayWidth?: string; minDayWidth?: string; maxDayWidth?: string; step?: number | string; persist?: boolean; controls?: { enabled?: boolean; [key: string]: unknown }; [key: string]: unknown; }; timeSettings?: Record<string, unknown>; columnWidth?: string; lang?: string; styles?: ArcWidgetCalendarTimelineStyles | string; borders?: ArcWidgetCalendarTimelineBorders; borderRadius?: string; }
export interface ArcWidgetCalendarTimelineProps extends ArcReactWidgetProps<ArcWidgetCalendarTimelineData> { onEntryClick?: (row_index: number, entry_index: number) => void; onEntryDragSave?: ( row_index: number, entry_index: number, start_data: ArcWidgetCalendarTimelineDragStart, row_change: ArcWidgetCalendarTimelineRowChange ) => void; onLabelClick?: (row_index: number, column_index: number) => void; onGhostClick?: (row_index: number, column_value: number) => void; }</code></pre>