ngwr 9.0.1 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,9 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { TemplateRef } from '@angular/core';
2
+ import { TemplateRef, ComponentRef, InjectionToken } from '@angular/core';
3
+ import { ComponentType } from '@angular/cdk/portal';
4
+ import { ConfigurableFocusTrap } from '@angular/cdk/a11y';
5
+ import { OverlayRef } from '@angular/cdk/overlay';
6
+ import { ReplaySubject } from 'rxjs';
3
7
 
4
8
  /**
5
9
  * @license
@@ -10,6 +14,44 @@ import { TemplateRef } from '@angular/core';
10
14
  /** Side of the viewport the drawer slides in from. */
11
15
  type WrDrawerPosition = 'left' | 'right' | 'top' | 'bottom';
12
16
 
17
+ /**
18
+ * @license
19
+ *
20
+ * Use of this source code is governed by an MIT-style license that can be
21
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
22
+ */
23
+
24
+ /**
25
+ * Options accepted by `WrDrawerManager.open()`.
26
+ *
27
+ * Mirrors the `<wr-drawer>` inputs, minus the ones that need the component's
28
+ * own wrapper markup (`showHandle` / swipe-to-dismiss).
29
+ */
30
+ interface WrDrawerOptions<D = unknown> {
31
+ /** Data payload exposed to the drawer content via `WR_DRAWER_DATA`. */
32
+ readonly data?: D;
33
+ /** Side the drawer slides in from. @default 'right' */
34
+ readonly position?: WrDrawerPosition;
35
+ /** Width when position is left/right. Any CSS length. @default '20rem' */
36
+ readonly width?: string;
37
+ /** Height when position is top/bottom. Any CSS length. @default '16rem' */
38
+ readonly height?: string;
39
+ /** Upper cap on height (top/bottom positions). Any CSS length. @default null (no cap) */
40
+ readonly maxHeight?: string | null;
41
+ /** Round the leading corners — the edge facing the viewport interior. @default false */
42
+ readonly rounded?: boolean;
43
+ /** Pad the trailing edge with `env(safe-area-inset-*)`. @default false */
44
+ readonly safeArea?: boolean;
45
+ /** Show the dimming backdrop. @default true */
46
+ readonly hasBackdrop?: boolean;
47
+ /** When `true`, clicks on the backdrop close the drawer. @default true */
48
+ readonly closeOnBackdropClick?: boolean;
49
+ /** When `true`, the Escape key closes the drawer. @default true */
50
+ readonly closeOnEscape?: boolean;
51
+ /** Extra CSS class(es) added to the panel. */
52
+ readonly panelClass?: string | readonly string[];
53
+ }
54
+
13
55
  /**
14
56
  * Side panel that slides in from an edge of the viewport. Two-way binds
15
57
  * `open` and renders into a CDK overlay so it sits above page content.
@@ -92,6 +134,170 @@ declare class WrDrawer {
92
134
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDrawer, "wr-drawer", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "showHandle": { "alias": "showHandle"; "required": false; "isSignal": true; }; "safeArea": { "alias": "safeArea"; "required": false; "isSignal": true; }; "hasBackdrop": { "alias": "hasBackdrop"; "required": false; "isSignal": true; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*"], true, never>;
93
135
  }
94
136
 
137
+ /**
138
+ * @license
139
+ *
140
+ * Use of this source code is governed by an MIT-style license that can be
141
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
142
+ */
143
+
144
+ /**
145
+ * Handle returned by `WrDrawerManager.open()`.
146
+ *
147
+ * Wraps the underlying `OverlayRef` and tracks the close result. It is also
148
+ * provided inside the drawer's own injector, so the projected content can
149
+ * inject it and close itself — the counterpart to `[wrDrawerClose]` when the
150
+ * close is programmatic (after a save succeeds, say) rather than a click.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * // Caller side.
155
+ * const ref = drawers.open<ChatComponent, boolean>(ChatComponent, { position: 'right' });
156
+ * const result = await ref.awaitClose(); // boolean | undefined
157
+ * ```
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * // Content side — the drawer closes itself.
162
+ * @Component({...})
163
+ * export class ChatComponent {
164
+ * private readonly ref = inject(WrDrawerRef);
165
+ *
166
+ * send(): void {
167
+ * this.store.send(this.draft());
168
+ * this.ref.close(true);
169
+ * }
170
+ * }
171
+ * ```
172
+ */
173
+ declare class WrDrawerRef<C, R = unknown> {
174
+ private readonly _overlayRef;
175
+ /**
176
+ * Emits the close result once and completes.
177
+ *
178
+ * A `ReplaySubject`, not a plain `Subject`, so the result survives a late
179
+ * subscriber: content can close itself before `open()` has even returned, and
180
+ * `awaitClose()` may be called long after the dismissal — both would otherwise
181
+ * see only `complete` and resolve `undefined`.
182
+ */
183
+ readonly closed: ReplaySubject<R | undefined>;
184
+ /** @internal */
185
+ componentRef: ComponentRef<C> | null;
186
+ /** @internal */
187
+ focusTrap: ConfigurableFocusTrap | null;
188
+ /** @internal */
189
+ previouslyFocused: HTMLElement | null;
190
+ constructor(_overlayRef: OverlayRef);
191
+ /** The instantiated drawer component. */
192
+ get componentInstance(): C;
193
+ private isClosed;
194
+ /** Close the drawer, optionally returning a result. */
195
+ close(result?: R): void;
196
+ private teardown;
197
+ /** Resolves with the close result when the drawer is dismissed. */
198
+ awaitClose(): Promise<R | undefined>;
199
+ /** Underlying overlay ref — escape hatch for advanced cases. */
200
+ get overlayRef(): OverlayRef;
201
+ }
202
+
203
+ /**
204
+ * Opens drawer components in an isolated NGWR overlay — the programmatic
205
+ * counterpart to `<wr-drawer [(open)]="…">`.
206
+ *
207
+ * Use the component when the drawer is part of a template and its open state
208
+ * is a signal you already own; use this service when the caller doesn't own
209
+ * the markup (opening a chat panel from a toolbar action, from an effect, from
210
+ * a route guard) or when you need the close result.
211
+ *
212
+ * Uses `WR_OVERLAY` so it composes cleanly with `provideWrOverlay()`
213
+ * — drawers render into NGWR's own overlay container and never collide
214
+ * with other CDK consumers (Material, NG-ZORRO, etc.).
215
+ *
216
+ * `showHandle` / swipe-to-dismiss is component-only: it needs the drawer's own
217
+ * wrapper markup, which the service path replaces with your component.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * const drawers = inject(WrDrawerManager);
222
+ *
223
+ * const ref = drawers.open(ChatComponent, {
224
+ * data: { threadId },
225
+ * position: 'right',
226
+ * width: '28rem',
227
+ * });
228
+ *
229
+ * await ref.awaitClose();
230
+ * ```
231
+ *
232
+ * @see https://ngwr.dev/reference/components/drawer
233
+ */
234
+ declare class WrDrawerManager {
235
+ private readonly overlay;
236
+ private readonly scrollStrategies;
237
+ private readonly parentInjector;
238
+ private readonly focusTrapFactory;
239
+ private readonly isBrowser;
240
+ open<C, R = unknown, D = unknown>(component: ComponentType<C>, options?: WrDrawerOptions<D>): WrDrawerRef<C, R>;
241
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDrawerManager, never>;
242
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<WrDrawerManager>;
243
+ }
244
+
245
+ /**
246
+ * @license
247
+ *
248
+ * Use of this source code is governed by an MIT-style license that can be
249
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
250
+ */
251
+
252
+ /**
253
+ * Token that exposes the `data` payload passed to `WrDrawerManager.open()`.
254
+ *
255
+ * @example
256
+ * ```ts
257
+ * @Component({...})
258
+ * export class ChatComponent {
259
+ * readonly data = inject<ChatData>(WR_DRAWER_DATA);
260
+ * }
261
+ * ```
262
+ */
263
+ declare const WR_DRAWER_DATA: InjectionToken<unknown>;
264
+
265
+ /**
266
+ * @license
267
+ *
268
+ * Use of this source code is governed by an MIT-style license that can be
269
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
270
+ */
271
+
272
+ /**
273
+ * Token exposing the open drawer's `WrDrawerRef` to components and
274
+ * directives rendered inside it (e.g. `[wrDrawerClose]`).
275
+ *
276
+ * **Prefer `inject(WrDrawerRef)`** — the ref is provided under the class token
277
+ * too, and the class path is the documented one. It already covers both cases
278
+ * you might reach for a token for: `inject(WrDrawerRef, { optional: true })`
279
+ * works for content that also renders outside a drawer, and
280
+ * `inject<WrDrawerRef<ChatComponent, boolean>>(WrDrawerRef)` types the generics
281
+ * without a cast.
282
+ *
283
+ * This token is the same object under a second key. It exists for the library's
284
+ * own directives (`[wrDrawerClose]`) and for swapping the provider out — a test
285
+ * stub, say — without touching the class.
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * @Component({...})
290
+ * export class ChatComponent {
291
+ * private readonly ref = inject<WrDrawerRef<ChatComponent, boolean>>(WrDrawerRef);
292
+ *
293
+ * dismiss(): void {
294
+ * this.ref.close(true);
295
+ * }
296
+ * }
297
+ * ```
298
+ */
299
+ declare const WR_DRAWER_REF: InjectionToken<WrDrawerRef<unknown, unknown>>;
300
+
95
301
  /**
96
302
  * Marks an element as the drawer's title row. Applies the `wr-drawer__title`
97
303
  * class so the drawer's stylesheet can lay it out alongside content and
@@ -147,17 +353,30 @@ declare class WrDrawerFooter {
147
353
  /**
148
354
  * Closes the parent drawer on click. Attach to any clickable element.
149
355
  *
356
+ * Works for both drawer flavours: inside `<wr-drawer>` it clears the
357
+ * component's `open` model, and inside a `WrDrawerManager.open()` drawer it
358
+ * closes the ref — optionally passing a `[wrDrawerClose]` value as the close
359
+ * result (the component flavour has no result to carry, so the value is
360
+ * ignored there).
361
+ *
150
362
  * @example
151
363
  * ```html
152
364
  * <wr-btn wrDrawerClose>Close</wr-btn>
365
+ * <wr-btn color="primary" [wrDrawerClose]="true">Save</wr-btn>
153
366
  * ```
154
367
  */
