UNPKG

@nebular/theme

Version:
241 lines 8.88 kB
/** * @license * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, HostBinding, Input, QueryList, } from '@angular/core'; import { from, merge, Subject } from 'rxjs'; import { filter, switchMap, takeUntil } from 'rxjs/operators'; import { NbStatusService } from '../../services/status.service'; import { convertToBoolProperty } from '../helpers'; import { NbButton } from '../button/base-button'; import { NbButtonToggleDirective } from './button-toggle.directive'; /** * `<nb-button-group>` visually groups buttons together and allow to control buttons properties and the state as a * group. * @stacked-example(Button Group Showcase, button-group/button-group-showcase.component) * * ### Installation * * Import `NbButtonGroupModule` to your feature module. * ```ts * @NgModule({ * imports: [ * // ... * NbButtonGroupModule, * ], * }) * export class PageModule { } * ``` * * ### Usage * * You can use `<nb-button-group>` to group a series of `[nbButton]` or `[nbButtonToggle]` components. * @stacked-example(Button and Button Toggle Groups, button-group/button-and-button-toggle-groups.component) * * For a group of multiple `[nbButtonToggle]` you also can control multi-selection behavior. By default, the group * component allows only one pressed button toggle at a time (similar to the radio group). To be able to keep multiple * toggles pressed, you need to add `multiple` attributes to the `<nb-button-toggle>`. * @stacked-example(Button Group Multiple, button-group/button-group-multiple.component) * * To disable a group of buttons, add a `disabled` attribute to the `<nb-button-group>`. * @stacked-example(Button Group Disabled, button-group/button-group-disabled.component) * * The group component controls all visual attributes of buttons such as `appearance`, `status`, `size`, `shape`. * You can change it via the appropriate attributes. * * Button group appearances: * @stacked-example(Button Group Appearances, button-group/button-group-appearances.component) * * Button group statuses: * @stacked-example(Button Group Statuses, button-group/button-group-statuses.component) * * Button group sizes: * @stacked-example(Button Group Sizes, button-group/button-group-sizes.component) * * Buttons group shapes: * @additional-example(Button Group Shapes, button-group/button-group-shapes.component) * * @styles * * button-group-filled-button-basic-text-color: * button-group-filled-button-primary-text-color: * button-group-filled-button-success-text-color: * button-group-filled-button-info-text-color: * button-group-filled-button-warning-text-color: * button-group-filled-button-danger-text-color: * button-group-filled-button-control-text-color: * button-group-filled-basic-divider-color: * button-group-filled-primary-divider-color: * button-group-filled-success-divider-color: * button-group-filled-info-divider-color: * button-group-filled-warning-divider-color: * button-group-filled-danger-divider-color: * button-group-filled-control-divider-color: * button-group-ghost-divider-color: **/ export class NbButtonGroupComponent { constructor(cd, statusService) { this.cd = cd; this.statusService = statusService; this.destroy$ = new Subject(); this.buttonsChange$ = new Subject(); /** * Button group size, available sizes: * `tiny`, `small`, `medium`, `large`, `giant` */ this.size = 'medium'; /** * Button group status (adds specific styles): * `basic`, `primary`, `info`, `success`, `warning`, `danger`, `control` */ this.status = 'basic'; /** * Button group shapes: `rectangle`, `round`, `semi-round` */ this.shape = 'rectangle'; /** * Button group appearance: `filled`, `outline`, `ghost` */ this.appearance = 'filled'; this._disabled = false; this._multiple = false; this.role = 'group'; } get disabled() { return this._disabled; } set disabled(value) { if (this.disabled !== convertToBoolProperty(value)) { this._disabled = !this.disabled; } } /** * Allows to keep multiple button toggles pressed. Off by default. */ get multiple() { return this._multiple; } set multiple(value) { this._multiple = convertToBoolProperty(value); } /** * Sets `filled` appearance */ get filled() { return this.appearance === 'filled'; } set filled(value) { if (convertToBoolProperty(value)) { this.appearance = 'filled'; } } /** * Sets `outline` appearance */ get outline() { return this.appearance === 'outline'; } set outline(value) { if (convertToBoolProperty(value)) { this.appearance = 'outline'; } } /** * Sets `ghost` appearance */ get ghost() { return this.appearance === 'ghost'; } set ghost(value) { if (convertToBoolProperty(value)) { this.appearance = 'ghost'; } } get additionalClasses() { if (this.statusService.isCustomStatus(this.status)) { return [this.statusService.getStatusClass(this.status)]; } return []; } ngOnChanges({ size, status, shape, multiple, filled, outline, ghost, disabled }) { var _a; if (size || status || shape || multiple || filled || outline || ghost || disabled) { this.syncButtonsProperties(((_a = this.buttons) === null || _a === void 0 ? void 0 : _a.toArray()) || []); } } ngAfterContentInit() { this.buttonsChange$ .pipe(takeUntil(this.destroy$)) .subscribe((buttons) => { this.listenButtonPressedState(buttons); this.syncButtonsProperties(buttons); }); this.buttons.changes .pipe( // `buttons.changes` emit during change detection run after projected content already was initialized. // So at this time, it's too late to update projected buttons properties as updating bindings after // initialization doesn't make sense. Changes won't be picked up and should cause an "expression changed" error. // Instead, we wrap the new buttons list into a promise to defer update to the following microtask and also to // trigger change detection one more time. switchMap((buttons) => from(Promise.resolve(buttons.toArray()))), takeUntil(this.destroy$)) .subscribe(this.buttonsChange$); this.buttonsChange$.next(this.buttons.toArray()); } listenButtonPressedState(buttons) { const toggleButtons = buttons.filter((button) => { return button instanceof NbButtonToggleDirective; }); if (!toggleButtons.length) { return; } const buttonsPressedChange$ = toggleButtons .map((button) => button.pressedChange$); merge(...buttonsPressedChange$) .pipe(filter(({ pressed }) => !this.multiple && pressed), takeUntil(merge(this.buttonsChange$, this.destroy$))) .subscribe(({ source }) => { toggleButtons .filter((button) => button !== source) .forEach((button) => button._updatePressed(false)); }); } syncButtonsProperties(buttons) { buttons.forEach((button) => { button.updateProperties({ appearance: this.appearance, size: this.size, status: this.status, shape: this.shape, disabled: this.disabled, }); }); } } NbButtonGroupComponent.decorators = [ { type: Component, args: [{ selector: 'nb-button-group', template: ` <ng-content></ng-content> `, changeDetection: ChangeDetectionStrategy.OnPush },] } ]; NbButtonGroupComponent.ctorParameters = () => [ { type: ChangeDetectorRef }, { type: NbStatusService } ]; NbButtonGroupComponent.propDecorators = { buttons: [{ type: ContentChildren, args: [NbButton,] }], size: [{ type: Input }], status: [{ type: Input }], shape: [{ type: Input }], appearance: [{ type: Input }], disabled: [{ type: Input }], multiple: [{ type: Input }], filled: [{ type: Input }], outline: [{ type: Input }], ghost: [{ type: Input }], role: [{ type: HostBinding, args: ['attr.role',] }], additionalClasses: [{ type: HostBinding, args: ['class',] }] }; //# sourceMappingURL=button-group.component.js.map