From cb86ef33dbad0cdf046a2310eae88f6e8cc26545 Mon Sep 17 00:00:00 2001 From: mrednic Date: Thu, 7 Mar 2024 14:26:43 +0100 Subject: [PATCH] feat: angular decorators to signal functions - component example --- angular/headless/src/slot.directive.ts | 9 ++--- angular/headless/src/types.ts | 2 +- .../progressbar/progressbar.component.ts | 34 +++++++++++-------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/angular/headless/src/slot.directive.ts b/angular/headless/src/slot.directive.ts index ba34f62462..f93e48f6a0 100644 --- a/angular/headless/src/slot.directive.ts +++ b/angular/headless/src/slot.directive.ts @@ -1,5 +1,5 @@ import {DOCUMENT} from '@angular/common'; -import type {ComponentRef, EmbeddedViewRef, OnChanges, OnDestroy, SimpleChanges, Type} from '@angular/core'; +import type {ComponentRef, EmbeddedViewRef, OnChanges, OnDestroy, Signal, SimpleChanges, Type} from '@angular/core'; import {Directive, EnvironmentInjector, Input, TemplateRef, ViewContainerRef, createComponent, inject, reflectComponentType} from '@angular/core'; import type {SlotContent} from './types'; import {ComponentTemplate} from './types'; @@ -128,7 +128,7 @@ class TemplateRefSlotHandler> extends SlotHand class ComponentTemplateSlotHandler< Props extends Record, K extends string, - T extends {[key in K]: TemplateRef}, + T extends {[key in K]: TemplateRef | Signal>}, > extends SlotHandler> { #componentRef: ComponentRef | undefined; #templateSlotHandler = new TemplateRefSlotHandler(this.viewContainerRef, this.document); @@ -142,8 +142,9 @@ class ComponentTemplateSlotHandler< elementInjector: this.viewContainerRef.injector, environmentInjector: this.viewContainerRef.injector.get(EnvironmentInjector), }); - this.#templateRef = this.#componentRef.instance[slot.templateProp]; - this.#templateSlotHandler.slotChange(this.#templateRef, props); + const tRef = this.#componentRef.instance[slot.templateProp]; + this.#templateRef = typeof tRef === 'function' ? tRef() : tRef; + this.#templateSlotHandler.slotChange(this.#templateRef!, props); } override propsChange(slot: ComponentTemplate, props: Props): void { diff --git a/angular/headless/src/types.ts b/angular/headless/src/types.ts index a3ddb40035..95f09ccec7 100644 --- a/angular/headless/src/types.ts +++ b/angular/headless/src/types.ts @@ -12,7 +12,7 @@ import {Directive, Input} from '@angular/core'; export * from '@agnos-ui/core/types'; -export class ComponentTemplate}> { +export class ComponentTemplate | Signal>}> { constructor( public readonly component: Type, public readonly templateProp: K, diff --git a/angular/lib/src/components/progressbar/progressbar.component.ts b/angular/lib/src/components/progressbar/progressbar.component.ts index d961be741a..fe72a7f2a0 100644 --- a/angular/lib/src/components/progressbar/progressbar.component.ts +++ b/angular/lib/src/components/progressbar/progressbar.component.ts @@ -12,7 +12,7 @@ import { import {type WritableSignal, writable} from '@amadeus-it-group/tansu'; import {NgClass} from '@angular/common'; import type {AfterContentChecked} from '@angular/core'; -import {ChangeDetectionStrategy, Component, ContentChild, Directive, Input, TemplateRef, ViewChild, inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Directive, TemplateRef, contentChild, inject, input, viewChild} from '@angular/core'; @Directive({selector: 'ng-template[auProgressbarStructure]', standalone: true}) export class ProgressbarStructureDirective { @@ -43,7 +43,7 @@ export class ProgressbarStructureDirective { `, }) export class ProgressbarDefaultSlotsComponent { - @ViewChild('structure', {static: true}) structure: TemplateRef; + structure = viewChild.required>('structure'); } export const progressbarDefaultSlotStructure = new ComponentTemplate(ProgressbarDefaultSlotsComponent, 'structure'); @@ -77,60 +77,64 @@ export class ProgressbarComponent extends BaseWidgetDirective /** * The aria label. */ - @Input('auAriaLabel') ariaLabel: string | undefined; + ariaLabel = input(undefined, {alias: 'auAriaLabel'}); /** * The minimum value. */ - @Input({alias: 'auMin', transform: auNumberAttribute}) min: number | undefined; + min = input(undefined, {alias: 'auMin', transform: auNumberAttribute}); /** * The maximum value. */ - @Input({alias: 'auMax', transform: auNumberAttribute}) max: number | undefined; + max = input(undefined, {alias: 'auMax', transform: auNumberAttribute}); /** * The current value. */ - @Input({alias: 'auValue', transform: auNumberAttribute}) value: number | undefined; + value = input(undefined, {alias: 'auValue', transform: auNumberAttribute}); /** * CSS classes to be applied on the widget main container */ - @Input('auClassName') className: string | undefined; + className = input(undefined, {alias: 'auClassName'}); - @Input('auSlotDefault') slotDefault: SlotContent; + slotDefault = input | undefined>(undefined, {alias: 'auSlotDefault'}); - @Input('auSlotStructure') slotStructure: SlotContent; - @ContentChild(ProgressbarStructureDirective, {static: false}) slotStructureFromContent: ProgressbarStructureDirective | undefined; + slotStructure = input | undefined>(undefined, {alias: 'auSlotStructure'}); + + slotStructureFromContent = contentChild(ProgressbarStructureDirective); /** * Height of the progressbar, can be any valid css height value. */ - @Input('auHeight') height: string | undefined; + height = input(undefined, {alias: 'auHeight'}); /** * If `true`, animates a striped progressbar. * Takes effect only for browsers supporting CSS3 animations, and if `striped` is `true`. */ - @Input({alias: 'auAnimated', transform: auBooleanAttribute}) animated: boolean | undefined; + animated = input(undefined, {alias: 'auAnimated', transform: auBooleanAttribute}); /** * If `true`, shows a striped progressbar. */ - @Input({alias: 'auStriped', transform: auBooleanAttribute}) striped: boolean | undefined; + striped = input(undefined, {alias: 'auStriped', transform: auBooleanAttribute}); /** * Return the value for the 'aria-valuetext' attribute. */ - @Input('auAriaValueTextFn') ariaValueTextFn: ((value: number, minimum: number, maximum: number) => string | undefined) | undefined; + ariaValueTextFn = input<((value: number, minimum: number, maximum: number) => string | undefined) | undefined>(undefined, { + alias: 'auAriaValueTextFn', + }); + // eslint-disable-next-line @agnos-ui/angular-check-props readonly _widget = callWidgetFactory({factory: createProgressbar, widgetName: 'progressbar', defaultConfig: this.defaultSlots, events: {}}); ngAfterContentChecked(): void { this._widget.patchSlots({ slotDefault: undefined, - slotStructure: this.slotStructureFromContent?.templateRef, + slotStructure: this.slotStructureFromContent()?.templateRef, }); } }