refactor: migra decoradores a signals (input/output/viewChild/contentChild)

This commit is contained in:
2026-07-27 22:01:52 +02:00
parent c84de249bf
commit c046e6ac23
140 changed files with 1679 additions and 1536 deletions

View File

@@ -1,7 +1,7 @@
<!-- HEADER OF THE WHOLE ACCORDION -->
<ng-content select="pi-accordion-header"></ng-content>
<ng-container *ngIf="direction === 'default'; else horizontal">
<ng-container *ngIf="direction() === 'default'; else horizontal">
<section
*ngFor="let item of items; index as i"
[class]="
@@ -13,7 +13,7 @@
>
<!-- TOPBAR -->
<div
*ngIf="item.isConfidential === true"
*ngIf="item.isConfidential() === true"
class="pi-accordion-item-content pi-accordion-item-content__topbar"
pi-dynamic-color
[color]="isItemExpanded(i) ? 'highlighted' : 'grey'"
@@ -49,11 +49,11 @@
<pi-chip-status
*ngIf="item.status"
[status]="item.status"
[label]="item.statusLabel"
[icon]="item.statusIcon"
[label]="item.statusLabel()"
[icon]="item.statusIcon()"
></pi-chip-status>
<span *ngIf="item.status"></span>
<ng-container *ngIf="hasForm; else defaultIcon">
<ng-container *ngIf="hasForm(); else defaultIcon">
<pi-icon-button
(execute)="toggleState(item, i)"
appearance="ghost"
@@ -69,8 +69,8 @@
<ng-template #defaultIcon>
<pi-icon
icon="chevron-forward"
[size]="appearance === 'outline' ? 'x-small' : 'small'"
[color]="color === 'white' ? 'grey' : color"
[size]="appearance() === 'outline' ? 'x-small' : 'small'"
[color]="color() === 'white' ? 'grey' : color()"
></pi-icon>
</ng-template>
</aside>
@@ -78,7 +78,7 @@
<!-- SUMMARY -->
<section
*ngIf="!!item?.summaryContent && !isItemExpanded(i)"
*ngIf="!!item?.summaryContent() && !isItemExpanded(i)"
class="pi-accordion-item-content pi-accordion-item-content__summary"
>
<ng-container
@@ -124,7 +124,7 @@
[ngTemplateOutlet]="item?.customHeader?.templateRef || defaultHeader"
[ngTemplateOutletContext]="{ $implicit: item, index: i, isExpanded: isItemExpanded(i) }"
></ng-container>
<aside *ngIf="hasChevron">
<aside *ngIf="hasChevron()">
<pi-chip-status
*ngIf="item.status && !isItemExpanded(i)"
[status]="item.status"
@@ -133,8 +133,8 @@
<span *ngIf="item.status && !isItemExpanded(i)"></span>
<pi-icon
icon="chevron-forward"
[size]="appearance === 'outline' ? 'x-small' : 'small'"
[color]="color === 'white' ? 'grey' : color"
[size]="appearance() === 'outline' ? 'x-small' : 'small'"
[color]="color() === 'white' ? 'grey' : color()"
></pi-icon>
</aside>
</header>

View File

