# Solución de problemas

> Resuelve problemas de integración habituales: estilos ausentes, contenedor sin altura, refs nulas, vistas vacías, imports erróneos, React duplicado, CSP y Tailwind.

Source: https://superscheduler.org/es/docs/troubleshooting/
Reviewed: 2026-10-07

La mayoría de los problemas tienen pocas causas: la hoja de estilos no está importada, el elemento anfitrión no tiene altura para `height="100%"`, el control se lee antes del montaje, o la vista muestra un día, el de hoy, mientras los datos están en otras fechas (`days` vale 1 por defecto y `startDate`, hoy). Comprueba también que las cadenas de fecha incluyan segundos, que los valores `resource` de los eventos coincidan exactamente con los ids de los recursos y que solo haya una copia de React instalada. Cada sección de abajo da el síntoma, la causa y la solución.

Busca el síntoma, comprueba la causa y aplica la solución. Las secciones se aplican a Pro y a Lite salvo que nombren una edición. Si tu problema no aparece aquí, la [referencia de la API](https://superscheduler.org/es/docs/api-reference/) enumera todas las opciones implementadas con su valor por defecto, y su sección de [APIs reservadas](https://superscheduler.org/es/docs/api-reference/#reserved) enumera lo que tiene tipos pero no está implementado.

## El scheduler se renderiza sin estilos
**Síntoma.** Aparecen filas y eventos, pero sin líneas de cuadrícula, sin colores y con las cabeceras desalineadas.

**Causa.** La hoja de estilos no está cargada, o está cargada la de la otra edición.

**Solución.** Impórtala una sola vez, en tu punto de entrada o en tu layout raíz: `import 'super-scheduler/styles.css'` para Pro, `import 'super-scheduler-lite/styles.css'` para Lite. La hoja de estilos de Pro vive en `@layer super-scheduler` con selectores de especificidad cero, así que cualquier regla tuya fuera de una capa prevalece; por eso, un reset amplio como `* { border: 0 }` también elimina los bordes de la librería (consulta [Tailwind](#tailwind)). `unstyled` desactiva a propósito las reglas visuales de la librería.

## El scheduler mide 0 px de alto o no tiene la altura que le diste
**Síntoma.** No se ve nada, o la cuadrícula es más baja o más alta de lo esperado.

**Causas y soluciones (Pro).**

- `heightSpec` vale `'Max'` por defecto: `height` (600 por defecto) es un techo, y la cuadrícula mide lo que sumen sus filas, hasta ese valor. Dos filas con `height={320}` se renderizan con unos 130 px de alto. Usa `heightSpec="Fixed"` para una caja de altura constante.
- `height="100%"` llena el elemento anfitrión del componente, un `<div>` sin estilos que `SuperSchedulerComponent` renderiza dentro de tu contenedor. Si ese `<div>` no tiene altura, el scheduler se queda en 0 px. Da a tu contenedor una altura definida y al elemento anfitrión el 100 %:

```tsx
// src/FillParent.tsx
import { SuperSchedulerComponent } from 'super-scheduler'
import type { SuperScheduler } from 'super-scheduler'

interface Props {
  readonly rooms: SuperScheduler.ResourceData[]
  readonly events: SuperScheduler.EventData[]
}

// height="100%" fills the component's own host <div>: .fill sizes it (see the CSS below).
export function FillParent({ rooms, events }: Props) {
  return (
    <div className="fill">
      <SuperSchedulerComponent
        height="100%"
        startDate="2026-10-01"
        days={31}
        scale="Day"
        resources={rooms}
        events={events}
      />
    </div>
  )
}
```
```css
.fill {
  height: 70vh; /* or a flex item with min-height: 0 */
}
.fill > div {
  height: 100%;
}
```

- `heightSpec="Auto"` ajusta el control a su contenido sin barra de scroll vertical, así que lo que se desplaza es la página.
- `SchedulerPanes` recibe su propio `height` numérico para el conjunto de los paneles.

En Lite, `height` es siempre un número fijo de píxeles (400 por defecto). En las dos ediciones, cuando el contenedor es un elemento flex, dale `min-width: 0` en una fila (o `min-height: 0` en una columna); si no, el tamaño mínimo automático del elemento flex puede dejar que la cuadrícula ensanche o alargue el layout en lugar de desplazarse.

## `ref.current` o `control` es null
**Causa.** El control se crea en `componentDidMount`. Durante el primer render, en el servidor y después de desmontar, no hay ningún control activo: `ref.current` es `null` antes del montaje, y los objetos ref pasados como `controlRef` vuelven a `null` al desmontar.

**Solución.** Lee el control en efectos y en handlers de eventos, nunca durante el render. `useSchedulerControl()` devuelve el control como estado, así que un efecto puede depender de él:

```tsx
// src/Planning.tsx
import { useEffect } from 'react'
import { SuperScheduler, SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'

const START = SuperScheduler.Date.today().addDays(-30)

export function Planning({ rooms }: { rooms: SuperScheduler.ResourceData[] }) {
  // `control` is null during the first render and the live control after mount.
  const { controlRef, control } = useSchedulerControl()

  useEffect(() => {
    if (control === null || control.disposed()) return
    control.scrollTo(SuperScheduler.Date.today(), false, 'middle')
  }, [control])

  return (
    <SuperSchedulerComponent
      controlRef={controlRef}
      startDate={START}
      days={90}
      scale="Day"
      resources={rooms}
    />
  )
}
```
En Pro, un `controlRef` de tipo función se llama con el control al montar y no se llama con `null` al desmontar. Una referencia al control guardada de antes de un desmontaje apunta a un control liberado: comprueba `control.disposed()` en el código asíncrono. Con la API imperativa, llama a `init()` antes que a nada; `update()` antes de `init()` lanza `SuperScheduler.Exception`.

## No aparece nada en la cuadrícula
Comprueba esto por orden:

1. **Rango.** `days` vale `1` por defecto y `startDate`, hoy. En Pro, `scale` también usa por defecto celdas de una hora (`'CellDuration'` con 60 minutos). Ajusta `startDate`, `days` y `scale="Day"` al periodo que cubren tus datos. Los conjuntos de datos de `super-scheduler/datasets` empiezan por defecto el 1 de enero de 2026.
2. **Cadenas de fecha.** `'2026-10-01T10:00'` lanza `SchedulerDate: "2026-10-01T10:00" is not an ISO 8601 date`. Usa `'2026-10-01'` o `'2026-10-01T10:00:00'`. Los objetos `Date` nativos no pasan la comprobación de tipos; conviértelos (consulta [fechas civiles](https://superscheduler.org/es/docs/locales-dates-timezones/#civil-dates)).
3. **Ids de recurso.** El `resource` de un evento tiene que ser exactamente igual al `id` de un recurso: `1` y `'1'` son distintos. Los eventos de recursos desconocidos no se dibujan.
4. **Árboles (Pro).** Los `children` solo se renderizan con `treeEnabled`, y un padre solo muestra a sus hijos cuando tiene `expanded: true`.
5. **Filtros e indicadores.** Un `control.events.filter()` o un `control.rows.filter()` activo, o `hidden: true` en el evento, lo ocultan.
6. **Estado vacío.** Sin filas visibles, Pro muestra `emptyState` si lo has definido; Lite muestra «No resources» por defecto.

## Los cambios no aparecen
- **Modificado en el sitio.** El componente React solo reenvía una prop cuando cambia su identidad. Hacer push en el mismo array `events` o `resources` y volver a renderizar no envía nada. Pasa un array nuevo, o llama a `control.update()` después de una edición en el sitio.
- **El array cambia solo (Pro).** El control adopta el array `events` que le pasas y lo modifica con splice cuando se añaden, eliminan o confirman eventos. Pasa una copia (`useMemo(() => events.slice(), [events])`) si ese array es estado compartido. Con un array congelado, como los que producen algunas librerías de estado en desarrollo, `control.events.add`, `update` y `remove` lanzan `TypeError`.
- **Actualizar un id desconocido.** `control.events.update(data)` no hace nada cuando el id no está cargado; usa `add` para los eventos nuevos. `add` lanza una excepción si el id está duplicado.
- **Ha cambiado `defaultEvents`.** Se lee una sola vez, en `init()`; los valores posteriores se ignoran con un aviso en desarrollo. Usa `events` controlados para los datos que cambian.
- **Hooks de celda (Pro).** Los resultados de `onBeforeCellRender` se guardan en caché por celda. Si una celda depende de los eventos, pon `cellsAutoUpdated: true` en su recurso o llama a `control.update()`.
- **Una prop eliminada.** Una prop que desaparece entre renders vuelve a su valor por defecto.

## Errores de import y subpaths incorrectos
Solo existen estos puntos de entrada; cualquier otro, como `super-scheduler/dist/...`, falla con un error de «not exported» de tu bundler o de Node:

- Pro: `super-scheduler`, `/styles.css`, `/react-render`, `/history`, `/minimap`, `/panes`, `/zoom-ui`, `/views`, `/ranges`, `/hooks`, `/tailwind`, `/datasets` y `/core`.
- Lite: solo `super-scheduler-lite` y `super-scheduler-lite/styles.css`. Los módulos de Pro no forman parte de Lite.

TypeScript los resuelve a través del campo `exports` del paquete con `moduleResolution` en `bundler`, `node16` o `nodenext`; el ajuste antiguo `node` funciona gracias al `typesVersions` del paquete. Con `noUncheckedSideEffectImports` (TypeScript 5.6 y posteriores), importar una hoja de estilos necesita una declaración `declare module '*.css'`, que ya aportan los tipos de cliente de los bundlers, como `vite/client`. `super-scheduler/tailwind` es un preset al estilo CommonJS: cárgalo con `require('super-scheduler/tailwind')`, o con un import por defecto si tu configuración admite la interoperabilidad con CommonJS.

## Mensajes de la consola
| Mensaje | Significado |
|---|---|
| `[super-scheduler] renderEvent needs the component from "super-scheduler/react-render"` | Se ha pasado una prop de render React (`renderEvent`, `renderCell`, `eventHover`, un handler `onBefore*DomAdd`...) al componente raíz. Importa `SuperSchedulerComponent` de `super-scheduler/react-render`. |
| `super-scheduler: <feature> is not supported yet` | Una API reservada: con tipos, aceptada e inerte. Consulta [APIs reservadas](https://superscheduler.org/es/docs/api-reference/#reserved). |
| `[super-scheduler] events wins over defaultEvents` | Se han pasado las dos props; se usa `events`. |
| `[super-scheduler] defaultEvents is read only during init()` | Se ignora un nuevo valor de `defaultEvents` después del montaje. |
| `SuperScheduler Lite: unsupported option "..."` | Lite lanza una excepción con cualquier opción que no implementa, también en producción. `scale` tiene que ser `'Day'`, y los `children`, `frozen`, `split` y `columns` de los recursos requieren Pro. |

Pro solo muestra estos avisos cuando `NODE_ENV` no es `production`, y los de APIs reservadas solo una vez por función. Los errores de Lite se lanzan en todos los builds.

## «Invalid hook call» o dos copias de React
**Síntoma.** «Invalid hook call» desde `useSchedulerControl` o `useScheduler`, contenido React en slots de renderizado que no ve tus providers de contexto, o errores de portales.

**Causa.** La librería resuelve una copia de React distinta de la de tu aplicación. Las dos ediciones declaran React como dependencia peer y nunca lo incluyen en su bundle, así que esto ocurre cuando la instalación o un enlace traen una segunda copia: un paquete enlazado o compilado en local, un monorepo con varias versiones de React o rangos peer no satisfechos (18.2 o posterior, o 19).

**Solución.** `npm ls react react-dom` tiene que mostrar una sola versión. Instala el tarball de Pro en lugar de enlazar una copia local. En Vite, añade `resolve: { dedupe: ['react', 'react-dom'] }`; en webpack, crea alias de `react` y `react-dom` hacia las copias de tu aplicación.

## Errores de Content Security Policy
La librería no necesita scripts en línea ni estilos `'unsafe-inline'`: se carga como módulos y escribe la geometría mediante `element.style`. Si la consola informa de infracciones, comprueba tres cosas: `script-src` tiene que permitir los chunks que se cargan de forma diferida; las pequeñas imágenes SVG `data:` de la hoja de estilos de Pro necesitan `img-src data:`; y los atributos `style` en línea dentro de las cadenas HTML que pasas (`html`, `bubbleHtml`) se bloquean, así que usa clases. Los detalles y una política de ejemplo están en [Renderizado en servidor](https://superscheduler.org/es/docs/ssr-prerender/#csp).

## Tailwind elimina bordes o sobrescribe el scheduler
El preflight de Tailwind v3 no está en ninguna capa y reinicia los bordes de todos los elementos, lo que se impone a las reglas en capa de la librería. Pon el preflight en una capa por debajo de SuperScheduler:

```css
@layer tw-base, super-scheduler;

@import 'super-scheduler/styles.css';

@layer tw-base {
  @tailwind base;
}
@tailwind components;
@tailwind utilities;
```

Con Tailwind v4, declara el orden de las capas antes de los imports para que la librería quede entre `base` y tus utilidades:

```css
@layer theme, base, super-scheduler, components, utilities;

@import 'tailwindcss';
@import 'super-scheduler/styles.css';
```

Consulta [Temas](https://superscheduler.org/es/docs/theming/) para el preset de Tailwind y la correspondencia de tokens.

## Otras sorpresas
- **Los eventos se ajustan a días completos (Pro).** `useEventBoxes` vale `'Always'` por defecto, lo que dibuja los eventos sobre celdas completas. Usa `'Never'` para dibujar las horas exactas, y añade `eventMoveByCell` si el arrastre debe seguir anclado a las celdas.
- **Un clic deja una selección (Pro).** Un clic en una celda vacía es una selección de una celda que se comunica a `onTimeRangeSelected` con `origin: 'click'`, y su sombra se queda hasta la siguiente selección o un clic en otro sitio. Llama a `args.control.clearSelection()` en el handler.
- **Las teclas no hacen nada (Pro).** `keyboardEnabled` vale `false` por defecto. `keyboardMode="Full"` también lo necesita. Con varios schedulers en una página, pon `keyboardTarget="component"`.
- **Las fechas se han convertido en objetos (Pro).** Después de un arrastre o un cambio de tamaño, el `start` y el `end` del evento son objetos `SuperScheduler.Date`. `String(date)` y `JSON.stringify` dan el valor ISO civil; `date.toString('d MMM', locale)` lo formatea.
- **Día de la semana incorrecto.** `SuperScheduler.Date#getDay()` devuelve el día del mes. Usa `getDayOfWeek()` (0 es domingo) o `dayOfWeekISO()` (1 es lunes).

Guías relacionadas: [Integración con React](https://superscheduler.org/es/docs/react-integration/), [Estado controlado](https://superscheduler.org/es/docs/controlled-state/), [Renderizado en servidor](https://superscheduler.org/es/docs/ssr-prerender/) y [Virtualización y rendimiento](https://superscheduler.org/es/docs/performance-virtualization/).
