Ir al contenido

Sobrescritura de componentes (Swizzling)

Rebase te permite sobrescribir los componentes de interfaz de usuario predeterminados con tus propias implementaciones personalizadas. Esto implementa un modelo de “component swizzling” al estilo de Docusaurus que admite dos patrones de personalización:

  • Modo eject (predeterminado): Tu componente reemplaza por completo al componente integrado.
  • Modo wrap (wrap: true): Tu componente envuelve al original. Lo que envuelve (normalmente el componente integrado) se pasa como la prop OriginalComponent para que puedas renderizarlo dentro de tu estructura/lógica personalizada.

Las sobrescrituras de componentes se pueden aplicar de forma global a nivel de aplicación (en el proveedor <Rebase>) o de forma local a nivel de colección (dentro de las definiciones de colecciones individuales).


Para sobrescribir componentes globalmente en toda tu aplicación, pasa un objeto components al proveedor raíz <Rebase>.

import { Rebase } from "@rebasepro/app";
import { MyAppBar } from "./components/MyAppBar";
function App() {
return (
<Rebase
client={rebaseClient}
components={{
// Eject Mode: Replace the default AppBar entirely
"Shell.AppBar": { Component: MyAppBar },
// Wrap Mode: Wrap the login view to insert branding
"Auth.LoginView": {
// `OriginalComponent` is injected at runtime when `wrap: true`; the override
// slot's type does not model it, hence the annotation.
Component: (({ OriginalComponent, ...props }: {
OriginalComponent: React.ComponentType<Record<string, unknown>>
}) => (
<div className="login-branding-container">
<header className="branding-header">My Custom Brand</header>
<OriginalComponent {...props} />
</div>
)) as unknown as React.ComponentType<Record<string, unknown>>,
wrap: true
}
}}
>
{/* your app */}
…
</Rebase>
);
}

Sobrescrituras de componentes a nivel de colección

Sección titulada «Sobrescrituras de componentes a nivel de colección»

Para sobrescribir componentes únicamente para una colección específica, añade un objeto components bajo su bloque admin. Esto es útil para personalizar estados vacíos, tarjetas o vistas de detalle para modelos particulares.

En el scaffold predeterminado, config/collections/ es cargado tanto por el panel de administración como por el backend, el cual lee los mismos archivos para derivar el esquema y la API. Por lo tanto, apunta a cada componente mediante una ruta de módulo en lugar de importarlo. Component admite las mismas formas que admin.Field y entityViews[].Builder: una ruta, un import() perezoso (lazy) o el componente en sí.

// config/collections/products.ts
import { defineCollection } from "@rebasepro/cms-types";
export const productsCollection = defineCollection({
name: "Products",
slug: "products",
table: "products",
properties: { /* ... */ },
admin: {
components: {
// Eject Mode: Replace the default entity form view
"Entity.Form": { Component: "../../frontend/src/ProductCustomForm" },
// Wrap Mode: Wrap the empty state to add quick links
"Collection.EmptyState": {
Component: "../../frontend/src/ProductsEmptyState",
wrap: true
}
}
}
});

El componente contenedor reside con el resto de tu código de frontend, y recibe lo que envuelve como OriginalComponent — el componente integrado, a menos que tu aplicación también lo sobrescriba (consulta Cuando ambos alcances sobrescriben un componente):

// frontend/src/ProductsEmptyState.tsx
import type React from "react";
export default function ProductsEmptyState({ OriginalComponent, ...props }: {
OriginalComponent: React.ComponentType<Record<string, unknown>>
}) {
return (
<div className="empty-state-wrapper">
<OriginalComponent {...props} />
<button onClick={() => importDemoProducts()}>
Load Demo Products
</button>
</div>
);
}

Cada módulo necesita una exportación por defecto (default export). El plugin de Vite para colecciones reescribe una ruta convirtiéndola en una importación perezosa (lazy import), de modo que el componente forme su propio chunk y se cargue la primera vez que la sobrescritura se renderice. Dicha reescritura cubre los archivos dentro del collectionsDir configurado. Una ruta en un archivo fuera de este llega al admin como una cadena simple: la consola lo advertirá, y el componente integrado se renderizará en su lugar. Fuera de collectionsDir, escribe la importación perezosa tú mismo: Component: () => import("../../frontend/src/ProductCustomForm").

