SuperScheduler es una librería React para planificación interactiva de recursos: una línea de tiempo rápida y accesible donde tus usuarios arrastran, redimensionan, hacen zoom y deshacen, adaptada a tu negocio y no al revés.
DiseñoInés G.Marc D.Yuki T.RedacciónLena F.Omar S.MotionSara N.Teo R.Sistema de marcaKey visual del lanzamientoMaquetas del lanzamientoKit para tiendasMoodboard de tiendasSet de iconosGuion del lanzamientoTextos del lanzamientoClaims para tiendasPieza audiovisualAnimación del logoBucles para tiendas12 oct19 octlun 12mar 13mié 14jue 15vie 16sáb 17dom 18lun 19mar 20mié 21jue 22vie 23sáb 24dom 25
Carga SuperScheduler Pro solo cuando lo pides.
Explorar el tiempo
Del trimestre al cuarto de hora.
Haz zoom continuo con un pellizco, Ctrl/⌘ y la rueda o los botones de abajo. Cabeceras, etiquetas y nivel de detalle se adaptan a la escala, y el minimapa mantiene toda la temporada a la vista.
01Una única escala de tiempo por píxel: el zoom nunca vuelve a renderizar React.
02Niveles de zoom definidos por ti, cada uno con sus cabeceras.
03El minimapa dibuja la carga que calcule tu aplicación.
Saltar a una escalaTrimestre · Mes · Semana · Día · Horas · 15 min
Equipos, salas y máquinas, ordenados como tú los piensas.
Los recursos pueden ser una lista plana, un árbol de varios niveles o una tabla con columnas. Reagrupa a las mismas personas por equipo o por especialidad, filtra mientras escribes y la línea de tiempo sigue alineada.
1Filas en árbolLos padres se pliegan y despliegan; los hijos conservan sus eventos.
2Columnas en la cabeceraColumnas redimensionables que leen tus datos de recursos.
3FiltrosFilas y eventos se filtran mediante callbacks que escribes tú.
Actuar con confianza
Muévelo. Lee el callback. Deshazlo.
Cada gesto llega a tu código como un callback tipado mientras ocurre y cuando termina. Rechaza un movimiento con un motivo, confírmalo con tu servidor o déjalo pasar. El historial está a un import de distancia.
/** * Booking-board handlers of the "act with confidence" demo. This file is shown on the page as * the code that runs: the library proposes, these handlers decide, React state persists. */import { type SuperScheduler } from'super-scheduler'importtype { SchedulerProps } from'super-scheduler'import { hitsMaintenance } from'../data/bookings'importtype { CallbackRecord } from'../callback-log'typeLog= (record:Omit<CallbackRecord,'seq'>) =>voidexportfunctioncreateBookingHandlers(log:Log, refusal:string):Partial<SchedulerProps> {return {// Visual and enforced: the library refuses drops on disabled cells.onBeforeCellRender: (args) => {const { resource,start,end } =args.cellif (hitsMaintenance(String(resource),start.value,end.value))args.cell.properties.disabled =true },// While dragging: explain the refusal next to the pointer.onEventMoving: (args) => {if (hitsMaintenance(String(args.resource),args.start.value,args.end.value)) {args.allowed =falseargs.message = refusal } },// Before the commit: the last word, e.g. after asking a server.onEventMove: (args) => {constrefused=hitsMaintenance(String(args.newResource),args.newStart.value,args.newEnd.value, )if (refused) args.preventDefault()log({ name:'onEventMove', args: {'e.id()':String(args.e.id()),'e.text()':args.e.text(), newResource:String(args.newResource), newStart:args.newStart.value, newEnd:args.newEnd.value, },...(refused ? { refused: refusal } : {}), }) },onEventMoved: (args) =>log({ name:'onEventMoved', args: {'e.id()':String(args.e.id()), newResource:String(args.newResource), newStart:args.newStart.value, newEnd:args.newEnd.value, }, }),onEventResized: (args) =>log({ name:'onEventResized', args: {'e.id()':String(args.e.id()), what:args.what, newStart:args.newStart.value, newEnd:args.newEnd.value, }, }), }}exportfunctionisBookingEvent( event:SuperScheduler.EventData,): event isSuperScheduler.EventData<{ client:string }> {return'client'in event &&typeofevent.client ==='string'}
Encaja en tu producto
Tus datos y tus reglas, sobre una línea de tiempo que no tienes que construir.
Un componente, props tipadas y callbacks. La librería se ocupa del render, los gestos, la virtualización y la accesibilidad; tu aplicación, de los datos, la validación y la persistencia.
SuperScheduler
Pinta recursos y eventos, virtualizados en ambas direcciones.
Comunica los cambios propuestos y aplica los aceptados.
Tu aplicación
Guarda el estado, valida y persiste en el servidor.
src/BookingBoard.tsxtsx
import { useMemo, useState } from'react'import { SuperSchedulerComponent } from'super-scheduler'importtype { SchedulerEventsChangeArgs, SuperScheduler } from'super-scheduler'typeBooking=SuperScheduler.EventData<{ locked?:boolean }>exportfunctionBookingBoard({ rooms, initial,}: { rooms:SuperScheduler.ResourceData[] initial:Booking[]}) {// Your state is the source of truth; the scheduler gets a copy it may mutate.const [bookings,setBookings] =useState(initial)constevents=useMemo(() =>bookings.slice(), [bookings])return ( <SuperSchedulerComponentstartDate="2026-10-01"days={31}scale="Day"resources={rooms}events={events}allowEventOverlap={false}// While dragging: explain why a drop is not allowed.onEventMoving={(args) => {if ('locked'inargs.e.data &&args.e.data.locked ===true) {args.allowed =falseargs.message ='This booking is confirmed and locked.' } }}// Before the commit: ask your server, then accept or cancel.onEventMove={(args) => {args.async =truesaveBooking({ id:String(args.e.id()), resource:String(args.newResource), start:args.newStart.value, end:args.newEnd.value, }).then( () =>args.loaded(), () => {args.preventDefault()args.loaded() }, ) }}onEventsChange={({ events: next }:SchedulerEventsChangeArgs) =>setBookings([...next])} /> )}
SuperScheduler
Monta contenido React en eventos y cabeceras, conservado y por lotes.
Tu aplicación
Decide cómo se ve una reserva o una fila.
src/RichPlanning.tsxtsx
import { SuperSchedulerComponent } from'super-scheduler/react-render'importtype { SuperScheduler } from'super-scheduler'import'super-scheduler/styles.css'interfaceStay { guest:string nights:number paid:boolean}/** Event data comes back untyped from the engine: read your fields explicitly. */functionreadStay(data:object):Stay|null {if (!('guest'in data) ||!('nights'in data) ||!('paid'in data)) returnnullconst { guest,nights,paid } = datareturntypeof guest ==='string'&&typeof nights ==='number'&&typeof paid ==='boolean'? { guest, nights, paid }:null}exportfunctionRichPlanning({ rooms, stays,}: { rooms:SuperScheduler.ResourceData[] stays:SuperScheduler.EventData<Stay>[]}) {return ( <SuperSchedulerComponentstartDate="2026-10-01"days={30}scale="Day"resources={rooms}events={stays}// React content inside each event; width is quantized, so it re-renders rarely.renderEvent={({ e, width }) => {conststay=readStay(e.data)if (stay ===null) returne.text()return ( <spanclassName="stay"> <strong>{stay.guest}</strong> {width >=120? <small>{stay.nights} nights</small> :null} {stay.paid ?null: <spanclassName="stay__due">Due</span>} </span> ) }}eventHover={{ pin:'click',render: ({ e, close }) => {conststay=readStay(e.data)return stay ===null?null: <StayCardstay={stay} onClose={close} /> }, }} /> )}functionStayCard({ stay, onClose }: { stay:Stay; onClose: () =>void }) {return ( <sectionaria-label={stay.guest}> <h3>{stay.guest}</h3> <p> {stay.nights} nights · {stay.paid ?'Paid':'Payment due'} </p> <buttontype="button"onClick={onClose}> Close </button> </section> )}
SuperScheduler
Expone tokens --super-scheduler-* y sigue tu modo oscuro.
Tu aplicación
Elige colores, radios y densidad.
theme.csscss
/* planning.css: the scheduler follows your tokens and your dark mode. */.planning { --super-scheduler-accent-rgb:25 97 68; --super-scheduler-surface:#fcfaf6; --super-scheduler-border:#ddd8d2; --super-scheduler-event-radius:7px; --super-scheduler-today-bg:rgb(25 97 68 / 0.06); --super-scheduler-selection:rgb(25 97 68 / 0.12);font-family:'Geist', system-ui, sans-serif;}[data-theme='dark'] .planning { --super-scheduler-accent-rgb:110 214 166; --super-scheduler-surface:#16181c; --super-scheduler-border:#2e3134;}.planning.super-scheduler__event[data-selected='true'] {outline:2px solid rgb(var(--super-scheduler-accent-rgb));}
Vístelo como tu producto
Tokens reales, contraste real, copia el CSS.
Estos controles cambian las propiedades --super-scheduler-* que lee la librería. La comprobación de contraste usa los ratios de WCAG 2; el CSS de abajo es el que pegas en tu hoja de estilos.
¿Es un componente React o un motor independiente del framework?+
Las dos cosas. SuperSchedulerComponent es el envoltorio React para React 18 y 19; debajo, un motor DOM gestiona el scroll, el zoom y los gestos sin renders de React. También puedes montarlo de forma imperativa con new SuperScheduler.Scheduler(elemento, opciones).
Las declaraciones vienen con el paquete. Opciones, callbacks y métodos del control están tipados, y los datos de evento son genéricos: EventData<TusCampos> mantiene tipados tus propios campos en handlers y hooks de render.
Sí. Colores, radios, densidad y modo oscuro salen de propiedades CSS documentadas; classNames y styles llegan a cada parte; los slots de renderizado React sustituyen el contenido de eventos, filas y cabeceras.
¿Quién guarda los datos y quién evita los conflictos?+
Tu aplicación. El scheduler muestra y edita lo que le das e informa de cada cambio mediante callbacks. La persistencia, los permisos y la última palabra sobre los conflictos son de tu backend; la librería ayuda con la prevención de solapes, las celdas bloqueadas y los rechazos con motivo.
Como un .tgz privado y versionado por HTTPS que npm instala como cualquier dependencia por URL. La clave de descarga aparece en tu manifiesto y en el lockfile, así que trátala como un secreto. Lite es un paquete público normal de npm.
¿Se puede usar con teclado y lectores de pantalla?+
Pro tiene un modo de teclado completo: las flechas mueven el foco, Intro activa, Alt+flechas mueve eventos y los cambios se anuncian a las tecnologías de apoyo en español, inglés, francés, alemán y cinco idiomas más. Lite también admite navegación por teclado.
Pro va de meses a celdas de 5 minutos, oculta noches o fines de semana cuando se lo pides y cambia de escala de forma continua. Lite es una línea de tiempo diaria.
Las fechas son valores civiles de reloj de pared, sin zona horaria a propósito. Convierte los instantes con zona y expande las recurrencias en tu aplicación antes de pasar los eventos al scheduler.