@desynth/web-components-angular
v14.9.26-alpha.5
Published
Angular proxy for @desynth/web-components
Readme
@desynth/web-components-angular
Proxies Angular standalone para los Custom Elements de @desynth/web-components, generados por @stencil/angular-output-target.
Compatibilidad e instalación
El workspace compila el paquete con Angular 19.0.x. El artefacto generado declara peer dependencies de @angular/core y @angular/common ^17.0.0; valida la combinación concreta con la versión de Angular de la aplicación.
Los proxies importan tipos y módulos Custom Element desde el paquete core, por lo que ambas bibliotecas deben estar disponibles:
npm install @desynth/web-components-angular @desynth/web-componentsEl manifiesto raíz expone actualmente la librería compilada mediante el subpath ./dist. Por tanto, los imports de consumo se hacen desde:
import { DesynthButton } from '@desynth/web-components-angular/dist';No se documenta un import desde la raíz porque el mapa exports publicado no define ..
Componentes standalone
Cada proxy generado tiene standalone: true, usa ChangeDetectionStrategy.OnPush y registra su propio Custom Element mediante el módulo individual de @desynth/web-components/dist. No es necesario llamar a defineCustomElements().
import { Component } from '@angular/core';
import {
DesynthButton,
DesynthTextInput,
} from '@desynth/web-components-angular/dist';
@Component({
selector: 'app-profile-form',
standalone: true,
imports: [DesynthButton, DesynthTextInput],
template: `
<desynth-text-input
inputId="display-name"
inputName="Nombre"
[inputValue]="name"
(handleInput)="updateName($event)"
/>
<desynth-button
buttonText="Guardar"
variant="solid"
[disabled]="saving"
(handleClick)="save()"
/>
`,
})
export class ProfileFormComponent {
name = '';
saving = false;
updateName(event: CustomEvent<HTMLInputElement>): void {
this.name = event.detail.value;
}
save(): void {
// Persistencia de la aplicación.
}
}Los selectores conservan las etiquetas originales: por ejemplo desynth-button, desynth-data-table, horizontal-cards y html-editor.
Módulo de compatibilidad
El paquete también exporta StencilWrapperModule, pero el módulo mantenido en el repositorio solo agrupa un subconjunto de los proxies. Para código nuevo, importa directamente las clases standalone que use cada componente; es explícito, permite tree shaking y evita asumir que el módulo contiene los 86 elementos.
Si una aplicación basada en NgModules usa únicamente ese subconjunto, puede importar:
import { NgModule } from '@angular/core';
import { StencilWrapperModule } from '@desynth/web-components-angular/dist';
@NgModule({
imports: [StencilWrapperModule],
})
export class SharedUiModule {}Inputs y bindings
Los nombres de @Input son las propiedades camelCase de Stencil. Usa property binding para valores dinámicos o no string:
<desynth-button
[buttonText]="submitLabel"
[disabled]="form.invalid"
[full]="true"
></desynth-button>En una plantilla, un atributo literal sigue siendo texto. Por eso [disabled]="false" y disabled="false" no son equivalentes para una entrada booleana.
Los proxies trasladan las asignaciones a la propiedad del Custom Element fuera de la zona de Angular. No hay ControlValueAccessor configurado: la lista valueAccessorConfigs del output target está vacía. En consecuencia, no asumas compatibilidad automática con [(ngModel)] o formControlName; conecta el valor y el evento explícitamente.
Propiedades JSON
En el paquete core, numerosas colecciones están tipadas como string y se parsean con JSON.parse. Serializa esos valores antes de enlazarlos:
import { Component } from '@angular/core';
import { DesynthDataTable } from '@desynth/web-components-angular/dist';
@Component({
selector: 'app-users-table',
standalone: true,
imports: [DesynthDataTable],
template: `
<desynth-data-table
[columns]="columnsJson"
[rows]="rowsJson"
[actions]="actionsJson"
emptyText="Sin resultados"
(handleAction)="handleAction($event)"
/>
`,
})
export class UsersTableComponent {
readonly columnsJson = JSON.stringify([
{ key: 'name', label: 'Nombre' },
]);
readonly rowsJson = JSON.stringify([
{ id: 'usr-1', name: 'Ada' },
]);
readonly actionsJson = JSON.stringify([
{ key: 'open', label: 'Abrir' },
]);
handleAction(
event: CustomEvent<{ rowId: string; action: string }>,
): void {
console.log(event.detail.rowId, event.detail.action);
}
}No serialices a ciegas: utiliza los tipos de los proxies y la referencia del componente core como fuente de verdad.
Outputs y eventos
Los eventos del Custom Element se exponen con el mismo nombre como outputs Angular: (handleClick), (handleChange), (handleAction), (htmlChanged), etc. El valor recibido sigue siendo un CustomEvent; la carga útil está en $event.detail.
<desynth-tabs
[items]="tabsJson"
(handleChange)="selectTab($event)"
></desynth-tabs>selectTab(event: CustomEvent<{ id: string; index: number }>): void {
console.log(event.detail.id, event.detail.index);
}La utilidad generada crea los outputs con fromEvent. Aunque las declaraciones usan EventEmitter<CustomEvent<...>>, no debes llamar a .emit() desde la aplicación: trata esos miembros como salidas del componente.
Proyección de contenido y slots
Los proxies usan <ng-content>, por lo que Angular proyecta el contenido al Custom Element. El atributo estándar slot selecciona slots con nombre:
import { Component } from '@angular/core';
import {
DesynthBookCard,
DesynthButton,
} from '@desynth/web-components-angular/dist';
@Component({
selector: 'app-book-card',
standalone: true,
imports: [DesynthBookCard, DesynthButton],
template: `
<desynth-book-card
title="Diseño de sistemas"
[chapters]="chaptersJson"
>
<div slot="actions">
<desynth-button buttonText="Leer" size="xs" />
</div>
</desynth-book-card>
`,
})
export class BookCardComponent {
readonly chaptersJson = JSON.stringify([
'Introducción',
'Arquitectura',
]);
}Los nombres de slot son específicos de cada componente.
SSR
El decorador generado intenta definir cada Custom Element al importar el proxy, pero comprueba typeof customElements !== 'undefined' antes de acceder al registro. Aun así, el renderizado interno del Web Component ocurre en el navegador: no asumas que Angular SSR produce su Shadow DOM completo en el HTML del servidor. Prueba la hidratación y cualquier acceso directo a window, archivos o APIs del navegador de los componentes usados.
Tokens
Carga las variables CSS globalmente, por ejemplo en styles.css:
@import '@desynth/style-tokens/dist/assets/css/variables-all.css';El paquete core utiliza esos tokens, pero no los inyecta como tema global del consumidor.
Build y regeneración local
Los archivos lib/src/directives/proxies.ts y proxies-list.tsx son generados por el build de Stencil; no deben editarse manualmente. Desde la raíz del monorepo:
npm run build --workspace=@desynth/web-components
npm run build --workspace=@desynth/web-components-angularEl primer comando sincroniza los proxies Angular con los componentes actuales. El segundo ejecuta:
ng build stencil-wrappery ng-packagr escribe el paquete en packages/components-angular/dist usando lib/index.ts como entrada pública.
No hay script de tests definido en el manifiesto de este paquete. Aunque angular.json contiene una configuración Karma, sus rutas apuntan a libs/stencil-wrapper, mientras la librería real vive en lib; corrige esa configuración antes de presentarla como un comando de test soportado.
Licencia
MPL-2.0 según el manifiesto raíz del paquete.
