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
JavaScript
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