diff --git a/.eslintrc.json b/.eslintrc.json index 15febd7..009a6f6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,10 +4,7 @@ "overrides": [ { "files": ["*.ts"], - "extends": [ - "plugin:@nrwl/nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], + "extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], "parserOptions": { "project": ["libs/common-ui/tsconfig.*?.json"] }, diff --git a/src/assets/styles/_buttons.scss b/src/assets/styles/_buttons.scss index a8d605c..22ba359 100644 --- a/src/assets/styles/_buttons.scss +++ b/src/assets/styles/_buttons.scss @@ -1,7 +1,9 @@ // This rebel line is crying (in WebStorm) but it actually works @import '~/src/assets/styles/variables'; -$dark-bg-hover: #e2e4e9 !default; +$btn-bg-hover: #e2e4e9 !default; +$btn-bg: #f0f1f4 !default; +$warn: #fdbd00 !default; .mat-button, .mat-flat-button { @@ -58,7 +60,7 @@ $dark-bg-hover: #e2e4e9 !default; iqser-icon-button, iqser-chevron-button, redaction-user-button, -redaction-circle-button { +iqser-circle-button { position: relative; display: flex; @@ -81,7 +83,7 @@ redaction-circle-button { } &.dark-bg:hover { - background-color: $dark-bg-hover; + background-color: $btn-bg-hover; } } @@ -97,7 +99,7 @@ redaction-circle-button { } iqser-chevron-button, -redaction-circle-button, +iqser-circle-button, iqser-icon-button { &[aria-expanded='true'] { button { diff --git a/src/index.ts b/src/index.ts index a611942..84b883b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,8 @@ export * from './lib/common-ui.module'; export * from './lib/buttons/icon-button/icon-button.component'; -export * from './lib/buttons/icon-button/icon-button-type.model'; +export * from './lib/buttons/icon-button/icon-button.type'; export * from './lib/base/auto-unsubscribe.component'; export * from './lib/utils/decorators/required.decorator'; +export * from './lib/buttons/circle-button/circle-button.component'; +export * from './lib/buttons/circle-button/circle-button.type'; +export * from './lib/types/tooltip-positions.type'; diff --git a/src/lib/buttons/circle-button/circle-button.component.html b/src/lib/buttons/circle-button/circle-button.component.html new file mode 100644 index 0000000..52e6123 --- /dev/null +++ b/src/lib/buttons/circle-button/circle-button.component.html @@ -0,0 +1,15 @@ +
+ +
+
diff --git a/src/lib/buttons/circle-button/circle-button.component.scss b/src/lib/buttons/circle-button/circle-button.component.scss new file mode 100644 index 0000000..0e44ca4 --- /dev/null +++ b/src/lib/buttons/circle-button/circle-button.component.scss @@ -0,0 +1,41 @@ +@import '../../../assets/styles/common'; + +:host { + height: var(--size); + width: var(--size); + align-items: center; + + button { + height: var(--size); + width: var(--size); + line-height: var(--size); + + mat-icon { + width: var(--iconSize); + height: var(--iconSize); + line-height: var(--iconSize); + margin: 0; + + svg { + line-height: var(--iconSize); + } + } + + &.mat-button-disabled { + cursor: not-allowed; + } + + &.primary.mat-button-disabled { + background-color: $btn-bg; + color: $white !important; + } + + &.warn:not([disabled]) { + background-color: $warn; + + &:hover { + background-color: $warn; + } + } + } +} diff --git a/src/lib/buttons/circle-button/circle-button.component.ts b/src/lib/buttons/circle-button/circle-button.component.ts new file mode 100644 index 0000000..6ed14e1 --- /dev/null +++ b/src/lib/buttons/circle-button/circle-button.component.ts @@ -0,0 +1,50 @@ +import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { MatTooltip } from '@angular/material/tooltip'; +import { CircleButtonType, CircleButtonTypes } from './circle-button.type'; +import { Required } from '../../utils/decorators/required.decorator'; +import { TooltipPositionsType, TooltipPositionsTypes } from '../../types/tooltip-positions.type'; + +@Component({ + selector: 'iqser-circle-button', + templateUrl: './circle-button.component.html', + styleUrls: ['./circle-button.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CircleButtonComponent implements OnInit { + readonly circleButtonTypes = CircleButtonTypes; + + @Input() @Required() icon!: string; + @Input() @Required() tooltip!: string; + @Input() tooltipClass?: string; + @Input() showDot = false; + @Input() tooltipPosition: TooltipPositionsType = TooltipPositionsTypes.above; + @Input() disabled = false; + @Input() type: CircleButtonType = CircleButtonTypes.default; + @Input() removeTooltip = false; + @Input() isSubmit = false; + @Input() size = 34; + @Input() iconSize = 14; + @Output() action = new EventEmitter(); + + @ViewChild(MatTooltip) private readonly _matTooltip!: MatTooltip; + + constructor(private readonly _elementRef: ElementRef) {} + + ngOnInit() { + this._elementRef.nativeElement.style.setProperty('--size', this.size + 'px'); + this._elementRef.nativeElement.style.setProperty('--iconSize', this.iconSize + 'px'); + } + + performAction($event: any) { + if (this.disabled) return; + + if (this.removeTooltip) { + this._matTooltip.hide(); + // Timeout to allow tooltip to disappear first, + // useful when removing an item from the list without a confirmation dialog + setTimeout(() => this.action.emit($event)); + } else { + this.action.emit($event); + } + } +} diff --git a/src/lib/buttons/circle-button/circle-button.type.ts b/src/lib/buttons/circle-button/circle-button.type.ts new file mode 100644 index 0000000..e8398d3 --- /dev/null +++ b/src/lib/buttons/circle-button/circle-button.type.ts @@ -0,0 +1,8 @@ +export const CircleButtonTypes = { + default: 'default', + primary: 'primary', + warn: 'warn', + dark: 'dark' +} as const; + +export type CircleButtonType = keyof typeof CircleButtonTypes; diff --git a/src/lib/buttons/icon-button/icon-button.component.html b/src/lib/buttons/icon-button/icon-button.component.html index eba6a0b..747bc00 100644 --- a/src/lib/buttons/icon-button/icon-button.component.html +++ b/src/lib/buttons/icon-button/icon-button.component.html @@ -3,7 +3,7 @@ [class.has-icon]="!!icon" [class.overlay]="showDot" [class.primary]="type === iconButtonTypes.primary" - [class.show-bg]="type === iconButtonTypes.show_bg" + [class.show-bg]="type === iconButtonTypes.dark" [disabled]="disabled" mat-button type="button" diff --git a/src/lib/buttons/icon-button/icon-button.component.scss b/src/lib/buttons/icon-button/icon-button.component.scss index c8de10e..787b413 100644 --- a/src/lib/buttons/icon-button/icon-button.component.scss +++ b/src/lib/buttons/icon-button/icon-button.component.scss @@ -9,10 +9,10 @@ button { } &.show-bg { - background-color: $grey-6; + background-color: $btn-bg; &:not(.mat-button-disabled):hover { - background-color: $dark-bg-hover; + background-color: $btn-bg-hover; } } diff --git a/src/lib/buttons/icon-button/icon-button.component.ts b/src/lib/buttons/icon-button/icon-button.component.ts index 994cb2a..0f59630 100644 --- a/src/lib/buttons/icon-button/icon-button.component.ts +++ b/src/lib/buttons/icon-button/icon-button.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { IconButtonType, IconButtonTypes } from './icon-button-type.model'; +import { IconButtonType, IconButtonTypes } from './icon-button.type'; import { Required } from '../../utils/decorators/required.decorator'; @Component({ diff --git a/src/lib/buttons/icon-button/icon-button-type.model.ts b/src/lib/buttons/icon-button/icon-button.type.ts similarity index 86% rename from src/lib/buttons/icon-button/icon-button-type.model.ts rename to src/lib/buttons/icon-button/icon-button.type.ts index 0b0646e..9a84b04 100644 --- a/src/lib/buttons/icon-button/icon-button-type.model.ts +++ b/src/lib/buttons/icon-button/icon-button.type.ts @@ -1,6 +1,6 @@ export const IconButtonTypes = { default: 'default', - show_bg: 'show_bg', + dark: 'dark', primary: 'primary' } as const; diff --git a/src/lib/common-ui.module.ts b/src/lib/common-ui.module.ts index 9df30f7..fea1ecd 100644 --- a/src/lib/common-ui.module.ts +++ b/src/lib/common-ui.module.ts @@ -5,10 +5,12 @@ import { MatIconModule, MatIconRegistry } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { ChevronButtonComponent } from './buttons/chevron-button/chevron-button.component'; import { DomSanitizer } from '@angular/platform-browser'; +import { CircleButtonComponent } from './buttons/circle-button/circle-button.component'; +import { MatTooltipModule } from '@angular/material/tooltip'; -const buttons = [IconButtonComponent, ChevronButtonComponent]; +const buttons = [IconButtonComponent, ChevronButtonComponent, CircleButtonComponent]; -const matModules = [MatIconModule, MatButtonModule]; +const matModules = [MatIconModule, MatButtonModule, MatTooltipModule]; @NgModule({ declarations: [...buttons], diff --git a/src/lib/types/tooltip-positions.type.ts b/src/lib/types/tooltip-positions.type.ts new file mode 100644 index 0000000..029ea2d --- /dev/null +++ b/src/lib/types/tooltip-positions.type.ts @@ -0,0 +1,8 @@ +export const TooltipPositionsTypes = { + below: 'below', + above: 'above', + before: 'before', + after: 'after' +} as const; + +export type TooltipPositionsType = keyof typeof TooltipPositionsTypes;