@engie-group/fluid-design-system-angular
Version:
Fluid Design System Angular
224 lines (193 loc) • 4.86 kB
text/typescript
import {CommonModule} from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
forwardRef,
Input,
Output,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
export class ToggleComponent implements ControlValueAccessor, AfterViewInit {
/**
* @ignore
*/
private toggleClassName = 'nj-toggle';
/**
* @ignore
*/
private _checked: boolean;
/**
* Input id
*/
inputId: string;
/**
* Input name
*/
name: string;
/**
* Input size
*/
size: 'md' | 'lg' = 'md';
/**
* Whether input is required or not
*/
required: boolean;
/**
* Whether the toggle is checked or not
*/
set isChecked(value: boolean) {
this._checked = value;
this.cdr.markForCheck();
}
get isChecked(): boolean {
return this._checked;
}
/**
* Whether the toggle is disabled or not
*/
isDisabled: boolean;
/**
* Whether the toggle color is inherited from parent
*/
isColorInherited?: boolean;
/**
* Text alternative for assistive technologies
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label
*/
ariaLabel: string;
/**
* Text alternative for assistive technologies based on visible text
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby
*/
ariaLabelledby: string;
/**
* Output that emits checked value on change only
*/
valueChange: EventEmitter<boolean> = new EventEmitter<boolean>();
/**
* @ignore
*/
private _inputElement: ElementRef<HTMLInputElement>;
/**
* @ignore
*/
iconWrapper;
/**
* Whether toggle has an icon
*/
hasIcon: boolean;
constructor(private cdr: ChangeDetectorRef) {
}
// Check if icon is provided on load
ngAfterViewInit() {
this.hasIcon = this.iconWrapper?.nativeElement && this.iconWrapper.nativeElement.innerHTML !== '';
}
/**
* @ignore
*/
private _onChange = (_: any): void => {
};
/**
* @ignore
*/
private _onTouched = (): void => {
};
/**
* @ignore
*/
_onChangeEvent(event: Event) {
event.stopPropagation();
if (this._inputElement?.nativeElement) {
this.isChecked = this._inputElement.nativeElement.checked;
this._onChange(this.isChecked);
this.valueChange.emit(this.isChecked);
}
}
/**
* @ignore
*/
_onInputClick(event: Event) {
// We have to stop propagation for click events on the visually hidden input element.
// By default, when a user clicks on a label element, a generated click event will be
// dispatched on the associated input element. Since we are using a label element as our
// root container, the click event on the `slide-toggle` will be executed twice.
// The real click event will bubble up, and the generated click event also tries to bubble up.
// This will lead to multiple click events.
// Preventing bubbling for the second event will solve that issue.
event.stopPropagation();
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
writeValue(value: any): void {
this.isChecked = !!value;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
registerOnChange(fn: any): void {
this._onChange = fn;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
registerOnTouched(fn: any): void {
this._onTouched = fn;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.cdr.markForCheck();
}
/**
* @ignore
*/
getToggleSizeClass(): string {
let sizeModifier: string;
switch (this.size) {
case 'lg':
sizeModifier = 'lg';
break;
default:
break;
}
return sizeModifier ? `${this.toggleClassName}--${sizeModifier}` : '';
}
/**
* @ignore
*/
getToggleIsDisabledClass(): string {
return this.isDisabled ? `${this.toggleClassName}--disabled` : '';
}
getToggleInheritColorClass(): string {
return this.isColorInherited ? `${this.toggleClassName}--inherit` : '';
}
}