migrate buttons to signal inputs

This commit is contained in:
Dan Percic 2024-06-17 21:26:02 +03:00
parent 76771023c2
commit 0738d8c4ef
6 changed files with 100 additions and 78 deletions

View File

@ -1,6 +1,8 @@
<button [class.overlay]="showDot" [class.primary]="primary" [disabled]="disabled" [id]="buttonId" mat-button> <button [class.overlay]="showDot()" [class.primary]="primary()" [disabled]="disabled()" [id]="buttonId()" mat-button>
<span>{{ label }}</span> <span>{{ label() }}</span>
<mat-icon class="chevron-icon" iconPositionEnd svgIcon="iqser:arrow-down"></mat-icon> <mat-icon class="chevron-icon" iconPositionEnd svgIcon="iqser:arrow-down"></mat-icon>
</button> </button>
<div *ngIf="showDot" class="dot"></div> @if (showDot()) {
<div class="dot"></div>
}

View File

@ -1,8 +1,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { booleanAttribute, ChangeDetectionStrategy, Component, input } from '@angular/core';
import { randomString } from '../../utils';
import { NgIf } from '@angular/common';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { randomString } from '../../utils';
@Component({ @Component({
selector: 'iqser-chevron-button', selector: 'iqser-chevron-button',
@ -10,12 +9,12 @@ import { MatIconModule } from '@angular/material/icon';
styleUrls: ['./chevron-button.component.scss'], styleUrls: ['./chevron-button.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true, standalone: true,
imports: [NgIf, MatIconModule, MatButtonModule], imports: [MatIconModule, MatButtonModule],
}) })
export class ChevronButtonComponent { export class ChevronButtonComponent {
@Input({ required: true }) label!: string; readonly label = input.required<string>();
@Input() showDot = false; readonly showDot = input(false, { transform: booleanAttribute });
@Input() primary = false; readonly primary = input(false, { transform: booleanAttribute });
@Input() disabled = false; readonly disabled = input(false, { transform: booleanAttribute });
@Input() buttonId = `${randomString()}-chevron-button`; readonly buttonId = input(`${randomString()}-chevron-button`);
} }

View File

@ -1,21 +1,25 @@
<div [matTooltipClass]="tooltipClass || ''" [matTooltipPosition]="tooltipPosition" [matTooltip]="tooltip || ''"> <div [matTooltipClass]="tooltipClass()" [matTooltipPosition]="tooltipPosition()" [matTooltip]="tooltip()">
<button <button
(click)="performAction($event)" (click)="performAction($event)"
[class.dark-bg]="type === _circleButtonTypes.dark" [class.dark-bg]="type() === _circleButtonTypes.dark"
[class.grey-selected]="greySelected" [class.grey-selected]="greySelected()"
[class.overlay]="showDot" [class.overlay]="showDot()"
[class.primary]="type === _circleButtonTypes.primary" [class.primary]="type() === _circleButtonTypes.primary"
[class.warn]="type === _circleButtonTypes.warn" [class.warn]="type() === _circleButtonTypes.warn"
[disabled]="disabled" [disabled]="disabled()"
[id]="buttonId" [id]="buttonId()"
[iqserStopPropagation]="action.observed && !_hasRouterLink" [iqserStopPropagation]="action.observed && !_hasRouterLink"
[type]="isSubmit ? 'submit' : 'button'" [type]="isSubmit() ? 'submit' : 'button'"
mat-icon-button mat-icon-button
> >
<mat-icon [svgIcon]="icon"></mat-icon> <mat-icon [svgIcon]="icon()"></mat-icon>
</button> </button>
<div *ngIf="showDot" class="dot"></div> @if (showDot()) {
<div class="dot"></div>
}
<div *ngIf="dropdownButton" [class.disabled]="disabled" class="arrow-down"></div> @if (dropdownButton()) {
<div [class.disabled]="disabled()" class="arrow-down"></div>
}
</div> </div>

View File

@ -1,5 +1,16 @@
import { NgIf } from '@angular/common'; import {
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Input, OnInit, Output, ViewChild } from '@angular/core'; booleanAttribute,
ChangeDetectionStrategy,
Component,
effect,
ElementRef,
EventEmitter,
inject,
input,
numberAttribute,
Output,
viewChild,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip';
@ -14,37 +25,39 @@ import { CircleButtonType, CircleButtonTypes } from '../types/circle-button.type
styleUrls: ['./circle-button.component.scss'], styleUrls: ['./circle-button.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true, standalone: true,
imports: [MatTooltipModule, MatIconModule, NgIf, MatButtonModule, StopPropagationDirective], imports: [MatTooltipModule, MatIconModule, MatButtonModule, StopPropagationDirective],
}) })
export class CircleButtonComponent implements OnInit { export class CircleButtonComponent {
readonly #elementRef = inject(ElementRef<HTMLElement>); readonly #elementRef = inject(ElementRef<HTMLElement>);
@ViewChild(MatTooltip) private readonly _matTooltip!: MatTooltip; protected readonly _matTooltip = viewChild.required(MatTooltip);
protected readonly _circleButtonTypes = CircleButtonTypes; protected readonly _circleButtonTypes = CircleButtonTypes;
protected readonly _hasRouterLink = !!inject(RouterLink, { optional: true, host: true }); protected readonly _hasRouterLink = !!inject(RouterLink, { optional: true, host: true });
@Input() buttonId = `${randomString()}-circle-button`; readonly buttonId = input(`${randomString()}-circle-button`);
@Input({ required: true }) icon!: string; readonly icon = input.required<string>();
@Input() tooltip?: string; readonly tooltip = input('');
@Input() tooltipClass?: string; readonly tooltipClass = input('');
@Input() showDot = false; readonly showDot = input(false, { transform: booleanAttribute });
@Input() tooltipPosition: IqserTooltipPosition = IqserTooltipPositions.above; readonly tooltipPosition = input<IqserTooltipPosition>(IqserTooltipPositions.above);
@Input() disabled = false; readonly disabled = input(false, { transform: booleanAttribute });
@Input() type: CircleButtonType = CircleButtonTypes.default; readonly type = input<CircleButtonType>(CircleButtonTypes.default);
@Input() greySelected = false; readonly greySelected = input(false, { transform: booleanAttribute });
@Input() removeTooltip = false; readonly removeTooltip = input(false, { transform: booleanAttribute });
@Input() isSubmit = false; readonly isSubmit = input(false, { transform: booleanAttribute });
@Input() dropdownButton = false; readonly dropdownButton = input(false, { transform: booleanAttribute });
@Input() size = 34; readonly size = input(34, { transform: numberAttribute });
@Input() iconSize = 14; readonly iconSize = input(14, { transform: numberAttribute });
@Output() readonly action = new EventEmitter<MouseEvent>(); @Output() readonly action = new EventEmitter<MouseEvent>();
ngOnInit() { constructor() {
this.#elementRef.nativeElement.style.setProperty('--circle-button-size', `${this.size}px`); effect(() => {
this.#elementRef.nativeElement.style.setProperty('--circle-button-icon-size', `${this.iconSize}px`); this.#elementRef.nativeElement.style.setProperty('--circle-button-size', `${this.size()}px`);
this.#elementRef.nativeElement.style.setProperty('--circle-button-icon-size', `${this.iconSize()}px`);
});
} }
performAction($event: MouseEvent) { performAction($event: MouseEvent) {
if (this.removeTooltip) { if (this.removeTooltip()) {
this._matTooltip.hide(); this._matTooltip().hide();
// Timeout to allow tooltip to disappear first, // Timeout to allow tooltip to disappear first,
// useful when removing an item from the list without a confirmation dialog // useful when removing an item from the list without a confirmation dialog
setTimeout(() => this.action.emit($event)); setTimeout(() => this.action.emit($event));

View File

@ -1,14 +1,19 @@
<button <button
(click)="!disabled && action.emit($event)" (click)="!disabled() && action.emit($event)"
[disabled]="disabled" [disabled]="disabled()"
[id]="buttonId" [id]="buttonId()"
[iqserStopPropagation]="action.observed && !_hasRouterLink" [iqserStopPropagation]="action.observed && !_hasRouterLink"
[ngClass]="classes" [ngClass]="_classes()"
[type]="submit ? 'submit' : 'button'" [type]="submit() ? 'submit' : 'button'"
mat-button mat-button
> >
<mat-icon *ngIf="icon" [svgIcon]="icon"></mat-icon> @if (icon(); as icon) {
<span>{{ label }}</span> <mat-icon [svgIcon]="icon"></mat-icon>
}
<span>{{ label() }}</span>
</button> </button>
<div *ngIf="showDot" class="dot"></div> @if (showDot()) {
<div class="dot"></div>
}

View File

@ -1,37 +1,36 @@
import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output } from '@angular/core'; import { NgClass } from '@angular/common';
import { IconButtonType, IconButtonTypes } from '../types/icon-button.type'; import { booleanAttribute, ChangeDetectionStrategy, Component, computed, EventEmitter, inject, input, Output } from '@angular/core';
import { randomString } from '../../utils';
import { NgClass, NgIf } from '@angular/common';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { StopPropagationDirective } from '../../directives';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { StopPropagationDirective } from '../../directives';
import { randomString } from '../../utils';
import { IconButtonType, IconButtonTypes } from '../types/icon-button.type';
@Component({ @Component({
selector: 'iqser-icon-button', selector: 'iqser-icon-button',
templateUrl: './icon-button.component.html', templateUrl: './icon-button.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true, standalone: true,
imports: [NgClass, MatButtonModule, NgIf, MatIconModule, StopPropagationDirective], imports: [NgClass, MatButtonModule, MatIconModule, StopPropagationDirective],
}) })
export class IconButtonComponent { export class IconButtonComponent {
@Input({ required: true }) label!: string;
@Input() buttonId = `${randomString()}-icon-button`;
@Input() icon?: string;
@Input() showDot = false;
@Input() active = false;
@Input() disabled = false;
@Input() submit = false;
@Input() type: IconButtonType = IconButtonTypes.default;
@Output() readonly action = new EventEmitter<MouseEvent>();
protected readonly _hasRouterLink = !!inject(RouterLink, { optional: true, host: true }); protected readonly _hasRouterLink = !!inject(RouterLink, { optional: true, host: true });
readonly label = input.required<string>();
get classes(): Record<string, boolean> { readonly buttonId = input(`${randomString()}-icon-button`);
readonly icon = input<string>();
readonly showDot = input(false, { transform: booleanAttribute });
readonly active = input(false, { transform: booleanAttribute });
readonly disabled = input(false, { transform: booleanAttribute });
readonly submit = input(false, { transform: booleanAttribute });
readonly type = input<IconButtonType>(IconButtonTypes.default);
protected readonly _classes = computed(() => {
return { return {
overlay: this.showDot, overlay: this.showDot(),
[this.type]: true, [this.type()]: true,
'has-icon': !!this.icon, 'has-icon': !!this.icon(),
active: this.active, active: this.active(),
}; };
} });
@Output() readonly action = new EventEmitter<MouseEvent>();
} }