Ir al contenido

Hooks

Todos los hooks deben usarse dentro de un componente <CalendarProvider>. Si estas usando el componente <Calendar>, el provider ya esta configurado.

Orquestador principal — combina estado, eventos y navegacion.

import { useCalendar } from "trud-calendar";
const {
currentDate, // DateString — fecha enfocada actual
view, // CalendarView — vista actual
events, // CalendarEvent[] — todos los eventos
visibleEvents, // CalendarEvent[] — filtrados al rango visible
visibleRange, // { start: DateString, end: DateString }
locale, // string — locale BCP 47
prev, // () => void — ir al periodo anterior
next, // () => void — ir al siguiente periodo
today, // () => void — ir a hoy
setDate, // (date: DateString) => void
setView, // (view: CalendarView) => void
} = useCalendar();

Navegacion de fechas y cambio de vistas. Mas ligero que useCalendar — usalo cuando solo necesitas controles de navegacion.

import { useNavigation } from "trud-calendar";
const {
currentDate, // DateString
view, // CalendarView
formattedDate, // string — titulo con formato de locale (ej: "marzo 2026")
prev, // () => void
next, // () => void
today, // () => void
setDate, // (date: DateString) => void
setView, // (view: CalendarView) => void
} = useNavigation();

Accede a los datos de eventos del rango visible actual.

import { useEvents } from "trud-calendar";
const {
visibleEvents, // CalendarEvent[] — ordenados, filtrados al rango visible
getForDay, // (date: DateString) => CalendarEvent[]
partitioned, // { allDay: CalendarEvent[], timed: CalendarEvent[] }
segments, // EventSegment[] — segmentos de eventos multi-dia
groupedByDate, // Map<DateString, CalendarEvent[]>
} = useEvents();

Ejemplo: Obtener eventos de un dia especifico

Sección titulada «Ejemplo: Obtener eventos de un dia especifico»
const { getForDay } = useEvents();
const eventosDeHoy = getForDay("2026-03-13");

Algoritmo de column-packing para eventos solapados. Usado internamente por la grilla de tiempo de semana/dia — usalo tu mismo cuando construyas layouts personalizados basados en tiempo.

import { useEventLayout } from "trud-calendar";
const positioned: PositionedEvent[] = useEventLayout(timedEvents);

Cada PositionedEvent contiene:

interface PositionedEvent {
event: CalendarEvent;
column: number; // Indice de columna (base 0) en grupo de solapamiento
totalColumns: number; // Total de columnas en grupo de solapamiento
top: number; // % desde arriba (0-100)
height: number; // % de altura (0-100)
}

Usa estos valores para posicionar eventos con CSS:

{positioned.map(({ event, column, totalColumns, top, height }) => (
<div
key={event.id}
style={{
position: "absolute",
top: `${top}%`,
height: `${height}%`,
left: `${(column / totalColumns) * 100}%`,
width: `${100 / totalColumns}%`,
}}
>
{event.title}
</div>
))}

Reloj en vivo para indicadores de “hora actual”. Se actualiza cada 60 segundos por defecto.

import { useCurrentTime } from "trud-calendar";
const {
now, // string — datetime ISO del momento actual
today, // string — YYYY-MM-DD de hoy
timeOfDay, // number — hora fraccional (14.5 = 2:30 PM)
} = useCurrentTime();
// Intervalo personalizado: actualizar cada 10 segundos
const time = useCurrentTime(10_000);
const { timeOfDay } = useCurrentTime();
const topPercent = ((timeOfDay - dayStartHour) / (dayEndHour - dayStartHour)) * 100;
<div
className="absolute left-0 right-0 border-t-2 border-red-500 z-10"
style={{ top: `${topPercent}%` }}
/>

Funciones de formato de fecha con soporte de locale, basadas en la API Intl.

import { useDateFormat } from "trud-calendar";
const fmt = useDateFormat();
fmt.toolbarTitle("2026-03-13", "month"); // "marzo 2026" (con locale es-ES)
fmt.time("2026-03-13T14:30:00"); // "14:30"
fmt.timeRange(start, end); // "14:30 – 15:00"
fmt.weekdayShort("2026-03-13"); // "vie"
fmt.weekdayNarrow("2026-03-13"); // "V"
fmt.dayNumber("2026-03-13"); // "13"
fmt.agendaDate("2026-03-13"); // "viernes, 13 de marzo"
fmt.monthDay("2026-03-13"); // "13 mar"

