kore-ui / calendar
Calendario de eventos y recursos para Laravel con Livewire 4, sobre kore-ui
Requires
- php: ^8.2
- illuminate/contracts: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- kore-ui/kore-ui: ^2.4
- livewire/livewire: ^4.0
- nesbot/carbon: ^3.0
- rlanvin/php-rrule: ^2.5
- symfony/http-foundation: ^7.0|^8.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0|^5.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-16 23:59:37 UTC
README
Calendario de eventos y recursos para Laravel + Livewire 4, construido sobre kore-ui: vistas mes, semana, día, agenda, columnas por recurso y timeline; arrastrar, redimensionar y seleccionar; formulario de evento; series recurrentes; horario laboral y conflictos; exportar e importar .ics.
- El layout se calcula en PHP y se pinta en Blade. Alpine solo previsualiza los gestos; lo que manda el navegador se vuelve a validar en el servidor.
- Sin dependencias JavaScript de terceros: el bundle propio pesa menos de 5 kB gzip.
- Temas con los tokens
--kore-*de kore-ui, dark mode incluido. - English and Spanish: textos y fechas en el idioma de la aplicación (o el que configures), con
lang/publicable. Ver Idioma y traducciones. - Se usa de dos formas: el componente
<x-kore::calendar>en cualquier página Blade (solo lectura, navegación con enlaces) o la clase baseKoreCalendar, un componente Livewire con estado, edición y eventos desde tu base de datos.
Estado: pre-release (
0.x, sin versión publicada). La API puede cambiar hasta la primera release; los cambios están en CHANGELOG.md.
Requisitos
| Versión | |
|---|---|
| PHP | 8.2 o superior (la CI prueba 8.2 a 8.4; Laravel 13 no se prueba en 8.2) |
| Laravel | 12 o 13 |
| Livewire | 4 |
kore-ui (kore-ui/kore-ui) |
2.3 o superior, con su layout configurado (@koreScripts, tema, Tailwind v4) |
nesbot/carbon 3 y rlanvin/php-rrule 2.5 se instalan solos con Composer. ext-intl es opcional: sin ella las fechas salen igual, y con ella el orden alfabético de títulos y recursos respeta el locale.
Instalación
composer require kore-ui/calendar
Sin release publicada, en el monorepo se instala como path repository, igual que kore-ui ("kore-ui/calendar": "@dev" y un repositorio {"type": "path", "url": "../kore-calendar"} en composer.json, como en demo/).
CSS. En resources/css/app.css, junto a lo de kore-ui:
@import '../../vendor/kore-ui/calendar/resources/css/kore-calendar.css'; @source '../../vendor/kore-ui/calendar/resources/**/*.blade.php'; @source '../../vendor/kore-ui/calendar/src/**/*.php';
El @import va después del tema de kore-ui (kore-theme.css): ver Theming.
Layout. Lo de kore-ui (@koreScripts antes de @livewireScripts) y, para el formulario de evento, el diálogo de series y los avisos, los dos gestores:
<livewire:kore-overlay-manager /> <livewire:kore-feedback-manager />
El JavaScript del calendario lo carga el propio componente cuando aparece (con @assets): no hay directiva que añadir.
Config (opcional).
php artisan vendor:publish --tag=kore-calendar-config # solo lo que cambias: se funde con el del paquete php artisan vendor:publish --tag=kore-calendar-views # vistas (componentes y Livewire) para sobrescribirlas
Ejemplo mínimo: componente
<x-kore::calendar :events="[ ['id' => 1, 'title' => 'Congreso', 'start' => '2026-10-14', 'end' => '2026-10-17'], ['id' => 2, 'title' => 'Revisión', 'start' => '2026-10-15 10:00', 'end' => '2026-10-15 11:30', 'color' => 'chart-3'], ]" view="month" timezone="Europe/Madrid" />
Ejemplo mínimo: KoreCalendar
use Carbon\CarbonImmutable; use KoreUi\Calendar\KoreCalendar; class TeamCalendar extends KoreCalendar { protected function configure(): void { $this->views(['month', 'week', 'list'])->timezone('Europe/Madrid'); } protected function events(CarbonImmutable $from, CarbonImmutable $to): iterable { return Meeting::query() ->where('team_id', auth()->user()->team_id) // el scope del tenant va aquí ->overlapping($from, $to)->get()->map->toCalendarEvent(); } }
<livewire:team-calendar />
La vista y la fecha quedan en la URL (?view=, ?date=). Para mover, redimensionar, crear y editar eventos, ->editable()->selectable()->eventForm() y los hooks persistMove(), persistResize(), createEvent()…: ver KoreCalendar.
Seguridad, en corto. events() es la frontera de acceso: mover, editar o eliminar un evento lo busca entre los que events() devuelve, así que lo que no devuelve no se puede tocar. Pon ahí el scope del tenant o del usuario, y vuelve a aplicarlo (más $this->authorize()) en los hooks de guardado, que reciben un id y no tu modelo. events(), resources(), configure() y los hooks son protected: Livewire deja llamar desde el navegador a cualquier método público. Detalle y ejemplos en Seguridad.
Vistas
| Vista | Qué muestra | Necesita recursos |
|---|---|---|
month |
Un mes en semanas completas; los eventos como barras, con «+N más» por celda | No |
week |
Columnas por día, eje de horas y carril de todo el día | No |
day |
Lo mismo para un solo día | No |
list |
Agenda: los eventos de la semana agrupados por día | No |
resource-week |
Semana con una columna por recurso y día | Sí |
resource-day |
Un día con una columna por recurso | Sí |
timeline-day |
Recursos en filas, horas en horizontal | Sí |
timeline-week |
Recursos en filas, días de la semana en horizontal | Sí |
timeline-month |
Recursos en filas, días del mes en horizontal | Sí |
Las vistas por recurso solo se ofrecen en el selector si el calendario tiene recursos.
Documentación
| Documento | Contenido |
|---|---|
| Calendar | El componente, eventos, recursos, recurrencia, horario laboral y conflictos |
| KoreCalendar | La clase base: configuración fluida, acciones, edición, formulario, deshacer, series, disponibilidad |
| Configuración | Todas las claves del config, los métodos de configure(), las props y las traducciones |
| Theming | Tokens --kore-calendar-*, color de eventos, dark mode |
| Accesibilidad | Teclado, lectores de pantalla, táctil y lo que falta |
| iCalendar | Exportar e importar .ics |
Diferencias con FullCalendar
El kernel de colocación es un port de FullCalendar v7.1.3 (MIT, aviso en THIRD-PARTY-NOTICES.md), pero el paquete no envuelve ni carga FullCalendar.
Hace igual
- La colocación de eventos: niveles, trozos de los eventos largos, «+N más» por celda y reparto horizontal por colisión en la rejilla horaria, con sus casos de prueba portados.
- El modelo de fechas: horas de pared con días de 24 h (los cambios de horario no rompen la rejilla), intervalos semiabiertos y fin exclusivo en los eventos de día completo.
- Muchas opciones con el mismo sentido: orden de eventos (
start,-duration,allDay,title),slotMinTime/slotMaxTime(admiten más de 24 h),hiddenDays,firstDay,weekNumbers,nextDayThreshold,slotEventOverlap,snapDuration(aquísnap),businessHours,validRange,editable/startEditable/durationEditable,overlapygroupId. - La semántica de accesibilidad: rejilla
role=table,aria-current="date"y «+N más» comorole=dialog.
No hace
- El modo
autodedayMaxEvents. Mide alturas en píxeles en el navegador y el servidor no mide. El límite es un número (month.max_events,month.max_event_rows). - Opciones que son funciones JavaScript (
eventAllow,eventContent,eventClassNames, los callbacks deselectoeventDrop). Aquí los hooks son métodos PHP protegidos (persistMove(),persistResize(),onDateSelect(),onEventClick(),createEvent()…) que corren tras validar en el servidor, y el HTML del evento es el del paquete.eventConstraintyselectConstraintsolo admiten'businessHours'; otra regla va en el hook. - Vistas a medida (año, duraciones propias): hay las nueve de la tabla.
- Arrastrar eventos desde fuera del calendario y renderizar el evento con una plantilla propia.
- Redimensionar desde el borde inicial con el ratón: el asa está solo en el final.
Distinto, a propósito
- Una clave desconocida en un evento lanza una excepción, en vez de acabar en
extendedProps: una errata comocolourno se pierde. Los datos libres van enmeta. eventConstraint('businessHours')sin horario definido deja pasar todo; FullCalendar rechaza todo.- Mover, redimensionar y seleccionar funcionan con el teclado y con pulsación larga en táctil, y el calendario anuncia los cambios con
aria-live. - Las series recurrentes se editan por alcance (solo esta, esta y las siguientes, toda la serie) con
RecurrenceEditor, que da lo que hay que guardar sin saber RFC 5545.
Gratis aquí, de pago allí
Las vistas de recursos y el timeline son Premium en FullCalendar (AGPLv3 o licencia comercial). Aquí son parte del paquete (MIT): columnas por recurso, timeline por horas, días o mes con filas agrupadas, en árbol, plegables y virtualizadas (en KoreCalendar), cambio de recurso arrastrando, horario laboral por recurso, búsqueda de huecos libres (AvailabilityFinder) y detección de conflictos.
Desarrollo
composer install && npm install ./vendor/bin/pest # PHP npm run test:js # JS npm run build # dist/kore-calendar.js (se versiona) npm run size # presupuesto del bundle
Licencia
MIT. El código derivado de FullCalendar conserva su aviso en THIRD-PARTY-NOTICES.md.