ADR 027: Template runtime por skin¶
Estado¶
Aceptado — 2026-07
Relacionado con ADR 026, ADR 003, ADR 012.
Contexto¶
Los widgets del panel eran componentes React monolíticos en @cortex/panel-shadcn. Cambiar la presentación por theme exigía recompilar el bundle npm, equivalente a editar el módulo PHP en lugar del .phtml del theme en Magento.
Decisión¶
Separar controller (headless) de template (view por skin):
| Capa Magento | HIVE |
|---|---|
| Block (lógica) | Hook/controller en @cortex/panel-core (useDataTableController, useFormWidgetController, useStatCardController) |
.phtml (markup theme) | View React en skin (*View.base.tsx) cargada en runtime vía SkinTemplateLoader |
| CSS theme | skins/{skin}.css bajo [data-skin] |
pub/static | public/skins/{skin}/assets/ |
Contrato controller¶
- Vive en
packages/cortex-panel-core/src/widgets/{widget}/. - Sin JSX; usa
usePanel()para datos y acciones. - Tests unitarios en
panel-core(vitest).
Contrato template¶
- Vive en
packages/cortex-panel-shadcn/src/widgets/{widget}/*View.base.tsx(fase 2). - En runtime, skin publica
public/skins/{skin}/templates/registry.jsconregisterSkinTemplates(registry)(fase 3). WidgetRegistry.resolve(type, skin, template)elige la view activa.
Skin manifest¶
skinManifest.ts y public/skins/manifest.json declaran por skin:
assetsPathtemplatesPathtemplatesEntry(ESM dinámico)
Consecuencias¶
- Nuevo skin = CSS + assets +
registry.jssin rebuild deweb-shadcn. - Plugins Python siguen declarando solo JSON CUS; no aportan React.
- Widgets de dominio pueden moverse al bundle del skin
operationso paquetes@cortex/widgets-*.
Referencias¶
packages/cortex-panel-core/src/widgets/packages/cortex-panel-shadcn/src/theme/skinTemplateLoader.tsframework/web-shadcn/public/skins/manifest.json