Headless Core
El paquete trud-calendar-core provee toda la logica de calendario con cero dependencias y cero dependencia de React. Usalo para construir UIs de calendario en cualquier framework — Vue, Svelte, Angular, vanilla JS o server-side.
Instalacion
Sección titulada «Instalacion»npm install trud-calendar-coreQue incluye
Sección titulada «Que incluye»Todas las interfaces TypeScript y definiciones de tipos:
import type { CalendarEvent, CalendarView, CalendarState, CalendarAction, CalendarConfig, CalendarSlots, CalendarLocale, CalendarLabels, DateString, DateTimeString, PositionedEvent, EventSegment, RecurrenceRule, RecurrenceDay, TimedEventSegment, UndoStack, VirtualRange, WallToUtcOptions,} from "trud-calendar-core";Utilidades de fecha
Sección titulada «Utilidades de fecha»Funciones puras para matematica de fechas — sin efectos secundarios, completamente tree-shakeable:
import { parseDate, toDateString, toDateTimeString, addDays, addMonths, addWeeks, startOfWeek, startOfMonth, endOfMonth, isSameDay, isSameMonth, isToday, isBefore, isAfter, rangesOverlap, dateInRange, daysBetween, eachDayOfRange, getWeekDays, getMonthViewRange, getWeekViewRange, getVisibleRange, getTimeOfDay, getDurationHours, getHourLabels,} from "trud-calendar-core";Formato
Sección titulada «Formato»Formato con soporte de locale via la API Intl (formatters memoizados):
import { formatToolbarTitle, formatWeekdayShort, formatWeekdayNarrow, formatDayNumber, formatTime, formatTimeRange, formatAgendaDate, formatMonthDay,} from "trud-calendar-core";
formatTime("2026-03-13T14:30:00", "en-US"); // "2:30 PM"formatTime("2026-03-13T14:30:00", "de-DE"); // "14:30"formatAgendaDate("2026-03-13", "es-ES"); // "viernes, 13 de marzo"formatToolbarTitle("2026-03-13", "month", "ja-JP"); // "2026年3月"Utilidades de eventos
Sección titulada «Utilidades de eventos»Ordenamiento, filtrado, algoritmos de layout:
import { sortEvents, filterEventsInRange, getEventsForDay, isMultiDayEvent, partitionEvents, segmentMultiDayEvent, segmentTimedMultiDayEvent, getEventSegments, buildOverlapGroups, assignColumns, computeTimePositions, groupEventsByDate,} from "trud-calendar-core";Zonas horarias
Sección titulada «Zonas horarias»Soporte de zonas horarias IANA con cero dependencias, construido sobre Intl.DateTimeFormat:
import { getTimeZoneOffset, wallTimeToUtc, utcToWallTime, convertWallTime, listTimeZones, isValidTimeZone, getTimeZoneAbbreviation, getBrowserTimeZone, eventWallToDisplay, displayWallToEvent,} from "trud-calendar-core";import type { WallToUtcOptions } from "trud-calendar-core";
// Offset (minutos al este de UTC) en un instante especifico.getTimeZoneOffset("2026-01-15T12:00:00Z", "America/New_York"); // -300getTimeZoneOffset("2026-07-15T12:00:00Z", "America/New_York"); // -240 (EDT)
// Wall-clock ⇄ UTC. Manejo de DST por defecto:// - hueco (spring-forward, wall no existe) → desplaza hacia adelante// - solapamiento (fall-back, wall ocurre dos veces) → instante anteriorwallTimeToUtc("2026-03-13T09:00:00", "America/New_York"); // "2026-03-13T13:00:00Z"wallTimeToUtc("2026-03-08T02:30:00", "America/New_York", { invalid: "throw" });wallTimeToUtc("2026-11-01T01:30:00", "America/New_York", { ambiguous: "later" });
// Conversion directa entre zonas (preserva el instante absoluto).convertWallTime("2026-01-15T09:00:00", "America/New_York", "Europe/Berlin");// → "2026-01-15T15:00:00"
// Pickers y validacion.listTimeZones(); // Lista IANA + "UTC"isValidTimeZone("Mars/Olympus"); // falsegetTimeZoneAbbreviation("Asia/Tokyo"); // "GMT+9"getBrowserTimeZone(); // e.g., "America/Argentina/Buenos_Aires"Consulta Zonas horarias para la guia completa, incluyendo casos limite de DST y como interactuan event.timeZone y displayTimeZone.
Recurrencia
Sección titulada «Recurrencia»Motor de expansion RFC 5545 RRULE:
import { expandRecurringEvents, generateOccurrences,} from "trud-calendar-core";
// Expandir todos los eventos recurrentes en un rango de fechasconst expanded = expandRecurringEvents(events, "2026-03-01", "2026-03-31");
// Generar fechas de ocurrencia para una regla individualconst dates = generateOccurrences( { freq: "weekly", byDay: ["MO", "WE", "FR"] }, "2026-03-01", // fecha de inicio "2026-03-01", // inicio del rango "2026-03-31", // fin del rango);Consulta Recurrencia para documentacion detallada.
Undo/Redo
Sección titulada «Undo/Redo»Un stack de undo generico, agnostico de framework:
import { createUndoStack, pushState, undo, redo, canUndo, canRedo,} from "trud-calendar-core";import type { UndoStack } from "trud-calendar-core";
let stack = createUndoStack(initialEvents); // UndoStack<CalendarEvent[]>stack = pushState(stack, newEvents); // snapshot del estado actualstack = undo(stack); // volver atrasstack = redo(stack); // ir adelantecanUndo(stack); // booleancanRedo(stack); // booleanEl stack es inmutable — cada operacion devuelve un nuevo UndoStack. El historial maximo por defecto es 30 estados.
Virtualizacion
Sección titulada «Virtualizacion»Filtrado de eventos basado en viewport para datasets grandes:
import { filterVisibleEvents, scrollToViewportRange,} from "trud-calendar-core";import type { VirtualRange } from "trud-calendar-core";
// Filtrar PositionedEvent[] a solo los visibles en el viewportconst visible = filterVisibleEvents(positioned, viewportTop, viewportBottom, overscan);
// Convertir posicion de scroll a rango de horasconst range: VirtualRange = scrollToViewportRange( scrollTop, // offset de scroll actual containerHeight, // altura visible del contenedor totalHeight, // altura total scrolleable dayStartHour, // ej: 0 dayEndHour, // ej: 24);// range.startHour, range.endHourGestion de estado
Sección titulada «Gestion de estado»Un reducer para el estado de navegacion del calendario:
import { calendarReducer, createInitialState,} from "trud-calendar-core";
const state = createInitialState("2026-03-13", "month");// { currentDate: "2026-03-13", view: "month" }
const next = calendarReducer(state, { type: "NAVIGATE_NEXT" });// { currentDate: "2026-04-13", view: "month" }Acciones: NAVIGATE_PREV, NAVIGATE_NEXT, NAVIGATE_TODAY, SET_DATE, SET_VIEW.
Constantes
Sección titulada «Constantes»import { DEFAULT_LABELS, DEFAULT_LOCALE, DEFAULT_VIEW, VIEWS, // ["month", "week", "day", "agenda"] DEFAULT_DAY_START_HOUR, // 0 DEFAULT_DAY_END_HOUR, // 24 HOURS_IN_DAY, // 24 MINUTES_IN_HOUR, // 60 MINUTES_IN_DAY, // 1440} from "trud-calendar-core";Exportar iCal
Sección titulada «Exportar iCal»Exporta eventos al formato estandar .ics:
import { eventsToICal, downloadICal } from "trud-calendar-core";
// Obtener string .icsconst icsContent = eventsToICal(events, "Mi Calendario");
// Descargar en el navegadordownloadICal(events, "mis-eventos.ics");Soporta eventos de dia completo, reglas de recurrencia (RRULE) y fechas de excepcion (EXDATE).
Ejemplo: Construir un calendario en vanilla JS
Sección titulada «Ejemplo: Construir un calendario en vanilla JS»import { getVisibleRange, filterEventsInRange, computeTimePositions, eachDayOfRange, formatTime, formatWeekdayShort,} from "trud-calendar-core";
// Obtener el rango de fechas visible para una vista de semana empezando en lunesconst range = getVisibleRange("2026-03-13", "week", 1);const days = eachDayOfRange(range.start, range.end);
// Filtrar eventosconst visible = filterEventsInRange(myEvents, range.start, range.end);
// Calcular posiciones de la grilla de tiempo para un diaconst dayEvents = visible.filter(e => e.start.startsWith("2026-03-13"));const positioned = computeTimePositions(dayEvents, 8, 20);
// Renderizarfor (const { event, top, height, column, totalColumns } of positioned) { const el = document.createElement("div"); el.textContent = `${formatTime(event.start, "en-US")} ${event.title}`; el.style.position = "absolute"; el.style.top = `${top}%`; el.style.height = `${height}%`; el.style.left = `${(column / totalColumns) * 100}%`; el.style.width = `${100 / totalColumns}%`; container.appendChild(el);}