ngx-bootstrap
Version:
Angular Bootstrap
466 lines (459 loc) • 19.6 kB
JavaScript
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