Todas las funciones respetan el locale configurado en el CalendarProvider.

Hook de drag basado en Pointer Events para construir interacciones de arrastre personalizadas. Usado internamente por WeekView y MonthView.

import { useEventDrag } from "trud-calendar";
const {
dragState, // DragState | null — estado actual del drag
onPointerDown, // (e: React.PointerEvent, event: CalendarEvent) => void
isDragging, // boolean
didDrag, // React.RefObject<boolean> — true si ocurrio un drag (suprime click)
} = useEventDrag({
mode: "time", // "time" para semana/dia, "date" para mes
onEventDrop, // (event, newStart, newEnd) => void
enabled: true, // boolean
snapDuration: 15, // incremento de snap en minutos
dragConstraint, // (event, newStart, newEnd) => boolean — opcional
});

DragState contiene:

  • event — el evento siendo arrastrado
  • ghostX, ghostY — posicion del cursor para renderizar el ghost de drag
  • targetDay — la columna de dia sobre la que esta el cursor (detectada via atributos data-day)

Soporta mouse y touch mediante la API de Pointer Events.

Auto-scroll del contenedor cuando el puntero se acerca al borde superior o inferior. Integrado en la vista semana/dia durante drag, resize y seleccion — solo necesitas este hook si construyes layouts scrollables personalizados.

import { useAutoScroll } from "trud-calendar";
const { handleAutoScroll, stopAutoScroll } = useAutoScroll({
containerRef: scrollRef, // React.RefObject<HTMLElement>
enabled: isDragging, // activar solo durante interacciones
});
// Llamar en cada pointermove:
handleAutoScroll(e.clientY);
// Llamar en pointerup:
stopAutoScroll();

Hook de navegacion por teclado que implementa el patron WAI-ARIA roving tabindex grid.

import { useGridKeyboard } from "trud-calendar";
const grid = useGridKeyboard({
cols: 7,
rows: 24,
onActivate: (row, col) => { /* Enter/Space presionado */ },
onEscape: () => { /* Escape presionado */ },
});

Devuelve:

  • registerCell(row, col) — callback ref para celdas de la grilla
  • getTabIndex(row, col) — devuelve 0 para la celda activa, -1 para las demas
  • handleKeyDown — manejador de eventos de teclado
  • handleFocus(row, col) — manejador de eventos de foco

Envuelve un CalendarEvent[] con un stack completo de undo/redo. Toma snapshots automaticamente antes de onEventDrop y onEventResize, y registra atajos de teclado Ctrl+Z / Ctrl+Shift+Z (Ctrl+Y).

import { useUndoableEvents } from "trud-calendar";
const {
events, // CalendarEvent[] — estado actual
setEvents, // (events: CalendarEvent[]) => void — actualizar + auto-snapshot
onEventDrop, // (event, newStart, newEnd) => void — snapshot antes de aplicar
onEventResize, // (event, newStart, newEnd) => void — snapshot antes de aplicar
undo, // () => void
redo, // () => void
canUndo, // boolean
canRedo, // boolean
snapshot, // () => void — snapshot manual (ej: antes de una actualizacion masiva)
} = useUndoableEvents({
initialEvents: myEvents,
maxHistory: 30, // opcional, por defecto 30
});
function App() {
const undoable = useUndoableEvents({ initialEvents: myEvents });
return (
<>
<div className="flex gap-2 mb-2">
<button onClick={undoable.undo} disabled={!undoable.canUndo}>Deshacer</button>
<button onClick={undoable.redo} disabled={!undoable.canRedo}>Rehacer</button>
</div>
<Calendar
events={undoable.events}
enableDnD
onEventDrop={undoable.onEventDrop}
onEventResize={undoable.onEventResize}
/>
</>
);
}

Gestion de multi-seleccion de eventos con seguimiento basado en Set. Soporta toggle (Ctrl+click), seleccion por rango (Shift+click), seleccionar todo y limpiar.

import { useEventSelection } from "trud-calendar";
const {
selectedIds, // Set<string> — IDs de eventos seleccionados
isSelected, // (id: string) => boolean
select, // (id: string) => void — seleccion individual (limpia otros)
toggle, // (id: string) => void — comportamiento Ctrl+click
rangeSelect, // (id: string, sortedIds: string[]) => void — Shift+click
clearSelection, // () => void
selectAll, // (ids: string[]) => void
lastSelectedId, // string | null — ancla para seleccion por rango
} = useEventSelection();

