UNPKG

ngx-bootstrap

Version:
466 lines (459 loc) 19.6 kB
import * as i0 from '@angular/core'; import { forwardRef, input, HostListener, HostBinding, Directive, effect, Optional, Inject, ContentChildren, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; // TODO: config: activeClass - Class to apply to the checked buttons const CHECKBOX_CONTROL_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ButtonCheckboxDirective), multi: true }; /** * Add checkbox functionality to any element */ class ButtonCheckboxDirective { constructor() { /** Truthy value, will be set to ngModel */ this.btnCheckboxTrue = input(true, ...(ngDevMode ? [{ debugName: "btnCheckboxTrue" }] : [])); /** Falsy value, will be set to ngModel */ this.btnCheckboxFalse = input(false, ...(ngDevMode ? [{ debugName: "btnCheckboxFalse" }] : [])); this.state = false; this.isDisabled = false; this.onChange = Function.prototype; this.onTouched = Function.prototype; } // view -> model onClick() { if (this.isDisabled) { return; } this.toggle(!this.state); this.onChange(this.value); } ngOnInit() { this.toggle(this.trueValue === this.value); } get trueValue() { const val = this.btnCheckboxTrue(); return typeof val !== 'undefined' ? val : true; } get falseValue() { const val = this.btnCheckboxFalse(); return typeof val !== 'undefined' ? val : false; } toggle(state) { this.state = state; this.value = this.state ? this.trueValue : this.falseValue; } // ControlValueAccessor // model -> view writeValue(value) { this.state = this.trueValue === value; this.value = value ? this.trueValue : this.falseValue; } setDisabledState(isDisabled) { this.isDisabled = isDisabled; } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonCheckboxDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.0", type: ButtonCheckboxDirective, isStandalone: true, selector: "[btnCheckbox]", inputs: { btnCheckboxTrue: { classPropertyName: "btnCheckboxTrue", publicName: "btnCheckboxTrue", isSignal: true, isRequired: false, transformFunction: null }, btnCheckboxFalse: { classPropertyName: "btnCheckboxFalse", publicName: "btnCheckboxFalse", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick()" }, properties: { "class.active": "this.state", "attr.aria-pressed": "this.state" } }, providers: [CHECKBOX_CONTROL_VALUE_ACCESSOR], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonCheckboxDirective, decorators: [{ type: Directive, args: [{ selector: '[btnCheckbox]', providers: [CHECKBOX_CONTROL_VALUE_ACCESSOR], standalone: true }] }], propDecorators: { btnCheckboxTrue: [{ type: i0.Input, args: [{ isSignal: true, alias: "btnCheckboxTrue", required: false }] }], btnCheckboxFalse: [{ type: i0.Input, args: [{ isSignal: true, alias: "btnCheckboxFalse", required: false }] }], state: [{ type: HostBinding, args: ['class.active'] }, { type: HostBinding, args: ['attr.aria-pressed'] }], onClick: [{ type: HostListener, args: ['click'] }] } }); const RADIO_CONTROL_VALUE_ACCESSOR$1 = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ButtonRadioDirective), multi: true }; /** * Create radio buttons or groups of buttons. * A value of a selected button is bound to a variable specified via ngModel. */ class ButtonRadioDirective { get value() { return this.group ? this.group.value : this._value; } set value(value) { if (this.group) { this.group.value = value; return; } this._value = value; this._onChange(value); } get disabled() { return this._disabled; } get controlOrGroupDisabled() { return this.disabled || (this.group && this.group.disabled) ? true : undefined; } get hasDisabledClass() { // Although the radio is disabled the active radio should still stand out. // The disabled class will prevent this so don't add it on the active radio return this.controlOrGroupDisabled && !this.isActive; } get isActive() { return this.btnRadio() === this.value; } get tabindex() { if (this.controlOrGroupDisabled) { // Disabled radio buttons should not receive focus return undefined; } else if (this.isActive || this.group == null) { return 0; } else { return -1; } } get hasFocus() { return this._hasFocus; } constructor(el, cdr, renderer, group) { this.el = el; this.cdr = cdr; this.renderer = renderer; this.group = group; this.onChange = Function.prototype; this.onTouched = Function.prototype; /** Radio button value, will be set to `ngModel` */ this.btnRadio = input(...(ngDevMode ? [undefined, { debugName: "btnRadio" }] : [])); /** If `true` — radio button can be unchecked */ this.uncheckable = input(false, ...(ngDevMode ? [{ debugName: "uncheckable" }] : [])); /** Current value of radio component or group */ // eslint-disable-next-line @angular-eslint/no-input-rename this.valueInput = input(undefined, { ...(ngDevMode ? { debugName: "valueInput" } : {}), alias: 'value' }); /** If `true` — radio button is disabled */ // eslint-disable-next-line @angular-eslint/no-input-rename this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : {}), alias: 'disabled' }); this.role = 'radio'; this._disabled = false; this._hasFocus = false; this._uncheckable = false; // Watch for value input changes effect(() => { const val = this.valueInput(); if (val !== undefined) { this._value = val; } }); // Watch for disabled input changes effect(() => { const disabled = this.disabledInput(); this.setDisabledState(disabled); }); // Watch for uncheckable input changes effect(() => { const val = this.uncheckable(); this._uncheckable = val !== false && typeof val !== 'undefined'; }); } toggleIfAllowed() { if (!this.canToggle()) { return; } if (this._uncheckable && this.btnRadio() === this.value) { this.value = undefined; } else { this.value = this.btnRadio(); } } onSpacePressed(event) { const ke = event; this.toggleIfAllowed(); if ('preventDefault' in ke) { ke.preventDefault(); } } focus() { this.el.nativeElement.focus(); } onFocus() { this._hasFocus = true; } onBlur() { this._hasFocus = false; this.onTouched(); } canToggle() { return !this.controlOrGroupDisabled && (this._uncheckable || this.btnRadio() !== this.value); } // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method ngOnChanges(changes) { // Keep for compatibility } _onChange(value) { if (this.group) { this.group.value = value; return; } this.onTouched(); this.onChange(value); } // ControlValueAccessor // model -> view writeValue(value) { this._value = value; this.cdr.markForCheck(); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(disabled) { this._disabled = disabled; if (disabled) { this.renderer.setAttribute(this.el.nativeElement, 'disabled', 'disabled'); return; } this.renderer.removeAttribute(this.el.nativeElement, 'disabled'); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonRadioDirective, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: forwardRef(() => ButtonRadioGroupDirective), optional: true }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.0", type: ButtonRadioDirective, isStandalone: true, selector: "[btnRadio]", inputs: { btnRadio: { classPropertyName: "btnRadio", publicName: "btnRadio", isSignal: true, isRequired: false, transformFunction: null }, uncheckable: { classPropertyName: "uncheckable", publicName: "uncheckable", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "toggleIfAllowed()", "keydown.space": "onSpacePressed($event)", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "attr.aria-disabled": "this.controlOrGroupDisabled", "class.disabled": "this.hasDisabledClass", "class.active": "this.isActive", "attr.aria-checked": "this.isActive", "attr.role": "this.role", "attr.tabindex": "this.tabindex" } }, providers: [RADIO_CONTROL_VALUE_ACCESSOR$1], usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonRadioDirective, decorators: [{ type: Directive, args: [{ selector: '[btnRadio]', providers: [RADIO_CONTROL_VALUE_ACCESSOR$1], standalone: true }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: ButtonRadioGroupDirective, decorators: [{ type: Optional }, { type: Inject, args: [forwardRef(() => ButtonRadioGroupDirective)] }] }], propDecorators: { btnRadio: [{ type: i0.Input, args: [{ isSignal: true, alias: "btnRadio", required: false }] }], uncheckable: [{ type: i0.Input, args: [{ isSignal: true, alias: "uncheckable", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], controlOrGroupDisabled: [{ type: HostBinding, args: ['attr.aria-disabled'] }], hasDisabledClass: [{ type: HostBinding, args: ['class.disabled'] }], isActive: [{ type: HostBinding, args: ['class.active'] }, { type: HostBinding, args: ['attr.aria-checked'] }], role: [{ type: HostBinding, args: ['attr.role'] }], tabindex: [{ type: HostBinding, args: ['attr.tabindex'] }], toggleIfAllowed: [{ type: HostListener, args: ['click'] }], onSpacePressed: [{ type: HostListener, args: ['keydown.space', ['$event']] }], onFocus: [{ type: HostListener, args: ['focus'] }], onBlur: [{ type: HostListener, args: ['blur'] }] } }); const RADIO_CONTROL_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ButtonRadioGroupDirective), multi: true }; /** * A group of radio buttons. * A value of a selected button is bound to a variable specified via ngModel. */ class ButtonRadioGroupDirective { constructor(cdr) { this.cdr = cdr; this.onChange = Function.prototype; this.onTouched = Function.prototype; this.role = 'radiogroup'; this._disabled = false; } get value() { return this._value; } set value(value) { this._value = value; this.onChange(value); } get disabled() { return this._disabled; } get tabindex() { if (this._disabled) { return null; } else { return 0; } } writeValue(value) { this._value = value; this.cdr.markForCheck(); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(disabled) { if (this.radioButtons) { this._disabled = disabled; this.radioButtons.forEach(buttons => { buttons.setDisabledState(disabled); }); this.cdr.markForCheck(); } } onFocus() { if (this._disabled) { return; } const activeRadio = this.getActiveOrFocusedRadio(); if (activeRadio) { activeRadio.focus(); return; } if (this.radioButtons) { const firstEnabled = this.radioButtons.find(r => !r.disabled); if (firstEnabled) { firstEnabled.focus(); } } } onBlur() { if (this.onTouched) { this.onTouched(); } } selectNext(event) { const ke = event; this.selectInDirection('next'); if ('preventDefault' in ke) { ke.preventDefault(); } } selectPrevious(event) { const ke = event; this.selectInDirection('previous'); if ('preventDefault' in ke) { ke.preventDefault(); } } selectInDirection(direction) { if (this._disabled) { return; } function nextIndex(currentIndex, buttonRadioDirectives) { const step = direction === 'next' ? 1 : -1; let calcIndex = (currentIndex + step) % buttonRadioDirectives.length; if (calcIndex < 0) { calcIndex = buttonRadioDirectives.length - 1; } return calcIndex; } const activeRadio = this.getActiveOrFocusedRadio(); if (activeRadio && this.radioButtons) { const buttonRadioDirectives = this.radioButtons.toArray(); const currentActiveIndex = buttonRadioDirectives.indexOf(activeRadio); for (let i = nextIndex(currentActiveIndex, buttonRadioDirectives); i !== currentActiveIndex; i = nextIndex(i, buttonRadioDirectives)) { if (buttonRadioDirectives[i].canToggle()) { buttonRadioDirectives[i].toggleIfAllowed(); buttonRadioDirectives[i].focus(); break; } } } } getActiveOrFocusedRadio() { if (!this.radioButtons) { return void 0; } return this.radioButtons.find(button => button.isActive) || this.radioButtons.find(button => button.hasFocus); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonRadioGroupDirective, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: ButtonRadioGroupDirective, isStandalone: true, selector: "[btnRadioGroup]", host: { listeners: { "focus": "onFocus()", "blur": "onBlur()", "keydown.ArrowRight": "selectNext($event)", "keydown.ArrowDown": "selectNext($event)", "keydown.ArrowLeft": "selectPrevious($event)", "keydown.ArrowUp": "selectPrevious($event)" }, properties: { "attr.role": "this.role", "attr.tabindex": "this.tabindex" } }, providers: [RADIO_CONTROL_VALUE_ACCESSOR], queries: [{ propertyName: "radioButtons", predicate: i0.forwardRef(() => ButtonRadioDirective) }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonRadioGroupDirective, decorators: [{ type: Directive, args: [{ selector: '[btnRadioGroup]', providers: [RADIO_CONTROL_VALUE_ACCESSOR], standalone: true }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { role: [{ type: HostBinding, args: ['attr.role'] }], radioButtons: [{ type: ContentChildren, args: [forwardRef(() => ButtonRadioDirective)] }], tabindex: [{ type: HostBinding, args: ['attr.tabindex'] }], onFocus: [{ type: HostListener, args: ['focus'] }], onBlur: [{ type: HostListener, args: ['blur'] }], selectNext: [{ type: HostListener, args: ['keydown.ArrowRight', ['$event']] }, { type: HostListener, args: ['keydown.ArrowDown', ['$event']] }], selectPrevious: [{ type: HostListener, args: ['keydown.ArrowLeft', ['$event']] }, { type: HostListener, args: ['keydown.ArrowUp', ['$event']] }] } }); class ButtonsModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: ButtonsModule, imports: [ButtonCheckboxDirective, ButtonRadioDirective, ButtonRadioGroupDirective], exports: [ButtonCheckboxDirective, ButtonRadioDirective, ButtonRadioGroupDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonsModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ButtonsModule, decorators: [{ type: NgModule, args: [{ imports: [ButtonCheckboxDirective, ButtonRadioDirective, ButtonRadioGroupDirective], exports: [ButtonCheckboxDirective, ButtonRadioDirective, ButtonRadioGroupDirective] }] }] }); /** * Generated bundle index. Do not edit. */ export { ButtonCheckboxDirective, ButtonRadioDirective, ButtonRadioGroupDirective, ButtonsModule }; //# sourceMappingURL=ngx-bootstrap-buttons.mjs.map