UNPKG

igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

499 lines (493 loc) 20.9 kB
import * as i2 from 'igniteui-angular/directives'; import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; import * as i0 from '@angular/core'; import { inject, ChangeDetectorRef, Renderer2, ElementRef, EventEmitter, booleanAttribute, ContentChildren, ViewChildren, Output, Input, HostBinding, Component, NgModule } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { IgxIconComponent } from 'igniteui-angular/icon'; /** * Determines the Button Group alignment */ const ButtonGroupAlignment = { horizontal: 'horizontal', vertical: 'vertical' }; let NEXT_ID = 0; /** * **Ignite UI for Angular Button Group** - * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/buttongroup.html) * * The Ignite UI Button Group displays a group of buttons either vertically or horizontally. The group supports * single, multi and singleRequired selection. * * Example: * ```html * <igx-buttongroup selectionMode="multi" [values]="fontOptions"> * </igx-buttongroup> * ``` * The `fontOptions` value shown above is defined as: * ```typescript * this.fontOptions = [ * { icon: 'format_bold', selected: false }, * { icon: 'format_italic', selected: false }, * { icon: 'format_underlined', selected: false }]; * ``` */ class IgxButtonGroupComponent { constructor() { this._cdr = inject(ChangeDetectorRef); this._renderer = inject(Renderer2); this._el = inject(ElementRef); /** * Gets/Sets the value of the `id` attribute. If not set it will be automatically generated. * ```html * <igx-buttongroup [id]="'igx-dialog-56'" [selectionMode]="'multi'" [values]="alignOptions"> * ``` */ this.id = `igx-buttongroup-${NEXT_ID++}`; /** * @hidden */ this.zIndex = 0; /** * An @Ouput property that emits an event when a button is selected. * ```typescript * @ViewChild("toast") * private toast: IgxToastComponent; * public selectedHandler(buttongroup) { * this.toast.open() * } * //... * ``` * ```html * <igx-buttongroup #MyChild [selectionMode]="'multi'" (selected)="selectedHandler($event)"></igx-buttongroup> * <igx-toast #toast>You have made a selection!</igx-toast> * ``` */ this.selected = new EventEmitter(); /** * An @Ouput property that emits an event when a button is deselected. * ```typescript * @ViewChild("toast") * private toast: IgxToastComponent; * public deselectedHandler(buttongroup){ * this.toast.open() * } * //... * ``` * ```html * <igx-buttongroup> #MyChild [selectionMode]="'multi'" (deselected)="deselectedHandler($event)"></igx-buttongroup> * <igx-toast #toast>You have deselected a button!</igx-toast> * ``` */ this.deselected = new EventEmitter(); /** * @hidden */ this.selectedIndexes = []; this.buttonClickNotifier$ = new Subject(); this.queryListNotifier$ = new Subject(); this._disabled = false; this._selectionMode = 'single'; this.observerConfig = { attributeFilter: ["data-selected"], childList: true, subtree: true, }; } /** * A collection containing all buttons inside the button group. */ get buttons() { return [...this.viewButtons.toArray(), ...this.templateButtons.toArray()]; } /** * Allows you to set a style using the `itemContentCssClass` input. * The value should be the CSS class name that will be applied to the button group. * ```typescript * public style1 = "styleClass"; * //.. * ``` * ```html * <igx-buttongroup [itemContentCssClass]="style1" [selectionMode]="'multi'" [values]="alignOptions"> * ``` */ set itemContentCssClass(value) { this._itemContentCssClass = value || this._itemContentCssClass; } /** * Returns the CSS class of the item content of the `IgxButtonGroup`. * ```typescript * @ViewChild("MyChild") * public buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * let buttonSelect = this.buttonG.itemContentCssClass; * } * ``` */ get itemContentCssClass() { return this._itemContentCssClass; } /** * Enables selecting multiple buttons. By default, multi-selection is false. * * @deprecated in version 16.1.0. Use the `selectionMode` property instead. */ get multiSelection() { if (this.selectionMode === 'multi') { return true; } else { return false; } } set multiSelection(selectionMode) { if (selectionMode) { this.selectionMode = 'multi'; } else { this.selectionMode = 'single'; } } /** * Gets/Sets the selection mode to 'single', 'singleRequired' or 'multi' of the buttons. By default, the selection mode is 'single'. * ```html * <igx-buttongroup [selectionMode]="'multi'" [alignment]="alignment"></igx-buttongroup> * ``` */ get selectionMode() { return this._selectionMode; } set selectionMode(selectionMode) { if (this.viewButtons && selectionMode !== this._selectionMode) { this.buttons.forEach((b, i) => { this.deselectButton(i); }); this._selectionMode = selectionMode; } else { this._selectionMode = selectionMode; } } /** * Disables the `igx-buttongroup` component. By default it's false. * ```html * <igx-buttongroup [disabled]="true" [selectionMode]="'multi'" [values]="fontOptions"></igx-buttongroup> * ``` */ get disabled() { return this._disabled; } set disabled(value) { if (this._disabled !== value) { this._disabled = value; if (this.viewButtons && this.templateButtons) { this.buttons.forEach((b) => (b.disabled = this._disabled)); } } } /** * Allows you to set the button group alignment. * Available options are `ButtonGroupAlignment.horizontal` (default) and `ButtonGroupAlignment.vertical`. * ```typescript * public alignment = ButtonGroupAlignment.vertical; * //.. * ``` * ```html * <igx-buttongroup [selectionMode]="'single'" [values]="cities" [alignment]="alignment"></igx-buttongroup> * ``` */ set alignment(value) { this._isVertical = value === ButtonGroupAlignment.vertical; } /** * Returns the alignment of the `igx-buttongroup`. * ```typescript * @ViewChild("MyChild") * public buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * let buttonAlignment = this.buttonG.alignment; * } * ``` */ get alignment() { return this._isVertical ? ButtonGroupAlignment.vertical : ButtonGroupAlignment.horizontal; } /** * Returns true if the `igx-buttongroup` alignment is vertical. * Note that in order for the accessor to work correctly the property should be set explicitly. * ```html * <igx-buttongroup #MyChild [alignment]="alignment" [values]="alignOptions"> * ``` * ```typescript * //... * @ViewChild("MyChild") * private buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * let orientation = this.buttonG.isVertical; * } * ``` */ get isVertical() { return this._isVertical; } /** * Gets the selected button/buttons. * ```typescript * @ViewChild("MyChild") * private buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * let selectedButton = this.buttonG.selectedButtons; * } * ``` */ get selectedButtons() { return this.buttons.filter((_, i) => this.selectedIndexes.indexOf(i) !== -1); } /** * Selects a button by its index. * ```typescript * @ViewChild("MyChild") * private buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * this.buttonG.selectButton(2); * this.cdr.detectChanges(); * } * ``` * * @memberOf {@link IgxButtonGroupComponent} */ selectButton(index) { if (index >= this.buttons.length || index < 0) { return; } const button = this.buttons[index]; button.select(); } /** * @hidden * @internal */ updateSelected(index) { const button = this.buttons[index]; if (this.selectedIndexes.indexOf(index) === -1) { this.selectedIndexes.push(index); } this._renderer.setAttribute(button.nativeElement, 'aria-pressed', 'true'); this._renderer.addClass(button.nativeElement, 'igx-button-group__item--selected'); const indexInViewButtons = this.viewButtons.toArray().indexOf(button); if (indexInViewButtons !== -1) { this.values[indexInViewButtons].selected = true; } // deselect other buttons if selectionMode is not multi if (this.selectionMode !== 'multi' && this.selectedIndexes.length > 1) { this.buttons.forEach((_, i) => { if (i !== index && this.selectedIndexes.indexOf(i) !== -1) { this.deselectButton(i); this.updateDeselected(i); } }); } } updateDeselected(index) { const button = this.buttons[index]; if (this.selectedIndexes.indexOf(index) !== -1) { this.selectedIndexes.splice(this.selectedIndexes.indexOf(index), 1); } this._renderer.setAttribute(button.nativeElement, 'aria-pressed', 'false'); this._renderer.removeClass(button.nativeElement, 'igx-button-group__item--selected'); const indexInViewButtons = this.viewButtons.toArray().indexOf(button); if (indexInViewButtons !== -1) { this.values[indexInViewButtons].selected = false; } } /** * Deselects a button by its index. * ```typescript * @ViewChild("MyChild") * private buttonG: IgxButtonGroupComponent; * ngAfterViewInit(){ * this.buttonG.deselectButton(2); * this.cdr.detectChanges(); * } * ``` * * @memberOf {@link IgxButtonGroupComponent} */ deselectButton(index) { if (index >= this.buttons.length || index < 0) { return; } const button = this.buttons[index]; button.deselect(); } /** * @hidden */ ngAfterViewInit() { const initButtons = () => { // Cancel any existing buttonClick subscriptions this.buttonClickNotifier$.next(); this.selectedIndexes.splice(0, this.selectedIndexes.length); // initial configuration this.buttons.forEach((button, index) => { const buttonElement = button.nativeElement; this._renderer.addClass(buttonElement, 'igx-button-group__item'); if (this.disabled) { button.disabled = true; } if (button.selected) { this.updateSelected(index); } button.buttonClick.pipe(takeUntil(this.buttonClickNotifier$)).subscribe((_) => this._clickHandler(index)); }); }; this.mutationObserver = this.setMutationsObserver(); this.viewButtons.changes.pipe(takeUntil(this.queryListNotifier$)).subscribe(() => { this.mutationObserver.disconnect(); initButtons(); this.mutationObserver?.observe(this._el.nativeElement, this.observerConfig); }); this.templateButtons.changes.pipe(takeUntil(this.queryListNotifier$)).subscribe(() => { this.mutationObserver.disconnect(); initButtons(); this.mutationObserver?.observe(this._el.nativeElement, this.observerConfig); }); initButtons(); this._cdr.detectChanges(); this.mutationObserver?.observe(this._el.nativeElement, this.observerConfig); } /** * @hidden */ ngOnDestroy() { this.buttonClickNotifier$.next(); this.buttonClickNotifier$.complete(); this.queryListNotifier$.next(); this.queryListNotifier$.complete(); this.mutationObserver?.disconnect(); } /** * @hidden */ _clickHandler(index) { const button = this.buttons[index]; const args = { owner: this, button, index }; if (this.selectionMode !== 'multi') { this.buttons.forEach((b, i) => { if (i !== index && this.selectedIndexes.indexOf(i) !== -1) { this.deselected.emit({ owner: this, button: b, index: i }); } }); } if (this.selectedIndexes.indexOf(index) === -1) { this.selectButton(index); this.selected.emit(args); } else { if (this.selectionMode !== 'singleRequired') { this.deselectButton(index); this.deselected.emit(args); } } } setMutationsObserver() { if (typeof MutationObserver !== 'undefined') { return new MutationObserver((records, observer) => { // Stop observing while handling changes observer.disconnect(); const updatedButtons = this.getUpdatedButtons(records); if (updatedButtons.length > 0) { updatedButtons.forEach((button) => { const index = this.buttons.map((b) => b.nativeElement).indexOf(button); this.updateButtonSelectionState(index); }); } // Watch for changes again observer.observe(this._el.nativeElement, this.observerConfig); }); } } getUpdatedButtons(records) { const updated = []; records .filter((x) => x.type === 'attributes') .reduce((prev, curr) => { prev.push(curr.target); return prev; }, updated); return updated; } updateButtonSelectionState(index) { if (this.buttons[index].selected) { this.updateSelected(index); } else { this.updateDeselected(index); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxButtonGroupComponent, isStandalone: true, selector: "igx-buttongroup", inputs: { id: "id", itemContentCssClass: "itemContentCssClass", multiSelection: "multiSelection", selectionMode: "selectionMode", values: "values", disabled: ["disabled", "disabled", booleanAttribute], alignment: "alignment" }, outputs: { selected: "selected", deselected: "deselected" }, host: { properties: { "attr.id": "this.id", "style.zIndex": "this.zIndex" } }, queries: [{ propertyName: "templateButtons", predicate: IgxButtonDirective }], viewQueries: [{ propertyName: "viewButtons", predicate: IgxButtonDirective, descendants: true }], ngImport: i0, template: "<div class=\"igx-button-group\" role=\"group\" [class.igx-button-group--vertical]=\"isVertical\">\n @for (button of values; track button) {\n <button\n type=\"button\"\n igxButton=\"flat\"\n [selected]=\"button.selected\"\n [attr.data-togglable]=\"button.togglable\"\n [disabled]=\"disabled || button.disabled\"\n [igxLabel]=\"button.label\"\n [igxRipple]=\"button.ripple\"\n >\n <span class=\"igx-button-group__item-content {{ itemContentCssClass }}\">\n @if (button.icon) {\n <igx-icon>{{button.icon}}</igx-icon>\n }\n @if (button.label) {\n <span class=\"igx-button-group__button-text\">{{button.label}}</span>\n }\n </span>\n </button>\n }\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: IgxButtonDirective, selector: "[igxButton]", inputs: ["selected", "igxButton", "igxLabel"], outputs: ["buttonSelected"] }, { kind: "directive", type: IgxRippleDirective, selector: "[igxRipple]", inputs: ["igxRippleTarget", "igxRipple", "igxRippleDuration", "igxRippleCentered", "igxRippleDisabled"] }, { kind: "component", type: IgxIconComponent, selector: "igx-icon", inputs: ["ariaHidden", "family", "name", "active"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupComponent, decorators: [{ type: Component, args: [{ selector: 'igx-buttongroup', imports: [IgxButtonDirective, IgxRippleDirective, IgxIconComponent], template: "<div class=\"igx-button-group\" role=\"group\" [class.igx-button-group--vertical]=\"isVertical\">\n @for (button of values; track button) {\n <button\n type=\"button\"\n igxButton=\"flat\"\n [selected]=\"button.selected\"\n [attr.data-togglable]=\"button.togglable\"\n [disabled]=\"disabled || button.disabled\"\n [igxLabel]=\"button.label\"\n [igxRipple]=\"button.ripple\"\n >\n <span class=\"igx-button-group__item-content {{ itemContentCssClass }}\">\n @if (button.icon) {\n <igx-icon>{{button.icon}}</igx-icon>\n }\n @if (button.label) {\n <span class=\"igx-button-group__button-text\">{{button.label}}</span>\n }\n </span>\n </button>\n }\n <ng-content></ng-content>\n</div>\n" }] }], propDecorators: { id: [{ type: HostBinding, args: ['attr.id'] }, { type: Input }], zIndex: [{ type: HostBinding, args: ['style.zIndex'] }], itemContentCssClass: [{ type: Input }], multiSelection: [{ type: Input }], selectionMode: [{ type: Input }], values: [{ type: Input }], disabled: [{ type: Input, args: [{ transform: booleanAttribute }] }], alignment: [{ type: Input }], selected: [{ type: Output }], deselected: [{ type: Output }], viewButtons: [{ type: ViewChildren, args: [IgxButtonDirective] }], templateButtons: [{ type: ContentChildren, args: [IgxButtonDirective] }] } }); /* Button group directives collection for ease-of-use import in standalone components scenario */ const IGX_BUTTON_GROUP_DIRECTIVES = [ IgxButtonGroupComponent, IgxButtonDirective ]; /** * @hidden * @deprecated * IMPORTANT: The following is NgModule exported for backwards-compatibility before standalone components */ class IgxButtonGroupModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupModule, imports: [IgxButtonGroupComponent, i2.IgxButtonDirective], exports: [IgxButtonGroupComponent, i2.IgxButtonDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupModule, imports: [IgxButtonGroupComponent] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxButtonGroupModule, decorators: [{ type: NgModule, args: [{ imports: [...IGX_BUTTON_GROUP_DIRECTIVES], exports: [...IGX_BUTTON_GROUP_DIRECTIVES] }] }] }); /** * Generated bundle index. Do not edit. */ export { ButtonGroupAlignment, IGX_BUTTON_GROUP_DIRECTIVES, IgxButtonGroupComponent, IgxButtonGroupModule }; //# sourceMappingURL=igniteui-angular-button-group.mjs.map