Ir al contenido

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.

Ventana de terminal
npm install trud-calendar-core

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";

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 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月"

Ordenamiento, filtrado, algoritmos de layout:

import {
sortEvents,
filterEventsInRange,
getEventsForDay,
isMultiDayEvent,
partitionEvents,
segmentMultiDayEvent,
segmentTimedMultiDayEvent,
getEventSegments,
buildOverlapGroups,
assignColumns,
computeTimePositions,
groupEventsByDate,
} from "trud-calendar-core";

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"); // -300
getTimeZoneOffset("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 anterior
wallTimeToUtc("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"); // false
getTimeZoneAbbreviation("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.

Motor de expansion RFC 5545 RRULE:

import {
expandRecurringEvents,
generateOccurrences,
} from "trud-calendar-core";
// Expandir todos los eventos recurrentes en un rango de fechas
const expanded = expandRecurringEvents(events, "2026-03-01", "2026-03-31");
// Generar fechas de ocurrencia para una regla individual
const 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.

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 actual
stack = undo(stack); // volver atras
stack = redo(stack); // ir adelante
canUndo(stack); // boolean
canRedo(stack); // boolean

El stack es inmutable — cada operacion devuelve un nuevo UndoStack. El historial maximo por defecto es 30 estados.

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 viewport
const visible = filterVisibleEvents(positioned, viewportTop, viewportBottom, overscan);
// Convertir posicion de scroll a rango de horas
const 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.endHour

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.

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";

Exporta eventos al formato estandar .ics:

import { eventsToICal, downloadICal } from "trud-calendar-core";
// Obtener string .ics
const icsContent = eventsToICal(events, "Mi Calendario");
// Descargar en el navegador
downloadICal(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 lunes
const range = getVisibleRange("2026-03-13", "week", 1);
const days = eachDayOfRange(range.start, range.end);
// Filtrar eventos
const visible = filterEventsInRange(myEvents, range.start, range.end);
// Calcular posiciones de la grilla de tiempo para un dia
const dayEvents = visible.filter(e => e.start.startsWith("2026-03-13"));
const positioned = computeTimePositions(dayEvents, 8, 20);
// Renderizar
for (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);
}