Files
pireon-ui/libs/ui/README.md

125 lines
6.9 KiB
Markdown

# @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()` |
| Control flow | `*ngIf`/`*ngFor`/`*ngSwitch` → `@if`/`@for`/`@switch` (110 `@if`, 26 `@for`, 3 `@switch`). Ya no se importa ninguna directiva de `CommonModule` |
Se usaron las migraciones oficiales de Angular (`@angular/core:standalone`,
`signal-input-migration`, `output-migration`, `signal-queries-migration`,
`control-flow-migration`, `cleanup-unused-imports`) 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` — el `onTabChange()` del setter pasa a un `effect()`.
- `PiBaseFormFieldComponent.isDisabled` — pasa a `input()`; el estado efectivo a leer sigue siendo `disabled` (lo escriben también el CVA y el efecto).
- `PiSearchFieldComponent.isExpanded` — `model()`; la emisión de `isActive` pasa a un `effect()`.
- `PiSelectOptionComponent.isSelected` — `model()` (los selects padre lo asignan sobre las instancias hijas); su `markForCheck()` 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.
**8. Los 3 selects se convirtieron a control flow a mano.**
La migración automática se rindió con ellos: tenían un `*ngIf ... else` que
apuntaba a un `<ng-template>` con un `[ngSwitch]` dentro. Al reescribirlos hubo
que renombrar plantillas duplicadas (`#defaultSelected` aparecía dos veces en
ramas distintas del switch) a `#defaultSelectedFill`/`#defaultSelectedOutline`,
y en select-period `#defaultOption` → `#defaultMonthOption`/`#defaultYearOption`.
Los `*ngFor` sin `trackBy` pasaron a `track <item>`, que es lo que hacía `ngFor`
por defecto. En data-grid y select-carousel la migración generó
`track trackByFn(i, item)` pero esos `trackByFn` sólo declaran `index`: se
corrigió la aridad a `track trackByFn(i)`.
## 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 importa `TranslatePipe`/`TranslateDirective`.
- **apollo-angular 14** — no hay `ApolloModule`. `PiSharedUtilDatoCmsModule` → `providePiDatoCms()`.
- **ngx-currency 19** — `CurrencyMaskInputMode`→`NgxCurrencyInputMode`, `NgxCurrencyModule`→`NgxCurrencyDirective`.
- **chart.js 4** — `chart.js/dist/types/utils` no es importable; los tipos se derivan de `ChartOptions`.
- **Angular** — `TransferState`/`StateKey`/`makeStateKey` vienen de `@angular/core`.
## Pendiente
- **Tests**: no se copiaron los `*.spec.ts` del origen.
- **`Sector`** vivía en `deale-saas/util/models` (lib de aplicación, fuera de alcance); se trajo la interfaz a `util/models`.
- **ngrx 21 con Angular 22**: instalado con `--legacy-peer-deps` (aún no declara soporte para 22).
- **Lint**: `nx lint ui` falla con avisos heredados del código original —
`prefer-inject` (51), `directive-selector` (46), `no-explicit-any` (35),
`no-unused-expressions` (33), a11y (`click-events-have-key-events`,
`interactive-supports-focus`, `label-has-associated-control`) y
`no-unused-vars`. Nada bloquea el build. Para el primer grupo hay migración
oficial: `nx g @angular/core:inject-migration`.