@pi/ui
Librería de componentes Angular migrada desde monorepo-nx-ddd-demo/libs/shared
(Angular 14, NgModules, decoradores) a Angular 22 con componentes standalone y
señales.
libs/ui/src/
index.ts barrel público de @pi/ui
lib/styles/ antes shared/styles
lib/util/<n>/ antes shared/util/<n> (24 libs)
lib/ui/<n>/ antes shared/ui/<n> (29 libs)
Construir: nx build ui · Lint: nx lint ui
Qué se hizo
| Prefijo | Dl→Pi, dl-→pi- (selectores, clases CSS, nombres de fichero), @deale-workspace/…→rutas relativas |
| NgModules | 41 → 4 (sólo quedan los que aportan providers: icon-registry, loaders, router-store, scroll-to) |
| Componentes | 70, todos con ChangeDetectionStrategy.OnPush |
| Decoradores | 0 restantes: 460 input(), 6 model(), 20 output(), 8 viewChild(), 2 viewChildren(), 17 contentChild(), 6 contentChildren() |
Se usaron las migraciones oficiales de Angular (@angular/core:standalone,
signal-input-migration, output-migration, signal-queries-migration) y se
resolvió a mano lo que no cubren.
Decisiones que cambian comportamiento
Revisar estos puntos antes de usar la librería en producción:
1. input.required no significa lo mismo que el antiguo !.
La migración convierte @Input() x!: T en input.required<T>(), pero en
Angular 14 no existían las entradas obligatorias: el ! sólo era una aserción
de asignación definida. Se devolvieron a opcionales las que las propias
plantillas de la librería demostraban que no eran obligatorias (allowPropagation,
flexDirection, value de text-viewer, gap/icon/label de divider,
link/gap de headline, device/justify/itemWidth de carousel, las de
grid-item…). Las input.required que quedan endurecen la API respecto al
original; conviene repasarlas contra el uso real en las aplicaciones.
2. Entradas con accessor → input()/model() + effect().
Seis entradas tenían getter/setter con efectos secundarios. El efecto se ejecuta
durante la detección de cambios, no de forma síncrona en la asignación:
PiTabComponent.defaultSelectedTab— elonTabChange()del setter pasa a uneffect().PiBaseFormFieldComponent.isDisabled— pasa ainput(); el estado efectivo a leer sigue siendodisabled(lo escriben también el CVA y el efecto).PiSearchFieldComponent.isExpanded—model(); la emisión deisActivepasa a uneffect().PiSelectOptionComponent.isSelected—model()(los selects padre lo asignan sobre las instancias hijas); sumarkForCheck()manual ya no hace falta.PiBaseMenuComponent.menuItems— el setter era un pass-through puro.PiSelectMultipleComponent.selectedOptions— sólo tenía getter, así que el@Input()nunca pudo asignarse desde fuera: era un valor derivado.
3. PiAccordionComponent.expandedItemIndex pasa a model().
Tenía un two-way binding hecho a mano (expandedItemIndex + expandedItemIndexChange).
model() genera el evento automáticamente. Ojo: el código original emitía el
valor anterior al plegar/desplegar (emit(expandedItemIndex) antes de reasignar);
model() emite el nuevo. Parece que el original tenía un bug. Su tipo pasa a
number | null porque toggleState asigna null al colapsar.
4. Suscripciones a .changes eliminadas.
Las signal queries no exponen QueryList.changes. Donde sólo se usaba para
markForCheck() (accordion, tab, carousel) se eliminó: Angular ya reevalúa la
plantilla al cambiar la señal. En los 4 selects se sustituyó por toObservable().
5. Salidas que emitían any.
changePage y toggledTo eran new EventEmitter() sin genérico. Ahora son
output<number>() y output<'on' | 'off'>().
6. Aserciones ! en plantillas.
*ngIf="icon()" no estrecha el tipo (TypeScript no estrecha resultados de
llamada entre expresiones), así que hay [svgIcon]="icon()!" en ~30 sitios.
Mantiene el runtime idéntico al original. Se pueden eliminar migrando a
@if (icon(); as icon).
7. Precedencia de pipes en select-multiple.
x | truncate : 33 || (placeholder() | translate) se parseaba como
truncate : (33 || …), así que el fallback nunca se aplicaba. Ahora está
parentizado como se pretendía.
Colisiones de nombres en el barrel
El origen tiene símbolos duplicados. En index.ts gana el primero y el otro se
omite (queda anotado en el fichero). Siguen siendo accesibles por ruta directa:
| Símbolo | Se exporta desde | Se omite de |
|---|---|---|
PiSlideToggleComponent |
ui/form-field |
ui/slide-toggle |
PiDisabledDirective |
util/status |
ui/text |
featureKey, getFeatureState, initialState |
util/device-configs |
util/list-configs |
APIs de terceros actualizadas
- ngx-translate 18 — no hay
TranslateModule.PiSharedUtilTranslateModule→providePiTranslate(); en plantillas se importaTranslatePipe/TranslateDirective. - apollo-angular 14 — no hay
ApolloModule.PiSharedUtilDatoCmsModule→providePiDatoCms(). - ngx-currency 19 —
CurrencyMaskInputMode→NgxCurrencyInputMode,NgxCurrencyModule→NgxCurrencyDirective. - chart.js 4 —
chart.js/dist/types/utilsno es importable; los tipos se derivan deChartOptions. - Angular —
TransferState/StateKey/makeStateKeyvienen de@angular/core.
Pendiente
- Tests: no se copiaron los
*.spec.tsdel origen. Sectorvivía endeale-saas/util/models(lib de aplicación, fuera de alcance); se trajo la interfaz autil/models.- ngrx 21 con Angular 22: instalado con
--legacy-peer-deps(aún no declara soporte para 22). - Lint:
nx lint uifalla con avisos heredados del código original —prefer-control-flow(104:*ngIf/*ngForen vez de@if/@for),directive-selector(40),prefer-inject(33), a11y yno-unused-vars. Nada bloquea el build. Hay migraciones oficiales para los dos primeros grupos:nx g @angular/core:control-flow-migrationynx g @angular/core:inject-migration.