@@ -4,13 +4,13 @@ import {
ChangeDetectorRef,
Component,
ContentChildren,
EventEmitter,
HostBinding,
Input,
OnChanges,
Output,
QueryList,
SimpleChanges,
input,
output
} from '@angular/core';
import { padding, styleType, textColor } from '../../../styles';
import { PiAccordionItemDirective } from '../directives/accordion-content.directive';
@@ -41,25 +41,27 @@ import { TranslatePipe } from '@ngx-translate/core';
})
export class PiAccordionComponent implements OnChanges, AfterContentInit {
@HostBinding('class') get classes(): string {
const colorClass = `pi-accordion__${this.color}`;
const colorClass = `pi-accordion__${this.color()}`;
const appearance = this.appearance();
const appearanceClass =
this.appearance !== 'default' && `pi-accordion__appearance--${this.appearance}`;
appearance !== 'default' && `pi-accordion__appearance--${appearance}`;
const direction = this.direction();
const directionClass =
this.direction !== 'default' && `pi-accordion__direction--${this.direction}`;
const paddingClass = `pi-accordion__padding--${this.padding}`;
direction !== 'default' && `pi-accordion__direction--${direction}`;
const paddingClass = `pi-accordion__padding--${this.padding()}`;
return ['pi-accordion', colorClass, appearanceClass, directionClass, paddingClass].join(' ');
}
@Input() expandedItemIndex!: number;
@Input() appearance: 'default' | 'outline' | 'fill' = 'default';
@Input() color: styleType = 'white';
@Input() direction: 'default' | 'horizontal' = 'default';
@Input() hasForm = false;
@Input() padding: padding = 'm';
readonly appearance = input<'default' | 'outline' | 'fill'>('default');
readonly color = input<styleType>('white');
readonly direction = input<'default' | 'horizontal'>('default');
readonly hasForm = input(false);
readonly padding = input<padding>('m');
@Input() hasChevron = true;
readonly hasChevron = input(true);
@Output() expandedItemIndexChange: EventEmitter<number> = new EventEmitter<number>();
readonly expandedItemIndexChange = output<number>();
@ContentChildren(PiAccordionItemDirective) items!: QueryList<PiAccordionItemDirective>;
@@ -81,7 +83,7 @@ export class PiAccordionComponent implements OnChanges, AfterContentInit {
}
toggleState = (item: PiAccordionItemDirective, index: number) => {
if (this.direction === 'horizontal' && this.isItemExpanded(index)) return;
if (this.direction() === 'horizontal' && this.isItemExpanded(index)) return;
if (item.status === 'disabled') return;
if (this.expandedItemIndex === index) {
this.expandedItemIndex = null;
@@ -96,12 +98,12 @@ export class PiAccordionComponent implements OnChanges, AfterContentInit {
setAccordionItemClasses(item: PiAccordionItemDirective, index: number): string {
const expandedClass = this.isItemExpanded(index) ? 'is-expanded' : 'is-collapsed';
const statusClass = item.status && 'has-status' + ' ' + `is-${item.status}`;
const isConfidentialClass = item.isConfidential ? 'is-confidential' : '';
const isConfidentialClass = item.isConfidential() ? 'is-confidential' : '';
return [expandedClass, statusClass, isConfidentialClass].join(' ');
}
getHeaderTextColor(): textColor {
switch (this.color) {
switch (this.color()) {
case 'primary':
return 'primary';
case 'accent':

View File

@@ -1,10 +1,11 @@
import {
AfterViewInit,
ContentChild,
Directive,
HostBinding,
Input,
TemplateRef,
input,
contentChild
} from '@angular/core';
import { status } from '../../../util/status';
@@ -50,14 +51,13 @@ export class PiAccordionFooterDirective {
@Directive({ selector: 'pi-accordion-item', })
export class PiAccordionItemDirective {
@Input() title = '';
@Input() subtitle = '';
readonly title = input('');
readonly subtitle = input('');
@Input() status!: status;
@Input() statusLabel: string;
@Input() statusIcon: string;
@Input() isConfidential = false;
@ContentChild(PiAccordionItemContentDirective) content: PiAccordionItemContentDirective;
@ContentChild(PiAccordionSummaryContentDirective)
summaryContent: PiAccordionSummaryContentDirective;
@ContentChild(PiAccordionItemHeaderDirective) customHeader: PiAccordionItemHeaderDirective;
readonly statusLabel = input<string>();
readonly statusIcon = input<string>();
readonly isConfidential = input(false);
readonly content = contentChild(PiAccordionItemContentDirective);
readonly summaryContent = contentChild(PiAccordionSummaryContentDirective);
readonly customHeader = contentChild(PiAccordionItemHeaderDirective);
}

View File

@@ -1,15 +1,15 @@
<main
(click)="execute.emit()"
pi-background-image
[isResponsive]="isImgResponsive"
[image]="pathImg"
[extension]="extension"
[isResponsive]="isImgResponsive()"
[image]="pathImg()"
[extension]="extension()"
position="right center"
size="contain"
>
<section>
<header>
<h3 bold>{{ title }}</h3>
<h3 bold>{{ title() }}</h3>
<span *ngIf="message">{{ message }}</span>
</header>
<!-- Action -->
@@ -19,7 +19,7 @@
icon="chevron-forward"
iconColor="white"
iconSize="small"
[appearance]="mode === 'light' ? 'ghost' : 'fill'"
[appearance]="mode() === 'light' ? 'ghost' : 'fill'"
[hasPadding]="false"
>{{ buttonText }}</pi-icon-button
>

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';
import { Component, HostBinding, Input, input, output } from '@angular/core';
import { PiBackgroundImageDirective } from '../../image/background-image.directive';
import { PiTextWeightBoldDirective } from '../../text/directives/text-weights.directive';
import { NgIf } from '@angular/common';
@@ -17,22 +17,22 @@ import { PiIconButtonComponent } from '../../button/icon-button/icon-button.comp
})
export class PiBannerComponent {
@HostBinding('class') get classes(): string {
const modeClass = `pi-banner__mode--${this.mode}`;
const modeClass = `pi-banner__mode--${this.mode()}`;
return ['pi-banner', modeClass].join(' ');
}
// Skin
@Input() mode: 'dark' | 'light' = 'dark';
readonly mode = input<'dark' | 'light'>('dark');
// Text
@Input() title: string | undefined;
readonly title = input<string>();
@Input() message: string | undefined;
@Input() buttonText: string | undefined;
// Image
@Input() pathImg: string | undefined;
@Input() isImgResponsive: boolean = true;
@Input() extension: 'jpg' | 'svg' | 'gif' = 'gif';
readonly pathImg = input<string>();
readonly isImgResponsive = input<boolean>(true);
readonly extension = input<'jpg' | 'svg' | 'gif'>('gif');
@Output() execute: EventEmitter<MouseEvent> = new EventEmitter();
readonly execute = output<MouseEvent>();
}

View File

@@ -1,7 +1,7 @@
<button
#button
(click)="onClickHandler($event)"
[disabled]="disabled"
[disabled]="disabled()"
[class]="[
'pi-button',
'pi-button__action',
@@ -16,7 +16,7 @@
>
<span *ngIf="text">{{ text }}</span>
<svg *ngIf="hasIcon" viewBox="0 0 6 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg *ngIf="hasIcon()" viewBox="0 0 6 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<path
d="M1 1C4.5 4 5 4.38484 5 4.5C5 4.61516 4.5 5 1 8"

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Input, input } from '@angular/core';
import { buttonSize, mode } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
import { NgIf } from '@angular/common';
@@ -17,27 +17,30 @@ export class PiActionButtonComponent extends PiBaseButtonComponent {
);
}
@Input() previous = false;
@Input() override size: buttonSize = 'medium';
readonly previous = input(false);
override readonly size = input<buttonSize>('medium');
@Input() text: string | undefined;
@Input() hasPadding = true;
@Input() hasIcon = true;
@Input() label: string | undefined;
@Input() buttonType: 'default' | 'menu-item' = 'default';
@Input() mode: mode = 'dark';
@Input() direction: 'back' | 'forward' = 'forward';
@Input() fontWeight: '300' | '400' | '600' = '600';
readonly hasPadding = input(true);
readonly hasIcon = input(true);
readonly label = input<string>();
readonly buttonType = input<'default' | 'menu-item'>('default');
readonly mode = input<mode>('dark');
readonly direction = input<'back' | 'forward'>('forward');
readonly fontWeight = input<'300' | '400' | '600'>('600');
get buttonColorClass(): string | null {
return this.color ? `pi-color__${this.color}` : null;
const color = this.color();
return color ? `pi-color__${color}` : null;
}
get directionClass(): string | null {
return this.direction ? `pi-action-button__direction--${this.direction}` : null;
const direction = this.direction();
return direction ? `pi-action-button__direction--${direction}` : null;
}
override get sizeClass(): string | null {
return this.size ? `pi-button__${this.size}` : null;
const size = this.size();
return size ? `pi-button__${size}` : null;
}
get textClass(): string | null {
@@ -45,26 +48,30 @@ export class PiActionButtonComponent extends PiBaseButtonComponent {
}
get fontWeightClass(): string | null {
return this.fontWeight ? `pi-action-button__font-weight--${this.fontWeight}` : '';
const fontWeight = this.fontWeight();
return fontWeight ? `pi-action-button__font-weight--${fontWeight}` : '';
}
get hasPaddingClass(): string | null {
return this.hasPadding ? null : 'pi-button__trimmed';
return this.hasPadding() ? null : 'pi-button__trimmed';
}
get hasIconClass(): string | null {
return this.hasIcon ? null : 'has-icon';
return this.hasIcon() ? null : 'has-icon';
}
override get appearanceClass(): string | null {
return this.appearance !== 'fill' ? `pi-button__appearance--${this.appearance}` : null;
const appearance = this.appearance();
return appearance !== 'fill' ? `pi-button__appearance--${appearance}` : null;
}
get buttonTypeClass(): string | null {
return this.buttonType !== 'default' ? `pi-button__type--${this.buttonType}` : null;
const buttonType = this.buttonType();
return buttonType !== 'default' ? `pi-button__type--${buttonType}` : null;
}
get modeClass(): string | null {
return this.mode && `pi-color__mode--${this.mode}`;
const modeValue = this.mode();
return modeValue && `pi-color__mode--${modeValue}`;
}
}

View File

@@ -1,18 +1,18 @@
// Angular
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Directive, OnInit, input, output } from '@angular/core';
import { buttonSize, styleType, buttonStyle, flexDirection } from '../../styles';
// Style definitions
@Directive()
export abstract class PiBaseButtonComponent implements OnInit {
@Input() size: buttonSize = 'medium';
@Input() color: styleType = 'primary';
@Input() appearance: buttonStyle = 'fill';
@Input() disabled = false;
@Input() allowPropagation!: boolean;
@Input() flexDirection!: flexDirection;
readonly size = input<buttonSize>('medium');
readonly color = input<styleType>('primary');
readonly appearance = input<buttonStyle>('fill');
readonly disabled = input(false);
readonly allowPropagation = input.required<boolean>();
readonly flexDirection = input.required<flexDirection>();
@Output() execute: EventEmitter<MouseEvent> = new EventEmitter();
readonly execute = output<MouseEvent>();
ngOnInit(): void {
this.sizeClass;
@@ -20,19 +20,19 @@ export abstract class PiBaseButtonComponent implements OnInit {
}
protected get colorClass(): string {
return `pi-color__${this.color}`;
return `pi-color__${this.color()}`;
}
protected get sizeClass(): string {
return `pi-button__${this.size}`;
return `pi-button__${this.size()}`;
}
protected get appearanceClass(): string {
return `pi-button__appearance--${this.appearance}`;
return `pi-button__appearance--${this.appearance()}`;
}
protected get flexDirectionClass(): string {
return `pi-button__flex-direction--${this.flexDirection}`;
return `pi-button__flex-direction--${this.flexDirection()}`;
}
protected get disabledClass(): string {
@@ -40,8 +40,8 @@ export abstract class PiBaseButtonComponent implements OnInit {
}
onClickHandler(event: any): void {
if (!this.disabled) {
if (!this.allowPropagation) {
if (!this.disabled()) {
if (!this.allowPropagation()) {
event.preventDefault();
event.stopPropagation();
}

View File

@@ -1,14 +1,14 @@
import { Directive, HostBinding, Input } from '@angular/core';
import { Directive, HostBinding, input } from '@angular/core';
import { buttonSize } from '../../styles';
// Style
@Directive({ selector: '[pi-ghost]', })
export class PiGhostButtonDirective {
@HostBinding('class') get classes(): string {
const hasPaddingClass = this.hasPadding ? '' : 'pi-button__trimmed';
const hasPaddingClass = this.hasPadding() ? '' : 'pi-button__trimmed';
return ['pi-button', 'pi-button__appearance--ghost', hasPaddingClass].join(' ');
}
@Input() hasPadding = true;
readonly hasPadding = input(true);
}
@Directive({ selector: '[pi-outline]', })
@@ -24,10 +24,11 @@ export class PiButtonSizeDirective {
return this.sizeClass;
}
@Input() size!: buttonSize;
readonly size = input.required<buttonSize>();
protected get sizeClass(): string {
return !!this.size && `pi-button__${this.size}`;
const size = this.size();
return !!size && `pi-button__${size}`;
}
}

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
output
} from '@angular/core';
import { ComponentFamilyClass } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
@@ -24,5 +23,5 @@ export class PiChevronButtonComponent extends PiBaseButtonComponent {
);
}
@Output() toggle: EventEmitter<void> = new EventEmitter<void>();
readonly toggle = output<void>();
}

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
output
} from '@angular/core';
import { ComponentFamilyClass } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
@@ -19,12 +18,12 @@ import { TranslatePipe } from '@ngx-translate/core';
})
export class PiCloseButtonComponent extends PiBaseButtonComponent {
@HostBinding('class') get classes(): string {
const hasLabelClass = this.hasLabel === false ? 'pi-close-button__single' : '';
const hasLabelClass = this.hasLabel() === false ? 'pi-close-button__single' : '';
return ['pi-close-button', ComponentFamilyClass.Button, this.sizeClass, hasLabelClass].join(
' '
);
}
@Input() hasLabel = true;
@Output() toggle: EventEmitter<void> = new EventEmitter<void>();
readonly hasLabel = input(true);
readonly toggle = output<void>();
}

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, output } from '@angular/core';
import { ComponentFamilyClass } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
import { TranslatePipe } from '@ngx-translate/core';
@@ -14,5 +14,5 @@ export class PiHamburgerComponent extends PiBaseButtonComponent {
@HostBinding('class') get classes(): string {
return ['pi-hamburger', ComponentFamilyClass.Button, this.colorClass].join(' ');
}
@Output() toggle: EventEmitter<void> = new EventEmitter<void>();
readonly toggle = output<void>();
}

View File

@@ -1,4 +1,4 @@
<ng-container *ngIf="iconType === 'custom'; else defaultIcon"
<ng-container *ngIf="iconType() === 'custom'; else defaultIcon"
><button
#content
(click)="onClickHandler($event)"
@@ -8,7 +8,7 @@
size="size"
width="width"
text="text"
[disabled]="disabled"
[disabled]="disabled()"
[class]="[
'pi-button',
'pi-button__icon',
@@ -22,7 +22,7 @@
>
<span *ngIf="text">{{ text }}</span>
<ng-content></ng-content>
<img src="/assets/icons/{{ icon }}.svg" /></button
<img src="/assets/icons/{{ icon() }}.svg" /></button
></ng-container>
<ng-template #defaultIcon
@@ -35,7 +35,7 @@
size="size"
width="width"
text="text"
[disabled]="disabled"
[disabled]="disabled()"
[class]="[
'pi-button',
'pi-button__icon',
@@ -47,8 +47,8 @@
modeClass
]"
>
<mat-icon *ngIf="previous" [svgIcon]="icon" alt="icon"></mat-icon>
<mat-icon *ngIf="previous()" [svgIcon]="icon()" alt="icon"></mat-icon>
<span *ngIf="text">{{ text }}</span>
<ng-content></ng-content>
<mat-icon *ngIf="!previous" [svgIcon]="icon" alt="icon"></mat-icon></button
<mat-icon *ngIf="!previous()" [svgIcon]="icon()" alt="icon"></mat-icon></button
></ng-template>

View File

@@ -4,7 +4,8 @@ import {
ElementRef,
HostBinding,
Input,
ViewChild,
input,
viewChild
} from '@angular/core';
import { buttonSize, mode } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
@@ -20,8 +21,8 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiIconButtonComponent extends PiBaseButtonComponent {
@HostBinding('class') get classes(): string {
const customIconClass = this.iconType === 'custom' && 'pi-icon-button__custom-icon';
const isResponsiveClass = this.isResponsive ? 'is-responsive' : '';
const customIconClass = this.iconType() === 'custom' && 'pi-icon-button__custom-icon';
const isResponsiveClass = this.isResponsive() ? 'is-responsive' : '';
return [
'pi-icon-button',
this.sizeClass,
@@ -31,28 +32,30 @@ export class PiIconButtonComponent extends PiBaseButtonComponent {
isResponsiveClass,
].join(' ');
}
@ViewChild('content', { static: false })
contentRef!: ElementRef;
readonly contentRef = viewChild.required<ElementRef>('content');
@Input() icon: string | undefined;
@Input() iconType: 'fill' | 'default' | 'custom' = 'default';
@Input() previous = false;
@Input() width: buttonSize = 'medium';
readonly icon = input<string>();
readonly iconType = input<'fill' | 'default' | 'custom'>('default');
readonly previous = input(false);
readonly width = input<buttonSize>('medium');
@Input() text: string | undefined;
@Input() hasPadding = true;
@Input() mode: mode = 'dark';
@Input() isResponsive = false;
readonly hasPadding = input(true);
readonly mode = input<mode>('dark');
readonly isResponsive = input(false);
get buttonTypeClass(): string | null {
return this.appearance ? `pi-button__appearance--${this.appearance}` : null;
const appearance = this.appearance();
return appearance ? `pi-button__appearance--${appearance}` : null;
}
get buttonColorClass(): string | null {
return this.color ? `pi-color__${this.color}` : null;
const color = this.color();
return color ? `pi-color__${color}` : null;
}
get widthClass(): string | null {
return this.width ? `pi-button__${this.width}` : null;
const width = this.width();
return width ? `pi-button__${width}` : null;
}
get textClass(): string | null {
@@ -60,14 +63,15 @@ export class PiIconButtonComponent extends PiBaseButtonComponent {
}
get iconPositionClass(): string | null {
return this.previous ? 'pi-button__icon--previous' : null;
return this.previous() ? 'pi-button__icon--previous' : null;
}
get hasPaddingClass(): string | null {
return this.hasPadding ? null : 'pi-button__trimmed';
return this.hasPadding() ? null : 'pi-button__trimmed';
}
get modeClass(): string | null {
return this.mode && `pi-color__mode--${this.mode}`;
const modeValue = this.mode();
return modeValue && `pi-color__mode--${modeValue}`;
}
}

View File

@@ -1,4 +1,4 @@
<span *ngIf="icon !== 'check'; else checkIconTemplate" (click)="execute.emit()"></span>
<span *ngIf="icon() !== 'check'; else checkIconTemplate" (click)="execute.emit()"></span>
<ng-template #checkIconTemplate
><mat-icon size="size" svgIcon="check" color="color" (click)="execute.emit()"></mat-icon

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { PiBaseButtonComponent } from '../base-button.component';
import { NgIf } from '@angular/common';
import { MatIcon } from '@angular/material/icon';
@@ -21,17 +21,17 @@ export class PiRadioButtonComponent extends PiBaseButtonComponent {
].join(' ');
}
@Input() icon: 'bullet' | 'check' = 'check';
readonly icon = input<'bullet' | 'check'>('check');
// Status
@Input() isActive!: boolean;
@Input() isDisabled!: boolean;
readonly isActive = input.required<boolean>();
readonly isDisabled = input.required<boolean>();
get iconClass(): string | null {
return this.icon === 'check' ? 'pi-radio-button__icon--check' : null;
return this.icon() === 'check' ? 'pi-radio-button__icon--check' : null;
}
get isActiveClass(): string | null {
return this.isActive ? 'is-active' : null;
return this.isActive() ? 'is-active' : null;
}
}

View File

@@ -5,8 +5,8 @@
<ng-container
*ngTemplateOutlet="
contentType === 'icon' ? iconTemplate : textTemplate;
context: { $implicit: content[0] }
contentType() === 'icon' ? iconTemplate : textTemplate;
context: { $implicit: content()[0] }
"
></ng-container>
@@ -19,8 +19,8 @@
<ng-container
*ngTemplateOutlet="
contentType === 'icon' ? iconTemplate : textTemplate;
context: { $implicit: content[1] }
contentType() === 'icon' ? iconTemplate : textTemplate;
context: { $implicit: content()[1] }
"
></ng-container>

View File

@@ -1,10 +1,10 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
output
} from '@angular/core';
import { ComponentFamilyClass } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
@@ -20,7 +20,7 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiSwitchButtonComponent extends PiBaseButtonComponent {
@HostBinding('class') get classes(): string {
const contentTypeClass = this.contentType === 'icon' ? 'has-icon' : '';
const contentTypeClass = this.contentType() === 'icon' ? 'has-icon' : '';
return [
'pi-switch-button',
ComponentFamilyClass.Button,
@@ -31,10 +31,13 @@ export class PiSwitchButtonComponent extends PiBaseButtonComponent {
}
@Input() isActive = true;
@Output() toggledTo = new EventEmitter();
readonly toggledTo = output();
@Input() contentType: 'icon' | 'text' = 'icon';
@Input() content!: [string, string];
readonly contentType = input<'icon' | 'text'>('icon');
readonly content = input.required<[
string,
string
]>();
toggleSelected(): void {
if (this.isActive) {

View File

@@ -1,6 +1,6 @@
<button (click)="onClickHandler($event)" [disabled]="isDisabled" class="pi-button__toggle">
<mat-icon *ngIf="icon" [svgIcon]="icon" [color]="color"></mat-icon>
<span>{{ text }}</span>
<button (click)="onClickHandler($event)" [disabled]="isDisabled()" class="pi-button__toggle">
<mat-icon *ngIf="icon" [svgIcon]="icon" [color]="color()"></mat-icon>
<span>{{ text() }}</span>
<ng-content></ng-content>
</button>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Input, input } from '@angular/core';
import { buttonSize } from '../../../styles';
import { PiBaseButtonComponent } from '../base-button.component';
import { NgIf } from '@angular/common';
@@ -13,9 +13,10 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiToggleButtonComponent extends PiBaseButtonComponent {
@HostBinding('class') get classes(): string {
const isActiveClass = this.isActive && 'is-active';
const isDisabledClass = this.isDisabled ? 'is-disabled' : '';
const iconTypeClass = this.iconType !== 'default' && `pi-toggle-button__icon--${this.iconType}`;
const isActiveClass = this.isActive() && 'is-active';
const isDisabledClass = this.isDisabled() ? 'is-disabled' : '';
const iconType = this.iconType();
const iconTypeClass = iconType !== 'default' && `pi-toggle-button__icon--${iconType}`;
return [
'pi-toggle-button',
this.sizeClass,
@@ -28,14 +29,14 @@ export class PiToggleButtonComponent extends PiBaseButtonComponent {
// Content
@Input() icon: string | undefined;
@Input() text: string | undefined;
readonly text = input<string>();
@Input() amount: number | undefined;
// Skin
@Input() width: buttonSize = 'large';
@Input() iconType: 'stroke' | 'default' = 'stroke';
readonly width = input<buttonSize>('large');
readonly iconType = input<'stroke' | 'default'>('stroke');
// Status
@Input() isActive!: boolean;
@Input() isDisabled!: boolean;
readonly isActive = input.required<boolean>();
readonly isDisabled = input.required<boolean>();
}

View File

@@ -1,27 +1,27 @@
// Angular
import { Directive, EventEmitter, HostBinding, Input, OnInit, Output } from '@angular/core';
import { Directive, HostBinding, Input, OnInit, input, output } from '@angular/core';
// Style definitions
import { alignment, context, gap, mode, opacity, padding } from '../../styles';
@Directive()
export abstract class PiBaseCardComponent implements OnInit {
@Input() hasShadow = true;
@Input() isClickable = false;
@Input() isStroked = false;
@Input() color: 'primary' | 'accent' | 'highlighted' | 'grey' | 'white' = 'white';
@Input() mode: mode = 'light';
@Input() alignment!: alignment;
@Input() gap!: gap;
@Input() padding: padding = 'xxl';
readonly hasShadow = input(true);
readonly isClickable = input(false);
readonly isStroked = input(false);
readonly color = input<'primary' | 'accent' | 'highlighted' | 'grey' | 'white'>('white');
readonly mode = input<mode>('light');
readonly alignment = input.required<alignment>();
readonly gap = input.required<gap>();
readonly padding = input<padding>('xxl');
@Input() linkLabel: string | undefined;
@Input() opacity: opacity;
@Input() innerPadding!: padding;
@Input() context!: context;
@Input() hasEqualPadding = false;
@Input() hasPadding = true;
readonly opacity = input<opacity>();
readonly innerPadding = input.required<padding>();
readonly context = input.required<context>();
readonly hasEqualPadding = input(false);
readonly hasPadding = input(true);
@Output() execute: EventEmitter<void> = new EventEmitter<void>();
readonly execute = output<void>();
ngOnInit(): void {
this.colorClass;
@@ -37,39 +37,44 @@ export abstract class PiBaseCardComponent implements OnInit {
}
protected get hasShadowClass(): string | boolean | undefined {
return this.hasShadow && 'has-shadow';
return this.hasShadow() && 'has-shadow';
}
protected get isClickableClass(): string | undefined {
return this.isClickable && 'is-clickable';
return this.isClickable() && 'is-clickable';
}
protected get colorClass(): string {
return this.color && `pi-color__${this.color}`;
const color = this.color();
return color && `pi-color__${color}`;
}
protected get alignmentClass(): string | undefined {
return this.alignment && `pi-card__align-items--${this.alignment}`;
const alignmentValue = this.alignment();
return alignmentValue && `pi-card__align-items--${alignmentValue}`;
}
protected get gapClass(): string | undefined {
return this.gap && `pi-card__gap--${this.gap}`;
const gapValue = this.gap();
return gapValue && `pi-card__gap--${gapValue}`;
}
protected get paddingClass(): string | undefined {
return this.padding && `pi-card__padding--${this.padding}`;
const paddingValue = this.padding();
return paddingValue && `pi-card__padding--${paddingValue}`;
}
protected get modeClass(): string | undefined {
return this.mode ? `pi-color__mode--${this.mode}` : '';
const modeValue = this.mode();
return modeValue ? `pi-color__mode--${modeValue}` : '';
}
protected get isStrokedClass(): string {
return this.isStroked ? 'is-stroked' : '';
return this.isStroked() ? 'is-stroked' : '';
}
protected get hasEqualPaddingClass(): string {
return this.hasEqualPadding ? 'has-equal-inner-padding' : '';
return this.hasEqualPadding() ? 'has-equal-inner-padding' : '';
}
protected get hasLinkLabelClass(): string {
@@ -77,22 +82,25 @@ export abstract class PiBaseCardComponent implements OnInit {
}
protected get opacityClass(): string {
return this.opacity ? `pi-color__opacity--${this.opacity}` : '';
const opacityValue = this.opacity();
return opacityValue ? `pi-color__opacity--${opacityValue}` : '';
}
protected get innerPaddingClass(): string {
return this.innerPadding ? `pi-card__inner-padding--${this.innerPadding}` : '';
const innerPadding = this.innerPadding();
return innerPadding ? `pi-card__inner-padding--${innerPadding}` : '';
}
protected get isContectPublicClass(): string | undefined {
return this.context === 'public' ? 'is-public' : '';
return this.context() === 'public' ? 'is-public' : '';
}
protected get hasPaddingClass(): string | undefined {
return !this.padding ? '' : 'has-padding';
return !this.padding() ? '' : 'has-padding';
}
protected get contextClass(): string | undefined {
return this.context && `is-${this.context}`;
const contextValue = this.context();
return contextValue && `is-${contextValue}`;
}
}

View File

@@ -5,7 +5,7 @@
<ng-content select="pi-card-left-content"> </ng-content>
<ng-content select="pi-card-right-content"></ng-content>
<span *ngIf="isClickable && !!linkLabel" (click)="execute.emit()">
<span *ngIf="isClickable() && !!linkLabel" (click)="execute.emit()">
<a>
{{ linkLabel }}
<pi-icon icon="open-details" color="primary"></pi-icon>

View File

@@ -1,6 +1,6 @@
<main>
<pi-icon-button
*ngIf="hasOverflow && !hideSwipeButtons"
*ngIf="hasOverflow && !hideSwipeButtons()"
[icon]="prevIcon"
(execute)="prev()"
[disabled]="!canSwipePrev"
@@ -14,7 +14,7 @@
</ng-container>
</section>
<pi-icon-button
*ngIf="hasOverflow && !hideSwipeButtons"
*ngIf="hasOverflow && !hideSwipeButtons()"
[icon]="nextIcon"
(execute)="next()"
[disabled]="!canSwipeNext"
@@ -23,7 +23,7 @@
</main>
<!-- Paginator -->
<footer *ngIf="hasOverflow && !hidePaginator">
<footer *ngIf="hasOverflow && !hidePaginator()">
<div
*ngFor="let i of pages; index as index"
[class]="index === currentPageIndex ? 'is-active' : ''"

View File

@@ -7,17 +7,16 @@ import {
Component,
ContentChildren,
ElementRef,
EventEmitter,
HostBinding,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
QueryList,
Renderer2,
SimpleChanges,
ViewChild,
input,
output,
viewChild
} from '@angular/core';
// Shared
@@ -46,11 +45,13 @@ export class PiCarouselComponent
@HostBinding('class') get classes(): string {
const itemsNumberClass =
this.carouselItems && `pi-carousel__${this.carouselItems.length}-items`;
const directionTypeClass = this.direction && `pi-carousel__${this.direction}`;
const colorClass = `pi-carousel__${this.color}`;
const typeClass = `pi-carousel__${this.type}`;
const isDraggableClass = this.isDraggable ? 'is-draggable' : '';
const justifyClass = this.justify && `pi-carousel__justify-content--${this.justify}`;
const direction = this.direction();
const directionTypeClass = direction && `pi-carousel__${direction}`;
const colorClass = `pi-carousel__${this.color()}`;
const typeClass = `pi-carousel__${this.type()}`;
const isDraggableClass = this.isDraggable() ? 'is-draggable' : '';
const justifyValue = this.justify();
const justifyClass = justifyValue && `pi-carousel__justify-content--${justifyValue}`;
return [
ComponentFamilyClass.Carousel,
itemsNumberClass,
@@ -63,24 +64,24 @@ export class PiCarouselComponent
}
// Skin
@Input() type: 'symmetric' | 'linear' = 'linear';
readonly type = input<'symmetric' | 'linear'>('linear');
@Input() direction: 'horizontal' | 'vertical' = 'horizontal';
readonly direction = input<'horizontal' | 'vertical'>('horizontal');
@Input() color: theming = 'primary';
@Input() justify!: justify;
readonly color = input<theming>('primary');
readonly justify = input.required<justify>();
@Input() device!: Device;
readonly device = input.required<Device>();
/**
* If true, the carousel will not show the next and previous buttons.
*/
@Input() hideSwipeButtons = true;
readonly hideSwipeButtons = input(true);
/**
* If true, the carousel will not show the pagination.
*/
@Input() hidePaginator = false;
readonly hidePaginator = input(false);
// BEHAVIOUR
@@ -88,44 +89,44 @@ export class PiCarouselComponent
* If a number of items per device (itemsDesktop, itemsTablet, itemsMobile) is provided,
* each item will take the total width of the carousel divided by the number of items.
*/
@Input() itemsDesktop!: number;
readonly itemsDesktop = input.required<number>();
/**
* If no number of items for tablet is provided,
* the number of items for desktop will be used.
*/
@Input() itemsTablet: number;
readonly itemsTablet = input<number>();
/**
* If no number of items for mobile is provided,
* the number of items for desktop will be used.
*/
@Input() itemsMobile: number;
readonly itemsMobile = input<number>();
/**
* If we want to set a custom width for each item,
* we can provide the width in pixels and this will override the number of items per device.
* The carousel will display per page the number of items that fit in the total width.
*/
@Input() itemWidth!: number;
readonly itemWidth = input.required<number>();
/**
* If true, the user will be able to drag the carousel to move across items.
*/
@Input() isDraggable: boolean = true;
readonly isDraggable = input<boolean>(true);
/**
* If true, when the user clicks on the next or previous button,
* the carousel will move to the next or previous page
* ie. currentItem will be incremented/decremented by itemsPerPage.
*/
@Input() movePerPage: boolean = false;
readonly movePerPage = input<boolean>(false);
// OUTPUTS
/**
* Emits the index of the current item when it changes.
*/
@Output() itemChanged: EventEmitter<number> = new EventEmitter<number>();
readonly itemChanged = output<number>();
/**
* carouselItems corresponds to the items that will be displayed in the carousel.
@@ -136,8 +137,7 @@ export class PiCarouselComponent
/**
* carouselContentWrapper corresponds to the section that contains the carousel items and excludes the control buttons
*/
@ViewChild('carouselContentWrapper', { read: ElementRef, static: false })
carouselContentWrapper!: ElementRef;
readonly carouselContentWrapper = viewChild.required('carouselContentWrapper', { read: ElementRef });
carouselItemsNativeElements: HTMLElement[] = [];
@@ -187,21 +187,21 @@ export class PiCarouselComponent
* Icon displayed in the next control button.
*/
get nextIcon(): string {
return this.direction === 'horizontal' ? 'chevron-forward' : 'chevron-down';
return this.direction() === 'horizontal' ? 'chevron-forward' : 'chevron-down';
}
/**
* Icon displayed in the prev control button.
*/
get prevIcon(): string {
return this.direction === 'horizontal' ? 'chevron-back' : 'chevron-up';
return this.direction() === 'horizontal' ? 'chevron-back' : 'chevron-up';
}
/**
* Returns the carousel content wrapper native element.
*/
get carouselContentElement(): HTMLElement {
return this.carouselContentWrapper.nativeElement;
return this.carouselContentWrapper().nativeElement;
}
get tallestElementHeightPx(): number {
@@ -220,13 +220,13 @@ export class PiCarouselComponent
}
get canSwipeNext(): boolean {
return this.movePerPage
return this.movePerPage()
? this.currentItem + this.itemsPerPage < this.carouselItems.length
: this.currentItem < this.carouselItems.length - 1;
}
get canSwipePrev(): boolean {
return this.movePerPage ? this.currentItem - this.itemsPerPage >= 0 : this.currentItem > 0;
return this.movePerPage() ? this.currentItem - this.itemsPerPage >= 0 : this.currentItem > 0;
}
/**
@@ -245,7 +245,7 @@ export class PiCarouselComponent
}
ngOnChanges(simpleChanges: SimpleChanges): void {
if (simpleChanges['itemWidth'] && !!this.carouselContentWrapper) {
if (simpleChanges['itemWidth'] && !!this.carouselContentWrapper()) {
this.setItemsPerPage();
}
}
@@ -254,7 +254,7 @@ export class PiCarouselComponent
this.setItemsPerPage();
this.setPages();
if (this.isDraggable) {
if (this.isDraggable()) {
this.setDragEventListeners();
}
@@ -284,7 +284,7 @@ export class PiCarouselComponent
}
next(): void {
if (this.movePerPage) {
if (this.movePerPage()) {
this.currentPageIndex < this.pages.length - 1
? (this.currentItem = (this.currentPageIndex + 1) * this.itemsPerPage)
: null;
@@ -295,7 +295,7 @@ export class PiCarouselComponent
}
prev(): void {
if (this.movePerPage) {
if (this.movePerPage()) {
this.currentPageIndex > 0
? (this.currentItem = (this.currentPageIndex - 1) * this.itemsPerPage)
: null;
@@ -306,18 +306,22 @@ export class PiCarouselComponent
}
setItemsPerPage(): void {
if (!!this.itemWidth) {
this.itemsPerPage = Math.floor(this.carouselContentElement.clientWidth / this.itemWidth) || 1;
const itemWidth = this.itemWidth();
if (!!itemWidth) {
this.itemsPerPage = Math.floor(this.carouselContentElement.clientWidth / itemWidth) || 1;
} else {
switch (this.device) {
const itemsDesktop = this.itemsDesktop();
const itemsTablet = this.itemsTablet();
const itemsMobile = this.itemsMobile();
switch (this.device()) {
case 'DESKTOP':
this.itemsPerPage = this.itemsDesktop ? this.itemsDesktop : this.carouselItems.length;
this.itemsPerPage = itemsDesktop ? itemsDesktop : this.carouselItems.length;
break;
case 'TABLET':
this.itemsPerPage = this.itemsTablet ? this.itemsTablet : this.carouselItems.length;
this.itemsPerPage = itemsTablet ? itemsTablet : this.carouselItems.length;
break;
case 'MOBILE':
this.itemsPerPage = this.itemsMobile ? this.itemsMobile : this.carouselItems.length;
this.itemsPerPage = itemsMobile ? itemsMobile : this.carouselItems.length;
break;
}
}
@@ -335,7 +339,7 @@ export class PiCarouselComponent
selectItem(index: number): void {
this.currentItem = index;
if (this.hasOverflow && !this.movePerPage) {
if (this.hasOverflow && !this.movePerPage()) {
this.carouselTranslation(index);
}
}
@@ -370,7 +374,7 @@ export class PiCarouselComponent
private setDragEventListeners(): void {
this.mousedownListener = this.renderer.listen(
this.carouselContentWrapper.nativeElement,
this.carouselContentWrapper().nativeElement,
'mousedown',
(event) => {
this.dragStart(event);
@@ -392,7 +396,7 @@ export class PiCarouselComponent
});
this.touchstartListener = this.renderer.listen(
this.carouselContentWrapper.nativeElement,
this.carouselContentWrapper().nativeElement,
'touchstart',
(event) => {
this.dragStart(event);
@@ -433,7 +437,8 @@ export class PiCarouselComponent
* Sets a minimum dragging width based on either 80% of the item width if provided
* Otherwise 80% of the width of one item in terms of the number of items displayed per page
*/
const minDraggingWidth = this.itemWidth ? 0.8 * this.itemWidth : 0.8 * (100 / this.itemsPerPage);
const itemWidth = this.itemWidth();
const minDraggingWidth = itemWidth ? 0.8 * itemWidth : 0.8 * (100 / this.itemsPerPage);
this.isDragging = true;
@@ -466,39 +471,40 @@ export class PiCarouselComponent
}
private carouselTranslation(currentItem: number): void {
if (this.type === 'linear' && currentItem <= this.carouselItems.length - this.itemsPerPage) {
this.carouselItemsTranslation(currentItem, `-${currentItem * 100}%`, this.direction);
} else if (this.type === 'symmetric') {
const type = this.type();
if (type === 'linear' && currentItem <= this.carouselItems.length - this.itemsPerPage) {
this.carouselItemsTranslation(currentItem, `-${currentItem * 100}%`, this.direction());
} else if (type === 'symmetric') {
if (currentItem < this.numberOfSideItems) {
// If we are at the beginning of the carousel
this.carouselItemsTranslation(currentItem, '0', this.direction);
this.carouselItemsTranslation(currentItem, '0', this.direction());
} else if (this.carouselItems.length - currentItem > this.numberOfSideItems) {
// If we are at the end of the carousel
this.carouselItemsTranslation(
currentItem,
`-${(currentItem - this.numberOfSideItems) * 100}%`,
this.direction
this.direction()
);
} else {
// If we are at the end of the carousel
this.carouselItemsTranslation(
currentItem,
`-${(this.carouselItems.length - this.itemsPerPage) * 100}%`,
this.direction
this.direction()
);
}
}
}
private setStyleOnInit(): void {
this.direction === 'horizontal'
this.direction() === 'horizontal'
? this.setHorizontalCarouselStyle()
: this.setVerticalCarouselStyle();
}
private carouselItemsTranslation(currentItem: number, translation: string, axis: string) {
this.carouselItemsNativeElements.forEach((item, index) => {
const scale: number = index === currentItem && this.type === 'symmetric' ? 1.15 : 1;
const scale: number = index === currentItem && this.type() === 'symmetric' ? 1.15 : 1;
const transform: string =
axis === 'horizontal' ? `translateX(${translation})` : `translateY(${translation})`;
this.renderer.setStyle(item, 'transform', `${transform} scale(${scale})`);
@@ -507,9 +513,10 @@ export class PiCarouselComponent
private setHorizontalCarouselStyle(): void {
this.carouselItemsNativeElements.forEach((item) => {
if (!!this.itemWidth) {
this.renderer.setStyle(item, 'min-width', `${this.itemWidth}px`);
this.renderer.setStyle(item, 'max-width', `${this.itemWidth}px`);
const itemWidth = this.itemWidth();
if (!!itemWidth) {
this.renderer.setStyle(item, 'min-width', `${itemWidth}px`);
this.renderer.setStyle(item, 'max-width', `${itemWidth}px`);
this.renderer.setStyle(item, 'width', 'unset');
} else {
this.renderer.setStyle(item, 'min-width', `${100 / this.itemsPerPage}%`);

View File

@@ -1,5 +1,5 @@
<ng-container *ngFor="let dataset of datasets ; let index = index">
<section [class]="hoveredDatasetIndex === index ? 'is-hovered' : ''" (mouseenter)="triggerDatasetHover.emit(index)" (mouseleave)="triggerDatasetHover.emit(-1)">
<ng-container *ngFor="let dataset of datasets() ; let index = index">
<section [class]="hoveredDatasetIndex() === index ? 'is-hovered' : ''" (mouseenter)="triggerDatasetHover.emit(index)" (mouseleave)="triggerDatasetHover.emit(-1)">
<div [style]="{'border-color': dataset.borderColor, 'background-color': dataset.backgroundColor}"></div>
<label [style.color]="dataset.borderColor" >
{{ dataset.label | translate }}

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output
input,
output
} from '@angular/core';
import { Dataset } from '../../../util/models';
import { NgFor } from '@angular/common';
@@ -19,13 +18,13 @@ import { TranslatePipe } from '@ngx-translate/core';
})
export class PiChartLegendComponent {
@HostBinding('class') get classes(): string {
const comparativeClass = this.isComparativeChart ? 'is-comparative' : '';
const comparativeClass = this.isComparativeChart() ? 'is-comparative' : '';
return ['pi-chart-legend', comparativeClass].join(' ');
}
@Input() datasets!: Array<Dataset>;
@Input() isComparativeChart: boolean = true;
@Input() hoveredDatasetIndex: number;
readonly datasets = input.required<Array<Dataset>>();
readonly isComparativeChart = input<boolean>(true);
readonly hoveredDatasetIndex = input<number>();
@Output() triggerDatasetHover: EventEmitter<number> = new EventEmitter<number>();
readonly triggerDatasetHover = output<number>();
}

View File

@@ -2,8 +2,8 @@
<canvas #chart aria-label="Chart"></canvas>
</div>
<pi-chart-legend
[datasets]="datasets"
[isComparativeChart]="isComparativeChart"
[datasets]="datasets()"
[isComparativeChart]="isComparativeChart()"
[hoveredDatasetIndex]="hoveredDatasetIndex"
(triggerDatasetHover)="datasetHoveredInLegend($event)"
></pi-chart-legend>

View File

@@ -4,9 +4,9 @@ import {
ChangeDetectorRef,
Component,
ElementRef,
Input,
OnInit,
ViewChild,
input,
viewChild
} from '@angular/core';
import { Device } from '../../../util/device-configs';
import { Dataset } from '../../../util/models';
@@ -49,11 +49,11 @@ registerChartComponents();
imports: [PiChartLegendComponent],
})
export class PiChartComponent implements OnInit, AfterViewInit {
@Input() type: 'line' | 'bar' = 'line';
@Input() datasets!: Array<Dataset>;
@Input() device!: Device;
@Input() xAxisMarks: Array<string>;
@Input() isComparativeChart: boolean = true;
readonly type = input<'line' | 'bar'>('line');
readonly datasets = input.required<Array<Dataset>>();
readonly device = input.required<Device>();
readonly xAxisMarks = input<Array<string>>();
readonly isComparativeChart = input<boolean>(true);
private _hoveredDatasetIndex: number;
set hoveredDatasetIndex(index: number) {
@@ -63,8 +63,7 @@ export class PiChartComponent implements OnInit, AfterViewInit {
return this._hoveredDatasetIndex;
}
@ViewChild('chart', { read: ElementRef<HTMLCanvasElement>, static: false })
chartRef!: ElementRef<HTMLCanvasElement>;
readonly chartRef = viewChild.required('chart', { read: (ElementRef<HTMLCanvasElement>) });
chart: Chart;
@@ -74,7 +73,7 @@ export class PiChartComponent implements OnInit, AfterViewInit {
) {}
get completedDatasets() {
return this.datasets.map((dataset) => {
return this.datasets().map((dataset) => {
const datasetWithTranslatedLabels = {
...dataset,
label: this.translate.instant(dataset.label),
@@ -109,17 +108,17 @@ export class PiChartComponent implements OnInit, AfterViewInit {
}
getLineChartConfigs(): void {
const isComparativeChart = this.isComparativeChart;
const isComparativeChart = this.isComparativeChart();
this.chart = new Chart(this.chartRef.nativeElement, {
this.chart = new Chart(this.chartRef().nativeElement, {
type: 'line',
data: {
labels: this.xAxisMarks,
labels: this.xAxisMarks(),
datasets: this.completedDatasets,
},
options: {
responsive: true,
maintainAspectRatio: this.device === 'DESKTOP' ? true : false,
maintainAspectRatio: this.device() === 'DESKTOP' ? true : false,
hover: {
mode: 'dataset',
},

View File

@@ -1,5 +1,5 @@
// Angular
import { Directive, HostBinding, Input } from '@angular/core';
import { Directive, HostBinding, Input, input } from '@angular/core';
// Style definitions
import { ComponentFamilyClass, density, mode, styleType } from '../../styles';
@@ -7,15 +7,19 @@ import { chipColor } from './entities/chip.model';
@Directive()
export abstract class PiBaseChipComponent {
@HostBinding('class') get classes(): string {
const colorClass = this.color && `pi-color__${this.color}`;
const sizeClass = this.size && `pi-chip__size--${this.size}`;
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const size = this.size();
const sizeClass = size && `pi-chip__size--${size}`;
const affixClass = this.icon || this.value ? 'has-affix' : '';
const affixAppearance = this.affixAppearance();
const appearanceClass =
this.affixAppearance && `pi-chip__affix-appearance--${this.affixAppearance}`;
const colorModeClass = this.mode && `pi-color__mode--${this.mode}`;
const isDisabledClass = this.isDisabled ? 'is-disabled' : '';
const isClosableClass = this.isClosable ? 'is-closable' : '';
const fillClass = this.fill !== 'fit-content' && 'pi-chip__fill--fill-available';
affixAppearance && `pi-chip__affix-appearance--${affixAppearance}`;
const modeValue = this.mode();
const colorModeClass = modeValue && `pi-color__mode--${modeValue}`;
const isDisabledClass = this.isDisabled() ? 'is-disabled' : '';
const isClosableClass = this.isClosable() ? 'is-closable' : '';
const fillClass = this.fill() !== 'fit-content' && 'pi-chip__fill--fill-available';
return [
ComponentFamilyClass.Chip,
colorClass,
@@ -34,19 +38,19 @@ export abstract class PiBaseChipComponent {
@Input() icon: string | undefined;
// Skin
@Input() color: chipColor;
readonly color = input<chipColor>();
@Input() mode: mode = 'light';
@Input() size: 'small' | 'medium' | 'large' = 'small';
@Input() fill: 'fit-content' | 'fill-available' = 'fit-content';
readonly mode = input<mode>('light');
readonly size = input<'small' | 'medium' | 'large'>('small');
readonly fill = input<'fit-content' | 'fill-available'>('fit-content');
// Affix
@Input() affixAppearance: 'fill' | 'ghost' = 'ghost';
@Input() affixPosition: 'previous' | 'after' = 'after';
readonly affixAppearance = input<'fill' | 'ghost'>('ghost');
readonly affixPosition = input<'previous' | 'after'>('after');
// Behavior
@Input() isClosable: boolean = true;
readonly isClosable = input<boolean>(true);
// Status
@Input() isDisabled = false;
readonly isDisabled = input(false);
}

View File

@@ -6,16 +6,16 @@
*ngIf="icon"
class="pi-chip-affix__icon"
[svgIcon]="icon"
[color]="color"
[color]="color()"
></mat-icon>
<span *ngIf="value" class="pi-chip-affix__value">{{ value }}</span>
</span>
</div>
<mat-icon
*ngIf="isClosable"
*ngIf="isClosable()"
svgIcon="close"
[color]="color"
[color]="color()"
class="pi-chip-close-icon"
></mat-icon>
</span>

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
output
} from '@angular/core';
import { ComponentFamilyClass, mode, styleType } from '../../../styles';
import { PiBaseChipComponent } from '../base-chip.component';
@@ -21,18 +20,20 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiChipActionComponent extends PiBaseChipComponent {
@HostBinding('class') get actionClasses(): string {
const hasActionIconClass = this.hasActionIcon && 'has-action';
const isActiveClass = this.isActive ? 'is-active' : '';
const hasActionIconClass = this.hasActionIcon() && 'has-action';
const isActiveClass = this.isActive() ? 'is-active' : '';
/**
* When the chip action is dismissible, the affix position will be always previous,
that's why we force the position--previous class binding
*/
const affixPosition = this.affixPosition();
const isClosableAffixPositionClass =
this.isClosable && this.affixPosition === 'after'
this.isClosable() && affixPosition === 'after'
? 'pi-chip__affix-position--previous'
: `pi-chip__affix-position--${this.affixPosition}`;
: `pi-chip__affix-position--${affixPosition}`;
const affixPositionValue = this.affixPosition();
const affixPositionClass =
this.affixPosition && `pi-chip__affix-position--${this.affixPosition}`;
affixPositionValue && `pi-chip__affix-position--${affixPositionValue}`;
return [
'pi-chip-action',
@@ -44,15 +45,15 @@ export class PiChipActionComponent extends PiBaseChipComponent {
].join(' ');
}
@Output() execute: EventEmitter<void> = new EventEmitter<void>();
readonly execute = output<void>();
// Content
@Input() hasActionIcon: boolean = true;
readonly hasActionIcon = input<boolean>(true);
// Skin
@Input() override size: 'small' | 'medium' | 'large' = 'small';
@Input() override color: chipColor = 'primary';
override readonly size = input<'small' | 'medium' | 'large'>('small');
override readonly color = input<chipColor>('primary');
// Status
@Input() isActive!: boolean;
readonly isActive = input.required<boolean>();
}

View File

@@ -1,5 +1,5 @@
<span (click)="isClickable ? click.emit() : null">
<span class="pi-chip-date__weekday" *ngIf="size === 'large'">{{ dateValue?.weekDay }}</span>
<span (click)="isClickable() ? click.emit() : null">
<span class="pi-chip-date__weekday" *ngIf="size() === 'large'">{{ dateValue?.weekDay }}</span>
<span class="pi-chip-date__day">{{ dateValue?.day }}</span>
<span class="pi-chip-date__month">{{ dateValue?.month.toUpperCase() }}</span>
</span>

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
output
} from '@angular/core';
import { ComponentFamilyClass, theming } from '../../../styles';
import { Date } from '../../../util/models';
@@ -22,13 +21,15 @@ import { NgIf } from '@angular/common';
})
export class PiChipDateComponent extends PiBaseChipComponent {
@HostBinding('class') get dateClasses(): string {
const colorClass = this.color && `pi-color__${this.color}`;
const isClickableClass = this.isClickable ? 'is-clickable' : '';
const isStrokeClass = !this.isClickable && !!this.isStroked && 'is-stroked';
const isActiveClass = !!this.isActive ? 'is-active' : '';
const hasWeekDayClass = this.size === 'large' ? 'has-weekday' : '';
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const isClickableClass = this.isClickable() ? 'is-clickable' : '';
const isStrokeClass = !this.isClickable() && !!this.isStroked() && 'is-stroked';
const isActiveClass = !!this.isActive() ? 'is-active' : '';
const hasWeekDayClass = this.size() === 'large' ? 'has-weekday' : '';
const flexDirection = this.flexDirection();
const flexDirectionClass =
this.flexDirection && `pi-chip-date__flex-direction--${this.flexDirection}`;
flexDirection && `pi-chip-date__flex-direction--${flexDirection}`;
return [
'pi-chip-date',
ComponentFamilyClass.Chip,
@@ -41,28 +42,28 @@ export class PiChipDateComponent extends PiBaseChipComponent {
].join(' ');
}
@Output() click: EventEmitter<void> = new EventEmitter<void>();
readonly click = output<void>();
// Content
@Input() date!: string; // ISO format in UTC time zone
readonly date = input.required<string>(); // ISO format in UTC time zone
// Skin
@Input() override color: theming = 'primary';
@Input() isStroked = false;
override readonly color = input<theming>('primary');
readonly isStroked = input(false);
// Size - weekday only available in LARGE
// No weekday - available in SMALL and MEDIUM
// row direction only available in S and M
@Input() override size: 'small' | 'medium' | 'large' = 'small';
override readonly size = input<'small' | 'medium' | 'large'>('small');
@Input() flexDirection: 'row' | 'column' = 'column';
readonly flexDirection = input<'row' | 'column'>('column');
// Status
@Input() isClickable = true;
@Input() isActive!: boolean;
readonly isClickable = input(true);
readonly isActive = input.required<boolean>();
get dateValue(): Date {
const dateObj = DateTime.fromISO(this.date).setLocale('es');
const dateObj = DateTime.fromISO(this.date()).setLocale('es');
const isDateToday = dateObj.hasSame(DateTime.now(), 'day');
return {
day: dateObj.day.toString() || '',

View File

@@ -1,6 +1,6 @@
<span>
<span class="pi-chip-label" *ngIf="label">{{ label }}</span>
<span class="pi-chip-affix">
<mat-icon *ngIf="icon" [svgIcon]="icon" [color]="color" class="pi-chip-affix__icon"></mat-icon>
<mat-icon *ngIf="icon" [svgIcon]="icon" [color]="color()" class="pi-chip-affix__icon"></mat-icon>
</span>
</span>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
// Shared
import { status } from '../../../util/status';
@@ -15,21 +15,23 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiChipStatusComponent extends PiBaseChipComponent {
@HostBinding('class') get statusClasses(): string {
const statusClass = this.status && `is-${this.status}`;
const appearanceClass = `pi-chip-status__appearance--${this.appearance}`;
const statusValue = this.status();
const statusClass = statusValue && `is-${statusValue}`;
const appearanceClass = `pi-chip-status__appearance--${this.appearance()}`;
const hasLabelClass = !this.label ? 'pi-chip__single-icon' : '';
const affixPosition = this.affixPosition();
const affixPositionClass =
this.affixPosition && `pi-chip__affix-position--${this.affixPosition}`;
affixPosition && `pi-chip__affix-position--${affixPosition}`;
return ['pi-chip-status', statusClass, appearanceClass, hasLabelClass, affixPositionClass].join(
' '
);
}
// Skin
@Input() appearance: 'ghost' | 'fill' = 'fill';
@Input() override affixPosition: 'previous' | 'after' = 'previous';
@Input() override size: 'small' | 'medium' = 'small';
readonly appearance = input<'ghost' | 'fill'>('fill');
override readonly affixPosition = input<'previous' | 'after'>('previous');
override readonly size = input<'small' | 'medium'>('small');
/* green | red | yellow | blue | opacity */
@Input() status!: status;
readonly status = input.required<status>();
}

View File

@@ -1,4 +1,4 @@
<span (click)="isClosable ? execute.emit() : null" *ngIf="time && date; else singleContentTemplate">
<span (click)="isClosable() ? execute.emit() : null" *ngIf="time() && date(); else singleContentTemplate">
<div>
<span class="pi-chip-affix">
<span class="pi-chip-affix__time"> {{ timeValue }}h </span>
@@ -7,18 +7,18 @@
</div>
<mat-icon
*ngIf="isClosable"
*ngIf="isClosable()"
svgIcon="close"
[color]="color"
[color]="color()"
class="pi-chip-close-icon"
></mat-icon>
</span>
<ng-template #singleContentTemplate>
<span (click)="isClosable ? execute.emit() : null">
<span (click)="isClosable() ? execute.emit() : null">
<div>
<span class="pi-chip-affix">
<span *ngIf="time; else dateTemplate" class="pi-chip-affix__time"> {{ timeValue }}h </span>
<span *ngIf="time(); else dateTemplate" class="pi-chip-affix__time"> {{ timeValue }}h </span>
<ng-template #dateTemplate>
<span class="pi-chip-affix__date"> {{ dateValue }} </span>
</ng-template>

View File

@@ -1,10 +1,9 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
output
} from '@angular/core';
import { ComponentFamilyClass } from '../../../styles';
import { DateTime } from 'luxon';
@@ -22,44 +21,45 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiChipTimeComponent extends PiBaseChipComponent {
@HostBinding('class') get dateClasses(): string {
const colorClass = this.color && `pi-color__${this.color}`;
const isActiveClass = this.isActive ? 'is-active' : '';
const affixClass = this.time && this.date ? 'has-affix' : '';
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const isActiveClass = this.isActive() ? 'is-active' : '';
const affixClass = this.time() && this.date() ? 'has-affix' : '';
return ['pi-chip-time', ComponentFamilyClass.Chip, colorClass, isActiveClass, affixClass].join(
' '
);
}
@Output() execute: EventEmitter<void> = new EventEmitter<void>();
readonly execute = output<void>();
// Content
@Input() date!: string; // ISO format in UTC time zone
@Input() time!: string; // ISO format in UTC time zone
@Input() timezone: string = 'utc';
readonly date = input.required<string>(); // ISO format in UTC time zone
readonly time = input.required<string>(); // ISO format in UTC time zone
readonly timezone = input<string>('utc');
// Skin
@Input() override color: chipThemingColor = 'primary';
override readonly color = input<chipThemingColor>('primary');
/**
* On the chip time cases, we override the affix position property because
it will be always used by the thime input and will be always previous
*/
@Input() override affixPosition: 'previous' = 'previous';
override readonly affixPosition = input<'previous'>('previous');
// time - available in S and M
// time + date - available in S
@Input() override size: 'small' | 'medium' = 'small';
override readonly size = input<'small' | 'medium'>('small');
// Status
@Input() isActive!: boolean;
readonly isActive = input.required<boolean>();
get dateObj(): DateTime {
return DateTime.fromISO(this.date, { zone: 'utc' });
return DateTime.fromISO(this.date(), { zone: 'utc' });
}
get timeValue(): string {
return this.dateObj.setZone(this.timezone).toFormat('H:mm');
return this.dateObj.setZone(this.timezone()).toFormat('H:mm');
}
get dateValue(): string {

View File

@@ -5,7 +5,7 @@
<aside>
<div class="pi-chip-affix">
<span class="pi-chip-affix__value">{{ value ? value : 'N/A' }}</span>
<span *ngIf="!!value" class="pi-chip-affix__unit">{{ unit }}</span>
<span *ngIf="!!value" class="pi-chip-affix__unit">{{ unit() }}</span>
</div>
</aside>
</span>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Input, input } from '@angular/core';
import { PiBaseChipComponent } from '../base-chip.component';
import { unit } from '../../../util/models';
import { NgIf } from '@angular/common';
@@ -14,10 +14,12 @@ export class PiChipValueComponent extends PiBaseChipComponent {
@HostBinding('class') get valueClasses(): string {
const colorClass = this.value > 0 ? 'pi-color__success' : 'pi-color__warn';
const hasLabelClass = !!this.label ? 'has-label' : '';
const unitPosition = this.unitPosition();
const unitPositionClass =
this.unitPosition && `pi-chip-value__unit-position--${this.unitPosition}`;
unitPosition && `pi-chip-value__unit-position--${unitPosition}`;
const affixPosition = this.affixPosition();
const affixPositionClass =
this.affixPosition && `pi-chip__affix-position--${this.affixPosition}`;
affixPosition && `pi-chip__affix-position--${affixPosition}`;
return ['pi-chip-value', colorClass, hasLabelClass, unitPositionClass, affixPositionClass].join(
' '
);
@@ -25,11 +27,11 @@ export class PiChipValueComponent extends PiBaseChipComponent {
// Content
@Input() override value!: number;
@Input() unit!: unit | string;
readonly unit = input.required<unit | string>();
// Skin
@Input() override size: 'medium' | 'large' = 'large';
override readonly size = input<'medium' | 'large'>('large');
// Unit
@Input() unitPosition: 'previous' | 'after' = 'after';
readonly unitPosition = input<'previous' | 'after'>('after');
}

View File

@@ -4,7 +4,7 @@
<span class="pi-chip-affix" *ngIf="icon || value">
<ng-container *ngIf="icon">
<img
*ngIf="iconType === 'custom'; else defaultIcon"
*ngIf="iconType() === 'custom'; else defaultIcon"
src="/assets/icons/{{ icon }}.svg"
class="pi-chip-affix__icon"
/>
@@ -12,7 +12,7 @@
<ng-template #defaultIcon
><mat-icon
[svgIcon]="icon"
[color]="appearance !== 'fill' ? color : ''"
[color]="appearance() !== 'fill' ? color() : ''"
class="pi-chip-affix__icon"
></mat-icon
></ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { theming } from '../../../styles';
import { PiBaseChipComponent } from '../base-chip.component';
import { NgIf } from '@angular/common';
@@ -13,18 +13,21 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiChipComponent extends PiBaseChipComponent {
@HostBinding('class') get chipClasses(): string {
const appearanceClass = this.appearance && `pi-chip__appearance--${this.appearance}`;
const iconTypeClass = this.iconType && `pi-chip__icon-type--${this.iconType}`;
const appearance = this.appearance();
const appearanceClass = appearance && `pi-chip__appearance--${appearance}`;
const iconType = this.iconType();
const iconTypeClass = iconType && `pi-chip__icon-type--${iconType}`;
const hasLabelClass = !this.label ? 'pi-chip__single-icon' : '';
const affixPosition = this.affixPosition();
const affixPositionClass =
this.affixPosition && `pi-chip__affix-position--${this.affixPosition}`;
affixPosition && `pi-chip__affix-position--${affixPosition}`;
return [appearanceClass, iconTypeClass, hasLabelClass, affixPositionClass].join(' ');
}
// Content
@Input() iconType: 'custom' | 'default' = 'default';
readonly iconType = input<'custom' | 'default'>('default');
// Skin
@Input() appearance: 'outline' | 'fill' = 'outline';
@Input() override color: theming = 'primary';
readonly appearance = input<'outline' | 'fill'>('outline');
override readonly color = input<theming>('primary');
}

View File

@@ -1,6 +1,6 @@
<header>
<div>
<mat-icon *ngIf="icon; else valueTemplate" [svgIcon]="icon" [color]="color"></mat-icon>
<mat-icon *ngIf="icon; else valueTemplate" [svgIcon]="icon" [color]="color()"></mat-icon>
<ng-template #valueTemplate>
<span>{{ value }}</span>
</ng-template>
@@ -8,4 +8,4 @@
<span *ngIf="icon && value">{{ value }}</span>
</header>
<label>{{ label }}</label>
<label>{{ label() }}</label>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Input, input } from '@angular/core';
import { ComponentFamilyClass, theming } from '../../../styles';
import { NgIf } from '@angular/common';
import { MatIcon } from '@angular/material/icon';
@@ -12,21 +12,23 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiTileComponent {
@HostBinding('class') get classes(): string {
const colorClass = this.color && `pi-color__${this.color}`;
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const hasIconClass = !this.icon ? 'has-value' : '';
const hasIconAndValueClass = this.icon && this.value ? 'has-icon-and-value' : '';
const flexDirection = this.flexDirection && `pi-tile__flex-direction--${this.flexDirection}`;
const flexDirectionValue = this.flexDirection();
const flexDirection = flexDirectionValue && `pi-tile__flex-direction--${flexDirectionValue}`;
return ['pi-tile', ComponentFamilyClass.Text, colorClass, flexDirection, hasIconClass].join(
' '
);
}
// Content
@Input() label: string | undefined;
readonly label = input<string>();
@Input() value: string | undefined;
@Input() icon: string | undefined;
// Skin
@Input() color: theming = 'primary';
@Input() flexDirection: 'row' | 'column' = 'column';
readonly color = input<theming>('primary');
readonly flexDirection = input<'row' | 'column'>('column');
}

View File

@@ -1,7 +1,7 @@
<!--
KEYS:
-->
<header *ngIf="keysTemplateRef && mode === 'list'" pi-grid-item context="keys">
<header *ngIf="keysTemplateRef && mode() === 'list'" pi-grid-item context="keys">
<ng-container *ngTemplateOutlet="keysTemplateRef || defaultErrorTemplate"> </ng-container>
</header>
@@ -9,25 +9,25 @@
Data Direction:
COLUMN
-->
<ng-container *ngIf="dataDirection === 'column'; else dataDirectionRowTemplate">
<ng-container *ngIf="dataDirection() === 'column'; else dataDirectionRowTemplate">
<!-- DataGrid (each iteration)-->
<ng-container *ngFor="let value of data; index as i; trackBy: trackByFn">
<ng-container *ngFor="let value of data(); index as i; trackBy: trackByFn">
<div
pi-grid-item
#gridItem
[class.pi-card]="mode === 'grid'"
[class.is-active]="index === i"
[class.pi-card]="mode() === 'grid'"
[class.is-active]="index() === i"
(click)="clickItem.emit(value)"
>
<!-- Key -->
<ng-container
*ngTemplateOutlet="mode === 'grid' ? keysTemplateRef || defaultErrorTemplate : null"
*ngTemplateOutlet="mode() === 'grid' ? keysTemplateRef || defaultErrorTemplate : null"
>
</ng-container>
<!-- Values -->
<ng-container
[ngTemplateOutlet]="valuesTemplateRef || null"
[ngTemplateOutlet]="valuesTemplateRef() || null"
[ngTemplateOutletContext]="{ $implicit: value, index: i }"
>
</ng-container>
@@ -44,31 +44,31 @@
<section class="pi-data-grid__content">
<div
id="pi-grid-item-{{ i }}"
*ngFor="let value of data; index as i"
*ngFor="let value of data(); index as i"
pi-grid-item
#gridItem
[class.pi-card]="mode === 'grid'"
[class.pi-card]="mode() === 'grid'"
(click)="clickItem.emit(value)"
>
<section class="pi-grid-item__content">
<!-- Keys -->
<ng-container *ngTemplateOutlet="(mode === 'grid' && keysTemplateRef) || null">
<ng-container *ngTemplateOutlet="(mode() === 'grid' && keysTemplateRef) || null">
</ng-container>
<!-- Values -->
<ng-container
[ngTemplateOutlet]="valuesTemplateRef || null"
[ngTemplateOutlet]="valuesTemplateRef() || null"
[ngTemplateOutletContext]="{ $implicit: value, index: i }"
>
</ng-container>
</section>
<!-- Expandable Content -->
<aside *ngIf="isExpandable">
<aside *ngIf="isExpandable()">
<!-- Keys -->
<header
class="pi-grid-item pi-grid-item__expandable-content pi-grid-item__expandable-content--keys-template"
>
<ng-container *ngTemplateOutlet="(mode === 'list' && expandableKeysTemplateRef) || null">
<ng-container *ngTemplateOutlet="(mode() === 'list' && expandableKeysTemplateRef()) || null">
</ng-container>
</header>
@@ -76,7 +76,7 @@
class="pi-grid-item pi-grid-item__expandable-content pi-grid-item__expandable-content--values-template"
>
<ng-container
[ngTemplateOutlet]="expandableValuesTemplateRef || null"
[ngTemplateOutlet]="expandableValuesTemplateRef() || null"
[ngTemplateOutletContext]="{ $implicit: value, index: i }"
>
</ng-container>

View File

@@ -3,13 +3,13 @@ import {
Component,
ContentChild,
ElementRef,
EventEmitter,
HostBinding,
Input,
OnInit,
Output,
TemplateRef,
ViewChild,
input,
output,
viewChild,
contentChild
} from '@angular/core';
import { justify } from '../../../styles';
import { ListMode } from '../../../util/list-configs';
@@ -45,46 +45,43 @@ export class PiDataGridComponent<T> {
}
// Content
@Input() data: Array<T> | null = [];
@Input() columns!: columnsNumber | number | null;
@Input() mode: ListMode | null = 'list';
@Input() content: 'key' | 'values' = 'values';
readonly data = input<Array<T> | null>([]);
readonly columns = input.required<columnsNumber | number | null>();
readonly mode = input<ListMode | null>('list');
readonly content = input<'key' | 'values'>('values');
/**
* dataDirection = colummn: 'headings will be dispplayed at left side'
* dataDirection = row: 'headings will be dispplayed at top'
**/
@Input() rows!: rowsNumber | null;
@Input() index!: number;
readonly rows = input.required<rowsNumber | null>();
readonly index = input.required<number>();
// Status
@Input() isActive!: boolean;
readonly isActive = input.required<boolean>();
// Behavior
@Input() isExpandable = false;
readonly isExpandable = input(false);
// Behavior
@Input() isEditable = false;
readonly isEditable = input(false);
// Skin
@Input() dataDirection: 'row' | 'column' = 'row';
@Input() cardType: cardType | null = 'vertical';
@Input() appearance: 'outline' | 'ghost' = 'outline';
@Input() hasPdding = true;
@Input() justify: justify = 'space-between';
readonly dataDirection = input<'row' | 'column'>('row');
readonly cardType = input<cardType | null>('vertical');
readonly appearance = input<'outline' | 'ghost'>('outline');
readonly hasPdding = input(true);
readonly justify = input<justify>('space-between');
@Output() clickItem: EventEmitter<T> = new EventEmitter<T>();
readonly clickItem = output<T>();
@ViewChild('gridItem', { static: false }) gridItemRef: ElementRef<Element> | undefined;
readonly gridItemRef = viewChild<ElementRef<Element>>('gridItem');
@ContentChild('keysTemplate', { static: false })
keysTemplateRef: TemplateRef<unknown> | undefined;
@ContentChild('valuesTemplate', { static: false })
valuesTemplateRef: TemplateRef<unknown> | undefined;
readonly valuesTemplateRef = contentChild<TemplateRef<unknown>>('valuesTemplate');
@ContentChild('expandableKeysTemplate', { static: false })
expandableKeysTemplateRef: TemplateRef<unknown> | undefined;
readonly expandableKeysTemplateRef = contentChild<TemplateRef<unknown>>('expandableKeysTemplate');
@ContentChild('expandableValuesTemplate', { static: false })
expandableValuesTemplateRef: TemplateRef<unknown> | undefined;
readonly expandableValuesTemplateRef = contentChild<TemplateRef<unknown>>('expandableValuesTemplate');
trackByFn(index: number): number | undefined {
return index;
@@ -106,7 +103,8 @@ export class PiDataGridComponent<T> {
*
*/
protected get appearanceClass(): string {
return this.appearance ? `pi-data-grid__appearance--${this.appearance}` : '';
const appearance = this.appearance();
return appearance ? `pi-data-grid__appearance--${appearance}` : '';
}
/**
@@ -127,7 +125,8 @@ export class PiDataGridComponent<T> {
*
*/
protected get cardTypeClass(): string {
return this.mode === 'grid' && this.cardType ? `pi-data-grid__card-type--${this.cardType}` : '';
const cardTypeValue = this.cardType();
return this.mode() === 'grid' && cardTypeValue ? `pi-data-grid__card-type--${cardTypeValue}` : '';
}
/**
@@ -138,7 +137,8 @@ export class PiDataGridComponent<T> {
*
*/
protected get columnsClass(): string {
return this.columns && `pi-data-grid__columns--${this.columns}`;
const columns = this.columns();
return columns && `pi-data-grid__columns--${columns}`;
}
/**
@@ -149,8 +149,9 @@ export class PiDataGridComponent<T> {
*
*/
protected get dataDirectionClass(): string {
return this.mode === 'list' && this.dataDirection
? `pi-data-grid__data-direction--${this.dataDirection}`
const dataDirection = this.dataDirection();
return this.mode() === 'list' && dataDirection
? `pi-data-grid__data-direction--${dataDirection}`
: '';
}
@@ -161,7 +162,7 @@ export class PiDataGridComponent<T> {
*
*/
protected get isEditableClass(): string {
return this.dataDirection === 'column' && this.isEditable ? 'is-editable' : '';
return this.dataDirection() === 'column' && this.isEditable() ? 'is-editable' : '';
}
/**
@@ -171,7 +172,7 @@ export class PiDataGridComponent<T> {
*
*/
protected get isExpandableClass(): string {
return this.dataDirection === 'row' && this.isExpandable ? 'is-expandable' : '';
return this.dataDirection() === 'row' && this.isExpandable() ? 'is-expandable' : '';
}
/**
@@ -181,8 +182,9 @@ export class PiDataGridComponent<T> {
*
*/
protected get justifyClass(): string {
return this.dataDirection === 'column' && this.justify
? `pi-data-grid__justify-content--${this.justify}`
const justifyValue = this.justify();
return this.dataDirection() === 'column' && justifyValue
? `pi-data-grid__justify-content--${justifyValue}`
: '';
}
@@ -203,7 +205,8 @@ export class PiDataGridComponent<T> {
*
*/
protected get modeClass(): string {
return this.mode && `pi-data-grid__mode--${this.mode}`;
const mode = this.mode();
return mode && `pi-data-grid__mode--${mode}`;
}
/**
@@ -214,6 +217,7 @@ export class PiDataGridComponent<T> {
*
*/
protected get rowsClass(): string {
return this.rows && `pi-data-grid__rows--${this.rows}`;
const rows = this.rows();
return rows && `pi-data-grid__rows--${rows}`;
}
}

View File

@@ -1,25 +1,28 @@
import { AfterViewInit, Directive, ElementRef, HostBinding, Input } from '@angular/core';
import { AfterViewInit, Directive, ElementRef, HostBinding, input } from '@angular/core';
import { itemType } from '../entities/data-grid.model';
@Directive({ selector: '[pi-cell]', })
export class PiCellDirective implements AfterViewInit {
@HostBinding(`class`) get cellType(): string | undefined {
const textAlignClass = this.textAlign !== 'left' && `pi-cell__text-align--${this.textAlign}`;
const indentClass = this.indent ? 'pi-cell__indented' : '';
const typeClass = this.type !== 'default' && `pi-cell__type--${this.type}`;
const textAlign = this.textAlign();
const textAlignClass = textAlign !== 'left' && `pi-cell__text-align--${textAlign}`;
const indentClass = this.indent() ? 'pi-cell__indented' : '';
const type = this.type();
const typeClass = type !== 'default' && `pi-cell__type--${type}`;
return ['pi-cell', textAlignClass, indentClass, typeClass].join(' ');
}
@Input() type: itemType = 'default';
@Input() indent = false;
@Input() index!: number;
@Input() textAlign: 'left' | 'center' | 'right' = 'left';
readonly type = input<itemType>('default');
readonly indent = input(false);
readonly index = input.required<number>();
readonly textAlign = input<'left' | 'center' | 'right'>('left');
constructor(private elRef: ElementRef) {}
ngAfterViewInit(): void {
if (this.index !== undefined) {
this.elRef?.nativeElement?.classList.add(`pi-cell__${this.index}`);
const index = this.index();
if (index !== undefined) {
this.elRef?.nativeElement?.classList.add(`pi-cell__${index}`);
}
}
}

View File

@@ -1,23 +1,24 @@
import { Directive, ElementRef, HostBinding, HostListener, Input, Renderer2 } from '@angular/core';
import { Directive, ElementRef, HostBinding, HostListener, Renderer2, input } from '@angular/core';
import { columnsNumber } from '../entities/data-grid.model';
@Directive({ selector: '[pi-grid-item]', })
export class PiGridItemDirective {
@HostBinding(`class`) get gridItemType(): string {
const isExpandableClass = this.isExpandable ? 'is-expandable' : '';
const isSelectedClass = this.isSelected ? 'is-selected' : '';
const contextClass = this.context && `pi-grid-item__context--${this.context}`;
const isExpandableClass = this.isExpandable() ? 'is-expandable' : '';
const isSelectedClass = this.isSelected() ? 'is-selected' : '';
const context = this.context();
const contextClass = context && `pi-grid-item__context--${context}`;
return ['pi-grid-item', isExpandableClass, isSelectedClass, contextClass].join(' ');
}
@Input() isExpandable = false;
@Input() isSelected = false;
@Input() context!: 'keys' | 'values';
readonly isExpandable = input(false);
readonly isSelected = input(false);
readonly context = input.required<'keys' | 'values'>();
@Input() cells!: columnsNumber | null;
@Input() isActive!: boolean | null;
readonly cells = input.required<columnsNumber | null>();
readonly isActive = input.required<boolean | null>();
@Input() isVisited = false;
readonly isVisited = input(false);
constructor(private elRef: ElementRef, private renderer: Renderer2) {}

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, OnInit, input } from '@angular/core';
import { Store } from '@ngrx/store';
import { DataTableItem } from '../entities/data-table-item.model';
@@ -25,10 +25,10 @@ export class PiBaseDataTableComponent implements OnInit {
this.typeClass,
].join(' ');
}
@Input() items: Array<DataTableItem>;
@Input() dataDirection: 'row' | 'column' = 'row';
@Input() type: 'header' | 'data' = 'data';
@Input() hideValues = false;
readonly items = input<Array<DataTableItem>>();
readonly dataDirection = input<'row' | 'column'>('row');
readonly type = input<'header' | 'data'>('data');
readonly hideValues = input(false);
constructor(private store: Store<DeviceConfigsState>) {}
@@ -39,11 +39,11 @@ export class PiBaseDataTableComponent implements OnInit {
}
get dataDirectionClass(): string {
return `pi-base-data-table__data-direction--${this.dataDirection}`;
return `pi-base-data-table__data-direction--${this.dataDirection()}`;
}
get typeClass(): string | void {
return this.type === 'header' && 'pi-base-data-table__type--header';
return this.type() === 'header' && 'pi-base-data-table__type--header';
}
private hideHeader(): void {
@@ -51,8 +51,8 @@ export class PiBaseDataTableComponent implements OnInit {
.select(DeviceTypeSelectors.getDevice)
.pipe(take(1))
.subscribe((deviceType: string) => {
if (deviceType !== 'DESKTOP' && this.hideValues) {
delete this.items[0].values;
if (deviceType !== 'DESKTOP' && this.hideValues()) {
delete this.items()[0].values;
}
});
}

View File

@@ -1,4 +1,4 @@
<ng-container [ngSwitch]="type">
<ng-container [ngSwitch]="type()">
<ng-container *ngSwitchCase="'amount'" [ngTemplateOutlet]="amount">
</ng-container>
@@ -20,19 +20,19 @@
<ng-template #amount>
<span>
{{ display }}
{{ display() }}
</span>
</ng-template>
<ng-template #text>
<span>
{{ display }}
{{ display() }}
</span>
</ng-template>
<ng-template #date>
<span>
{{ display }}
{{ display() }}
</span>
</ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { NgSwitch, NgSwitchCase, NgTemplateOutlet } from '@angular/common';
import { PiBaseDataTableComponent } from '../base-data-table/base-data-table.component';
@@ -19,25 +19,25 @@ export class PiCellTypeComponent {
@HostBinding('class') className = 'pi-cell-type';
@HostBinding('class.pi-cell-type__amount') get isAmount(): boolean {
return this.type === 'amount';
return this.type() === 'amount';
}
@HostBinding('class.pi-cell-type__text') get isText(): boolean {
return this.type === 'text';
return this.type() === 'text';
}
@HostBinding('class.pi-cell-type__date') get isDate(): boolean {
return this.type === 'date';
return this.type() === 'date';
}
@HostBinding('class.pi-cell-type__input') get isInput(): boolean {
return this.type === 'input';
return this.type() === 'input';
}
@HostBinding('class.pi-cell-type__action') get isAction(): boolean {
return this.type === 'action';
return this.type() === 'action';
}
@Input() type: PiDropdownSelectorTemplateType = 'text';
readonly type = input<PiDropdownSelectorTemplateType>('text');
/**
* Data to display
*/
@Input() display: string | number;
readonly display = input<string | number>();
}

View File

@@ -1,9 +1,9 @@
<h4>{{ heading }}</h4>
<h4>{{ heading() }}</h4>
<article #componentItem>
<ng-container *ngFor="let value of values; let i = index">
<ng-container *ngFor="let value of values(); let i = index">
<ng-content
*ngTemplateOutlet="item; context: { value: value, index: i }"
*ngTemplateOutlet="item(); context: { value: value, index: i }"
></ng-content>
</ng-container>
</article>

View File

@@ -2,12 +2,12 @@ import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ContentChild,
ElementRef,
HostBinding,
Input,
TemplateRef,
ViewChild,
input,
contentChild,
viewChild
} from '@angular/core';
import { textStyle, justify, borderType } from '../../../styles';
import { Store } from '@ngrx/store';
@@ -33,14 +33,14 @@ export class PiDataTableItemComponent implements AfterViewInit {
return ['pi-data-table-item', this.textStyleClass, this.justifyClass].join(' ');
}
@Input() heading: string;
@Input() values: Array<string>;
@Input() textStyle: textStyle = 'regular';
@Input() justify: justify = 'flex-start';
@Input() borderType: borderType;
readonly heading = input<string>();
readonly values = input<Array<string>>();
readonly textStyle = input<textStyle>('regular');
readonly justify = input<justify>('flex-start');
readonly borderType = input<borderType>();
@ContentChild('item', { static: false }) item: TemplateRef<Element>;
@ViewChild('componentItem') componentItem: ElementRef;
readonly item = contentChild<TemplateRef<Element>>('item');
readonly componentItem = viewChild<ElementRef>('componentItem');
constructor(private store: Store<DeviceConfigsState>) {}
@@ -49,16 +49,16 @@ export class PiDataTableItemComponent implements AfterViewInit {
}
setCellClassByIndex(): void {
this.values?.forEach((item: string, index: number) => {
this.componentItem.nativeElement.children[index].classList.add(`pi-cell__${index}`);
this.values()?.forEach((item: string, index: number) => {
this.componentItem().nativeElement.children[index].classList.add(`pi-cell__${index}`);
});
}
get textStyleClass(): string {
return `pi-data-table-item__text-style--${this.textStyle}`;
return `pi-data-table-item__text-style--${this.textStyle()}`;
}
get justifyClass(): string {
return `pi-data-table-item__justify--${this.justify}`;
return `pi-data-table-item__justify--${this.justify()}`;
}
}

View File

@@ -1,10 +1,10 @@
<ng-container *ngIf="!label; else labelDividerTemplate">
<pi-icon *ngIf="icon" [icon]="icon" [appearance]="iconType" [isStroked]="isStroked"></pi-icon>
<ng-container *ngIf="!label(); else labelDividerTemplate">
<pi-icon *ngIf="icon" [icon]="icon" [appearance]="iconType()" [isStroked]="isStroked()"></pi-icon>
<hr align="center" />
</ng-container>
<ng-template #labelDividerTemplate
><hr align="center" />
<span>{{ label }}</span>
<span>{{ label() }}</span>
<hr align="center" />
</ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Input, input } from '@angular/core';
// Shared
import { alignment, gap, iconSize, textColor } from '../../../styles';
@@ -14,16 +14,21 @@ import { PiIconComponent } from '../../icon/icon/icon.component';
})
export class PiDividerComponent {
@HostBinding('class') get classes(): string {
const aligmentClass = `pi-divider__aligment--${this.aligment}`;
const colorClass = this.color && `pi-color__${this.color}`;
const gapClass = this.gap && `pi-divider__gap--${this.gap}`;
const aligmentClass = `pi-divider__aligment--${this.aligment()}`;
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const gapValue = this.gap();
const gapClass = gapValue && `pi-divider__gap--${gapValue}`;
const hasIconClass = this.icon ? 'has-icon' : '';
const heightClass = `pi-divider__height--${this.height}`;
const iconSizeClass = !!this.iconSize && `pi-divider__icon-size--${this.iconSize}`;
const labelClass = this.label ? 'has-label' : '';
const positionClass = !!this.iconPosition && `pi-divider__position--${this.iconPosition}`;
const widthClass = `pi-divider__width--${this.width}`;
const directionClass = !!this.direction && `pi-divider__direction--${this.direction}`;
const heightClass = `pi-divider__height--${this.height()}`;
const iconSizeValue = this.iconSize();
const iconSizeClass = !!iconSizeValue && `pi-divider__icon-size--${iconSizeValue}`;
const labelClass = this.label() ? 'has-label' : '';
const iconPosition = this.iconPosition();
const positionClass = !!iconPosition && `pi-divider__position--${iconPosition}`;
const widthClass = `pi-divider__width--${this.width()}`;
const direction = this.direction();
const directionClass = !!direction && `pi-divider__direction--${direction}`;
return [
'pi-divider',
aligmentClass,
@@ -39,20 +44,20 @@ export class PiDividerComponent {
].join(' ');
}
@Input() width: 'xx-small' | 'x-small' | 'small' | 'medium' | 'large' = 'large';
@Input() height: 'small' | 'medium' | 'large' = 'small';
readonly width = input<'xx-small' | 'x-small' | 'small' | 'medium' | 'large'>('large');
readonly height = input<'small' | 'medium' | 'large'>('small');
// Color: 1st hr 2nd icon
@Input() color!: textColor;
@Input() gap!: gap;
@Input() aligment: alignment = 'center';
@Input() direction: 'horizontal' | 'vertical' = 'horizontal';
readonly color = input.required<textColor>();
readonly gap = input.required<gap>();
readonly aligment = input<alignment>('center');
readonly direction = input<'horizontal' | 'vertical'>('horizontal');
// Divider Icon
@Input() icon!: string;
@Input() iconSize: iconSize = 'x-large';
@Input() iconType: 'fill' | 'default' = 'default';
@Input() iconPosition: 'before' | 'after' = 'after';
@Input() isStroked = false;
readonly iconSize = input<iconSize>('x-large');
readonly iconType = input<'fill' | 'default'>('default');
readonly iconPosition = input<'before' | 'after'>('after');
readonly isStroked = input(false);
@Input() label!: string;
readonly label = input.required<string>();
}

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, HostBinding, Injector, Input, Output } from '@angular/core';
import { Component, HostBinding, Injector, Input, input, output } from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ComponentFamilyClass } from '../../styles';
import { PiFormControl } from '../../util/form-control';
@@ -24,23 +24,23 @@ export abstract class PiBaseFormFieldComponent extends PiFormControl {
].join(' ');
}
@Input() formControlName!: string;
readonly formControlName = input.required<string>();
@Input() placeholder: string | undefined;
readonly placeholder = input<string>();
@Input() isAutofocus = false;
readonly isAutofocus = input(false);
@Input() appearance: 'outline' | 'fill' = 'outline';
readonly appearance = input<'outline' | 'fill'>('outline');
@Input() enableErrorMessage = true;
readonly enableErrorMessage = input(true);
@Input() isControlStatusReactive = false;
readonly isControlStatusReactive = input(false);
@Input()
set isDisabled(value: boolean) {
this.disabled = value;
// Update control status reactively
if (this.isControlStatusReactive) {
if (this.isControlStatusReactive()) {
if (this.disabled) {
this.control.disable();
} else {
@@ -52,14 +52,14 @@ export abstract class PiBaseFormFieldComponent extends PiFormControl {
return this.disabled;
}
@Output() isActive: EventEmitter<boolean> = new EventEmitter();
readonly isActive = output<boolean>();
constructor(injector: Injector) {
super(injector);
}
get control(): FormControl {
return this.controlContainer.control?.get(this.formControlName) as FormControl;
return this.controlContainer.control?.get(this.formControlName()) as FormControl;
}
get hasError(): boolean {

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" class="pi-currency-field" floatLabel="always">
<mat-form-field [appearance]="appearance()" class="pi-currency-field" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<ng-container matSuffix>
@@ -8,15 +8,15 @@
<input
*ngIf="control"
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
currencyMask
[options]="customCurrencyMaskConfig"
/>
<mat-error *ngIf="enableErrorMessage && control.errors">
<mat-error *ngIf="enableErrorMessage() && control.errors">
<ng-container *ngFor="let text of control.errors['message']">
{{ text | translate }}
</ng-container>

View File

@@ -1,21 +1,21 @@
import { Directive, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { Directive, OnChanges, OnInit, SimpleChanges, input } from '@angular/core';
import { MatInput } from '@angular/material/input';
@Directive({ selector: '[pi-autofocus]', })
export class PiAutofocusDirective implements OnInit, OnChanges {
@Input() isAutofocusSelected: boolean;
readonly isAutofocusSelected = input<boolean>();
constructor(private matInput: MatInput) {}
ngOnInit() {
if (this.isAutofocusSelected) {
if (this.isAutofocusSelected()) {
setTimeout(() => this.matInput.focus());
}
}
ngOnChanges(changes: SimpleChanges): void {
if (changes) {
if (this.isAutofocusSelected) this.matInput.focus();
if (this.isAutofocusSelected()) this.matInput.focus();
}
}
}

View File

@@ -1,14 +1,16 @@
import { Directive, HostBinding, Input } from '@angular/core';
import { Directive, HostBinding, input } from '@angular/core';
@Directive({ selector: '[pi-checkbox-grid]', })
export class PiCheckboxGridDirective {
@HostBinding('class') get classes(): string {
const columns = this.columns();
const columnClass =
this.columns && `pi-checkbox-grid__column pi-checkbox-grid__column--${this.columns}`;
const fillClass = this.fill && `pi-checkbox-grid__fill pi-checkbox-grid__fill--${this.fill}`;
columns && `pi-checkbox-grid__column pi-checkbox-grid__column--${columns}`;
const fill = this.fill();
const fillClass = fill && `pi-checkbox-grid__fill pi-checkbox-grid__fill--${fill}`;
return ['pi-checkbox-grid', columnClass, fillClass].join(' ');
}
@Input() columns: '1' | '2' | '3' | '4' = '2';
@Input() fill: 'fit-content' | 'fill-available' = 'fit-content';
readonly columns = input<'1' | '2' | '3' | '4'>('2');
readonly fill = input<'fit-content' | 'fill-available'>('fit-content');
}

View File

@@ -1,19 +1,19 @@
import { Directive, ElementRef, HostBinding, Input, OnInit, Renderer2 } from '@angular/core';
import { Directive, ElementRef, HostBinding, OnInit, Renderer2, input } from '@angular/core';
@Directive({ selector: 'pi-label', })
export class PiLabelDirective implements OnInit {
@HostBinding('class') get classes(): string {
const validationClass = this.isRequired ? 'is-required' : '';
const validationClass = this.isRequired() ? 'is-required' : '';
return ['pi-label', validationClass].join(' ');
}
@HostBinding('class') className = 'pi-label';
@Input() isRequired: boolean = false;
readonly isRequired = input<boolean>(false);
constructor(private renderer: Renderer2, private el: ElementRef) {}
ngOnInit() {
if (this.isRequired) {
if (this.isRequired()) {
const span = this.renderer.createElement('span');
const text = this.renderer.createText('*');

View File

@@ -1,17 +1,20 @@
import { Directive, HostBinding, Input } from '@angular/core';
import { Directive, HostBinding, input } from '@angular/core';
import { justify } from '../../../styles';
// Flex
@Directive({ selector: '[pi-radio-grid]', })
export class PiRadioGridDirective {
@HostBinding('class') get classes(): string {
const typeClass = this.type && `pi-radio-grid__type--${this.type}`;
const justifyClass = this.justify && `pi-radio-grid__justify--${this.justify}`;
const columnsClass = this.columns && `pi-radio-grid__columns--${this.columns}`;
const type = this.type();
const typeClass = type && `pi-radio-grid__type--${type}`;
const justifyValue = this.justify();
const justifyClass = justifyValue && `pi-radio-grid__justify--${justifyValue}`;
const columns = this.columns();
const columnsClass = columns && `pi-radio-grid__columns--${columns}`;
return ['pi-radio-grid', typeClass, justifyClass, columnsClass].join(' ');
}
@Input() type: 'grid' | 'flex' = 'flex';
@Input() justify: justify = 'flex-start';
@Input() columns: 1 | 2 | 3 | 4 = 1;
readonly type = input<'grid' | 'flex'>('flex');
readonly justify = input<justify>('flex-start');
readonly columns = input<1 | 2 | 3 | 4>(1);
}

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<ng-container matSuffix>
@@ -7,12 +7,12 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
autocomplete="username email"
type="email"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -1,6 +1,6 @@
<section>
<pi-icon
[icon]="icon"
[icon]="icon()"
color="primary"
size="x-large"
appearance="fill"
@@ -10,14 +10,14 @@
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
</mat-form-field>
</section>
<mat-error *ngIf="control.errors && enableErrorMessage">
<mat-error *ngIf="control.errors && enableErrorMessage()">
<ng-container *ngFor="let text of control.errors['message']">
{{ text | translate }}
</ng-container>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { iconSize } from '../../../styles';
import { PiBaseFormFieldComponent } from '../base-form-field.component';
@@ -39,6 +39,6 @@ export class PiIconFieldComponent extends PiBaseFormFieldComponent {
return ['pi-form-field__text-icon'].join(' ');
}
@Input() icon: string | undefined;
@Input() iconSize: iconSize = 'x-large';
readonly icon = input<string>();
readonly iconSize = input<iconSize>('x-large');
}

View File

@@ -1,9 +1,9 @@
<mat-form-field appearance="fill" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<pi-prefix [unit]="this.unit === '$' ? this.unit : null" matPrefix>
<pi-prefix [unit]="this.unit() === '$' ? this.unit() : null" matPrefix>
<pi-icon
*ngIf="showIncrementButtons"
*ngIf="showIncrementButtons()"
(click)="decrementValue()"
[class.is-disabled]="isDecrementButtonDisabled()"
icon="substract"
@@ -13,9 +13,9 @@
></pi-icon>
</pi-prefix>
<pi-suffix [unit]="this.unit !== '$' ? this.unit : null" matSuffix>
<pi-suffix [unit]="this.unit() !== '$' ? this.unit() : null" matSuffix>
<pi-icon
*ngIf="showIncrementButtons"
*ngIf="showIncrementButtons()"
(click)="incrementValue()"
[class.is-disabled]="isIncrementButtonDisabled()"
icon="add"
@@ -27,11 +27,11 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
matInput
type="number"
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Injectable, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Injectable, input } from '@angular/core';
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { unit } from '../../../util/models';
import { PiBaseFormFieldComponent } from '../base-form-field.component';
@@ -44,24 +44,25 @@ import { TranslatePipe } from '@ngx-translate/core';
export class PiIncrementalNumberFieldComponent extends PiBaseFormFieldComponent {
@HostBinding('class') className = 'pi-form-field__incremental';
@Input() slot: number = 1;
readonly slot = input<number>(1);
@Input() max: number;
readonly max = input<number>();
@Input() min: number = 0;
readonly min = input<number>(0);
@Input() unit: unit = '';
readonly unit = input<unit>('');
@Input() showIncrementButtons: boolean = true;
readonly showIncrementButtons = input<boolean>(true);
incrementValue(): void {
if (this.isDisabled) return
let currentValue = Number(this.control.value);
// Handle decimal numbers
if (Number.isInteger(this.slot)) {
this.control.setValue(currentValue + this.slot);
const slot = this.slot();
if (Number.isInteger(slot)) {
this.control.setValue(currentValue + slot);
} else {
this.control.setValue((currentValue + this.slot).toFixed(2));
this.control.setValue((currentValue + slot).toFixed(2));
}
}
@@ -69,20 +70,22 @@ export class PiIncrementalNumberFieldComponent extends PiBaseFormFieldComponent
if (this.isDisabled) return
let currentValue = Number(this.control.value);
// Handle decimal numbers
if (Number.isInteger(this.slot)) {
this.control.setValue(currentValue - this.slot);
const slot = this.slot();
if (Number.isInteger(slot)) {
this.control.setValue(currentValue - slot);
} else {
this.control.setValue((currentValue - this.slot).toFixed(2));
this.control.setValue((currentValue - slot).toFixed(2));
}
}
isIncrementButtonDisabled(): boolean {
return this.isDisabled || this.control.value + this.slot > this.max;
return this.isDisabled || this.control.value + this.slot() > this.max();
}
isDecrementButtonDisabled(): boolean {
if (this.min || this.min === 0) {
return this.isDisabled || this.control.value - this.slot < this.min;
const min = this.min();
if (min || min === 0) {
return this.isDisabled || this.control.value - this.slot() < min;
}
return this.isDisabled;
}

View File

@@ -4,12 +4,12 @@
<span>{{ 'common.min' | translate }}</span>
</pi-label>
<pi-incremental-number-field
[slot]="step"
[unit]="unit"
[min]="minValue"
[slot]="step()"
[unit]="unit()"
[min]="minValue()"
formControlName="from"
[placeholder]="placeholder"
[showIncrementButtons]="showIncrementButtons"
[placeholder]="placeholder()"
[showIncrementButtons]="showIncrementButtons()"
>
</pi-incremental-number-field>
</div>
@@ -21,16 +21,16 @@
<span>{{ 'common.max' | translate }}</span>
</pi-label>
<pi-incremental-number-field
[slot]="step"
[unit]="unit"
[min]="minValue"
[slot]="step()"
[unit]="unit()"
[min]="minValue()"
formControlName="to"
[placeholder]="placeholder"
[showIncrementButtons]="showIncrementButtons"
[placeholder]="placeholder()"
[showIncrementButtons]="showIncrementButtons()"
>
</pi-incremental-number-field>
</div>
<mat-error *ngIf="form.errors && showError">
<mat-error *ngIf="form.errors && showError()">
<ng-container *ngFor="let text of form.errors['message']">
{{ text | translate }}
</ng-container>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { FormGroup, FormGroupDirective, ReactiveFormsModule } from '@angular/forms';
import { unit } from '../../../util/models';
import { PiLabelDirective } from '../directives/label.directive';
@@ -29,18 +29,18 @@ export class PiIncrementalRangeFieldComponent {
@HostBinding('class') className =
'pi-field pi-form-field__incremental pi-form-field__incremental--range';
@Input() formGroupName!: string;
@Input() minValue!: number;
@Input() maxValue!: number;
@Input() unit!: unit;
@Input() step!: number;
@Input() showError = false;
@Input() showIncrementButtons: boolean = true;
@Input() placeholder: string | undefined;
readonly formGroupName = input.required<string>();
readonly minValue = input.required<number>();
readonly maxValue = input.required<number>();
readonly unit = input.required<unit>();
readonly step = input.required<number>();
readonly showError = input(false);
readonly showIncrementButtons = input<boolean>(true);
readonly placeholder = input<string>();
constructor(private rootFormGroup: FormGroupDirective) {}
get form() {
return this.rootFormGroup.control.get(this.formGroupName) as FormGroup;
return this.rootFormGroup.control.get(this.formGroupName()) as FormGroup;
}
}

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<ng-container matPrefix>
@@ -11,11 +11,11 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
matInput
type="number"
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<pi-suffix matSuffix>
@@ -14,12 +14,12 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
[type]="hide ? 'password' : 'text'"
autocomplete="current-password"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<ng-container matSuffix>
@@ -7,11 +7,11 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
type="tel"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -10,12 +10,12 @@
(focus)="onFocus()"
(blur)="onBlur()"
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
type="search"
/>
</fieldset>
<pi-icon
*ngIf="isClosable"
*ngIf="isClosable()"
(click)="closeField()"
icon="close"
size="small"

View File

@@ -2,11 +2,11 @@ import {
ChangeDetectionStrategy,
Component,
ElementRef,
EventEmitter,
HostBinding,
Input,
Output,
ViewChild,
input,
output,
viewChild
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { OnInit } from '@angular/core';
@@ -38,14 +38,13 @@ export class PiSearchFieldComponent extends PiBaseFormFieldComponent implements
return ['pi-field pi-form-field__search', isExpandedClass].join(' ');
}
@Output() searchClick: EventEmitter<void> = new EventEmitter();
readonly searchClick = output<void>();
@Output() resetClick: EventEmitter<void> = new EventEmitter();
readonly resetClick = output<void>();
@ViewChild('input', { read: ElementRef, static: true })
inputRef!: ElementRef;
readonly inputRef = viewChild.required('input', { read: ElementRef });
@Input() isClosable = true;
readonly isClosable = input(true);
private _isExpanded = false;
@Input()
@@ -59,7 +58,7 @@ export class PiSearchFieldComponent extends PiBaseFormFieldComponent implements
}
ngOnInit(): void {
this.isExpanded = !!this.control.value || !this.isClosable;
this.isExpanded = !!this.control.value || !this.isClosable();
this.control.valueChanges.subscribe((value: any) => {
if (value) {
this.isExpanded = true;
@@ -69,11 +68,11 @@ export class PiSearchFieldComponent extends PiBaseFormFieldComponent implements
openField(): void {
this.isExpanded = true;
this.inputRef.nativeElement.focus();
this.inputRef().nativeElement.focus();
}
closeField(): void {
if (this.isClosable) {
if (this.isClosable()) {
this.isExpanded = false;
}
if (this.control.value) {

View File

@@ -1,4 +1,4 @@
<label [for]="formControlName + 'checkbox'">
<input [formControl]="control" type="checkbox" [id]="formControlName + 'checkbox'" />
<label [for]="formControlName() + 'checkbox'">
<input [formControl]="control" type="checkbox" [id]="formControlName() + 'checkbox'" />
<span></span>
</label>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, OnChanges, OnInit, SimpleChanges, input } from '@angular/core';
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { PiBaseFormFieldComponent } from '../base-form-field.component';
@@ -22,7 +22,7 @@ export class PiSlideToggleComponent extends PiBaseFormFieldComponent implements
return ['pi-slide-toggle', isCheckedClass, this.isDisabledClass].join(' ');
}
@Input() label: string | undefined;
readonly label = input<string>();
isChecked!: boolean;

View File

@@ -1,4 +1,4 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<ng-container matSuffix>
@@ -7,10 +7,10 @@
<input
[formControl]="control"
[placeholder]="placeholder"
[placeholder]="placeholder()"
matInput
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
/>
<mat-error *ngIf="control.errors">

View File

@@ -1,10 +1,10 @@
<mat-form-field [appearance]="appearance" floatLabel="always">
<mat-form-field [appearance]="appearance()" floatLabel="always">
<mat-label><ng-content select="pi-label"></ng-content></mat-label>
<textarea
[formControl]="control"
[placeholder]="placeholder"
[name]="formControlName"
[placeholder]="placeholder()"
[name]="formControlName()"
[maxLength]="maxLength"
matInput
cdkTextareaAutosize
@@ -12,10 +12,10 @@
cdkAutosizeMinRows="4"
cdkAutosizeMaxRows="2"
pi-autofocus
[isAutofocusSelected]="isAutofocus"
[isAutofocusSelected]="isAutofocus()"
></textarea>
</mat-form-field>
<mat-error *ngIf="control.errors && enableErrorMessage">
<mat-error *ngIf="control.errors && enableErrorMessage()">
<ng-container *ngFor="let text of control.errors['message']">
{{ text | translate }}
</ng-container>

View File

@@ -1,5 +1,5 @@
<img *ngIf="type === 'custom'; else defaultIcon" src="/assets/icons/{{ icon }}.svg" />
<img *ngIf="type() === 'custom'; else defaultIcon" src="/assets/icons/{{ icon() }}.svg" />
<ng-template #defaultIcon
><mat-icon size="size" [svgIcon]="icon" color="color"></mat-icon
><mat-icon size="size" [svgIcon]="icon()" color="color"></mat-icon
></ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
// Shared
import {
@@ -20,14 +20,20 @@ import { MatIcon } from '@angular/material/icon';
})
export class PiIconComponent {
@HostBinding('class') get classes(): string {
const colorClass = this.color && `pi-color__${this.color}`;
const sizeClass = this.size && `pi-icon__${this.size}`;
const animationClass = this.animation && `pi-icon__animation--${this.animation}`;
const color = this.color();
const colorClass = color && `pi-color__${color}`;
const size = this.size();
const sizeClass = size && `pi-icon__${size}`;
const animationValue = this.animation();
const animationClass = animationValue && `pi-icon__animation--${animationValue}`;
const appearance = this.appearance();
const appearanceClass =
this.appearance !== 'default' ? `pi-icon__appearance--${this.appearance}` : '';
const typeClass = this.type !== 'default' ? `pi-icon__type--${this.type}` : '';
const borderRadiusClass = this.borderRadius && `pi-icon__border-radius--${this.borderRadius}`;
const strokeClass = this.isStroked === true && 'is-stroked';
appearance !== 'default' ? `pi-icon__appearance--${appearance}` : '';
const type = this.type();
const typeClass = type !== 'default' ? `pi-icon__type--${type}` : '';
const borderRadiusValue = this.borderRadius();
const borderRadiusClass = borderRadiusValue && `pi-icon__border-radius--${borderRadiusValue}`;
const strokeClass = this.isStroked() === true && 'is-stroked';
return [
'pi-icon',
ComponentFamilyClass.Text,
@@ -40,12 +46,12 @@ export class PiIconComponent {
typeClass,
].join(' ');
}
@Input() color: styleType;
@Input() icon: string;
@Input() size: iconSize = 'medium';
@Input() animation: animation;
@Input() appearance: 'fill' | 'default' = 'default';
@Input() type: 'custom' | 'default' = 'default';
@Input() borderRadius: borderRadius;
@Input() isStroked = false;
readonly color = input<styleType>();
readonly icon = input<string>();
readonly size = input<iconSize>('medium');
readonly animation = input<animation>();
readonly appearance = input<'fill' | 'default'>('default');
readonly type = input<'custom' | 'default'>('default');
readonly borderRadius = input<borderRadius>();
readonly isStroked = input(false);
}

View File

@@ -4,9 +4,9 @@ import {
Directive,
ElementRef,
HostBinding,
Input,
Renderer2,
OnDestroy,
input
} from '@angular/core';
// RxJS
@@ -19,26 +19,18 @@ import { takeUntil } from 'rxjs/operators';
@Directive({ selector: '[pi-background-image]', })
export class PiBackgroundImageDirective implements AfterViewInit, OnDestroy {
@HostBinding('class') get classes(): string {
const animationClass = this.animation && `pi-background-image__animation--${this.animation}`;
const animation = this.animation();
const animationClass = animation && `pi-background-image__animation--${animation}`;
return ['pi-image', 'pi-background-image', animationClass].join(' ');
}
@Input() extension: 'jpg' | 'png' | 'svg' | 'gif' | 'webp' = 'svg';
@Input() animation: 'infinite';
@Input() image: string | undefined;
@Input() isResponsive = false;
@Input() origin: 'content-box' | 'border-box' = 'content-box';
@Input() size: 'auto' | 'contain' | 'cover' = 'cover';
@Input() position:
| 'left top'
| 'left center'
| 'left bottom'
| 'right top'
| 'right center'
| 'right bottom'
| 'center top'
| 'center center'
| 'center bottom' = 'center center';
readonly extension = input<'jpg' | 'png' | 'svg' | 'gif' | 'webp'>('svg');
readonly animation = input<'infinite'>();
readonly image = input<string>();
readonly isResponsive = input(false);
readonly origin = input<'content-box' | 'border-box'>('content-box');
readonly size = input<'auto' | 'contain' | 'cover'>('cover');
readonly position = input<'left top' | 'left center' | 'left bottom' | 'right top' | 'right center' | 'right bottom' | 'center top' | 'center center' | 'center bottom'>('center center');
private destroy$: Subject<void> = new Subject<void>();
@@ -63,25 +55,25 @@ export class PiBackgroundImageDirective implements AfterViewInit, OnDestroy {
const el = this.element.nativeElement;
this.renderer.setStyle(el, 'background-repeat', 'no-repeat');
this.renderer.setStyle(el, 'background-position', this.position);
this.renderer.setStyle(el, 'background-size', this.size);
if (this.origin === 'content-box') {
this.renderer.setStyle(el, 'background-position', this.position());
this.renderer.setStyle(el, 'background-size', this.size());
if (this.origin() === 'content-box') {
this.renderer.setStyle(el, 'background-origin', 'content-box');
} else {
this.renderer.setStyle(el, 'background-origin', 'border-box');
}
if (this.isResponsive) {
if (this.isResponsive()) {
this.renderer.setStyle(
el,
'background-image',
`url(https://d2m4265u67f2xu.cloudfront.net/assets/images/${this.image}-${device}.${this.extension})`
`url(https://d2m4265u67f2xu.cloudfront.net/assets/images/${this.image()}-${device}.${this.extension()})`
);
} else {
this.renderer.setStyle(
el,
'background-image',
`url(https://d2m4265u67f2xu.cloudfront.net/assets/images/${this.image}.${this.extension})`
`url(https://d2m4265u67f2xu.cloudfront.net/assets/images/${this.image()}.${this.extension()})`
);
}
}

View File

@@ -1,21 +1,21 @@
<figure>
<a *ngIf="link; else image" [href]="link" target="_blank"
><img
src="https://d2m4265u67f2xu.cloudfront.net/assets/images/{{ pathImg }}"
[alt]="pathImg | sanitizerAltImage"
src="https://d2m4265u67f2xu.cloudfront.net/assets/images/{{ pathImg() }}"
[alt]="pathImg() | sanitizerAltImage"
width="100%"
height="auto"
/></a>
<ng-template #image>
<img
src="https://d2m4265u67f2xu.cloudfront.net/assets/images/{{ pathImg }}"
[alt]="pathImg | sanitizerAltImage"
src="https://d2m4265u67f2xu.cloudfront.net/assets/images/{{ pathImg() }}"
[alt]="pathImg() | sanitizerAltImage"
width="100%"
height="auto"
/>
</ng-template>
</figure>
<aside *ngIf="hasContent">
<aside *ngIf="hasContent()">
<ng-content select="pi-headline-label-content"></ng-content>
<ng-content select="pi-headline-description-content"></ng-content>
</aside>

View File

@@ -5,6 +5,7 @@ import {
Directive,
HostBinding,
Input,
input
} from '@angular/core';
// Shared
@@ -38,12 +39,18 @@ export class PiHeadlineDescriptionContentDirective {}
})
export class PiHeadlineComponent {
@HostBinding('class') get classes(): string {
const alignmentClass = this.alignment && `pi-headline__align--${this.alignment}`;
const flexDirectionClass = this.flexDirection && `pi-headline__flex--${this.flexDirection}`;
const gapClass = this.gap && `pi-headline__gap--${this.gap}`;
const paddingClass = this.padding && `pi-headline__padding--${this.padding}`;
const typeClass = this.type !== 'default' && `pi-headline__type--${this.type}`;
const widthClass = this.width && `pi-headline__width--${this.width}`;
const alignmentValue = this.alignment();
const alignmentClass = alignmentValue && `pi-headline__align--${alignmentValue}`;
const flexDirectionValue = this.flexDirection();
const flexDirectionClass = flexDirectionValue && `pi-headline__flex--${flexDirectionValue}`;
const gapValue = this.gap();
const gapClass = gapValue && `pi-headline__gap--${gapValue}`;
const padding = this.padding();
const paddingClass = padding && `pi-headline__padding--${padding}`;
const type = this.type();
const typeClass = type !== 'default' && `pi-headline__type--${type}`;
const width = this.width();
const widthClass = width && `pi-headline__width--${width}`;
return [
ComponentFamilyClass.Image,
@@ -56,24 +63,16 @@ export class PiHeadlineComponent {
paddingClass,
].join(' ');
}
@Input() alt: string | undefined;
@Input() hasContent = true;
readonly alt = input<string>();
readonly hasContent = input(true);
@Input() link!: string | undefined;
@Input() pathImg!: string | undefined;
readonly pathImg = input.required<string | undefined>();
// Skin
@Input() alignment: alignment = 'center';
@Input() flexDirection: flexDirection = 'column';
@Input() gap!: gap | undefined;
@Input() type: 'logo' | 'default' | 'avatar' = 'default';
@Input() padding: 'xxxxl' | 'xxxl' | 'xxl' | 'xl' | 'l' | 'm';
@Input() width:
| 'quarter'
| 'third'
| 'half'
| 'fifth'
| 'sixth'
| 'three-quarters'
| 'two-thirds'
| undefined;
readonly alignment = input<alignment>('center');
readonly flexDirection = input<flexDirection>('column');
readonly gap = input.required<gap | undefined>();
readonly type = input<'logo' | 'default' | 'avatar'>('default');
readonly padding = input<'xxxxl' | 'xxxl' | 'xxl' | 'xl' | 'l' | 'm'>();
readonly width = input<'quarter' | 'third' | 'half' | 'fifth' | 'sixth' | 'three-quarters' | 'two-thirds'>();
}

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Directive, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, Directive, HostBinding, input } from '@angular/core';
import {
alignment,
@@ -61,69 +61,77 @@ export class PiListItemComponent {
].join(' ');
}
@Input() alignment: alignment = 'center';
@Input() appearance: 'default' | 'fill' = 'default';
@Input() borderType!: borderType;
@Input() color!: styleType;
@Input() isActive = false;
@Input() isClickable = false;
@Input() isDisabled = false;
@Input() isResponsive = false;
@Input() isStroked = false;
@Input() maxWidth: 'full' | 'half' | 'third' = 'full';
@Input() mode: mode = 'light';
@Input() opacity: opacity;
@Input() padding: padding = 'xl';
readonly alignment = input<alignment>('center');
readonly appearance = input<'default' | 'fill'>('default');
readonly borderType = input.required<borderType>();
readonly color = input.required<styleType>();
readonly isActive = input(false);
readonly isClickable = input(false);
readonly isDisabled = input(false);
readonly isResponsive = input(false);
readonly isStroked = input(false);
readonly maxWidth = input<'full' | 'half' | 'third'>('full');
readonly mode = input<mode>('light');
readonly opacity = input<opacity>();
readonly padding = input<padding>('xl');
protected get alignmentClass(): string {
return this.alignment ? `pi-list-item__align-items--${this.alignment}` : '';
const alignmentValue = this.alignment();
return alignmentValue ? `pi-list-item__align-items--${alignmentValue}` : '';
}
protected get borderTypeClass(): string {
return this.borderType ? `pi-list-item__border--${this.borderType}` : '';
const borderTypeValue = this.borderType();
return borderTypeValue ? `pi-list-item__border--${borderTypeValue}` : '';
}
protected get colorClass(): string {
return this.color ? `pi-color__${this.color}` : '';
const color = this.color();
return color ? `pi-color__${color}` : '';
}
protected get maxWidthClass(): string {
return this.maxWidth !== 'full' && `pi-list-item__max-width--${this.maxWidth}`;
const maxWidth = this.maxWidth();
return maxWidth !== 'full' && `pi-list-item__max-width--${maxWidth}`;
}
protected get isActiveClass(): string {
return this.isActive ? 'is-active' : '';
return this.isActive() ? 'is-active' : '';
}
protected get isClickableClass(): string {
return this.isClickable ? 'is-clickable' : '';
return this.isClickable() ? 'is-clickable' : '';
}
protected get isDisabledClass(): string {
return this.isDisabled ? 'is-disabled' : '';
return this.isDisabled() ? 'is-disabled' : '';
}
protected get isResponsiveClass(): string {
return this.isResponsive ? 'is-responsive' : '';
return this.isResponsive() ? 'is-responsive' : '';
}
protected get isStrokedClass(): string {
return this.isStroked && this.appearance === 'fill' ? 'is-stroked' : '';
return this.isStroked() && this.appearance() === 'fill' ? 'is-stroked' : '';
}
protected get paddingClass(): string {
return this.padding ? `pi-list-item__padding--${this.padding}` : '';
const paddingValue = this.padding();
return paddingValue ? `pi-list-item__padding--${paddingValue}` : '';
}
protected get appearanceClass(): string {
return this.appearance !== 'default' ? `pi-list-item__appearance--${this.appearance}` : '';
const appearance = this.appearance();
return appearance !== 'default' ? `pi-list-item__appearance--${appearance}` : '';
}
protected get opacityClass(): string {
return this.opacity ? `pi-color__opacity--${this.opacity}` : '';
const opacityValue = this.opacity();
return opacityValue ? `pi-color__opacity--${opacityValue}` : '';
}
protected get modeClass(): string | undefined {
return this.mode ? `pi-color__mode--${this.mode}` : '';
const modeValue = this.mode();
return modeValue ? `pi-color__mode--${modeValue}` : '';
}
}

View File

@@ -5,6 +5,7 @@ import {
HostBinding,
Input,
OnInit,
input
} from '@angular/core';
import { NoteDataService } from '../infrastructure/note-data.service';
import { NoteStatus } from '../entities/note.model';
@@ -41,18 +42,27 @@ export class PiNoteActionContentDirective {}
})
export class PiNoteComponent implements OnInit {
@HostBinding('class') get classes(): string {
const alignmentClass = this.alignment && `pi-note__align-items--${this.alignment}`;
const alignmentValue = this.alignment();
const alignmentClass = alignmentValue && `pi-note__align-items--${alignmentValue}`;
const flexDirection = this.flexDirection();
const flexDirectionClass =
this.flexDirection && `pi-note__flex-direction--${this.flexDirection}`;
const justifyContentClass = this.justify && `pi-note__justify-content--${this.justify}`;
const gapClass = this.gap && `pi-note__gap--${this.gap}`;
const isResponsiveClass = this.isResponsive && 'is-responsive';
const isStickyClass = this.isSticky && 'is-sticky';
const modeClass = this.mode && `pi-note__mode--${this.mode}`;
const positionClass = this.position && `pi-note__position--${this.position}`;
const statusClass = this.status && `pi-note__status--${this.status}`;
const appearanceClass = this.appearance && `pi-note__appearance--${this.appearance}`;
const typeClass = this.type && `pi-note__${this.type}`;
flexDirection && `pi-note__flex-direction--${flexDirection}`;
const justify = this.justify();
const justifyContentClass = justify && `pi-note__justify-content--${justify}`;
const gapValue = this.gap();
const gapClass = gapValue && `pi-note__gap--${gapValue}`;
const isResponsiveClass = this.isResponsive() && 'is-responsive';
const isStickyClass = this.isSticky() && 'is-sticky';
const mode = this.mode();
const modeClass = mode && `pi-note__mode--${mode}`;
const position = this.position();
const positionClass = position && `pi-note__position--${position}`;
const statusValue = this.status();
const statusClass = statusValue && `pi-note__status--${statusValue}`;
const appearance = this.appearance();
const appearanceClass = appearance && `pi-note__appearance--${appearance}`;
const type = this.type();
const typeClass = type && `pi-note__${type}`;
return [
'pi-note',
alignmentClass,
@@ -74,19 +84,19 @@ export class PiNoteComponent implements OnInit {
@Input() text!: string | undefined;
// Behavior
@Input() status!: status;
readonly status = input.required<status>();
// Skin
@Input() alignment: alignment = 'center';
@Input() justify: 'center' | 'space-between' = 'space-between';
@Input() flexDirection: 'row' | 'column' = 'row';
@Input() gap!: gap | undefined;
@Input() isResponsive = false;
@Input() isSticky = false;
@Input() mode: 'dark' | 'light' = 'light';
@Input() position: 'top' | 'bottom' = 'bottom';
@Input() appearance: 'fill' | 'ghost' = 'fill';
@Input() type: 'status' | 'simple' = 'status';
readonly alignment = input<alignment>('center');
readonly justify = input<'center' | 'space-between'>('space-between');
readonly flexDirection = input<'row' | 'column'>('row');
readonly gap = input.required<gap | undefined>();
readonly isResponsive = input(false);
readonly isSticky = input(false);
readonly mode = input<'dark' | 'light'>('light');
readonly position = input<'top' | 'bottom'>('bottom');
readonly appearance = input<'fill' | 'ghost'>('fill');
readonly type = input<'status' | 'simple'>('status');
noteStatus!: NoteStatus;
@@ -98,6 +108,6 @@ export class PiNoteComponent implements OnInit {
getNoteStatus(): NoteStatus {
const noteStatusOptions = this.noteDataService.getNoteStatusData();
return noteStatusOptions.find((noteStatus) => this.status === noteStatus.statusType);
return noteStatusOptions.find((noteStatus) => this.status() === noteStatus.statusType);
}
}

View File

@@ -7,6 +7,6 @@
</section>
<ng-template #button>
<button (click)="dismiss()" pi-ghost>
{{ text }}
{{ text() }}
</button>
</ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Inject, Input, Optional, forwardRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, Inject, Input, Optional, forwardRef, input } from '@angular/core';
import { MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar';
import { styleType } from '../../../styles';
import { NgIf } from '@angular/common';
@@ -37,7 +37,7 @@ export class PiSnackBarComponent {
@Input() message: string;
@Input() text: string;
readonly text = input<string>();
@Input() icon: string;
@Input() type: 'success' | 'error' | 'info' = 'success';
@Input() dismissible = false;

View File

@@ -22,7 +22,7 @@
<footer>
<ng-container
*ngIf="totalPages < 5; then defaultPaginator; else advancedPaginator"
*ngIf="totalPages() < 5; then defaultPaginator; else advancedPaginator"
></ng-container>
</footer>
@@ -33,7 +33,7 @@
density="200"
size="x-small"
(execute)="paginateNext()"
[disabled]="currentPage === totalPages || isDisabled"
[disabled]="currentPage === totalPages() || isDisabled()"
>
Next
</pi-icon-button>
@@ -56,7 +56,7 @@
</div>
<!-- when total pages > 6 || the difference is > 6 -->
<pi-icon
*ngIf="totalPages > 6 && totalPages - firstPages[firstPages.length - 1] > 6"
*ngIf="totalPages() > 6 && totalPages() - firstPages[firstPages.length - 1] > 6"
(click)="movePages()"
icon="more"
></pi-icon>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, EventEmitter, Component, Output, Input, OnInit, HostBinding, forwardRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnInit, HostBinding, forwardRef, input, output } from '@angular/core';
import { PiIconButtonComponent } from '../../button/icon-button/icon-button.component';
import { NgIf, NgFor } from '@angular/common';
import { PiIconComponent } from '../../icon/icon/icon.component';
@@ -20,11 +20,11 @@ import { PiIconComponent } from '../../icon/icon/icon.component';
export class PiPaginatorComponent implements OnInit {
@HostBinding('class') className = 'pi-paginator';
@Input() currentPage = 1;
@Input() pageSize!: number;
@Input() totalPages!: number;
@Input() isDisabled!: boolean;
readonly pageSize = input.required<number>();
readonly totalPages = input.required<number>();
readonly isDisabled = input.required<boolean>();
@Output() changePage = new EventEmitter();
readonly changePage = output();
firstPages!: number[];
@@ -35,7 +35,7 @@ export class PiPaginatorComponent implements OnInit {
}
get pages() {
return [...new Array(this.totalPages).keys()].map((el) => el + 1);
return [...new Array(this.totalPages()).keys()].map((el) => el + 1);
}
// get firstPages() {
@@ -51,11 +51,11 @@ export class PiPaginatorComponent implements OnInit {
// keys(o: object): string[];
get lastPages() {
return [...new Array(this.totalPages).keys()].slice(-3).map((el) => el + 1);
return [...new Array(this.totalPages()).keys()].slice(-3).map((el) => el + 1);
}
protected initFirstPages(): void {
this.firstPages = [...new Array(this.totalPages).slice(0, 3).keys()].map((el) => el + 1);
this.firstPages = [...new Array(this.totalPages()).slice(0, 3).keys()].map((el) => el + 1);
}
protected paginateBack(): void {
@@ -71,7 +71,7 @@ export class PiPaginatorComponent implements OnInit {
}
protected paginateNext(): void {
if (this.currentPage < this.totalPages) {
if (this.currentPage < this.totalPages()) {
const updatedCurrentPage = this.currentPage + 1;
if (this.firstPages.indexOf(this.currentPage) >= 2) {
this.firstPagesRange = this.firstPagesRange + 3;
@@ -83,7 +83,7 @@ export class PiPaginatorComponent implements OnInit {
}
protected paginateTo(selectedPage: number): void {
if (this.isDisabled && selectedPage > this.currentPage) {
if (this.isDisabled() && selectedPage > this.currentPage) {
return;
} else {
this.currentPage = selectedPage;
@@ -98,7 +98,7 @@ export class PiPaginatorComponent implements OnInit {
}
protected movePages(): void {
if (!this.isDisabled) {
if (!this.isDisabled()) {
this.firstPagesRange = this.firstPagesRange + 3;
this.firstPages = this.incrementPaginatorRangeBy(3);
this.currentPage = this.firstPages[0];
@@ -107,13 +107,13 @@ export class PiPaginatorComponent implements OnInit {
}
private incrementPaginatorRangeBy(range: number): Array<number> {
return [...new Array(this.totalPages).keys()]
return [...new Array(this.totalPages()).keys()]
.slice(this.firstPagesRange, this.firstPagesRange + range)
.map((el) => el + 1);
}
private decrementPaginatorRangeBy(range: number): Array<number> {
return [...new Array(this.totalPages).keys()]
return [...new Array(this.totalPages()).keys()]
.slice(this.firstPagesRange - range, this.firstPagesRange)
.map((el) => el + 1);
}

View File

@@ -1,5 +1,5 @@
// Angular
import { Directive, Input, OnInit } from '@angular/core';
import { Directive, OnInit, input } from '@angular/core';
import {
alignment,
borderRadius,
@@ -14,25 +14,25 @@ import { status } from '../../util/status';
@Directive()
export abstract class PiBasePanelComponent implements OnInit {
@Input() alignment: alignment = 'center';
@Input() borderRadius: borderRadius = 'large';
@Input() color: styleType = 'white';
@Input() flexDirection: flexDirection = 'column';
@Input() isStroked = false;
@Input() hasShadow = false;
@Input() justify: justify = 'center';
@Input() width: 'quarter' | 'third' | 'half' | 'fifth' | 'sixth' | 'two-thirds' | undefined;
readonly alignment = input<alignment>('center');
readonly borderRadius = input<borderRadius>('large');
readonly color = input<styleType>('white');
readonly flexDirection = input<flexDirection>('column');
readonly isStroked = input(false);
readonly hasShadow = input(false);
readonly justify = input<justify>('center');
readonly width = input<'quarter' | 'third' | 'half' | 'fifth' | 'sixth' | 'two-thirds'>();
// TODO: remove on the advisor dashboard refactor
@Input() height!: 'small' | 'medium' | 'large' | 'x-large' | undefined;
@Input() outline!: styleType;
@Input() padding: padding = 'l';
@Input() grid: 'half' | 'quarter' | 'reverse-quarter';
@Input() gap: gap = 'l';
@Input() mode: 'dark' | 'light' = 'dark';
@Input() innerPadding!: padding;
@Input() opacity: opacity;
readonly height = input.required<'small' | 'medium' | 'large' | 'x-large' | undefined>();
readonly outline = input.required<styleType>();
readonly padding = input<padding>('l');
readonly grid = input<'half' | 'quarter' | 'reverse-quarter'>();
readonly gap = input<gap>('l');
readonly mode = input<'dark' | 'light'>('dark');
readonly innerPadding = input.required<padding>();
readonly opacity = input<opacity>();
@Input() status!: status | '';
readonly status = input.required<status | ''>();
ngOnInit(): void {
this.alignmentClass;
@@ -51,72 +51,86 @@ export abstract class PiBasePanelComponent implements OnInit {
}
protected get widthClass(): string | undefined {
return this.width && `pi-panel__width--${this.width}`;
const width = this.width();
return width && `pi-panel__width--${width}`;
}
protected get alignmentClass(): string {
return this.alignment && `pi-panel__align--${this.alignment}`;
const alignmentValue = this.alignment();
return alignmentValue && `pi-panel__align--${alignmentValue}`;
}
protected get justifyClass(): string {
return this.justify && `pi-panel__justify--${this.justify}`;
const justifyValue = this.justify();
return justifyValue && `pi-panel__justify--${justifyValue}`;
}
protected get flexDirectionClass(): string {
return this.flexDirection && `pi-panel__flex-direction--${this.flexDirection}`;
const flexDirectionValue = this.flexDirection();
return flexDirectionValue && `pi-panel__flex-direction--${flexDirectionValue}`;
}
protected get borderRadiusClass(): string {
return this.borderRadius && `pi-panel__border-radius--${this.borderRadius}`;
const borderRadiusValue = this.borderRadius();
return borderRadiusValue && `pi-panel__border-radius--${borderRadiusValue}`;
}
protected get colorClass(): string {
return `pi-color__${this.color}`;
return `pi-color__${this.color()}`;
}
protected get hasShadowClass(): string | boolean {
return this.hasShadow && 'has-shadow';
return this.hasShadow() && 'has-shadow';
}
protected get heightClass(): string | undefined {
return this.height && `pi-panel__height--${this.height}`;
const height = this.height();
return height && `pi-panel__height--${height}`;
}
protected get outlineClass(): string {
return this.outline && `is-stroked pi-panel__border-color--${this.outline}`;
const outline = this.outline();
return outline && `is-stroked pi-panel__border-color--${outline}`;
}
protected get paddingClass(): string {
return this.padding ? `pi-panel__padding--${this.padding}` : '';
const paddingValue = this.padding();
return paddingValue ? `pi-panel__padding--${paddingValue}` : '';
}
protected get gridClass(): string {
return this.grid && `pi-panel__grid--${this.grid}`;
const grid = this.grid();
return grid && `pi-panel__grid--${grid}`;
}
protected get isStrokedClass(): string {
return this.isStroked ? 'is-stroked' : '';
return this.isStroked() ? 'is-stroked' : '';
}
protected get gapClass(): string {
return this.gap && `pi-panel__gap--${this.gap}`;
const gapValue = this.gap();
return gapValue && `pi-panel__gap--${gapValue}`;
}
protected get statusClass(): string {
return this.status && `is-${this.status}`;
const statusValue = this.status();
return statusValue && `is-${statusValue}`;
}
protected get modeClass(): string {
return this.mode && `pi-color__mode--${this.mode}`;
const mode = this.mode();
return mode && `pi-color__mode--${mode}`;
}
protected get innerPaddingClass(): string {
return this.innerPadding
? `pi-panel__inner-padding pi-panel__inner-padding--${this.innerPadding}`
const innerPadding = this.innerPadding();
return innerPadding
? `pi-panel__inner-padding pi-panel__inner-padding--${innerPadding}`
: '';
}
protected get opacityClass(): string {
return this.opacity ? `pi-color__opacity--${this.opacity}` : '';
const opacityValue = this.opacity();
return opacityValue ? `pi-color__opacity--${opacityValue}` : '';
}
}

View File

@@ -1,9 +1,9 @@
<ng-container *ngIf="type === 'form'; else customPanelTemplate">
<form [formGroup]="formGroup">
<ng-container *ngIf="type() === 'form'; else customPanelTemplate">
<form [formGroup]="formGroup()">
<!-- Top -->
<header>
<div>
<h2 m medium>{{ title }}</h2>
<h2 m medium>{{ title() }}</h2>
<h4 pi-grey light xs *ngIf="subtitle">{{ subtitle }}</h4>
</div>
<aside>
@@ -38,7 +38,7 @@
<ng-template #customPanelTemplate>
<!-- Top -->
<header class="pi-panel-content pi-panel-content__top">
<ng-container *ngTemplateOutlet="topContentRef"></ng-container>
<ng-container *ngTemplateOutlet="topContentRef()"></ng-container>
<aside>
<pi-divider direction="vertical" color="grey" height="medium"></pi-divider>
<pi-icon
@@ -51,13 +51,13 @@
</header>
<!-- Center -->
<ng-container *ngTemplateOutlet="centerContentRef"></ng-container>
<ng-container *ngTemplateOutlet="centerContentRef()"></ng-container>
<!-- Bottom & Expansion -->
<section
[class]="isCollapsed ? 'is-collapsed' : 'is-expanded'"
class="pi-panel-content pi-panel-content__expandable"
>
<ng-container *ngTemplateOutlet="expandableContentRef"> </ng-container>
<ng-container *ngTemplateOutlet="expandableContentRef()"> </ng-container>
</section>
</ng-template>

View File

@@ -1,15 +1,15 @@
import {
ChangeDetectionStrategy,
Component,
ContentChild,
EventEmitter,
HostBinding,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
TemplateRef,
input,
output,
contentChild
} from '@angular/core';
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
import { ComponentFamilyClass } from '../../../styles';
@@ -47,7 +47,8 @@ import { TranslatePipe } from '@ngx-translate/core';
})
export class PiExpansionPanelComponent extends PiBasePanelComponent implements OnInit, OnChanges {
@HostBinding('class') get classes(): string {
const typeClass = this.type && `pi-panel__expansion--type-${this.type}`;
const type = this.type();
const typeClass = type && `pi-panel__expansion--type-${type}`;
return [
'pi-panel__expansion',
ComponentFamilyClass.Panel,
@@ -58,24 +59,21 @@ export class PiExpansionPanelComponent extends PiBasePanelComponent implements O
].join(' ');
}
@Input() type: 'form' | 'custom' = 'form';
readonly type = input<'form' | 'custom'>('form');
@Input() isCollapsed = false;
@Input() title: string | undefined;
readonly title = input<string>();
@Input() subtitle: string | undefined;
@Input() formGroup!: FormGroup;
@Output() edit: EventEmitter<void> = new EventEmitter<void>();
readonly formGroup = input.required<FormGroup>();
readonly edit = output<void>();
@ContentChild('topContent', { static: false })
topContentRef: TemplateRef<unknown> | undefined;
readonly topContentRef = contentChild<TemplateRef<unknown>>('topContent');
@ContentChild('centerContent', { static: false })
centerContentRef: TemplateRef<unknown> | undefined;
readonly centerContentRef = contentChild<TemplateRef<unknown>>('centerContent');
@ContentChild('expandableContent', { static: false })
expandableContentRef: TemplateRef<unknown> | undefined;
readonly expandableContentRef = contentChild<TemplateRef<unknown>>('expandableContent');
override ngOnInit(): void {
if (this.status === 'disabled') this.isCollapsed = true;
if (this.status() === 'disabled') this.isCollapsed = true;
}
ngOnChanges({ status }: SimpleChanges): void {
@@ -83,11 +81,12 @@ export class PiExpansionPanelComponent extends PiBasePanelComponent implements O
}
toggle(): void {
if (this.status !== 'disabled' && this.status !== 'info') this.isCollapsed = !this.isCollapsed;
const status = this.status();
if (status !== 'disabled' && status !== 'info') this.isCollapsed = !this.isCollapsed;
}
onEdit(): void {
if (this.status !== 'disabled') {
if (this.status() !== 'disabled') {
if (this.isCollapsed) this.toggle();
this.edit.emit();
}

View File

@@ -1,4 +1,4 @@
import { Directive, HostBinding, Input, OnInit } from '@angular/core';
import { Directive, HostBinding, OnInit, input } from '@angular/core';
import { padding } from '../../styles';
@Directive()
@@ -7,14 +7,15 @@ export abstract class PiBasePanelContentDirective implements OnInit {
return ['pi-panel-content', this.innerPaddingClass].join(' ');
}
@Input() innerPadding: padding;
readonly innerPadding = input<padding>();
ngOnInit(): void {
this.innerPaddingClass;
}
protected get innerPaddingClass(): string {
return this.innerPadding ? `pi-panel-content__inner-padding--${this.innerPadding}` : '';
const innerPadding = this.innerPadding();
return innerPadding ? `pi-panel-content__inner-padding--${innerPadding}` : '';
}
}

View File

@@ -1,2 +1,2 @@
<h5>{{ label }}</h5>
<mat-progress-bar mode="determinate" [value]="value"></mat-progress-bar>
<h5>{{ label() }}</h5>
<mat-progress-bar mode="determinate" [value]="value()"></mat-progress-bar>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input, forwardRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, forwardRef, input } from '@angular/core';
import { MatProgressBar } from '@angular/material/progress-bar';
@@ -12,6 +12,6 @@ import { MatProgressBar } from '@angular/material/progress-bar';
export class PiProgressBarComponent {
@HostBinding('class') className = 'pi-progress-bar';
@Input() label!: string;
@Input() value!: number;
readonly label = input.required<string>();
readonly value = input.required<number>();
}

View File

@@ -1,29 +1,29 @@
<!-- Progress spinner -->
<mat-progress-spinner
mode="determinate"
[diameter]="diameter"
[strokeWidth]="strokeWidth"
[value]="value"
[diameter]="diameter()"
[strokeWidth]="strokeWidth()"
[value]="value()"
>
</mat-progress-spinner>
<!-- Value -->
<span
*ngIf="appearance === 'compact'; else defaultValue"
[style.width]="diameter + 'px'"
[style.height]="diameter + 'px'"
[style.margin-top]="-diameter + 'px'"
[style.line-height]="diameter + 'px'"
*ngIf="appearance() === 'compact'; else defaultValue"
[style.width]="diameter() + 'px'"
[style.height]="diameter() + 'px'"
[style.margin-top]="-diameter() + 'px'"
[style.line-height]="diameter() + 'px'"
>
<span>{{ value }}</span
<span>{{ value() }}</span
><span>%</span>
</span>
<!-- Value -->
<ng-template #defaultValue>
<span>
<span>{{ value }}</span
<span>{{ value() }}</span
><span>%</span>
</span>
<span>{{ label }}</span>
<span>{{ label() }}</span>
</ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding, input } from '@angular/core';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import { NgIf } from '@angular/common';
import { PiProgressBarComponent } from '../progress-bar/progress-bar.component';
@@ -18,13 +18,17 @@ export class PiProgressSpinnerComponent {
className = 'pi-spinner pi-spinner__progress';
@HostBinding('class') get classes(): string {
const appearance = this.appearance();
const appearanceClass =
this.appearance !== 'default' && `pi-spinner__appearance--${this.appearance}`;
const strokeWidthClass = this.strokeWidth && `pi-spinner__stroke--${this.strokeWidth}`;
appearance !== 'default' && `pi-spinner__appearance--${appearance}`;
const strokeWidth = this.strokeWidth();
const strokeWidthClass = strokeWidth && `pi-spinner__stroke--${strokeWidth}`;
const diameter = this.diameter();
const smallDiameterClass =
this.diameter === 60 || (this.diameter === 70 && 'pi-spinner__diameter--small');
diameter === 60 || (diameter === 70 && 'pi-spinner__diameter--small');
const diameterValue = this.diameter();
const largeDiameterClass =
this.diameter === 110 || (this.diameter === 130 && 'pi-spinner__diameter--large');
diameterValue === 110 || (diameterValue === 130 && 'pi-spinner__diameter--large');
return [
'pi-spinner',
'pi-spinner__progress',
@@ -35,9 +39,9 @@ export class PiProgressSpinnerComponent {
].join(' ');
}
@Input() value!: number;
@Input() label!: string;
@Input() appearance: 'compact' | 'default' = 'default';
@Input() strokeWidth: 2 | 3 | 4 | 5 | 6 | 7 | 8 = 6;
@Input() diameter!: number;
readonly value = input.required<number>();
readonly label = input.required<string>();
readonly appearance = input<'compact' | 'default'>('default');
readonly strokeWidth = input<2 | 3 | 4 | 5 | 6 | 7 | 8>(6);
readonly diameter = input.required<number>();
}

View File

@@ -1,6 +1,5 @@
import {
Component,
ContentChild,
ContentChildren,
ElementRef,
HostBinding,
@@ -10,6 +9,10 @@ import {
Renderer2,
TemplateRef,
ViewChildren,
input,
contentChild,
contentChildren,
viewChildren
} from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { PiFormControl } from '../../util/form-control';
@@ -44,12 +47,12 @@ export class PiBaseSelectComponent extends PiFormControl {
/**
* Name of the form control.
*/
@Input() formControlName!: string;
readonly formControlName = input.required<string>();
/**
* Property used for comparisons.
*/
@Input() keyIdProperty!: string;
readonly keyIdProperty = input.required<string>();
// ======================
// SKIN
@@ -58,47 +61,47 @@ export class PiBaseSelectComponent extends PiFormControl {
/**
* Specifies the layout for the menu.
*/
@Input() menuType: 'default' | 'flex-wrap' | 'custom-grid' = 'default';
readonly menuType = input<'default' | 'flex-wrap' | 'custom-grid'>('default');
/**
* Defines the type of the select component.
*/
@Input() type: 'default' | 'dropdown' = 'default';
readonly type = input<'default' | 'dropdown'>('default');
/**
* The appearance style of the select component.
*/
@Input() appearance: 'fill' | 'outline' | 'ghost' = 'fill';
readonly appearance = input<'fill' | 'outline' | 'ghost'>('fill');
/**
* The type of the input.
*/
@Input() pickedOptionType: 'button' | 'input' = 'input';
readonly pickedOptionType = input<'button' | 'input'>('input');
/**
* Defines the color of the select component and its child components.
*/
@Input() color: SelectColor = 'primary';
readonly color = input<SelectColor>('primary');
/**
* Defines the color of the select component and its child components.
*/
@Input() menuColor: 'white' | 'transparent' = 'white';
readonly menuColor = input<'white' | 'transparent'>('white');
/**
* The flex direction property binded in the select component is used to bind
* the pre definded select option flex direction property.
*/
@Input() flexDirection: SelectOptionFlexDirection = 'row';
readonly flexDirection = input<SelectOptionFlexDirection>('row');
/**
* The text align property defines if the picked option text in type dropdown cases and
* can extends the text alignment from the selec option when we use Back End data.
*/
@Input() textAlign: 'left' | 'center' = 'left';
readonly textAlign = input<'left' | 'center'>('left');
/**
* An optional icon for the select.
*/
@@ -107,7 +110,7 @@ export class PiBaseSelectComponent extends PiFormControl {
/**
* An optional icon for the select.
*/
@Input() actionIcon: actionIcon = 'chevron-forward';
readonly actionIcon = input<actionIcon>('chevron-forward');
// ======================
// CONTENT & DATA
@@ -116,28 +119,28 @@ export class PiBaseSelectComponent extends PiFormControl {
/**
* List of selectable options.
*/
@Input() options: Array<any> = [];
readonly options = input<Array<any>>([]);
/**
* An optional label for the select.
*/
@Input() label: string | undefined;
readonly label = input<string>();
/**
* Placeholder for the select when no option is selected.
*/
@Input() placeholder: string | undefined;
readonly placeholder = input<string>();
/**
* Defines the select an select option size in picked option type button cases
*/
@Input() size: 'small' | 'medium' = 'medium';
readonly size = input<'small' | 'medium'>('medium');
/**
* Defines if the picked option is responsive or not (ie. if it disappears in small devices or not)
*/
@Input() isResponsive = true;
readonly isResponsive = input(true);
// ======================
// CONTENT PROJECTIONS
@@ -146,13 +149,12 @@ export class PiBaseSelectComponent extends PiFormControl {
/**
* Provides a reference to the custom template for the options if provided.
*/
@ContentChild('optionTemplate', { static: false })
optionTemplateRef!: TemplateRef<any>;
readonly optionTemplateRef = contentChild.required<TemplateRef<any>>('optionTemplate');
/**
* Provides a reference to the custom template for the selected item if provided.
*/
@ContentChild('selectedTemplate') selectedTemplateRef!: TemplateRef<Element>;
readonly selectedTemplateRef = contentChild.required<TemplateRef<Element>>('selectedTemplate');
/**
* A query list of all the child option components that are content projected from an external consumer.
@@ -167,8 +169,7 @@ export class PiBaseSelectComponent extends PiFormControl {
* that are content projected from an external consumer.
* This provides direct access to their corresponding DOM elements.
*/
@ContentChildren(PiSelectOptionComponent, { read: ElementRef })
childrenOptionsEl!: QueryList<ElementRef>;
readonly childrenOptionsEl = contentChildren(PiSelectOptionComponent, { read: ElementRef });
/**
* A query list of all the child option components that are directly defined (view children)
@@ -183,8 +184,7 @@ export class PiBaseSelectComponent extends PiFormControl {
* that are directly defined (view children) within this component's template.
* This provides direct access to their corresponding DOM elements.
*/
@ViewChildren(PiSelectOptionComponent, { read: ElementRef })
viewChildOptionsEl: QueryList<ElementRef>;
readonly viewChildOptionsEl = viewChildren(PiSelectOptionComponent, { read: ElementRef });
constructor(
protected el: ElementRef,
@@ -202,7 +202,7 @@ export class PiBaseSelectComponent extends PiFormControl {
* Returns the FormControl associated with the formControlName.
*/
get control(): FormControl {
return this.controlContainer.control?.get(this.formControlName) as FormControl;
return this.controlContainer.control?.get(this.formControlName()) as FormControl;
}
/**
@@ -261,17 +261,17 @@ export class PiBaseSelectComponent extends PiFormControl {
get selectOptionSize(): SelectOptionSize {
switch (true) {
case this.type === 'dropdown' && this.pickedOptionType === 'input':
case this.type() === 'dropdown' && this.pickedOptionType() === 'input':
return SelectOptionSize.Small;
case this.type === 'dropdown' && this.pickedOptionType === 'button' && this.size === 'medium':
case this.type() === 'dropdown' && this.pickedOptionType() === 'button' && this.size() === 'medium':
return SelectOptionSize.Medium;
case this.type === 'dropdown' && this.pickedOptionType === 'button' && this.size === 'small':
case this.type() === 'dropdown' && this.pickedOptionType() === 'button' && this.size() === 'small':
return SelectOptionSize.Small;
case this.type === 'default' && this.menuType === 'flex-wrap':
case this.type() === 'default' && this.menuType() === 'flex-wrap':
return SelectOptionSize.Large;
case this.type === 'default' && this.menuType === 'default' && this.appearance === 'ghost':
case this.type() === 'default' && this.menuType() === 'default' && this.appearance() === 'ghost':
return SelectOptionSize.Medium;
case this.type === 'default' && this.menuType === 'default' && this.appearance !== 'ghost':
case this.type() === 'default' && this.menuType() === 'default' && this.appearance() !== 'ghost':
return SelectOptionSize.Small;
default:
return SelectOptionSize.Medium;
@@ -287,10 +287,11 @@ export class PiBaseSelectComponent extends PiFormControl {
* Manage the Select & Select Multiple appearance property
*/
protected get appearanceClass(): string | undefined {
const appearance = this.appearance();
return (
this.menuType !== 'custom-grid' &&
this.appearance &&
`pi-select__appearance--${this.appearance}`
this.menuType() !== 'custom-grid' &&
appearance &&
`pi-select__appearance--${appearance}`
);
}
@@ -306,7 +307,8 @@ export class PiBaseSelectComponent extends PiFormControl {
* color depending on the user profile.
*/
protected get colorClass(): string | undefined {
return this.menuType !== 'custom-grid' && this.color && `pi-color__${this.color}`;
const color = this.color();
return this.menuType() !== 'custom-grid' && color && `pi-color__${color}`;
}
/**
@@ -315,8 +317,9 @@ export class PiBaseSelectComponent extends PiFormControl {
* This property can be modified from the default one (white) specially when type !== 'dropdown'.
*/
protected get menuColorClass(): string | undefined {
return this.menuType !== 'custom-grid' && this.menuColor !== 'white'
? `pi-select__menu-color--${this.menuColor}`
const menuColor = this.menuColor();
return this.menuType() !== 'custom-grid' && menuColor !== 'white'
? `pi-select__menu-color--${menuColor}`
: '';
}
@@ -332,9 +335,10 @@ export class PiBaseSelectComponent extends PiFormControl {
* to display the select options as a mosaic in the page
*/
protected get menuTypeClass(): string | undefined {
return this.menuType === 'default'
const menuType = this.menuType();
return menuType === 'default'
? 'pi-select__menu-type--column'
: `pi-select__menu-type--${this.menuType}`;
: `pi-select__menu-type--${menuType}`;
}
/**
@@ -350,11 +354,12 @@ export class PiBaseSelectComponent extends PiFormControl {
* it means that the picked option emulate a Button.
*/
protected get pickedOptionTypeClass(): string | undefined {
const pickedOptionType = this.pickedOptionType();
return (
this.type === 'dropdown' &&
this.menuType !== 'custom-grid' &&
this.pickedOptionType &&
`pi-select__picked-option-type--${this.pickedOptionType}`
this.type() === 'dropdown' &&
this.menuType() !== 'custom-grid' &&
pickedOptionType &&
`pi-select__picked-option-type--${pickedOptionType}`
);
}
@@ -379,7 +384,8 @@ export class PiBaseSelectComponent extends PiFormControl {
* in a static positioned menu.
*/
protected get typeClass(): string | undefined {
return this.type && `pi-select__type--${this.type}`;
const type = this.type();
return type && `pi-select__type--${type}`;
}
/**
@@ -399,10 +405,12 @@ export class PiBaseSelectComponent extends PiFormControl {
*
*/
protected get textAlignClass(): string | boolean {
return (this.textAlign !== 'left' && this.pickedOptionType === 'button') ||
(this.menuType === 'flex-wrap' && this.flexDirection === 'row') ||
this.menuType === 'default'
? `pi-select__text-align--${this.textAlign}`
const menuType = this.menuType();
const textAlign = this.textAlign();
return (textAlign !== 'left' && this.pickedOptionType() === 'button') ||
(menuType === 'flex-wrap' && this.flexDirection() === 'row') ||
menuType === 'default'
? `pi-select__text-align--${textAlign}`
: '';
}
@@ -415,7 +423,8 @@ export class PiBaseSelectComponent extends PiFormControl {
*
*/
protected get sizeClass(): string | boolean {
return this.pickedOptionType === 'button' && this.size ? `pi-select__${this.size}` : '';
const size = this.size();
return this.pickedOptionType() === 'button' && size ? `pi-select__${size}` : '';
}
/**
@@ -426,6 +435,6 @@ export class PiBaseSelectComponent extends PiFormControl {
* When the Select Picked Option Type === Button
*/
protected get isResponsiveClass(): string | boolean {
return this.pickedOptionType === 'button' && this.isResponsive ? 'is-responsive' : '';
return this.pickedOptionType() === 'button' && this.isResponsive() ? 'is-responsive' : '';
}
}

View File

@@ -1,23 +1,23 @@
<pi-carousel
class="pi-select-options-menu"
color="highlighted"
[device]="device"
[itemsDesktop]="itemsDesktop"
[itemsTablet]="itemsTablet"
[itemWidth]="itemWidth"
[hideSwipeButtons]="hideSwipeButtons"
[isDraggable]="isDraggable"
[device]="device()"
[itemsDesktop]="itemsDesktop()"
[itemsTablet]="itemsTablet()"
[itemWidth]="itemWidth()"
[hideSwipeButtons]="hideSwipeButtons()"
[isDraggable]="isDraggable()"
[hidePaginator]="true"
[movePerPage]="movePerPage"
[justify]="justifyCarousel"
[movePerPage]="movePerPage()"
[justify]="justifyCarousel()"
(itemChanged)="onItemChanged($event)"
>
<ng-template pi-carousel-item *ngFor="let option of options; index as i; trackBy: trackByFn">
<ng-template pi-carousel-item *ngFor="let option of options(); index as i; trackBy: trackByFn">
<span class="pi-select__carousel--option">
<!-- Default options template menu for static data -->
<ng-template #defaultOption>
<pi-select-option
[id]="option?.[keyIdProperty] || option?.id"
[id]="option?.[keyIdProperty()] || option?.id"
[label]="option?.name | translate"
[initials]="option?.initials"
[icon]="option?.icon"
@@ -29,7 +29,7 @@
</ng-template>
<!-- Default options template menu for server data -->
<ng-container
[ngTemplateOutlet]="optionTemplateRef || defaultOption"
[ngTemplateOutlet]="optionTemplateRef() || defaultOption"
[ngTemplateOutletContext]="{ $implicit: option, index: i }"
>
</ng-container>

View File

@@ -6,9 +6,9 @@ import {
ElementRef,
HostBinding,
Injector,
Input,
QueryList,
Renderer2,
input
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
@@ -62,23 +62,23 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
}
//CAROUSEL PROPERTIES
@Input() device: Device;
readonly device = input<Device>();
@Input() itemsDesktop!: number;
readonly itemsDesktop = input.required<number>();
@Input() itemsTablet: number;
readonly itemsTablet = input<number>();
@Input() itemsMobile: number;
readonly itemsMobile = input<number>();
@Input() itemWidth: number;
readonly itemWidth = input<number>();
@Input() movePerPage: boolean;
readonly movePerPage = input<boolean>();
@Input() hideSwipeButtons: boolean;
readonly hideSwipeButtons = input<boolean>();
@Input() isDraggable: boolean;
readonly isDraggable = input<boolean>();
@Input() justifyCarousel: justify;
readonly justifyCarousel = input<justify>();
/**
* Component's constructor. Initializes the component with required services.
@@ -110,7 +110,7 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
* @returns The selected option.
*/
get selectedOption(): any {
return this.options.find((option) => _.isEqual(this.controlValue, option));
return this.options().find((option) => _.isEqual(this.controlValue, option));
}
/**
@@ -166,7 +166,7 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
}
onItemChanged(event: number) {
this.onSelectOption(this.options[event]);
this.onSelectOption(this.options()[event]);
}
/**
@@ -187,17 +187,17 @@ export class PiSelectCarouselComponent extends PiBaseSelectComponent implements
// Check if we have child options that are content projected from a parent component.
if (this.childrenOptionsComponents && this.childrenOptionsComponents.length > 0) {
childrenOptionsComponent = this.childrenOptionsComponents.toArray();
childrenOptionsElementRef = this.childrenOptionsEl;
childrenOptionsElementRef = this.childrenOptionsEl();
} else {
// If not, it means they're internally defined (default), so we fetch from viewChildren.
childrenOptionsComponent = this.viewChildOptionsComponents?.toArray();
childrenOptionsElementRef = this.viewChildOptionsEl;
childrenOptionsElementRef = this.viewChildOptionsEl();
}
// Update the visual state of each child option.
childrenOptionsComponent?.forEach((childOption, index) => {
const isSelected = selectedOption
? selectedOption[this.keyIdProperty] === childOption['id']
? selectedOption[this.keyIdProperty()] === childOption['id']
: false;
// If the current child option matches the selected option, highlight it.
if (isSelected) {

View File

@@ -1,6 +1,6 @@
<input hidden [formControl]="control" />
<ng-container *ngIf="type === 'dropdown'">
<ng-container *ngIf="pickedOptionType === 'button'; else pickedOptionInputTemplate">
<ng-container *ngIf="type() === 'dropdown'">
<ng-container *ngIf="pickedOptionType() === 'button'; else pickedOptionInputTemplate">
<fieldset (click)="onToggleDropdown()" class="pi-select-picked-option">
<!-- Button -->
<div>
@@ -15,18 +15,18 @@
[isDisabled]="disabled"
></pi-icon>
<span class="pi-select-picked-option__label">{{
(selectedOptionsNames?.join(', ') | truncate : 33) || (label | translate)
(selectedOptionsNames?.join(', ') | truncate : 33) || (label() | translate)
}}</span>
</div>
<pi-icon
class="pi-select-picked-option__action-icon"
[icon]="actionIcon"
[icon]="actionIcon()"
size="small"
></pi-icon>
</fieldset>
</ng-container>
<ng-template #pickedOptionInputTemplate>
<ng-container [ngSwitch]="appearance">
<ng-container [ngSwitch]="appearance()">
<!-- Input Fill Appearance -->
<ng-container *ngSwitchCase="'fill'">
<fieldset (click)="onToggleDropdown()" class="pi-select-picked-option">
@@ -42,14 +42,14 @@
<!-- Input field -->
<div>
<span>
<label class="pi-select-picked-option__label">{{ label | translate }}</label>
<label class="pi-select-picked-option__label">{{ label() | translate }}</label>
<ng-template #defaultSelected>
<span class="pi-select-picked-option__placeholder">{{
selectedOptionsNames?.join(', ') | truncate : 33 || (placeholder | translate)
selectedOptionsNames?.join(', ') | truncate : 33 || (placeholder() | translate)
}}</span>
</ng-template>
<ng-container
[ngTemplateOutlet]="selectedTemplateRef || defaultSelected"
[ngTemplateOutlet]="selectedTemplateRef() || defaultSelected"
[ngTemplateOutletContext]="{ $implicit: controlValue }"
>
</ng-container>
@@ -57,7 +57,7 @@
<pi-icon
class="pi-select-picked-option__action-icon"
[icon]="actionIcon"
[icon]="actionIcon()"
size="small"
></pi-icon>
</div>
@@ -68,16 +68,16 @@
<ng-container *ngSwitchCase="'outline'">
<fieldset (click)="onToggleDropdown()" class="pi-select-picked-option">
<!-- Input field -->
<label class="pi-select-picked-option__label">{{ label | translate }}</label>
<label class="pi-select-picked-option__label">{{ label() | translate }}</label>
<div>
<span>
<ng-template #defaultSelected>
<span class="pi-select-picked-option__placeholder">{{
selectedOptionsNames?.join(', ') | truncate : 33 || (placeholder | translate)
selectedOptionsNames?.join(', ') | truncate : 33 || (placeholder() | translate)
}}</span>
</ng-template>
<ng-container
[ngTemplateOutlet]="selectedTemplateRef || defaultSelected"
[ngTemplateOutlet]="selectedTemplateRef() || defaultSelected"
[ngTemplateOutletContext]="{ $implicit: controlValue }"
>
</ng-container>
@@ -85,7 +85,7 @@
<pi-icon
class="pi-select-picked-option__action-icon"
[icon]="actionIcon"
[icon]="actionIcon()"
size="small"
></pi-icon>
</div>
@@ -98,49 +98,49 @@
<!-- Options menu -->
<nav class="pi-select-options-menu">
<!-- Select All Options -->
<fieldset *ngIf="hasSelectAllOptions" class="pi-select-options-menu__select-all">
<fieldset *ngIf="hasSelectAllOptions()" class="pi-select-options-menu__select-all">
<mat-checkbox
pi-dynamic-color
[color]="color"
[color]="color()"
[checked]="areAllEnabledOptionsSelected"
(change)="onSelectAllOptions($event)"
>
</mat-checkbox>
<label pi-dynamic-color [color]="color">
{{ selectAllLabel }}
<label pi-dynamic-color [color]="color()">
{{ selectAllLabel() }}
</label>
</fieldset>
<header *ngIf="pickedOptionType === 'button'" class="pi-select-options-menu__picked-option">
<header *ngIf="pickedOptionType() === 'button'" class="pi-select-options-menu__picked-option">
<!-- Only visible in a header of Button -->
<pi-icon
*ngIf="icon"
[icon]="icon"
class="pi-select-options-menu-picked-option__custom-icon"
[color]="color"
[color]="color()"
size="medium"
pi-disabled
[isDisabled]="disabled"
></pi-icon>
<span class="pi-select-options-menu-picked-option__placeholder">{{
(selectedOptionsNames?.join(', ') | truncate : 33) || (placeholder | translate)
(selectedOptionsNames?.join(', ') | truncate : 33) || (placeholder() | translate)
}}</span>
<pi-icon
(click)="onToggleDropdown()"
class="pi-select-options-menu-picked-option__action-icon"
[icon]="actionIcon"
[icon]="actionIcon()"
[class.pi-select-options-menu-picked-option__action-icon--chevron]="
actionIcon === 'chevron-forward'
actionIcon() === 'chevron-forward'
"
size="small"
></pi-icon>
</header>
<!-- List of options -->
<div class="pi-select-options-menu__options">
<span *ngFor="let option of options; index as i" (click)="onSelectOption(option)">
<span *ngFor="let option of options(); index as i" (click)="onSelectOption(option)">
<!-- Default options template menu for static data -->
<ng-template #defaultOption>
<pi-select-option
@@ -149,20 +149,20 @@
[label]="option?.name | translate"
[initials]="option.initials ? option.initials : ''"
[isSelected]="option === selectedOptions.includes(option)"
[flexDirection]="flexDirection"
[flexDirection]="flexDirection()"
[size]="selectOptionSize"
></pi-select-option>
</ng-template>
<!-- Default options template menu for server data -->
<ng-container
[ngTemplateOutlet]="optionTemplateRef || defaultOption"
[ngTemplateOutlet]="optionTemplateRef() || defaultOption"
[ngTemplateOutletContext]="{ $implicit: option, index: i }"
>
</ng-container>
</span>
</div>
<footer *ngIf="type === 'dropdown'">
<footer *ngIf="type() === 'dropdown'">
<span>
<button (click)="onClickReset()" pi-ghost pi-primary w100>Borrar</button>
<button (click)="onClickSave()" pi-primary w100>Guardar</button>

View File

@@ -9,6 +9,7 @@ import {
Input,
QueryList,
Renderer2,
input
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
@@ -81,18 +82,18 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
* Specifies the maximum number of selectable options.
* Defaults to `Infinity` if not provided.
*/
@Input() maxLength: number | undefined = Infinity;
readonly maxLength = input<number | undefined>(Infinity);
/**
* Specifies whether the select component has an option to select all options at once.
* Defaults to `false` if not provided.
*/
@Input() hasSelectAllOptions = false;
readonly hasSelectAllOptions = input(false);
/**
* Provides the label to display next to the select all option.
*/
@Input() selectAllLabel: string;
readonly selectAllLabel = input<string>();
constructor(
private readonly translateService: TranslateService,
@@ -116,7 +117,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
*/
@Input() get selectedOptions(): Array<any> {
if (!this.controlValue) return [];
return this.options.filter((option) => _.some(this.controlValue, option));
return this.options().filter((option) => _.some(this.controlValue, option));
}
/**
@@ -127,7 +128,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
}
get enabledOptions(): Array<any> {
return this.options.filter((option) => !option.disabled);
return this.options().filter((option) => !option.disabled);
}
get areAllEnabledOptionsSelected(): boolean {
@@ -135,7 +136,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
}
get areAllOptionsSelected(): boolean {
return this.options.length === this.selectedOptions.length;
return this.options().length === this.selectedOptions.length;
}
/**
@@ -200,12 +201,12 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
if (option.disabled) return;
const selectedOptions: any[] = [...(this.selectedOptions || [])];
const optionIndex = selectedOptions.findIndex(
(id) => id[this.keyIdProperty] === option[this.keyIdProperty]
(id) => id[this.keyIdProperty()] === option[this.keyIdProperty()]
);
if (optionIndex !== -1) {
selectedOptions.splice(optionIndex, 1);
} else if (selectedOptions.length < (this.maxLength || Infinity)) {
} else if (selectedOptions.length < (this.maxLength() || Infinity)) {
selectedOptions.push(option);
} else {
return;
@@ -248,16 +249,16 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
// Check if we have child options that are content projected from a parent component.
if (this.childrenOptionsComponents && this.childrenOptionsComponents.length > 0) {
childrenOptionsComponent = this.childrenOptionsComponents.toArray();
childrenOptionsElementRef = this.childrenOptionsEl;
childrenOptionsElementRef = this.childrenOptionsEl();
} else {
// If not, it means they're internally defined (default), so we fetch from viewChildren.
childrenOptionsComponent = this.viewChildOptionsComponents.toArray();
childrenOptionsElementRef = this.viewChildOptionsEl;
childrenOptionsElementRef = this.viewChildOptionsEl();
}
childrenOptionsComponent?.forEach((childOption, index) => {
const isSelected = selectedOptions.some(
(selectedOption) => selectedOption[this.keyIdProperty] === childOption['id']
(selectedOption) => selectedOption[this.keyIdProperty()] === childOption['id']
);
if (isSelected) {
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-selected');
@@ -289,7 +290,7 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
*/
private updateChildrenOptionsDisabledState(selectedOptions: any[]): void {
// Disable all options if the maximum number of selections has been reached.
const disableOthers = selectedOptions.length >= (this.maxLength || Infinity);
const disableOthers = selectedOptions.length >= (this.maxLength() || Infinity);
// Array of child option components to work with.
let childrenOptionsComponent: Array<PiSelectOptionComponent>;
// Reference to the child option elements for DOM manipulation.
@@ -298,19 +299,19 @@ export class PiSelectMultipleComponent extends PiBaseSelectComponent implements
// Check if we have child options that are content projected from a parent component.
if (this.childrenOptionsComponents && this.childrenOptionsComponents.length > 0) {
childrenOptionsComponent = this.childrenOptionsComponents.toArray();
childrenOptionsElementRef = this.childrenOptionsEl;
childrenOptionsElementRef = this.childrenOptionsEl();
} else {
// If not, it means they're internally defined (default), so we fetch from viewChildren.
childrenOptionsComponent = this.viewChildOptionsComponents.toArray();
childrenOptionsElementRef = this.viewChildOptionsEl;
childrenOptionsElementRef = this.viewChildOptionsEl();
}
childrenOptionsComponent?.forEach((childOption, index) => {
const isSelected = selectedOptions.some(
(selectedOption) => selectedOption[this.keyIdProperty] === childOption['id']
(selectedOption) => selectedOption[this.keyIdProperty()] === childOption['id']
);
const isDisabled = childOption.isDisabled;
const isDisabled = childOption.isDisabled();
if ((!isSelected && disableOthers) || isDisabled) {
this._renderer.addClass(childrenOptionsElementRef.get(index)?.nativeElement, 'is-disabled');
} else {

Some files were not shown because too many files have changed in this diff Show More