El componente <Calendar> usa SelectionProvider internamente, que envuelve useEventSelection con deteccion de teclas modificadoras. Los eventos seleccionados muestran un resaltado visual con ring.

Hook de layout adaptativo usando ResizeObserver. Devuelve flags de breakpoint y el numero recomendado de columnas de dias visibles.

import { useResponsiveView } from "trud-calendar";
const ref = useRef<HTMLDivElement>(null);
const {
isMobile, // boolean — contenedor < 640px
isTablet, // boolean — contenedor 640px–1024px
containerWidth, // number — ancho medido en px
visibleDays, // 1 (movil) | 3 (tablet) | 7 (escritorio)
} = useResponsiveView(ref);

El componente <Calendar> lo usa internamente para adaptar las columnas de la vista semanal y el tamano de celdas en la vista mensual.

Deteccion de swipe tactil para navegacion prev/next. Solo se activa para pointerType === "touch" — los arrastres de mouse se ignoran.

import { useSwipeNavigation } from "trud-calendar";
const swipe = useSwipeNavigation({
onSwipeLeft: () => next(), // navegar adelante
onSwipeRight: () => prev(), // navegar atras
threshold: 50, // min px horizontal (default: 50)
maxVertical: 30, // max px vertical (default: 30)
});
// Aplicar al elemento contenedor:
<div
onPointerDown={swipe.onPointerDown}
onPointerMove={swipe.onPointerMove}
onPointerUp={swipe.onPointerUp}
>
{/* contenido del calendario */}
</div>

Seguimiento de scroll basado en viewport para filtrar eventos visibles. Util para datasets grandes donde renderizar todos los eventos es costoso.

import { useVirtualScroll } from "trud-calendar";
const {
viewportTop, // number — borde superior como % (0–100)
viewportBottom, // number — borde inferior como % (0–100)
isVirtualized, // boolean — true cuando esta habilitado
} = useVirtualScroll({
containerRef: scrollRef,
totalHours: 24,
enabled: true, // default: false
overscanHours: 2, // horas extra a renderizar arriba/abajo del viewport
});

Combinar con filterVisibleEvents() de trud-calendar-core para eliminar eventos fuera de pantalla:

import { filterVisibleEvents } from "trud-calendar-core";
const visible = filterVisibleEvents(positioned, viewportTop, viewportBottom);

Obtiene eventos de una o mas fuentes basandose en el rango de fechas visible. Cachea resultados por rango y deduplica peticiones.

import { useEventSources, useCalendar } from "trud-calendar";
const { visibleRange } = useCalendar();
const { events, isLoading, refetch } = useEventSources({
sources: [
{ url: "/api/events" },
{ fetcher: async (start, end) => {
const res = await fetch(`/api/team-events?from=${start}&to=${end}`);
return res.json();
}},
],
start: visibleRange.start,
end: visibleRange.end,
});
// Pass to Calendar
<Calendar events={events} />

Cada fuente puede ser una url (los parametros start y end se agregan automaticamente) o una funcion fetcher. Los resultados de todas las fuentes se combinan en un solo array.

Devuelve:

  • events — eventos combinados de todas las fuentes
  • isLoading — true mientras alguna fuente esta cargando
  • refetch() — limpia el cache y re-obtiene todas las fuentes

Permite arrastrar elementos desde fuera del calendario hacia franjas horarias. Usa la API nativa de HTML5 Drag and Drop.

import { useExternalDrag } from "trud-calendar";
const { makeDraggable, dropTargetProps } = useExternalDrag({
onExternalDrop: (info) => {
console.log(info.day); // "2026-03-25"
console.log(info.start); // "2026-03-25T10:00:00"
console.log(info.resourceId); // "room-a" (if resource view)
console.log(info.data); // { taskId: "123", title: "My Task" }
},
dayStartHour: 8,
dayEndHour: 20,
snapDuration: 15,
});
// Hacer arrastrables los items del sidebar
<div {...makeDraggable({ taskId: "123", title: "My Task" })}>
Arrastra al calendario
</div>
// Envolver el calendario para aceptar drops
<div {...dropTargetProps}>
<Calendar events={events} />
</div>

ExternalDropInfo contiene:

  • day — la fecha destino
  • start — hora de inicio ajustada al snap
  • resourceId — ID del recurso si se solta en una columna de recurso
  • data — el objeto de datos adjuntado via makeDraggable