Premium Widgets
Custom Calendar (Week)
CalendarWeek en React
Muestra citas en una vista semanal con cuadrícula horaria. El ejemplo mantiene la selección y las citas en la aplicación.
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 { ArcWidgetCalendarWeek } 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 locale = lang === 'en' ? 'en-US' : lang === 'es' ? 'es-ES' : 'de-DE'; const day = (offset: number) => new Date(2026, 8, 14 + offset).getTime(); const hour = (value: number) => value * 3600000;
const chrome = { backgroundColor: '#ffffff', fontColor: '#18181b', mutedColor: '#52525b', borders: { color: '#e4e4e7', outer: true, columns: true, rows: true }, };
const look = (backgroundColor: string, color: string) => ({ backgroundColor, color, fontColor: color, });
const teal = '#115e59'; const tealFill = '#ccfbf1'; const travelFill = '#99f6e4'; const pauseFill = '#f4f4f5'; const pauseInk = '#52525b';
type Entry = { id: string; title: string; dateFrom: number; dateTo: number; timeFrom: number; timeTo: number; clickable: true; draggable: true; styles: ReturnType<typeof look>; insetBorder: { enabled: true; color: string }; segments?: Array<{ title: string; linked?: boolean; dateFrom: number; dateTo: number; timeFrom: number; timeTo: number; styles: ReturnType<typeof look>; insetBorder: { enabled: true; color: string }; splits?: Array<{ title: string; timeFrom: number; timeTo: number; styles: ReturnType<typeof look>; }>; }>; };
const event = ( id: string, title: string, offset: number, from: number, to: number, backgroundColor: string, color: string, ): Entry => ({ id, title, dateFrom: day(offset), dateTo: day(offset), timeFrom: hour(from), timeTo: hour(to), clickable: true, draggable: true, styles: look(backgroundColor, color), insetBorder: { enabled: true, color }, });
const siteVisit = (): Entry => ({ id: 'visit', title: t('Kundentermin', 'Site visit', 'Visita'), dateFrom: day(3), dateTo: day(3), timeFrom: hour(11), timeTo: hour(14), clickable: true, draggable: true, styles: look(tealFill, teal), insetBorder: { enabled: true, color: teal }, segments: [ { title: t('Anfahrt', 'Travel there', 'Ida'), linked: false, dateFrom: day(2), dateTo: day(2), timeFrom: hour(16), timeTo: hour(17), styles: look(travelFill, teal), insetBorder: { enabled: true, color: teal }, }, { title: t('Hauptarbeit', 'On site', 'Trabajo principal'), linked: true, dateFrom: day(3), dateTo: day(3), timeFrom: hour(11), timeTo: hour(14), styles: look(tealFill, teal), insetBorder: { enabled: true, color: teal }, splits: [ { title: t('Pause', 'Break', 'Pausa'), timeFrom: hour(12) + 30 * 60 * 1000, timeTo: hour(13), styles: look(pauseFill, pauseInk), }, ], }, { title: t('Abfahrt', 'Travel back', 'Vuelta'), linked: false, dateFrom: day(4), dateTo: day(4), timeFrom: hour(8), timeTo: hour(9), styles: look(travelFill, teal), insetBorder: { enabled: true, color: teal }, }, ], });
const demoEntries: Entry[] = [ event( 'plan', t('Planung', 'Planning', 'Planificación'), 0, 9, 10, '#d1fae5', '#065f46', ), event( 'workshop', t('Workshop', 'Workshop', 'Taller'), 1, 10, 12, '#fef3c7', '#92400e', ), event( 'review', t('Review', 'Review', 'Revisión'), 2, 14, 15, '#ffe4e6', '#9f1239', ), siteVisit(), ];
const busyEntries: Entry[] = [ ...demoEntries, event( 'stand', t('Standabnahme', 'Booth check', 'Revisión stand'), 4, 10, 12, '#ede9fe', '#5b21b6', ), event('retro', t('Retro', 'Retro', 'Retro'), 4, 15, 16, '#e0f2fe', '#075985'), ];
export default function Example() { const [entries, setEntries] = useState( pack === 'empty' ? [] : pack === 'busy' ? busyEntries : demoEntries, ); const [selected, setSelected] = useState( t( 'Termin ziehen oder anklicken', 'Drag or click an event', 'Arrastra o pulsa un evento', ), ); return ( <> <ArcWidgetCalendarWeek id="week" data={{ timeZoneBalance: 0, height: '480px', lang, styles: chrome, dateSettings: { startDate: day(0), duration: 7, day: { clickable: true }, }, timeSettings: { timeStart: hour(8), duration: hour(10), }, timeEntries: entries, }} onEntryClick={() => setSelected( t('Termin ausgewählt', 'Event selected', 'Evento seleccionado'), ) } onDayClick={(date) => setSelected(new Date(date).toLocaleDateString(locale)) } onEntryDragSave={(index, start) => { setEntries((previous) => { if (index >= previous.length || previous[index].segments) return previous; return previous.map((entry, i) => i === index ? { ...entry, dateFrom: Number(start.dateFrom ?? entry.dateFrom), dateTo: Number(start.dateTo ?? entry.dateTo), timeFrom: Number(start.timeFrom ?? entry.timeFrom), timeTo: Number(start.timeTo ?? entry.timeTo), } : entry, ); }); setSelected(t('Termin verschoben', 'Event moved', 'Evento movido')); }} /> <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 ArcWidgetCalendarWeekData. 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?: (entry_index: number) => void;
onDayClick
Fecha del día seleccionado como marca de tiempo en milisegundos.
onDayClick?: (date_millis: number) => void;
onEntryDragSave
Fin del arrastre con los datos originales. No hay horas de destino completas nuevas; consulta las notas sobre persistencia.
onEntryDragSave?: (entry_index: number, start_data: ArcWidgetCalendarWeekDragStart) => void;
onDailyEntryDragSave
Fin del arrastre de una cita de todo el día con los datos originales.
onDailyEntryDragSave?: (entry_index: number, start_data: ArcWidgetCalendarWeekDragStart) => void;
onCreate
Nueva selección de fecha/hora. La validación y el guardado los realiza la aplicación.
onCreate?: (values: {
dateFrom?: number;
dateTo?: number;
timeFrom?: number;
timeTo?: number;
[key: string]: unknown;
}) => 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.
styles
Colores, espaciados y bordes comunes; los campos ofrecidos son específicos del widget.
Tipo: ArcWidgetCalendarWeekStyles | string.
weekdaySettings
Selección de una semana calendario y del año.
Tipo: { week?: number; year?: number; [key: string]: unknown }.
weekStart
Inicio de semana alternativo.
Tipo: unknown.
dateSettings
Rango de fechas, cabeceras y marcados.
Tipo: ArcWidgetCalendarDateSettings.
timeZoneBalance
Corrección en horas; los ejemplos usan 0 y valores de día generados localmente.
Tipo: number | string.
timeSettings
Rango horario y cuadrícula; las unidades son milisegundos.
Tipo: ArcWidgetCalendarTimeSettings.
currentTime
Representación de la hora actual.
Tipo: string.
lang
Idioma de las etiquetas del calendario.
Tipo: string.
timeSlotWidth
Ancho de una columna de día.
Tipo: string.
timeSlotHeight
Altura de una franja horaria.
Tipo: string.
allDayHeight
Altura del área para citas de todo el día.
Tipo: string.
createNew
Selección para crear nuevas citas. El guardado se realiza mediante onCreate.
Tipo: ArcWidgetCalendarCreateNew.
timeEntries
Citas con valores de fecha, horas y contenidos.
Tipo: ArcWidgetCalendarTimeEntry[].
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.
- El rango horario visible se configura mediante
timeSettings.timeStart y timeSettings.duration en milisegundos. Los campos históricos from y to no tienen efecto aquí.
onCreate entrega los valores de la selección. Tu aplicación los valida, asigna un ID y adopta la nueva cita.
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 ArcWidgetCalendarWeekBorderLine = boolean | {
color?: string;
width?: string;
borderColor?: string;
borderWidth?: string;
borderSize?: string;
enabled?: boolean;
};
export interface ArcWidgetCalendarWeekBorders { color?: string; width?: string; outer?: ArcWidgetCalendarWeekBorderLine; columns?: ArcWidgetCalendarWeekBorderLine; rows?: ArcWidgetCalendarWeekBorderLine; }
export interface ArcWidgetCalendarWeekStyles extends ArcWidgetStyles { borders?: ArcWidgetCalendarWeekBorders; headerBackgroundColor?: string; mutedColor?: string; }
export interface ArcWidgetCalendarHighlight { date?: unknown; weekday?: number; color?: string; styles?: ArcWidgetCalendarWeekStyles | string; [key: string]: unknown; }
export interface ArcWidgetCalendarWeekDay { clickable?: boolean; [key: string]: unknown; }
export interface ArcWidgetCalendarDateSettings { startDate?: unknown; endDate?: unknown; duration?: number; highlights?: ArcWidgetCalendarHighlight[]; day?: ArcWidgetCalendarWeekDay; header?: { days?: unknown; months?: unknown; weeks?: unknown; [key: string]: unknown; }; month?: number; year?: number; [key: string]: unknown; }
export interface ArcWidgetCalendarTimeSettings { from?: number; to?: number; timeStart?: number; duration?: number; [key: string]: unknown; }
export interface ArcWidgetCalendarPlaceOffset { days?: number; time?: number; }
export interface ArcWidgetCalendarPlaceSplit { title?: string; subtitle?: string; value?: string; styles?: ArcWidgetStyles | string; timeFrom?: unknown; timeTo?: unknown; offset?: number; duration?: number; [key: string]: unknown; }
export interface ArcWidgetCalendarPlaceSegment { duration?: number; linked?: boolean; offset?: ArcWidgetCalendarPlaceOffset; title?: string; subtitle?: string; value?: string; customLayout?: ArcWidgetSlot; styles?: ArcWidgetStyles | string; insetBorder?: unknown; dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; splits?: ArcWidgetCalendarPlaceSplit[]; [key: string]: unknown; }
export interface ArcWidgetCalendarPlaceItem { active?: boolean; offset?: ArcWidgetCalendarPlaceOffset; splits?: ArcWidgetCalendarPlaceSplit[]; duration?: number; title?: string; subtitle?: string; value?: string; customLayout?: ArcWidgetSlot; styles?: ArcWidgetStyles | string; insetBorder?: unknown; segments?: ArcWidgetCalendarPlaceSegment[]; [key: string]: unknown; }
export interface ArcWidgetCalendarCreateNew { item?: ArcWidgetCalendarPlaceItem | null; [key: string]: unknown; }
export interface ArcWidgetCalendarWeekDragStart { dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; }
export interface ArcWidgetCalendarTimeEntry { id?: string | number; title?: string; subtitle?: string; value?: string; customLayout?: ArcWidgetSlot; dateFrom?: unknown; dateTo?: unknown; timeFrom?: unknown; timeTo?: unknown; styles?: ArcWidgetStyles | string; clickable?: boolean; draggable?: boolean; segments?: ArcWidgetCalendarPlaceSegment[]; tooltip?: { value?: ArcWidgetSlot; width?: string; maxWidth?: string; maxHeight?: string; position?: string; styles?: ArcWidgetStyles | string; [key: string]: unknown; }; [key: string]: unknown; }
export interface ArcWidgetCalendarWeekData extends Omit<ArcWidgetBaseData, 'actions'> { height?: string; styles?: ArcWidgetCalendarWeekStyles | string; weekdaySettings?: { week?: number; year?: number; [key: string]: unknown }; weekStart?: unknown; dateSettings?: ArcWidgetCalendarDateSettings; timeZoneBalance?: number | string; timeSettings?: ArcWidgetCalendarTimeSettings; currentTime?: string; lang?: string; timeSlotWidth?: string; timeSlotHeight?: string; allDayHeight?: string; createNew?: ArcWidgetCalendarCreateNew; timeEntries?: ArcWidgetCalendarTimeEntry[]; }
export interface ArcWidgetCalendarWeekProps extends ArcReactWidgetProps<ArcWidgetCalendarWeekData> { onEntryClick?: (entry_index: number) => void; onDayClick?: (date_millis: number) => void; onEntryDragSave?: (entry_index: number, start_data: ArcWidgetCalendarWeekDragStart) => void; onDailyEntryDragSave?: (entry_index: number, start_data: ArcWidgetCalendarWeekDragStart) => void; onCreate?: (values: { dateFrom?: number; dateTo?: number; timeFrom?: number; timeTo?: number; [key: string]: unknown; }) => void; }</code></pre>