UNPKG

@taiga-ui/kit

Version:
455 lines (446 loc) 20.1 kB
import { __decorate, __param } from 'tslib'; import { EventEmitter, Optional, Self, Inject, ChangeDetectorRef, Input, HostBinding, Output, ContentChild, TemplateRef, ViewChild, Component, ChangeDetectionStrategy, forwardRef, Pipe, Directive, ContentChildren, NgModule } from '@angular/core'; import { AbstractTuiMultipleControl, TUI_DEFAULT_STRINGIFY, TUI_DEFAULT_IDENTITY_MATCHER, ALWAYS_FALSE_HANDLER, EMPTY_ARRAY, isNativeFocused, setNativeFocused, tuiDefaultProp, tuiPure, TUI_FOCUSABLE_ITEM_ACCESSOR, EMPTY_QUERY, itemsQueryListObservable, getOriginalArrayFromQueryList, isPresent, tuiReplayedValueChangesFrom, EMPTY_FUNCTION, TuiPreventDefaultModule, TuiActiveZoneModule, TuiLetModule, TuiMapperPipeModule, TuiHoveredModule } from '@taiga-ui/cdk'; import { NgControl, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import { TuiSvgService, TuiTextfieldLabelOutsideDirective, TUI_TEXTFIELD_LABEL_OUTSIDE, TuiDataListDirective, TUI_DATA_LIST_ACCESSOR, TuiHostedDropdownComponent, TUI_DATA_LIST_HOST, TUI_OPTION_CONTENT, sizeBigger, TuiOptionComponent, TuiSvgModule, TuiHostedDropdownModule, TuiPrimitiveCheckboxModule, TuiDataListModule } from '@taiga-ui/core'; import { TuiStringifiableItem } from '@taiga-ui/kit/classes'; import { TuiInputTagComponent, TuiInputTagModule } from '@taiga-ui/kit/components/input-tag'; import { iconBlank } from '@taiga-ui/kit/constants'; import { FIXED_DROPDOWN_CONTROLLER_PROVIDER } from '@taiga-ui/kit/providers'; import { CommonModule } from '@angular/common'; import { TUI_MULTI_SELECT_OPTION, TuiMultiSelectOptionModule } from '@taiga-ui/kit/components/multi-select-option'; import { PolymorpheusModule } from '@tinkoff/ng-polymorpheus'; import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; var TuiMultiSelectComponent_1; let TuiMultiSelectComponent = TuiMultiSelectComponent_1 = class TuiMultiSelectComponent extends AbstractTuiMultipleControl { constructor(control, changeDetectorRef, svgService, textfieldLabelOutside) { super(control, changeDetectorRef); this.textfieldLabelOutside = textfieldLabelOutside; this.stringify = TUI_DEFAULT_STRINGIFY; this.identityMatcher = TUI_DEFAULT_IDENTITY_MATCHER; this.expandable = true; this.search = ''; this.editable = true; this.disabledItemHandler = ALWAYS_FALSE_HANDLER; this.valueContent = ''; this.searchChange = new EventEmitter(); this.open = false; this.valueMapper = (value, stringify, group) => group ? EMPTY_ARRAY : value.map(item => new TuiStringifiableItem(item, stringify)); this.disabledItemHandlerWrapper = handler => stringifiable => typeof stringifiable === 'string' || handler(stringifiable.item); this.datalist = ''; svgService.define({ iconBlank }); } get nativeFocusableElement() { return this.input ? this.input.nativeFocusableElement : null; } get focused() { return ((!!this.input && this.input.focused) || (!!this.hostedDropdown && this.hostedDropdown.focused)); } get computedValue() { return this.computedGroup ? EMPTY_ARRAY : this.value; } // @bad TODO: think of a better way get searchOrSpace() { return this.computedGroup ? ' ' : this.searchString; } get searchString() { return this.search === null ? '' : this.search; } get tagIcon() { return this.interactive ? 'iconBlank' : 'tuiIconChevronDownLarge'; } get interactive() { return !this.disabled && !this.readOnly; } get inputHidden() { return !this.editable && !this.computedGroup; } get computedGroup() { return (!!this.valueContent && this.value.length > 0 && (!this.focused || !this.editable)); } get context() { return this.getContext(this.value); } getStringifier(stringify) { return ({ $implicit }) => stringify($implicit); } onHoveredChange(hovered) { this.updateHovered(hovered); } onSpace(event) { if (!this.editable) { event.preventDefault(); } if (!this.readOnly) { this.open = true; } } handleOption(option) { const { value, identityMatcher } = this; const index = value.findIndex(item => identityMatcher(item, option)); this.updateValue(index === -1 ? [...value, option] : [...value.slice(0, index), ...value.slice(index + 1)]); this.updateSearch(null); } onEnter(event) { const { value } = this; const options = this.accessor ? this.accessor.getOptions() : []; if (options.length !== 1) { return; } const index = value.indexOf(options[0]); event.preventDefault(); this.updateValue(index === -1 ? [...value, options[0]] : [...value.slice(0, index), ...value.slice(index + 1)]); this.updateSearch(null); } onClick({ nativeFocusableElement }) { if (this.interactive && nativeFocusableElement && isNativeFocused(nativeFocusableElement)) { this.open = !this.open; } } onArrowClick() { this.open = !this.open; this.focusInput(); } onInput(value) { this.updateValue(value.map(({ item }) => item)); } onSearch(search) { this.open = true; this.updateSearch(search); } onActiveZone(active) { this.updateFocused(active); } setDisabledState() { super.setDisabledState(); this.open = false; } updateSearch(search) { if (this.search === search) { return; } this.search = search; this.searchChange.emit(search); } focusInput(preventScroll = false) { if (this.nativeFocusableElement) { setNativeFocused(this.nativeFocusableElement, true, preventScroll); } } getContext($implicit) { return { $implicit }; } }; TuiMultiSelectComponent.ctorParameters = () => [ { type: NgControl, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NgControl,] }] }, { type: ChangeDetectorRef, decorators: [{ type: Inject, args: [ChangeDetectorRef,] }] }, { type: TuiSvgService, decorators: [{ type: Inject, args: [TuiSvgService,] }] }, { type: TuiTextfieldLabelOutsideDirective, decorators: [{ type: Inject, args: [TUI_TEXTFIELD_LABEL_OUTSIDE,] }] } ]; __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "stringify", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "identityMatcher", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "expandable", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "search", void 0); __decorate([ Input(), HostBinding('class._editable'), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "editable", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "disabledItemHandler", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectComponent.prototype, "valueContent", void 0); __decorate([ Output() ], TuiMultiSelectComponent.prototype, "searchChange", void 0); __decorate([ ContentChild(TuiDataListDirective, { read: TemplateRef }) ], TuiMultiSelectComponent.prototype, "datalist", void 0); __decorate([ ContentChild(TUI_DATA_LIST_ACCESSOR) ], TuiMultiSelectComponent.prototype, "accessor", void 0); __decorate([ ViewChild(TuiHostedDropdownComponent) ], TuiMultiSelectComponent.prototype, "hostedDropdown", void 0); __decorate([ ViewChild(TuiInputTagComponent) ], TuiMultiSelectComponent.prototype, "input", void 0); __decorate([ tuiPure ], TuiMultiSelectComponent.prototype, "getStringifier", null); __decorate([ tuiPure ], TuiMultiSelectComponent.prototype, "getContext", null); TuiMultiSelectComponent = TuiMultiSelectComponent_1 = __decorate([ Component({ selector: 'tui-multi-select', template: "<tui-hosted-dropdown\n class=\"wrapper\"\n [canOpen]=\"interactive\"\n [content]=\"datalist || ''\"\n [(open)]=\"open\"\n (tuiHoveredChange)=\"onHoveredChange($event)\"\n (tuiActiveZoneChange)=\"onActiveZone($event)\"\n>\n <tui-input-tag\n tuiHostedDropdownHost\n #inputTag\n automation-id=\"tui-multi-select__input\"\n class=\"input\"\n [nativeId]=\"nativeId\"\n [icon]=\"tagIcon\"\n [disabled]=\"disabled\"\n [disabledItemHandler]=\"disabledItemHandler | tuiMapper : disabledItemHandlerWrapper\"\n [readOnly]=\"readOnly\"\n [inputHidden]=\"!editable\"\n [pseudoHovered]=\"hovered\"\n [pseudoFocused]=\"focused\"\n [pseudoInvalid]=\"computedInvalid\"\n [editable]=\"false\"\n [expandable]=\"expandable\"\n [search]=\"searchOrSpace\"\n [ngModel]=\"computedValue | tuiMapper: valueMapper: stringify\"\n (ngModelChange)=\"onInput($event)\"\n (searchChange)=\"onSearch($event)\"\n (keydown.space)=\"onSpace($event)\"\n (keydown.enter)=\"onEnter($event)\"\n (click.stop)=\"onClick(inputTag)\"\n >\n <ng-content></ng-content>\n </tui-input-tag>\n <div\n *ngIf=\"computedGroup\"\n polymorpheus-outlet\n class=\"group\"\n [class.group_fullsize]=\"textfieldLabelOutside.labelOutside\"\n [context]=\"context\"\n [content]=\"valueContent\"\n ></div>\n <tui-svg\n *ngIf=\"interactive\"\n automation-id=\"tui-multi-select__arrow\"\n class=\"arrow\"\n src=\"tuiIconChevronDownLarge\"\n tuiPreventDefault=\"mousedown\"\n [class.arrow_open]=\"open\"\n (click.prevent)=\"onArrowClick()\"\n ></tui-svg>\n</tui-hosted-dropdown>\n", changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: TUI_FOCUSABLE_ITEM_ACCESSOR, useExisting: forwardRef(() => TuiMultiSelectComponent_1), }, { provide: TUI_DATA_LIST_HOST, useExisting: forwardRef(() => TuiMultiSelectComponent_1), }, FIXED_DROPDOWN_CONTROLLER_PROVIDER, ], styles: [":host{position:relative;display:block}:host._disabled{pointer-events:none}.wrapper{display:block}:host:not(._editable):not(._readonly) .input{cursor:pointer}.arrow{transition-duration:.3s;transition-timing-function:ease-in-out;display:flex;width:24px;align-items:center;justify-content:center;color:var(--tui-text-03);box-sizing:border-box;transition-property:color,transform;position:absolute;top:50%;transform:translate(0,-50%);right:12px;height:24px;box-sizing:content-box;cursor:pointer}.arrow:hover{color:var(--tui-text-02)}:host._disabled .arrow,:host._readonly .arrow{pointer-events:none}:host[data-mode=onDark] .arrow{color:var(--tui-text-03-night)}:host[data-mode=onDark] .arrow:hover{color:var(--tui-text-01-night)}.arrow_open{transform:rotate(-180deg) translate(0,50%)}.group{position:absolute;top:0;left:0;bottom:0;display:flex;align-items:center;padding:27px 16px 9px;pointer-events:none}.group_fullsize{padding-top:1px;padding-bottom:0}:host[data-tui-host-size='m'] .group_fullsize.group_fullsize{padding-top:0}:host[data-tui-host-size='m'] .group{padding:19px 12px 0;font-size:13px}"] }), __param(0, Optional()), __param(0, Self()), __param(0, Inject(NgControl)), __param(1, Inject(ChangeDetectorRef)), __param(2, Inject(TuiSvgService)), __param(3, Inject(TUI_TEXTFIELD_LABEL_OUTSIDE)) ], TuiMultiSelectComponent); let TuiHideSelectedPipe = class TuiHideSelectedPipe { constructor(component) { this.component = component; } transform(items, { value, identityMatcher } = this.component) { return items && this.filter(items, value, identityMatcher); } filter(items, value, matcher) { return items.filter(item => value.every(selected => !matcher(selected, item))); } }; TuiHideSelectedPipe.ctorParameters = () => [ { type: TuiMultiSelectComponent, decorators: [{ type: Inject, args: [TuiMultiSelectComponent,] }] } ]; __decorate([ tuiPure ], TuiHideSelectedPipe.prototype, "filter", null); TuiHideSelectedPipe = __decorate([ Pipe({ name: 'tuiHideSelected', pure: false, }), __param(0, Inject(TuiMultiSelectComponent)) ], TuiHideSelectedPipe); // TODO: Remove and switch to viewProviders when Angular is updated to Ivy /** @deprecated */ let TuiMultiSelectGroupResetDirective = class TuiMultiSelectGroupResetDirective { }; TuiMultiSelectGroupResetDirective = __decorate([ Directive({ selector: '[tuiMultiSelectGroupReset]', providers: [ { provide: TUI_OPTION_CONTENT, useValue: null, }, ], }) ], TuiMultiSelectGroupResetDirective); let TuiMultiSelectGroupComponent = class TuiMultiSelectGroupComponent { constructor(host, control) { this.host = host; this.control = control; this.label = ''; this.options = EMPTY_QUERY; } get size() { return (this.options.first && this.options.first.size) || 'm'; } get checkboxSize() { return this.options.first && sizeBigger(this.options.first.size) ? 'l' : 'm'; } get empty$() { return itemsQueryListObservable(this.options).pipe(map(({ length }) => !length)); } get disabled$() { return itemsQueryListObservable(this.options).pipe(map(items => items.every(({ disabled }) => disabled))); } get value$() { return combineLatest(this.items$, this.valueChanges$).pipe(map(([items, current]) => { let result = false; for (let i = 0; i < items.length; i++) { const selected = current.some(selected => this.matcher(selected, items[i])); if ((!selected && result) || (selected && !result && i)) { return null; } result = selected; } return result; })); } onClick(checked) { if (!this.control.control) { return; } const controlValue = this.control.value || []; const { values } = this; const filtered = controlValue.filter(current => values.every(item => !this.matcher(current, item))); this.control.control.setValue(checked ? filtered : [...filtered, ...values]); } get values() { return this.filter(getOriginalArrayFromQueryList(this.options)); } get matcher() { return this.host.identityMatcher || TUI_DEFAULT_IDENTITY_MATCHER; } get items$() { return itemsQueryListObservable(this.options).pipe(map(options => options.map(({ value }) => value).filter(isPresent))); } get valueChanges$() { return tuiReplayedValueChangesFrom(this.control).pipe(map(value => value || [])); } filter(items) { return items.map(({ value }) => value).filter(isPresent); } }; TuiMultiSelectGroupComponent.ctorParameters = () => [ { type: undefined, decorators: [{ type: Inject, args: [TUI_DATA_LIST_HOST,] }] }, { type: NgControl, decorators: [{ type: Inject, args: [NgControl,] }] } ]; __decorate([ Input(), tuiDefaultProp() ], TuiMultiSelectGroupComponent.prototype, "label", void 0); __decorate([ ContentChildren(TuiOptionComponent) ], TuiMultiSelectGroupComponent.prototype, "options", void 0); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "empty$", null); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "disabled$", null); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "value$", null); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "items$", null); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "valueChanges$", null); __decorate([ tuiPure ], TuiMultiSelectGroupComponent.prototype, "filter", null); TuiMultiSelectGroupComponent = __decorate([ Component({ selector: 'tui-opt-group[tuiMultiSelectGroup]', template: "<ng-container *tuiLet=\"value$ | async as value\">\n <button\n *ngIf=\"label && !(empty$ | async)\"\n tuiMultiSelectGroupReset\n tuiOption\n [size]=\"size\"\n [disabled]=\"disabled$ | async\"\n (click)=\"onClick(value)\"\n >\n <tui-primitive-checkbox\n class=\"tui-space_right-3\"\n [size]=\"checkboxSize\"\n [value]=\"value\"\n ></tui-primitive-checkbox>\n <span class=\"label\">{{label}}</span>\n </button>\n</ng-container>\n<ng-content></ng-content>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:flex;flex-direction:column}:host:before{content:''}.label{font:var(--tui-font-text-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;color:var(--tui-text-02)}"] }), __param(0, Inject(TUI_DATA_LIST_HOST)), __param(1, Inject(NgControl)) ], TuiMultiSelectGroupComponent); function hostFallbackFactory(control, host) { return (host || { handleOption: option => { if (!control.control) { return; } const value = control.value || []; const index = value.indexOf(option); control.control.setValue(index === -1 ? [...value, option] : [...value.slice(0, index), ...value.slice(index + 1)]); }, }); } const ɵ0 = TUI_MULTI_SELECT_OPTION, ɵ1 = { writeValue: EMPTY_FUNCTION, registerOnChange: EMPTY_FUNCTION, registerOnTouched: EMPTY_FUNCTION, }; let TuiMultiSelectGroupDirective = class TuiMultiSelectGroupDirective { }; TuiMultiSelectGroupDirective = __decorate([ Directive({ selector: '[tuiMultiSelectGroup]', providers: [ { provide: TUI_OPTION_CONTENT, useValue: ɵ0, }, { provide: TUI_DATA_LIST_HOST, deps: [ NgControl, [new Optional(), forwardRef(() => TuiMultiSelectComponent)], ], useFactory: hostFallbackFactory, }, { provide: NG_VALUE_ACCESSOR, multi: true, useValue: ɵ1, }, ], }) ], TuiMultiSelectGroupDirective); let TuiMultiSelectModule = class TuiMultiSelectModule { }; TuiMultiSelectModule = __decorate([ NgModule({ imports: [ CommonModule, FormsModule, PolymorpheusModule, TuiPreventDefaultModule, TuiActiveZoneModule, TuiLetModule, TuiMapperPipeModule, TuiHoveredModule, TuiSvgModule, TuiHostedDropdownModule, TuiInputTagModule, TuiMultiSelectOptionModule, TuiPrimitiveCheckboxModule, TuiDataListModule, ], declarations: [ TuiMultiSelectComponent, TuiMultiSelectGroupComponent, TuiMultiSelectGroupDirective, TuiMultiSelectGroupResetDirective, TuiHideSelectedPipe, ], exports: [ TuiMultiSelectComponent, TuiMultiSelectGroupComponent, TuiMultiSelectGroupDirective, TuiHideSelectedPipe, ], }) ], TuiMultiSelectModule); /** * Generated bundle index. Do not edit. */ export { TuiHideSelectedPipe, TuiMultiSelectComponent, TuiMultiSelectGroupComponent, TuiMultiSelectGroupDirective, TuiMultiSelectGroupResetDirective, TuiMultiSelectModule, hostFallbackFactory, ɵ0, ɵ1 }; //# sourceMappingURL=taiga-ui-kit-components-multi-select.js.map