UNPKG

ng-select2-component

Version:
955 lines (946 loc) 188 kB
import * as i0 from '@angular/core'; import { inject, ElementRef, input, signal, Directive, booleanAttribute, contentChildren, Pipe, ChangeDetectorRef, numberAttribute, computed, output, viewChild, viewChildren, effect, untracked, TemplateRef, Component } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop'; import { CdkConnectedOverlay, ConnectionPositionPair, CdkOverlayOrigin } from '@angular/cdk/overlay'; import { ViewportRuler } from '@angular/cdk/scrolling'; import { NgTemplateOutlet } from '@angular/common'; import { toObservable } from '@angular/core/rxjs-interop'; import { NgForm, FormGroupDirective, NgControl } from '@angular/forms'; import { Subject, Subscription, fromEvent, debounceTime } from 'rxjs'; const timeout = 200; /** * Latin - `[\u0300-\u036F]` matches combining diacritical marks: * - `\u0300-\u036F`: grave, acute, circumflex, tilde, macron, breve, dot above, diaeresis, ring above, etc. */ const latinDiacritical = { tmp: '\uE000', pattern: '[\\u0300-\\u036F]*' }; /** * Arabic - `[\u064B-\u0652\u0670]` matches Arabic diacritics (harakat): * - `\u064B-\u0652`: fatha, damma, kasra, sukun, shadda, tanwin, etc. * - `\u0670`: alif khanjariyah (superscript alif) */ const arabicDiacritical = { tmp: '\uE001', pattern: '[\\u064B-\\u0652\\u0670]*' }; /** * Hebrew - `[\u05B0-\u05BC\u05C1\u05C2]` matches Hebrew diacritics (niqqud): * - `\u05B0-\u05BC`: vowel points (sheva, hataf, hiriq, tsere, segol, patah, qamats, holam, qubuts, dagesh, etc.) * - `\u05C1-\u05C2`: shin dot (right) and sin dot (left) */ const hebrewDiacritical = { tmp: '\uE002', pattern: '[\\u05B0-\\u05BC\\u05C1\\u05C2]*' }; const unicodePatterns = [ // Latin { l: 'a', s: /[ⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ]/gi, e: 'a(?![aeouvy])', d: latinDiacritical }, { l: 'aa', s: /ꜳ/gi, d: latinDiacritical }, { l: 'ae', s: /[æǽǣ]/gi, d: latinDiacritical }, { l: 'ao', s: /ꜵ/gi, d: latinDiacritical }, { l: 'au', s: /ꜷ/gi, d: latinDiacritical }, { l: 'av', s: /[ꜹꜻ]/gi, d: latinDiacritical }, { l: 'ay', s: /ꜽ/gi, d: latinDiacritical }, { l: 'b', s: /[ⓑbḃḅḇƀƃɓ]/gi, d: latinDiacritical }, { l: 'c', s: /[ⓒcćĉċčçḉƈȼꜿↄ]/gi, d: latinDiacritical }, { l: 'd', s: /[ⓓdḋďḍḑḓḏđƌɖɗꝺ]/gi, e: 'd(?!z)', d: latinDiacritical }, { l: 'dz', s: /[dzdž]/gi, d: latinDiacritical }, { l: 'e', s: /(?<!o)[eⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ]/gi, e: '(?<!o)e', d: latinDiacritical }, { l: 'f', s: /[ⓕfḟƒꝼ]/gi, d: latinDiacritical }, { l: 'g', s: /[ⓖgǵĝḡğġǧģǥɠꞡᵹꝿ]/gi, d: latinDiacritical }, { l: 'h', s: /[ⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ]/gi, e: 'h(?!v)', d: latinDiacritical }, { l: 'hv', s: /ƕ/gi, d: latinDiacritical }, { l: 'i', s: /[ⓘiìíîĩīĭİïḯỉǐȉȋịįḭɨı]/gi, d: latinDiacritical }, { l: 'j', s: /[ⓙjĵǰɉ]/gi, e: '(?<![ln])j', d: latinDiacritical }, { l: 'k', s: /[ⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ]/gi, d: latinDiacritical }, { l: 'l', s: /[ⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇꝆ]/gi, e: 'l(?!j)', d: latinDiacritical }, { l: 'lj', s: /lj/gi, d: latinDiacritical }, { l: 'm', s: /[ⓜmḿṁṃɱɯ]/gi, d: latinDiacritical }, { l: 'n', s: /[ⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥ]/gi, e: 'n(?!j)', d: latinDiacritical }, { l: 'nj', s: /nj/gi, d: latinDiacritical }, { l: 'o', s: /[ⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔƟꝋꝍɵ]/gi, e: 'o(?![ieou])', d: latinDiacritical }, { l: 'oi', s: /ƣ/gi, d: latinDiacritical }, { l: 'oe', s: /œ/gi, d: latinDiacritical }, { l: 'oo', s: /ꝏ/gi, d: latinDiacritical }, { l: 'ou', s: /ȣ/gi, d: latinDiacritical }, { l: 'p', s: /[ⓟpṕṗƥᵽꝑꝓꝕ]/gi, d: latinDiacritical }, { l: 'q', s: /[ⓠqɋꝗꝙ]/gi, d: latinDiacritical }, { l: 'r', s: /[ⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ]/gi, d: latinDiacritical }, { l: 's', s: /[ⓢsßẞśṥŝṡšṧṣṩșşȿꞩꞅẛ]/gi, d: latinDiacritical }, { l: 't', s: /[ⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ]/gi, e: 't(?!z)', d: latinDiacritical }, { l: 'tz', s: /ꜩ/gi, d: latinDiacritical }, { l: 'u', s: /[ⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ]/gi, d: latinDiacritical }, { l: 'v', s: /[ⓥvṽṿʋꝟʌ]/gi, e: 'v(?!y)', d: latinDiacritical }, { l: 'vy', s: /ꝡ/gi, d: latinDiacritical }, { l: 'w', s: /[ⓦwẁẃŵẇẅẘẉⱳ]/gi, d: latinDiacritical }, { l: 'x', s: /[ⓧxẋẍ]/gi, d: latinDiacritical }, { l: 'y', s: /[ⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ]/gi, d: latinDiacritical }, { l: 'z', s: /[ⓩzźẑżžẓẕƶȥɀⱬꝣ]/gi, d: latinDiacritical }, // Japanese - Hiragana/Katakana { l: 'あ', s: /[あアぁァ]゙?/gi }, { l: 'い', s: /[いイぃィ]゙?/gi }, { l: 'う', s: /[うウぅゥゔヴ]゙?/gi }, { l: 'え', s: /[えエぇェ]゙?/gi }, { l: 'お', s: /[おオぉォ]゙?/gi }, { l: 'か', s: /[かカがガゕヵ]゙?/gi }, { l: 'き', s: /[きキぎギ]゙?/gi }, { l: 'く', s: /[くクぐグ]゙?/gi }, { l: 'け', s: /[けケげゲゖヶ]゙?/gi }, { l: 'こ', s: /[こコごゴ]゙?/gi }, { l: 'さ', s: /[さサざザ]゙?/gi }, { l: 'し', s: /[しシじジ]゙?/gi }, { l: 'す', s: /[すスずズ]゙?/gi }, { l: 'せ', s: /[せセぜゼ]゙?/gi }, { l: 'そ', s: /[そソぞゾ]゙?/gi }, { l: 'た', s: /[たタだダ]゙?/gi }, { l: 'ち', s: /[ちチぢヂ]゙?/gi }, { l: 'つ', s: /[つツっッづヅ]゙?/gi }, { l: 'て', s: /[てテでデ]゙?/gi }, { l: 'と', s: /[とトどド]゙?/gi }, { l: 'な', s: /ナ/gi }, { l: 'に', s: /ニ/gi }, { l: 'ぬ', s: /ヌ/gi }, { l: 'ね', s: /ネ/gi }, { l: 'の', s: /ノ/gi }, { l: 'は', s: /[はハばバぱパ][゙゚]?/gi }, { l: 'ひ', s: /[ひヒびビぴピ][゙゚]?/gi }, { l: 'ふ', s: /[ふフぶブぷプ][゙゚]?/gi }, { l: 'へ', s: /[へヘべベぺペ][゙゚]?/gi }, { l: 'ほ', s: /[ほホぼボぽポ][゙゚]?/gi }, { l: 'ま', s: /マ/gi }, { l: 'み', s: /ミ/gi }, { l: 'む', s: /ム/gi }, { l: 'め', s: /メ/gi }, { l: 'も', s: /モ/gi }, { l: 'や', s: /[ヤゃャ]/gi }, { l: 'ゆ', s: /[ユゅュ]/gi }, { l: 'よ', s: /[ヨょョ]/gi }, { l: 'ら', s: /ラ/gi }, { l: 'り', s: /リ/gi }, { l: 'る', s: /ル/gi }, { l: 'れ', s: /レ/gi }, { l: 'ろ', s: /ロ/gi }, { l: 'わ', s: /[わワゎヮヷ]゙?/gi }, { l: 'ゐ', s: /[ゐヰヸ]゙?/gi }, { l: 'ゑ', s: /[ゑヱヹ]゙?/gi }, { l: 'を', s: /[をヲヺ]゙?/gi }, { l: 'ん', s: /[ン]/gi }, // Cyrillic { l: 'а', s: /[аӐӑӒӓӔӕ]/gi }, { l: 'г', s: /[гѓґҐғҒҕҔ]/gi }, { l: 'д', s: /[дђѐ]/gi }, { l: 'е', s: /[еѐёЁӖӗ]/gi }, { l: 'ж', s: /[жӁӂӜӝ]/gi }, { l: 'з', s: /[зӞӟ]/gi }, { l: 'и', s: /[иѝӢӣӤӥ]/gi }, { l: 'й', s: /[йЙ]/gi }, { l: 'к', s: /[кќҚқҜҝҞҟҠҡ]/gi }, { l: 'л', s: /[лљЉ]/gi }, { l: 'н', s: /[нњЊҢңӉӊ]/gi }, { l: 'о', s: /[оӦӧӨӫ]/gi }, { l: 'с', s: /[сҪҫ]/gi }, { l: 'т', s: /[тћЋ]/gi }, { l: 'у', s: /[уўЎӮӯӰӱӲӳ]/gi }, { l: 'х', s: /[хҲҳӇӈ]/gi }, { l: 'ч', s: /[чҴҵӴӵ]/gi }, { l: 'ы', s: /[ыӸӹ]/gi }, // Greek { l: 'α', s: /[αάἀἁἂἃἄἅἆἇὰάᾀᾁᾂᾃᾄᾅᾆᾇᾰᾱᾲᾳᾴᾶᾷ]/gi }, { l: 'β', s: /[βϐ]/gi }, { l: 'η', s: /[ηήἠἡἢἣἤἥἦἧὴήᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄῆῇ]/gi }, { l: 'θ', s: /[θϑ]/gi }, { l: 'ι', s: /[ιίϊΐἰἱἲἳἴἵἶἷὶίῐῑῒΐῖῗ]/gi }, { l: 'κ', s: /[κϰ]/gi }, { l: 'ο', s: /[οόὀὁὂὃὄὅὸό]/gi }, { l: 'π', s: /[πϖ]/gi }, { l: 'ρ', s: /[ρϱῤῥ]/gi }, { l: 'σ', s: /[σςϲ]/gi }, { l: 'υ', s: /[υύϋΰὐὑὒὓὔὕὖὗὺύῠῡῢΰῦῧ]/gi }, { l: 'φ', s: /[φϕ]/gi }, { l: 'ω', s: /[ωώὠὡὢὣὤὥὦὧὼώᾠᾡᾢᾣᾤᾥᾦᾧῲῳῴῶῷ]/gi }, // Arabic { l: 'ا', s: /[اأإآٱ]/gi, d: arabicDiacritical }, { l: 'ب', s: /ب/gi, d: arabicDiacritical }, { l: 'ت', s: /[تة]/gi, d: arabicDiacritical }, { l: 'ث', s: /ث/gi, d: arabicDiacritical }, { l: 'ج', s: /ج/gi, d: arabicDiacritical }, { l: 'ح', s: /ح/gi, d: arabicDiacritical }, { l: 'خ', s: /خ/gi, d: arabicDiacritical }, { l: 'د', s: /د/gi, d: arabicDiacritical }, { l: 'ذ', s: /ذ/gi, d: arabicDiacritical }, { l: 'ر', s: /ر/gi, d: arabicDiacritical }, { l: 'ز', s: /ز/gi, d: arabicDiacritical }, { l: 'س', s: /س/gi, d: arabicDiacritical }, { l: 'ش', s: /ش/gi, d: arabicDiacritical }, { l: 'ص', s: /ص/gi, d: arabicDiacritical }, { l: 'ض', s: /ض/gi, d: arabicDiacritical }, { l: 'ط', s: /ط/gi, d: arabicDiacritical }, { l: 'ظ', s: /ظ/gi, d: arabicDiacritical }, { l: 'ع', s: /ع/gi, d: arabicDiacritical }, { l: 'غ', s: /غ/gi, d: arabicDiacritical }, { l: 'ف', s: /ف/gi, d: arabicDiacritical }, { l: 'ق', s: /ق/gi, d: arabicDiacritical }, { l: 'ك', s: /[كک]/gi, d: arabicDiacritical }, { l: 'ل', s: /ل/gi, d: arabicDiacritical }, { l: 'م', s: /م/gi, d: arabicDiacritical }, { l: 'ن', s: /ن/gi, d: arabicDiacritical }, { l: 'ه', s: /[هە]/gi, d: arabicDiacritical }, { l: 'و', s: /[وؤ]/gi, d: arabicDiacritical }, { l: 'ي', s: /[يىئ]/gi, d: arabicDiacritical }, // Hebrew { l: 'א', s: /א/gi, d: hebrewDiacritical }, { l: 'ב', s: /ב/gi, d: hebrewDiacritical }, { l: 'ג', s: /ג/gi, d: hebrewDiacritical }, { l: 'ד', s: /ד/gi, d: hebrewDiacritical }, { l: 'ה', s: /ה/gi, d: hebrewDiacritical }, { l: 'ו', s: /ו/gi, d: hebrewDiacritical }, { l: 'ז', s: /ז/gi, d: hebrewDiacritical }, { l: 'ח', s: /ח/gi, d: hebrewDiacritical }, { l: 'ט', s: /ט/gi, d: hebrewDiacritical }, { l: 'י', s: /י/gi, d: hebrewDiacritical }, { l: 'כ', s: /[כך]/gi, d: hebrewDiacritical }, { l: 'ל', s: /ל/gi, d: hebrewDiacritical }, { l: 'מ', s: /[םמ]/gi, d: hebrewDiacritical }, { l: 'נ', s: /[ןנ]/gi, d: hebrewDiacritical }, { l: 'ס', s: /ס/gi, d: hebrewDiacritical }, { l: 'ע', s: /ע/gi, d: hebrewDiacritical }, { l: 'פ', s: /[פף]/gi, d: hebrewDiacritical }, { l: 'צ', s: /[ץצ]/gi, d: hebrewDiacritical }, { l: 'ק', s: /ק/gi, d: hebrewDiacritical }, { l: 'ר', s: /ר/gi, d: hebrewDiacritical }, { l: 'ש', s: /ש/gi, d: hebrewDiacritical }, { l: 'ת', s: /ת/gi, d: hebrewDiacritical }, ]; const defaultMinCountForSearch = 6; const protectRegexp = new RegExp('[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]', 'g'); /** * Shared base for the <ng-option> and <ng-group> directives. * * Holds the inputs common to both (classes, templateId, data, dir) and the projected-content * reactivity: plain text content (interpolation in the element body) is not a tracked signal, so * the host component dirty-checks it in ngDoCheck and pushes changes into {@link _projectedContent}, * which the rebuild effect depends on through {@link _resolveLabel}. */ class Select2ContentDirective { constructor() { this._elementRef = inject((ElementRef)); /** Additional CSS classes */ this.classes = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ [])); /** Template id */ this.templateId = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "templateId" }] : /* istanbul ignore next */ [])); /** Arbitrary data attached to the option/group */ this.data = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ [])); /** Force text direction */ this.dir = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ [])); /** * Reactive trigger for the projected text content (interpolation in the element body). * The host component dirty-checks the DOM in its ngDoCheck and updates this signal when the * rendered text changes, so the component's rebuild effect re-runs even though plain text * content is not otherwise a tracked dependency. */ this._projectedContent = signal(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_projectedContent" }] : /* istanbul ignore next */ [])); } /** Read the host element's rendered text content (innerHTML, then textContent, then ''). */ _readContent() { const el = this._elementRef.nativeElement; return el.innerHTML?.trim() || el.textContent?.trim() || ''; } /** * Re-read the host element's rendered content and update {@link _projectedContent} when it * changed. Returns true if a change was detected. Called from the host component's ngDoCheck. */ _refreshProjectedContent() { const content = this._readContent(); if (content !== this._projectedContent()) { this._projectedContent.set(content); return true; } return false; } /** * Resolve the label: prefer the explicit [label] input, then the cached projected content, * then a one-off DOM read. Reading _projectedContent() registers it as a dependency of the * rebuild effect so interpolation/content changes propagate; the cached value avoids a second * DOM read, and _readContent() only runs on the initial pass. */ _resolveLabel(label) { return label ?? this._projectedContent() ?? this._readContent(); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2ContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: Select2ContentDirective, isStandalone: true, inputs: { classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null }, templateId: { classPropertyName: "templateId", publicName: "templateId", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2ContentDirective, decorators: [{ type: Directive }], propDecorators: { classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }], templateId: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateId", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } }); /** * Directive representing a single option inside a <ng-select2> or <ng-group>. * * Usage: * ```html * <ng-select2> * <ng-option value="foo">Foo</ng-option> * <ng-option value="bar" [disabled]="true">Bar</ng-option> * </ng-select2> * ``` */ class Select2OptionDirective extends Select2ContentDirective { constructor() { super(...arguments); /** The option value */ this.value = input.required(/* @ts-ignore */ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ [])); /** Explicit label — falls back to the element's text content if omitted */ this.label = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ [])); /** Whether the option is disabled */ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Template selection id */ this.templateSelectionId = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "templateSelectionId" }] : /* istanbul ignore next */ [])); /** Hide this option */ this.hide = input(false, { ...(ngDevMode ? { debugName: "hide" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); } /** Build a plain Select2Option object from the current input values */ toOption() { return { value: this.value(), label: this._resolveLabel(this.label()), disabled: this.disabled() || undefined, classes: this.classes(), templateId: this.templateId(), templateSelectionId: this.templateSelectionId(), data: this.data(), hide: this.hide() || undefined, dir: this.dir(), }; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2OptionDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: Select2OptionDirective, isStandalone: true, selector: "ng-option", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, templateSelectionId: { classPropertyName: "templateSelectionId", publicName: "templateSelectionId", isSignal: true, isRequired: false, transformFunction: null }, hide: { classPropertyName: "hide", publicName: "hide", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2OptionDirective, decorators: [{ type: Directive, args: [{ selector: 'ng-option' }] }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], templateSelectionId: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateSelectionId", required: false }] }], hide: [{ type: i0.Input, args: [{ isSignal: true, alias: "hide", required: false }] }] } }); /** * Directive representing an option group inside a <ng-select2>. * * Usage: * ```html * <ng-select2> * <ng-group label="Fruits"> * <ng-option value="apple">Apple</ng-option> * <ng-option value="banana">Banana</ng-option> * </ng-group> * </ng-select2> * ``` */ class Select2GroupDirective extends Select2ContentDirective { constructor() { super(...arguments); /** The group label (required) */ this.label = input.required(/* @ts-ignore */ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ [])); /** Child <ng-option> directives nested inside this group */ this._ngOptions = contentChildren(Select2OptionDirective, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_ngOptions" }] : /* istanbul ignore next */ [])); } /** Build a plain Select2Group object from the current input values */ toGroup() { return { label: this._resolveLabel(this.label()), options: this._ngOptions().map(o => o.toOption()), classes: this.classes(), templateId: this.templateId(), data: this.data(), dir: this.dir(), }; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2GroupDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.1", type: Select2GroupDirective, isStandalone: true, selector: "ng-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, queries: [{ propertyName: "_ngOptions", predicate: Select2OptionDirective, isSignal: true }], usesInheritance: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2GroupDirective, decorators: [{ type: Directive, args: [{ selector: 'ng-group' }] }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], _ngOptions: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => Select2OptionDirective), { isSignal: true }] }] } }); class Select2Utils { static getOptionByValue(data, value) { for (const groupOrOption of data) { const options = groupOrOption.options; if (options) { for (const option of options) { if (option.value === value) { return option; } } } else if (groupOrOption.value === value) { return groupOrOption; } } return null; } static getOptionsByValue(data, value, multiple) { if (multiple) { const values = Array.isArray(value) ? value : []; const result = []; for (const v of values) { const option = Select2Utils.getOptionByValue(data, v); if (option) { result.push(option); } } return result; } return Select2Utils.getOptionByValue(data, value); } static getFirstAvailableOption(data) { for (const groupOrOption of data) { const options = groupOrOption.options; if (options) { for (const option of options) { if (!option.disabled) { return option; } } } else { const option = groupOrOption; if (!option.disabled) { return option; } } } return null; } static optionIsNotInFilteredData(filteredData, option) { if (Select2Utils.isNullOrUndefined(option)) { return true; } for (const groupOrOption of filteredData) { const options = groupOrOption.options; if (options && options.includes(option)) { return false; } else if (groupOrOption === option) { return false; } } return true; } static getPreviousOption(filteredData, hoveringOption) { let findIt = Select2Utils.isNullOrUndefined(hoveringOption); for (let i = filteredData.length - 1; i >= 0; i--) { const groupOrOption = filteredData[i]; const options = groupOrOption.options; if (options) { for (let j = options.length - 1; j >= 0; j--) { const option = options[j]; if (findIt && !option.disabled && !option.hide) { return option; } if (!findIt) { findIt = option === hoveringOption; } } } else { const option = groupOrOption; if (findIt && !option.disabled && !option.hide) { return option; } if (!findIt) { findIt = option === hoveringOption; } } } return null; } static getNextOption(filteredData, hoveringOption) { let findIt = Select2Utils.isNullOrUndefined(hoveringOption); if (filteredData) { for (const groupOrOption of filteredData) { const options = groupOrOption.options; if (options) { for (const option of options) { if (findIt) { if (!option.disabled && !option.hide) { return option; } } else { findIt = option === hoveringOption; } } } else { const option = groupOrOption; if (findIt) { if (!option.disabled && !option.hide) { return option; } } else { findIt = option === hoveringOption; } } } } return null; } static getFirstOption(filteredData) { const firstElement = filteredData[0]; if (this.isOption(firstElement)) { return firstElement; } else { return firstElement.options[0] ?? null; } } static getLastOption(filteredData) { const lastElement = filteredData.at(-1); if (!lastElement) { return null; } if (this.isOption(lastElement)) { return lastElement; } else { return lastElement.options.at(-1) ?? null; } } static isGroup(element) { return !!element.options; } static isOption(element) { return !this.isGroup(element); } static getReduceData(data, maxResults = 0) { if (maxResults > 0) { let counter = 0; const result = []; // debugger; for (const groupOrOption of data) { const options = groupOrOption.options; if (options) { const group = { ...groupOrOption, options: [], }; result.push(group); for (const item of options) { group.options.push(item); counter++; if (counter === maxResults) { return { result, reduce: true }; } } } else { result.push(groupOrOption); counter++; } if (counter === maxResults) { return { result, reduce: true }; } } return { result, reduce: false }; } else { return { result: data, reduce: false }; } } static getFilteredData(data, searchText, editPattern) { if (searchText) { const result = []; for (const groupOrOption of data) { const options = groupOrOption.options; if (options) { if (options.some(group => Select2Utils.containSearchText(group.label, searchText, editPattern))) { const filteredOptions = options.filter(group => Select2Utils.containSearchText(group.label, searchText, editPattern)); result.push({ ...groupOrOption, options: filteredOptions, }); } } else if (Select2Utils.containSearchText(groupOrOption.label, searchText, editPattern)) { result.push(groupOrOption); } } return result; } else { return data; } } static getFilteredSelectedData(data, selectedOptions) { const result = []; for (const groupOrOption of data) { const options = groupOrOption.options; if (options) { const filteredOptions = options.filter(group => Select2Utils.isSelected(selectedOptions, group, true) === 'false'); if (filteredOptions.length) { result.push({ ...groupOrOption, options: filteredOptions, }); } } else if (Select2Utils.isSelected(selectedOptions, groupOrOption, true) === 'false') { result.push(groupOrOption); } } return result; } static isSearchboxHidden(data, minCountForSearch) { if (minCountForSearch === undefined || minCountForSearch === null || isNaN(+minCountForSearch)) { minCountForSearch = defaultMinCountForSearch; } const optionCount = Select2Utils.getOptionsCount(data); return optionCount < +minCountForSearch; } static isSelected(options, option, multiple) { return multiple ? options && options.some(op => op.value === option.value) ? 'true' : 'false' : options && option.value === options.value ? 'true' : 'false'; } static removeSelection(options, option) { for (let i = 0; i < options.length; i++) { if (options[i].value === option.value) { options.splice(i, 1); return; } } } static getOptionsCount(data) { let count = 0; if (Array.isArray(data)) { for (const groupOrOption of data) { const options = groupOrOption.options; count += options ? options.length : 1; } } return count; } static isNullOrUndefined(value) { return value === null || value === undefined; } static containSearchText(label, searchText, editPattern) { return (Select2Utils.formatSansUnicode(label).match(new RegExp(Select2Utils.formatPattern(searchText, editPattern), 'i')) !== null); } static protectPattern(str) { return str.replace(protectRegexp, '\\$&'); } static formatSansUnicode(str) { for (const unicodePattern of unicodePatterns) { str = str.replace(unicodePattern.s, unicodePattern.l); } return str; } static patternUnicode(str) { for (const unicodePattern of unicodePatterns) { const pattern = unicodePattern.s.toString().replace('/gi', '').substring(1); str = str.replace(new RegExp(`((${unicodePattern.e ?? unicodePattern.l}|${pattern})${unicodePattern.d?.pattern ?? ''})`, 'gi'), `((${unicodePattern.l}|${pattern})${unicodePattern.d?.tmp ?? ''})`); } str = str .replaceAll(latinDiacritical.tmp, latinDiacritical.pattern) .replaceAll(arabicDiacritical.tmp, arabicDiacritical.pattern) .replaceAll(hebrewDiacritical.tmp, hebrewDiacritical.pattern); return str; } static formatPattern(str, editPattern) { str = Select2Utils.formatSansUnicode(Select2Utils.protectPattern(str)); if (editPattern && typeof editPattern === 'function') { str = editPattern(str); } return str; } } class Select2HighlightPipe { constructor() { this.sanitizer = inject(DomSanitizer); } transform(value, search, disabled = false) { if (!value || !search || disabled) { return value ?? ''; } const escapedSearch = Select2Utils.patternUnicode(Select2Utils.protectPattern(search)); const result = value.replace(new RegExp(`(${escapedSearch})`, 'gi'), '<span class="select2-highlight-text">$1</span>'); return this.sanitizer.bypassSecurityTrustHtml(result); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2HighlightPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } /** @nocollapse */ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.1", ngImport: i0, type: Select2HighlightPipe, isStandalone: true, name: "highlightText" }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2HighlightPipe, decorators: [{ type: Pipe, args: [{ name: 'highlightText' }] }] }); class Select2Hint { /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2Hint, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: Select2Hint, isStandalone: true, selector: "select2-hint, ng-select2-hint", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2Hint, decorators: [{ type: Directive, args: [{ selector: 'select2-hint, ng-select2-hint' }] }] }); class Select2Label { /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2Label, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: Select2Label, isStandalone: true, selector: "select2-label, ng-select2-label", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: Select2Label, decorators: [{ type: Directive, args: [{ selector: 'select2-label, ng-select2-label' }] }] }); let nextUniqueId = 0; const OPEN_KEYS_NATIVE = ['Enter', ' ']; const CLOSE_KEYS_NATIVE = ['ArrowDown', 'ArrowUp', 'Home', 'End', 'PageUp', 'PageDown']; const OPEN_KEYS = ['ArrowDown', 'ArrowUp', 'Enter', ' ', 'Home', 'End', 'PageUp', 'PageDown']; const ON_OPEN_KEYS = ['Home', 'End', 'PageUp', 'PageDown']; const CLOSE_KEYS = ['Escape', 'Tab', { key: 'ArrowUp', altKey: true }]; class Select2 { get select2Options() { return this.multiple() ? (this.selectedOption ?? []) : []; } get select2Option() { return this.multiple() ? null : this.selectedOption; } get searchText() { return this.innerSearchText; } set searchText(text) { this.innerSearchText = text; } get disabledState() { return this._control?.disabled ?? this._disabled; } get resultsElement() { const container = this.resultContainer(); return container ? container.nativeElement : undefined; } /** Tab index for the element. */ get _tabIndex() { return this.disabledState ? -1 : this.tabIndex(); } constructor() { this._viewportRuler = inject(ViewportRuler); this._changeDetectorRef = inject(ChangeDetectorRef); this._parentForm = inject(NgForm, { optional: true }); this._parentFormGroup = inject(FormGroupDirective, { optional: true }); this._control = inject(NgControl, { optional: true, self: true }); this._uid = `select2-${nextUniqueId++}`; // ----------------------- signal-input /** data of options & option groups */ this.data = input([], /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ [])); /** minimum characters to start filter search */ this.minCharForSearch = input(0, { ...(ngDevMode ? { debugName: "minCharForSearch" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** text placeholder */ this.displaySearchStatus = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "displaySearchStatus" }] : /* istanbul ignore next */ [])); /** text placeholder */ this.placeholder = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ [])); /** in multiple: maximum selection element (0 = no limit) */ this.limitSelection = input(0, { ...(ngDevMode ? { debugName: "limitSelection" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** dropdown position */ this.listPosition = input('below', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "listPosition" }] : /* istanbul ignore next */ [])); /** overlay with CDK Angular position */ this.overlay = input(false, { ...(ngDevMode ? { debugName: "overlay" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** select one or more item */ this.multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** drag'n drop list of items in multiple */ this.multipleDrag = input(false, { ...(ngDevMode ? { debugName: "multipleDrag" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** use the material style */ this.styleMode = input('default', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "styleMode" }] : /* istanbul ignore next */ [])); /** message when no result */ this.noResultMessage = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "noResultMessage" }] : /* istanbul ignore next */ [])); /** maximum results limit (0 = no limit) */ this.maxResults = input(0, { ...(ngDevMode ? { debugName: "maxResults" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** message when maximum results */ this.maxResultsMessage = input('Too many results…', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "maxResultsMessage" }] : /* istanbul ignore next */ [])); /** infinite scroll distance */ this.infiniteScrollDistance = input(1.5, { ...(ngDevMode ? { debugName: "infiniteScrollDistance" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** infinite scroll distance */ this.infiniteScrollThrottle = input(150, { ...(ngDevMode ? { debugName: "infiniteScrollThrottle" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** infinite scroll activated */ this.infiniteScroll = input(false, { ...(ngDevMode ? { debugName: "infiniteScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** auto create if not exist */ this.autoCreate = input(false, { ...(ngDevMode ? { debugName: "autoCreate" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** no template for label selection */ this.noLabelTemplate = input(false, { ...(ngDevMode ? { debugName: "noLabelTemplate" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** use it for change the pattern of the filter search */ this.editPattern = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "editPattern" }] : /* istanbul ignore next */ [])); /** template(s) for formatting */ this.templates = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ [])); /** template for formatting selected option */ this.templateSelection = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "templateSelection" }] : /* istanbul ignore next */ [])); /** the max height of the results container when opening the select */ this.resultMaxHeight = input('200px', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "resultMaxHeight" }] : /* istanbul ignore next */ [])); /** Active Search event */ this.customSearchEnabled = input(false, { ...(ngDevMode ? { debugName: "customSearchEnabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** minimal data of show the search field */ this.minCountForSearch = input(undefined, { ...(ngDevMode ? { debugName: "minCountForSearch" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** Unique id of the element. */ this.id = input(this._uid, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ [])); /** Unique id of label element. */ this.idLabel = computed(() => `${this.id()}-label`, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "idLabel" }] : /* istanbul ignore next */ [])); /** Unique id of combo element. */ this.idCombo = computed(() => `${this.id()}-combo`, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "idCombo" }] : /* istanbul ignore next */ [])); /** Unique id of options element. */ this.idOptions = computed(() => `${this.id()}-options`, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "idOptions" }] : /* istanbul ignore next */ [])); /** Unique id of overlay element. */ this.idOverlay = computed(() => `${this.id()}-overlay`, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "idOverlay" }] : /* istanbul ignore next */ [])); /** Whether the element is required. */ this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Whether selected items should be hidden. */ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Whether items are hidden when has. */ this.hideSelectedItems = input(false, { ...(ngDevMode ? { debugName: "hideSelectedItems" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Whether the element is readonly. */ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** The input element's value. */ this.value = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ [])); /** Tab index for the select2 element. */ this.tabIndex = input(0, { ...(ngDevMode ? { debugName: "tabIndex" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** reset with no selected value */ this.resettable = input(false, { ...(ngDevMode ? { debugName: "resettable" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** selected value when × is clicked */ this.resetSelectedValue = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "resetSelectedValue" }] : /* istanbul ignore next */ [])); /** like native select keyboard navigation (only single mode) */ this.nativeKeyboard = input(false, { ...(ngDevMode ? { debugName: "nativeKeyboard" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** highlight search text */ this.highlightText = input(false, { ...(ngDevMode ? { debugName: "highlightText" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** grid: item by line * * 0 = no grid * * number = item by line (4) * * string = minimal size item (100px) */ this.grid = input('', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "grid" }] : /* istanbul ignore next */ [])); /** * Replace selection by a text * * if string: `%size%` = total selected options * * if function: juste show the string */ this.selectionOverride = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "selectionOverride" }] : /* istanbul ignore next */ [])); /** force selection on one line */ this.selectionNoWrap = input(false, { ...(ngDevMode ? { debugName: "selectionNoWrap" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Add an option to select or remove all (if all is selected) */ this.showSelectAll = input(false, { ...(ngDevMode ? { debugName: "showSelectAll" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Show a checkbox next to each option */ this.showOptionCheckbox = input(false, { ...(ngDevMode ? { debugName: "showOptionCheckbox" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** Text for remove all options */ this.removeAllText = input('Remove all', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "removeAllText" }] : /* istanbul ignore next */ [])); /** Text for select all options */ this.selectAllText = input('Select all', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "selectAllText" }] : /* istanbul ignore next */ [])); // -- WAI related inputs --- /** title attribute applied to the input */ this.title = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ [])); /** aria-labelledby attribute applied to the input, to specify en external label */ this.ariaLabelledby = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ [])); /** aria-describedby attribute applied to the input */ this.ariaDescribedby = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "ariaDescribedby" }] : /* istanbul ignore next */ [])); /** aria-invalid attribute applied to the input, to force error state */ this.ariaInvalid = input(false, { ...(ngDevMode ? { debugName: "ariaInvalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** description of the reset button when using 'resettable'. Default value : 'Reset' */ this.ariaResetButtonDescription = input('Reset', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "ariaResetButtonDescription" }] : /* istanbul ignore next */ [])); // ----------------------- output this.update = output(); this.autoCreateItem = output(); this.open = output(); this.close = output(); this.focus = output(); this.blur = output(); this.search = output(); this.scroll = output(); this.removeOption = output(); // ----------------------- signal viewChild this.cdkConnectedOverlay = viewChild.required(CdkConnectedOverlay); this.selection = viewChild.required('selection'); this.resultContainer = viewChild('results', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "resultContainer" }] : /* istanbul ignore next */ [])); this.results = viewChildren('result', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "results" }] : /* istanbul ignore next */ [])); this.searchInput = viewChild('searchInput', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ [])); this.dropdown = viewChild('dropdown', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "dropdown" }] : /* istanbul ignore next */ [])); // ----------------------- content children (ng-option / ng-group template mode) /** Top-level <ng-option> elements (not inside a <ng-group>) */ this._ngOptions = contentChildren(Select2OptionDirective, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_ngOptions" }] : /* istanbul ignore next */ [])); /** <ng-group> elements */ this._ngGroups = contentChildren(Select2GroupDirective, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_ngGroups" }] : /* istanbul ignore next */ [])); // ----------------------- internal var this.classMaterial = computed(() => this.styleMode() === 'material', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "classMaterial" }] : /* istanbul ignore next */ [])); this.classNostyle = computed(() => this.styleMode() === 'noStyle', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "classNostyle" }] : /* istanbul ignore next */ [])); this.classBorderless = computed(() => this.styleMode() === 'borderless', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "classBorderless" }] : /* istanbul ignore next */ [])); this.select2above = computed(() => !this.overlay() ? this.listPosition() === 'above' : this._isAbobeOverlay(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "select2above" }] : /* istanbul ignore next */ [])); this.selectedOption = null; this.isOpen = false; /** Whether the element is focused or not. */ this.focused = false; this.filteredData = signal(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "filteredData" }] : /* istanbul ignore next */ [])); this.overlayWidth = ''; this.overlayHeight = ''; this._positions = computed(() => { switch (this.listPosition()) { case 'above': return [ new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' }), ]; case 'auto': return [ new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }), new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' }), ]; default: return [ new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }), ]; } }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_positions" }] : /* istanbul ignore next */ [])); this.hoveringOption = signal(null, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "hoveringOption" }] : /* istanbul ignore next */ [])); this.hoveringOptionId = computed(() => this.getElementId(this.hoveringOption()), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "hoveringOptionId" }] : /* istanbul ignore next */ [])); this.innerSearchText = ''; this._stateChanges = new Subject(); this._data = []; this._disabled = false; this._destroyed = false; this._value = null; this._overlayPosition = signal(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_overlayPosition" }] : /*