Una referencia directa (Component: ProductCustomForm) también funciona, pero solo en un archivo de colección que nada en el servidor cargue, ya que importar el componente también importa React y todo lo que este arrastre consigo.

Cuando ambos alcances sobrescriben un componente

Sección titulada «Cuando ambos alcances sobrescriben un componente»

Desde 0.25 En 0.24 el contenedor (wrapper) de una colección siempre recibe el componente integrado, y la sobrescritura a nivel de aplicación se omite dentro de esa colección.

Los dos alcances se componen. La sobrescritura a nivel de aplicación (<Rebase components>) se aplica primero al componente integrado, y la de la colección (admin.components) se aplica al resultado:

Nivel de aplicación Nivel de colección Qué se renderiza dentro de esa colección
cualquiera ninguno lo que se renderiza en todos los demás sitios: la sobrescritura a nivel de aplicación, o el componente integrado
ninguno wrap el contenedor de la colección alrededor del componente integrado
replace o wrap wrap el contenedor de la colección alrededor de la sobrescritura a nivel de aplicación, pasada como OriginalComponent
cualquiera replace el componente de la colección por sí solo; reemplaza a ambos

Así, una colección puede añadir algo alrededor de un componente que tu aplicación ya personaliza sin perder esa personalización. Para descartar la versión a nivel de aplicación en una colección, reemplaza en lugar de envolver.


Componentes con alcance de aplicación (AppComponentName)

Sección titulada «Componentes con alcance de aplicación (AppComponentName)»

Estos componentes solo pueden sobrescribirse a nivel del proveedor raíz <Rebase>, ya que representan la estructura base del shell.

Clave del componente Descripción
"Shell.AppBar" La barra de cabecera en la parte superior de la página
"Shell.Drawer" El menú lateral principal desplegable de navegación
"Shell.DrawerNavigationItem" Enlaces individuales dentro de la barra lateral
"Shell.DrawerNavigationGroup" Encabezados de grupos de navegación desplegables en la barra lateral
"HomePage" La página de inicio predeterminada en modo contenido
"HomePage.CollectionCard" Tarjetas de colecciones individuales en la página de inicio
"Auth.LoginView" La superposición (overlay) mostrada cuando se solicita autenticación

Componentes con alcance de colección (CollectionComponentName)

Sección titulada «Componentes con alcance de colección (CollectionComponentName)»

Estos componentes pueden sobrescribirse globalmente (actuando como valores predeterminados para todas las colecciones) o en colecciones individuales.

Clave del componente Descripción
"Collection.View" La página principal completa de la colección
"Collection.Table" La vista tabular predeterminada tipo hoja de cálculo
"Collection.Card" El contenedor del elemento en vista de tarjeta
"Collection.EmptyState" Vista mostrada cuando una colección está vacía
"Collection.Actions" Botones de la barra de herramientas sobre la tabla/tarjetas
"Collection.FilterField" Campo de filtro personalizado para una columna
"Entity.Form" El formulario de detalle para creación/actualización
"EditView.FormActions" Barra de botones para envío/cancelación del formulario
"DetailView" Vista de detalle de solo lectura
"Entity.SidePanel" El panel lateral contenedor para formulario/detalle
"EntityPreview" Vista previa incrustada de referencia/relación en formato chip
"Entity.MissingReference" Renderizado cuando falta una entidad referenciada

Tu reemplazo recibe las mismas props que se le pasaron al componente integrado. El mapa de sobrescrituras no define un tipo de props por clave (ComponentOverride<P> asigna por defecto P a Record<string, unknown>), por lo que debes tipar el parámetro tú mismo, o pasar un argumento de tipo, cuando desees que las props sean verificadas. Algunos de los componentes integrados exportan un tipo de props que puedes importar y reutilizar: CollectionViewProps (@rebasepro/ui); CollectionEmptyStateProps, CollectionActionsProps y FilterFieldBindingProps (@rebasepro/cms-types); EntityFormProps y EntityFormActionsProps (@rebasepro/cms). El resto no tiene un tipo de props exportado; define la estructura que realmente utilices.

  • Extender Rebase — los puntos de extensión que no necesitan una sobrescritura
  • Campos personalizados — reemplazar el editor de una propiedad en lugar de un componente
  • Slots — añadir elementos a un componente en lugar de reemplazarlo