Skip to content

Commit

Permalink
feat: angular decorators to signal functions - component example
Browse files Browse the repository at this point in the history
  • Loading branch information
mrednic-1A committed Mar 7, 2024
1 parent d6583a6 commit cb86ef3
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 20 deletions.
9 changes: 5 additions & 4 deletions angular/headless/src/slot.directive.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -128,7 +128,7 @@ class TemplateRefSlotHandler<Props extends Record<string, any>> extends SlotHand
class ComponentTemplateSlotHandler<
Props extends Record<string, any>,
K extends string,
T extends {[key in K]: TemplateRef<Props>},
T extends {[key in K]: TemplateRef<Props> | Signal<TemplateRef<Props>>},
> extends SlotHandler<Props, ComponentTemplate<Props, K, T>> {
#componentRef: ComponentRef<T> | undefined;
#templateSlotHandler = new TemplateRefSlotHandler(this.viewContainerRef, this.document);
Expand All @@ -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, K, T>, props: Props): void {
Expand Down
2 changes: 1 addition & 1 deletion angular/headless/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Directive, Input} from '@angular/core';

export * from '@agnos-ui/core/types';

export class ComponentTemplate<Props, K extends string, T extends {[key in K]: TemplateRef<Props>}> {
export class ComponentTemplate<Props, K extends string, T extends {[key in K]: TemplateRef<Props> | Signal<TemplateRef<Props>>}> {
constructor(
public readonly component: Type<T>,
public readonly templateProp: K,
Expand Down
34 changes: 19 additions & 15 deletions angular/lib/src/components/progressbar/progressbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -43,7 +43,7 @@ export class ProgressbarStructureDirective {
`,
})
export class ProgressbarDefaultSlotsComponent {
@ViewChild('structure', {static: true}) structure: TemplateRef<ProgressbarContext>;
structure = viewChild.required<TemplateRef<ProgressbarContext>>('structure');
}

export const progressbarDefaultSlotStructure = new ComponentTemplate(ProgressbarDefaultSlotsComponent, 'structure');
Expand Down Expand Up @@ -77,60 +77,64 @@ export class ProgressbarComponent extends BaseWidgetDirective<ProgressbarWidget>
/**
* The aria label.
*/
@Input('auAriaLabel') ariaLabel: string | undefined;
ariaLabel = input<string | undefined>(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<string | undefined>(undefined, {alias: 'auClassName'});

@Input('auSlotDefault') slotDefault: SlotContent<ProgressbarContext>;
slotDefault = input<SlotContent<ProgressbarContext> | undefined>(undefined, {alias: 'auSlotDefault'});

@Input('auSlotStructure') slotStructure: SlotContent<ProgressbarContext>;
@ContentChild(ProgressbarStructureDirective, {static: false}) slotStructureFromContent: ProgressbarStructureDirective | undefined;
slotStructure = input<SlotContent<ProgressbarContext> | 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<string | undefined>(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,
});
}
}

0 comments on commit cb86ef3

Please sign in to comment.