UNPKG

@progress/kendo-angular-inputs

Version:

Kendo UI for Angular Inputs Package - Everything you need to build professional form functionality (Checkbox, ColorGradient, ColorPalette, ColorPicker, FlatColorPicker, FormField, MaskedTextBox, NumericTextBox, RadioButton, RangeSlider, Slider, Switch, Te

585 lines (582 loc) 21.4 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2024 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { ElementRef, Renderer2, Component, EventEmitter, HostBinding, Input, Output, ViewChild, forwardRef, ChangeDetectorRef, NgZone, Injector } from '@angular/core'; import { NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n'; import { hasObservers, guid, Keys, KendoInput } from '@progress/kendo-angular-common'; import { validatePackage } from '@progress/kendo-licensing'; import { packageMetadata } from '../package-metadata'; import { requiresZoneOnBlur, getStylingClasses } from '../common/utils'; import { skip, take } from "rxjs/operators"; import { browser } from '@progress/kendo-common'; import { LocalizedSwitchMessagesDirective } from './localization/localized-switch-messages.directive'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-l10n"; const FOCUSED = 'k-focus'; const DEFAULT_SIZE = 'medium'; const DEFAULT_THUMB_ROUNDED = 'full'; const DEFAULT_TRACK_ROUNDED = 'full'; /** * Represents the [Kendo UI Switch component for Angular]({% slug overview_switch %}). */ export class SwitchComponent { constructor(renderer, hostElement, localizationService, injector, changeDetector, ngZone) { this.renderer = renderer; this.hostElement = hostElement; this.localizationService = localizationService; this.injector = injector; this.changeDetector = changeDetector; this.ngZone = ngZone; /** * Determines whether the Switch is disabled ([see example]({% slug disabled_switch %})). To learn how to disable the component in reactive forms, refer to the article on [Forms Support](slug:formssupport_switch#toc-managing-the-switch-disabled-state-in-reactive-forms). */ this.disabled = false; /** * Determines whether the Switch is in its read-only state ([see example]({% slug readonly_switch %})). * * @default false */ this.readonly = false; /** * Specifies the [tabindex](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of the Switch. */ this.tabindex = 0; /** * Fires each time the Switch component is focused as a result of user interaction. */ this.onFocus = new EventEmitter(); /** * Fires each time the Switch component is blurred as a result of user interaction. */ this.onBlur = new EventEmitter(); /** * Fires each time the user selects a new value. */ this.valueChange = new EventEmitter(); this.hostRole = 'switch'; this.hostClasses = true; /** * @hidden */ this.initialized = false; this.domSubscriptions = []; this._checked = false; this._size = 'medium'; this._trackRounded = 'full'; this._thumbRounded = 'full'; this.ngChange = (_) => { }; this.ngTouched = () => { }; /** * @hidden */ this.handleFocus = (event) => { if (this.isFocused) { return; } event.stopImmediatePropagation(); this.focused = true; if (hasObservers(this.onFocus)) { this.ngZone.run(() => { const eventArgs = { originalEvent: event }; this.onFocus.emit(eventArgs); }); } }; /** * @hidden */ this.handleBlur = (event) => { const relatedTarget = event && event.relatedTarget; if (this.hostElement.nativeElement.contains(relatedTarget)) { return; } event.stopImmediatePropagation(); this.changeDetector.markForCheck(); this.focused = false; if (hasObservers(this.onBlur) || requiresZoneOnBlur(this.control)) { this.ngZone.run(() => { this.ngTouched(); const eventArgs = { originalEvent: event }; this.onBlur.emit(eventArgs); }); } }; validatePackage(packageMetadata); this.direction = localizationService.rtl ? 'rtl' : 'ltr'; this.keyDownHandler = this.keyDownHandler.bind(this); this.clickHandler = this.clickHandler.bind(this); } /** * @hidden */ get focusableId() { if (this.hostElement.nativeElement.hasAttribute('id')) { return this.hostElement.nativeElement.getAttribute('id'); } return `k-${guid()}`; } /** * Sets the value of the Switch when it is initially displayed. */ set checked(value) { this.setHostClasses(value); this._checked = value; } get checked() { return this._checked; } /** * Specifies the width and height of the Switch. * * The possible values are: * * `small` * * `medium` (default) * * `large` * * `none` */ set size(size) { const newSize = size ? size : DEFAULT_SIZE; this.handleClasses(newSize, 'size'); this._size = newSize; } get size() { return this._size; } /** * Specifies the border radius of the Switch thumb. * * The possible values are: * * `full` (default) * * `small` * * `medium` * * `large` * * `none` */ set thumbRounded(thumbRounded) { const newThumbRounded = thumbRounded ? thumbRounded : DEFAULT_THUMB_ROUNDED; this.handleThumbClasses(newThumbRounded); this._thumbRounded = newThumbRounded; } get thumbRounded() { return this._thumbRounded; } /** * Specifies the border radius of the Switch track. * * The possible values are: * * `full` (default) * * `small` * * `medium` * * `large` * * `none` */ set trackRounded(trackRounded) { const newTrackRounded = trackRounded ? trackRounded : DEFAULT_TRACK_ROUNDED; this.handleTrackClasses(newTrackRounded); this._trackRounded = newTrackRounded; } get trackRounded() { return this._trackRounded; } /** * @hidden */ set tabIndex(tabIndex) { this.tabindex = tabIndex; } get tabIndex() { return this.tabindex; } get ieClass() { return browser && browser.msie; } get hostId() { return this.focusableId; } get ariaChecked() { return this.checked; } get ariaInvalid() { return this.isControlInvalid ? true : undefined; } get hostTabIndex() { return this.disabled ? undefined : this.tabIndex; } get ariaDisabled() { return this.disabled ? true : undefined; } get ariaReadonly() { return this.readonly; } get disabledClass() { return this.disabled; } /** * @hidden */ get onLabelMessage() { return this.onLabel !== undefined ? this.onLabel : this.localizationService.get('on'); } /** * @hidden */ get offLabelMessage() { return this.offLabel !== undefined ? this.offLabel : this.localizationService.get('off'); } get isEnabled() { return !this.disabled && !this.readonly; } ngOnInit() { if (this.hostElement) { const wrapper = this.hostElement.nativeElement; this.renderer.removeAttribute(wrapper, "tabindex"); } this.localizationChangeSubscription = this.localizationService .changes .pipe(skip(1)) .subscribe(({ rtl }) => { this.direction = rtl ? 'rtl' : 'ltr'; }); this.control = this.injector.get(NgControl, null); this.ngZone.onStable.pipe(take(1)).subscribe(() => this.initialized = true); } ngAfterViewInit() { const wrapper = this.hostElement.nativeElement; if (!this.checked && !wrapper.classList.contains('k-switch-off')) { this.renderer.addClass(wrapper, 'k-switch-off'); } this.handleClasses(this.size, 'size'); this.handleTrackClasses(this.trackRounded); this.handleThumbClasses(this.thumbRounded); this.attachHostHandlers(); } ngOnDestroy() { if (this.localizationChangeSubscription) { this.localizationChangeSubscription.unsubscribe(); } this.domSubscriptions.forEach(subscription => subscription()); const wrapper = this.hostElement.nativeElement; wrapper.removeEventListener('focus', this.handleFocus, true); wrapper.removeEventListener('blur', this.handleBlur, true); } /** * Focuses the Switch. * * @example * ```ts-no-run * _@Component({ * selector: 'my-app', * template: ` * <button (click)="switch.focus()">Focus</button> * <kendo-switch #switch></kendo-switch> * ` * }) * class AppComponent { } * ``` */ focus() { if (!this.hostElement) { return; } this.hostElement.nativeElement.focus(); } /** * Blurs the Switch. */ blur() { if (!this.hostElement) { return; } this.hostElement.nativeElement.blur(); } /** * @hidden * Called when the status of the component changes to or from `disabled`. * Depending on the value, it enables or disables the appropriate DOM element. */ setDisabledState(isDisabled) { this.disabled = isDisabled; this.changeDetector.markForCheck(); } /** * @hidden */ get isControlInvalid() { return this.control && this.control.touched && !this.control.valid; } /** * @hidden */ writeValue(value) { this.checked = value === null ? false : value; this.changeDetector.markForCheck(); } /** * @hidden */ registerOnChange(fn) { this.ngChange = fn; } /** * @hidden */ registerOnTouched(fn) { this.ngTouched = fn; } /** * @hidden */ keyDownHandler(e) { const keyCode = e.keyCode; if (this.isEnabled && (keyCode === Keys.Space || keyCode === Keys.Enter)) { this.changeValue(!this.checked); e.preventDefault(); } } /** * @hidden */ clickHandler() { if (this.isEnabled) { this.changeValue(!this.checked); } } /** * @hidden * Used by the FloatingLabel to determine if the component is empty. */ isEmpty() { return false; } changeValue(value) { if (this.checked !== value) { this.ngZone.run(() => { this.checked = value; this.ngChange(value); this.valueChange.emit(value); this.changeDetector.markForCheck(); }); } } set focused(value) { if (this.isFocused !== value && this.hostElement) { const wrapper = this.hostElement.nativeElement; if (value) { this.renderer.addClass(wrapper, FOCUSED); } else { this.renderer.removeClass(wrapper, FOCUSED); } this.isFocused = value; } } attachHostHandlers() { this.ngZone.runOutsideAngular(() => { const wrapper = this.hostElement.nativeElement; this.domSubscriptions.push(this.renderer.listen(wrapper, 'click', this.clickHandler), this.renderer.listen(wrapper, 'keydown', this.keyDownHandler)); wrapper.addEventListener('focus', this.handleFocus, true); wrapper.addEventListener('blur', this.handleBlur, true); }); } setHostClasses(value) { const wrapper = this.hostElement.nativeElement; if (value) { this.renderer.removeClass(wrapper, 'k-switch-off'); this.renderer.addClass(wrapper, 'k-switch-on'); } else { this.renderer.removeClass(wrapper, 'k-switch-on'); this.renderer.addClass(wrapper, 'k-switch-off'); } } handleClasses(value, input) { const elem = this.hostElement.nativeElement; const classes = getStylingClasses('switch', input, this[input], value); if (classes.toRemove) { this.renderer.removeClass(elem, classes.toRemove); } if (classes.toAdd) { this.renderer.addClass(elem, classes.toAdd); } } handleTrackClasses(value) { const elem = this.hostElement?.nativeElement; const track = this.track?.nativeElement; if (!elem || !track) { return; } const classes = getStylingClasses('switch', 'rounded', this.trackRounded, value); if (classes.toRemove) { this.renderer.removeClass(elem, classes.toRemove); this.renderer.removeClass(track, classes.toRemove); } if (classes.toAdd) { this.renderer.addClass(elem, classes.toAdd); this.renderer.addClass(track, classes.toAdd); } } handleThumbClasses(value) { const thumb = this.thumb?.nativeElement; if (!thumb) { return; } const classes = getStylingClasses('switch', 'rounded', this.thumbRounded, value); if (classes.toRemove) { this.renderer.removeClass(thumb, classes.toRemove); } if (classes.toAdd) { this.renderer.addClass(thumb, classes.toAdd); } } } SwitchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SwitchComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i1.LocalizationService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); SwitchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SwitchComponent, isStandalone: true, selector: "kendo-switch", inputs: { focusableId: "focusableId", onLabel: "onLabel", offLabel: "offLabel", checked: "checked", disabled: "disabled", readonly: "readonly", tabindex: "tabindex", size: "size", thumbRounded: "thumbRounded", trackRounded: "trackRounded", tabIndex: "tabIndex" }, outputs: { onFocus: "focus", onBlur: "blur", valueChange: "valueChange" }, host: { properties: { "class.k-readonly": "this.readonly", "attr.dir": "this.direction", "class.k-ie": "this.ieClass", "attr.role": "this.hostRole", "attr.id": "this.hostId", "attr.aria-checked": "this.ariaChecked", "attr.aria-invalid": "this.ariaInvalid", "attr.tabindex": "this.hostTabIndex", "attr.aria-disabled": "this.ariaDisabled", "attr.aria-readonly": "this.ariaReadonly", "class.k-switch": "this.hostClasses", "class.k-disabled": "this.disabledClass" } }, providers: [ LocalizationService, { provide: L10N_PREFIX, useValue: 'kendo.switch' }, { multi: true, provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SwitchComponent) /* eslint-disable-line*/ }, { provide: KendoInput, useExisting: forwardRef(() => SwitchComponent) } ], viewQueries: [{ propertyName: "track", first: true, predicate: ["track"], descendants: true, static: true }, { propertyName: "thumb", first: true, predicate: ["thumb"], descendants: true, static: true }], exportAs: ["kendoSwitch"], ngImport: i0, template: ` <ng-container kendoSwitchLocalizedMessages i18n-on="kendo.switch.on|The **On** label of the Switch." on="ON" i18n-off="kendo.switch.off|The **Off** label of the Switch." off="OFF" > <span #track class="k-switch-track" [style.transitionDuration]="initialized ? '200ms' : '0ms'" > <span class="k-switch-label-on" [attr.aria-hidden]="true" >{{onLabelMessage}}</span> <span class="k-switch-label-off" [attr.aria-hidden]="true">{{offLabelMessage}}</span> </span> <span class="k-switch-thumb-wrap" [style.transitionDuration]="initialized ? '200ms' : '0ms'"> <span #thumb class="k-switch-thumb"></span> </span> `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedSwitchMessagesDirective, selector: "[kendoSwitchLocalizedMessages]" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SwitchComponent, decorators: [{ type: Component, args: [{ exportAs: 'kendoSwitch', providers: [ LocalizationService, { provide: L10N_PREFIX, useValue: 'kendo.switch' }, { multi: true, provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SwitchComponent) /* eslint-disable-line*/ }, { provide: KendoInput, useExisting: forwardRef(() => SwitchComponent) } ], selector: 'kendo-switch', template: ` <ng-container kendoSwitchLocalizedMessages i18n-on="kendo.switch.on|The **On** label of the Switch." on="ON" i18n-off="kendo.switch.off|The **Off** label of the Switch." off="OFF" > <span #track class="k-switch-track" [style.transitionDuration]="initialized ? '200ms' : '0ms'" > <span class="k-switch-label-on" [attr.aria-hidden]="true" >{{onLabelMessage}}</span> <span class="k-switch-label-off" [attr.aria-hidden]="true">{{offLabelMessage}}</span> </span> <span class="k-switch-thumb-wrap" [style.transitionDuration]="initialized ? '200ms' : '0ms'"> <span #thumb class="k-switch-thumb"></span> </span> `, standalone: true, imports: [LocalizedSwitchMessagesDirective] }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i1.LocalizationService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { focusableId: [{ type: Input }], onLabel: [{ type: Input }], offLabel: [{ type: Input }], checked: [{ type: Input }], disabled: [{ type: Input }], readonly: [{ type: Input }, { type: HostBinding, args: ['class.k-readonly'] }], tabindex: [{ type: Input }], size: [{ type: Input }], thumbRounded: [{ type: Input }], trackRounded: [{ type: Input }], tabIndex: [{ type: Input }], onFocus: [{ type: Output, args: ['focus'] }], onBlur: [{ type: Output, args: ['blur'] }], valueChange: [{ type: Output }], direction: [{ type: HostBinding, args: ['attr.dir'] }], ieClass: [{ type: HostBinding, args: ['class.k-ie'] }], hostRole: [{ type: HostBinding, args: ['attr.role'] }], hostId: [{ type: HostBinding, args: ['attr.id'] }], ariaChecked: [{ type: HostBinding, args: ['attr.aria-checked'] }], ariaInvalid: [{ type: HostBinding, args: ['attr.aria-invalid'] }], hostTabIndex: [{ type: HostBinding, args: ['attr.tabindex'] }], ariaDisabled: [{ type: HostBinding, args: ['attr.aria-disabled'] }], ariaReadonly: [{ type: HostBinding, args: ['attr.aria-readonly'] }], hostClasses: [{ type: HostBinding, args: ['class.k-switch'] }], disabledClass: [{ type: HostBinding, args: ['class.k-disabled'] }], track: [{ type: ViewChild, args: ['track', { static: true }] }], thumb: [{ type: ViewChild, args: ['thumb', { static: true }] }] } });