155
- declare class WrDrawerClose {
368
+ declare class WrDrawerClose<R = unknown> {
369
+ /**
370
+ * Value to pass to `close()` for service-opened drawers. When unset — or
371
+ * used as a bare attribute — the drawer closes with `undefined`.
372
+ */
373
+ readonly result: _angular_core.InputSignalWithTransform<R | undefined, "" | R | undefined>;
156
374
  private readonly drawer;
375
+ private readonly ref;
157
376
  protected close(): void;
158
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDrawerClose, never>;
159
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrDrawerClose, "[wrDrawerClose]", never, {}, {}, never, never, true, never>;
377
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDrawerClose<any>, never>;
378
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrDrawerClose<any>, "[wrDrawerClose]", never, { "result": { "alias": "wrDrawerClose"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
160
379
  }
161
380
 
162
- export { WrDrawer, WrDrawerClose, WrDrawerContent, WrDrawerFooter, WrDrawerTitle };
163
- export type { WrDrawerPosition };
381
+ export { WR_DRAWER_DATA, WR_DRAWER_REF, WrDrawer, WrDrawerClose, WrDrawerContent, WrDrawerFooter, WrDrawerManager, WrDrawerRef, WrDrawerTitle };
382
+ export type { WrDrawerOptions, WrDrawerPosition };
@@ -81,8 +81,18 @@ interface WrSelectContext {
81
81
  * no filter applied — options treat that as "show me".
82
82
  */
83
83
  readonly searchQuery: Signal<string>;
84
- /** True only when `mode="search"`. Options gate filtering on this. */
84
+ /** True only when `mode="search"`. */
85
85
  readonly isSearch: Signal<boolean>;
86
+ /**
87
+ * True when a filter is active — `mode="search"` or `[searchable]`. Options
88
+ * gate self-hiding on this.
89
+ */
90
+ readonly isSearchable: Signal<boolean>;
91
+ /**
92
+ * False when the option list is already query-scoped upstream (`[loader]` or
93
+ * `[serverSearch]`), in which case options must NOT self-hide.
94
+ */
95
+ readonly clientFilter: Signal<boolean>;
86
96
  /** Is the given option value currently selected? Handles both single and multi. */
87
97
  isSelected(value: unknown): boolean;
88
98
  /**
@@ -120,6 +130,11 @@ interface SelectedChip {
120
130
  * - `'tag'` — free-text + chips with `[separators]` / `[validate]` /
121
131
  * `[allowDuplicates]`. Replaces `<wr-chips-input>`.
122
132
  *
133
+ * `[searchable]` is orthogonal to the mode — it adds the type-ahead filter to
134
+ * `single` / `multi` without changing the value shape, which is how you get a
135
+ * searchable multi-select. Server-side search hangs off the `(searchChange)` output
136
+ * plus `[options]` / `[loading]`.
137
+ *
123
138
  * A signal-forms native control: it implements `FormValueControl<unknown>`, so
124
139
  * `[formField]` binds straight to its `value` model — no
125
140
  * `ControlValueAccessor` in between. `[(value)]` works standalone, and classic
@@ -139,6 +154,16 @@ interface SelectedChip {
139
154
  * <wr-option value="ts">TypeScript</wr-option>
140
155
  * <wr-option value="ng">Angular</wr-option>
141
156
  * </wr-select>
157
+ *
158
+ * <!-- Multi + type-ahead, options from a store -->
159
+ * <wr-select
160
+ * mode="multi"
161
+ * searchable
162
+ * [options]="results()"
163
+ * [loading]="pending()"
164
+ * [(value)]="categories"
165
+ * (searchChange)="store.search($event)"
166
+ * />
142
167
  * ```
143
168
  *
144
169
  * The legacy `[multi]="true"` boolean is still accepted but is now an
@@ -192,15 +217,44 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
192
217
  protected readonly isTag: _angular_core.Signal<boolean>;
193
218
  /** Convenience — `effectiveMode() === 'search'`. Exposed via context for options. */
194
219
  readonly isSearch: _angular_core.Signal<boolean>;
220
+ /**
221
+ * Add a type-ahead filter without changing the value shape — the missing
222
+ * multi-with-search combination, since `[mode]` picks exactly one shape:
223
+ *
224
+ * ```html
225
+ * <wr-select mode="multi" searchable [(value)]="categories">…</wr-select>
226
+ * ```
227
+ *
228
+ * On `multi` the trigger keeps its chips and grows an inline text field (the
229
+ * shape `tag` mode already uses); on `single` it is equivalent to
230
+ * `mode="search"`. Every search input (`[options]`, `[loader]`,
231
+ * `[debounceMs]`, `[minChars]`, `[virtualScroll]`, the `(searchChange)` output, …)
232
+ * applies either way. Ignored in `tag` mode, which owns its own input.
233
+ * @default false
234
+ */
235
+ readonly searchable: _angular_core.InputSignalWithTransform<boolean, any>;
236
+ /**
237
+ * Filtering is active — either `mode="search"` or `[searchable]`. Exposed via
238
+ * context so each `<wr-option>` can self-hide non-matching rows.
239
+ */
240
+ readonly isSearchable: _angular_core.Signal<boolean>;
241
+ /** The trigger *is* the search input: `mode="search"`, or a searchable single. */
242
+ protected readonly isSearchTrigger: _angular_core.Signal<boolean>;
243
+ /** Chips plus an inline search field — a searchable multi-select. */
244
+ protected readonly hasChipSearch: _angular_core.Signal<boolean>;
195
245
  /** WrSelectContext — resolved multi-selection flag for child options. */
196
246
  readonly multi: _angular_core.Signal<boolean>;
197
247
  /** Both multi and tag render chips on the trigger. */
198
248
  protected readonly hasChips: _angular_core.Signal<boolean>;
199
249
  /**
200
- * Search-mode query. Empty string = no filter. Exposed via context so
250
+ * The live search query. Empty string = no filter. Exposed via context so
201
251
  * each `<wr-option>` can self-hide non-matching rows.
252
+ *
253
+ * Two-way bindable, so the query can be owned or reset from outside:
254
+ * `[(searchQuery)]="query"`. For server-side search prefer the debounced
255
+ * {@link searchChange} output — `searchQueryChange` fires on every keystroke.
202
256
  */
203
- readonly searchQuery: _angular_core.WritableSignal<string>;
257
+ readonly searchQuery: _angular_core.ModelSignal<string>;
204
258
  /**
205
259
  * Search mode: dynamic option array. Each item is rendered as a
206
260
  * `<wr-option>` whose label comes from `[displayWith]`. Works
@@ -216,6 +270,21 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
216
270
  * Observables, Promises, and plain arrays.
217
271
  */
218
272
  readonly loader: _angular_core.InputSignal<WrSelectSearchLoader<unknown> | null>;
273
+ /**
274
+ * The option list is already scoped to the query upstream — skip the built-in
275
+ * client-side label filter. Set it when `[options]` is fed from a server via
276
+ * the {@link searchChange} output; the async `[loader]` path implies it.
277
+ *
278
+ * Without this, a server that ranks or fuzzy-matches (returning rows whose
279
+ * labels don't literally contain the query) would have those rows hidden
280
+ * again on the client. @default false
281
+ */
282
+ readonly serverSearch: _angular_core.InputSignalWithTransform<boolean, any>;
283
+ /**
284
+ * Whether the built-in label filter runs. Exposed via context so each
285
+ * `<wr-option>` knows whether to self-hide. @internal
286
+ */
287
+ readonly clientFilter: _angular_core.Signal<boolean>;
219
288
  /** Search mode: debounce (ms) applied to the loader. @default 250 */
220
289
  readonly debounceMs: _angular_core.InputSignalWithTransform<number, unknown>;
221
290
  /** Search mode: minimum query length before the panel opens / loader fires. @default 0 */
@@ -253,10 +322,42 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
253
322
  readonly loadingText: _angular_core.InputSignal<string | null>;
254
323
  protected readonly resolvedNoResults: _angular_core.Signal<string>;
255
324
  protected readonly resolvedLoading: _angular_core.Signal<string>;
325
+ /**
326
+ * Debounced search query, gated to searchable selects. Emits on every settled
327
+ * change — including the empty string when the field is cleared — so a
328
+ * store-backed option list can stay in sync and reset itself. `[debounceMs]`
329
+ * controls the delay; `[minChars]` does NOT gate it, for the same reason the
330
+ * `[loader]` path clears its results below that threshold.
331
+ *
332
+ * This is the hook for server-side search: dispatch on `(searchChange)`, feed
333
+ * the results back through `[options]` (plus `[serverSearch]`), and drive the
334
+ * panel's progress row with `[loading]`. Prefer it over the model's raw
335
+ * `(searchQueryChange)`, which fires on every keystroke.
336
+ *
337
+ * @example
338
+ * ```html
339
+ * <wr-select
340
+ * mode="search"
341
+ * serverSearch
342
+ * [options]="results()"
343
+ * [loading]="pending()"
344
+ * (searchChange)="store.search($event)"
345
+ * />
346
+ * ```
347
+ */
348
+ readonly searchChange: _angular_core.OutputEmitterRef<string>;
349
+ /**
350
+ * Show the panel's progress row. Independent of `[loader]`, which raises and
351
+ * lowers its own flag — use this when the options come from a store fed by
352
+ * the {@link searchChange} output. @default false
353
+ */
354
+ readonly loading: _angular_core.InputSignalWithTransform<boolean, any>;
256
355
  /** Search mode: results returned by the async loader. @internal */
257
356
  protected readonly loadedOptions: _angular_core.WritableSignal<readonly unknown[]>;
258
- /** Search mode: true while the loader is in flight. @internal */
259
- protected readonly loading: _angular_core.WritableSignal<boolean>;
357
+ /** True while the async `[loader]` is in flight. @internal */
358
+ private readonly loaderLoading;
359
+ /** Either flag shows the panel's progress row. @internal */
360
+ protected readonly isLoading: _angular_core.Signal<boolean>;
260
361
  /**
261
362
  * Tag mode: keys / characters that commit the current draft into a chip.
262
363
  * `'Enter'` is the key name; everything else is a literal character watched
@@ -331,7 +432,7 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
331
432
  * `dynamicOptions()` narrowed to the current search query. `dynamicOptions()`
332
433
  * is intentionally UNFILTERED (projected `<wr-option>` self-hide via CSS), so
333
434
  * the virtual path — which renders plain rows that can't self-hide — filters
334
- * here. Loader results are already query-scoped upstream.
435
+ * here. Loader / `serverSearch` results are already query-scoped upstream.
335
436
  */
336
437
  protected readonly filteredDynamicOptions: _angular_core.Signal<readonly unknown[]>;
337
438
  /**
@@ -376,12 +477,17 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
376
477
  /** Search mode: is this option hidden by the current query? @internal */
377
478
  private isOptionHidden;
378
479
  protected readonly panelTpl: _angular_core.Signal<TemplateRef<any>>;
379
- /** Tag-mode inline input. Present only when `mode="tag"`. @internal */
480
+ /** The inline input inside a chip trigger — tag mode or a searchable multi. @internal */
380
481
  protected readonly tagInputEl: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
381
482
  /** Search-mode inline input. Present only when `mode="search"`. @internal */
382
483
  protected readonly searchInputEl: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
383
484
  protected focusTagInput(): void;
384
485
  protected focusSearchInput(): void;
486
+ protected onChipsInput(event: Event): void;
487
+ protected onChipsKeydown(event: KeyboardEvent): void;
488
+ protected onChipsFocus(): void;
489
+ protected onChipsPaste(event: ClipboardEvent): void;
490
+ protected onChipsBlur(): void;
385
491
  protected onSearchInput(event: Event): void;
386
492
  protected onSearchFocus(): void;
387
493
  protected onSearchKey(event: KeyboardEvent): void;
@@ -426,7 +532,7 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
426
532
  private openOverlay;
427
533
  private closeOverlay;
428
534
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrSelect, never>;
429
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrSelect, "wr-select", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "clearLabel": { "alias": "clearLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "displayWith": { "alias": "displayWith"; "required": false; "isSignal": true; }; "loader": { "alias": "loader"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "minChars": { "alias": "minChars"; "required": false; "isSignal": true; }; "freeText": { "alias": "freeText"; "required": false; "isSignal": true; }; "virtualScroll": { "alias": "virtualScroll"; "required": false; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": false; "isSignal": true; }; "viewportHeight": { "alias": "viewportHeight"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "noResultsText": { "alias": "noResultsText"; "required": false; "isSignal": true; }; "loadingText": { "alias": "loadingText"; "required": false; "isSignal": true; }; "separators": { "alias": "separators"; "required": false; "isSignal": true; }; "allowDuplicates": { "alias": "allowDuplicates"; "required": false; "isSignal": true; }; "validate": { "alias": "validate"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "maxItems": { "alias": "maxItems"; "required": false; "isSignal": true; }; "maxTagCount": { "alias": "maxTagCount"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, ["projectedOptions"], ["*"], true, never>;
535
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrSelect, "wr-select", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "clearLabel": { "alias": "clearLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchQuery": { "alias": "searchQuery"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "displayWith": { "alias": "displayWith"; "required": false; "isSignal": true; }; "loader": { "alias": "loader"; "required": false; "isSignal": true; }; "serverSearch": { "alias": "serverSearch"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "minChars": { "alias": "minChars"; "required": false; "isSignal": true; }; "freeText": { "alias": "freeText"; "required": false; "isSignal": true; }; "virtualScroll": { "alias": "virtualScroll"; "required": false; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": false; "isSignal": true; }; "viewportHeight": { "alias": "viewportHeight"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "noResultsText": { "alias": "noResultsText"; "required": false; "isSignal": true; }; "loadingText": { "alias": "loadingText"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "separators": { "alias": "separators"; "required": false; "isSignal": true; }; "allowDuplicates": { "alias": "allowDuplicates"; "required": false; "isSignal": true; }; "validate": { "alias": "validate"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "maxItems": { "alias": "maxItems"; "required": false; "isSignal": true; }; "maxTagCount": { "alias": "maxTagCount"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "searchQuery": "searchQueryChange"; "searchChange": "searchChange"; "value": "valueChange"; "touch": "touch"; }, ["projectedOptions"], ["*"], true, never>;
430
536
  }
431
537
 
432
538
  /**
@@ -458,7 +564,7 @@ declare class WrOption {
458
564
  /** @internal — true when this option is the keyboard cursor target. */
459
565
  protected readonly active: _angular_core.Signal<boolean>;
460
566
  /**
461
- * @internal — search mode only. True when the parent has a query that
567
+ * @internal — searchable selects only. True when the parent has a query that
462
568
  * the option's text content does not match (case-insensitive substring).
463
569
  * Hidden options stay in the DOM so registration order survives but
464
570
  * collapse via CSS.
@@ -16,7 +16,7 @@ import { InjectionToken } from '@angular/core';
16
16
  * Distinct from `Version` exported by `@angular/core`, which reports the
17
17
  * loaded Angular runtime version (e.g. `'21.2.13'`), not ngwr's.
18
18
  */
19
- declare const NGWR_VERSION = "9.0.1";
19
+ declare const NGWR_VERSION = "9.1.0";
20
20
 
21
21
  /**
22
22
  * @license