quang 19.3.15-2 → 19.3.15-3

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.
@@ -5,16 +5,19 @@ The `QuangAutocompleteComponent` is a comprehensive autocomplete input with real
5
5
  ## Inputs
6
6
 
7
7
  - `selectOptions`: `SelectOption[]` — Array of available options for selection. Each option should have `value` and `label` properties. **(Required)**
8
+ - `allowFreeText`: `boolean` — When true, allows any text input as a valid form value, not just option values. The form value will sync with whatever text the user types. When false, the form value must match one of the option values. Default: `false`
9
+ - `autoSelectOnExactMatch`: `boolean` — When true and `allowFreeText` is false, automatically selects an option if the user's input text matches an option's label exactly (case-insensitive, trimmed). This provides a better UX by auto-selecting when users type a complete option label. Default: `true`
10
+ - `updateValueOnType`: `boolean` — When true, updates the form value as the user types (after debounce). When false, the form value is only updated when the user selects an option from the dropdown or when the input loses focus (blur). Default: `false`
8
11
  - `multiple`: `boolean` — Enable multiple selection mode with chip display. Default: `false`
9
12
  - `multiSelectDisplayMode`: `'vertical' | 'horizontal'` — Layout direction for chips in multiple mode. Horizontal mode includes scroll support. Default: `'vertical'`
10
13
  - `chipMaxLength`: `number` — Maximum character length for chip labels. Longer labels will be truncated with ellipsis. Default: `0` (no limit)
11
- - `syncFormWithText`: `boolean` — Synchronize form control value with input text as user types. Useful for free-text input with suggestions. Default: `false`
12
14
  - `optionListMaxHeight`: `string` — Maximum height for dropdown option list with CSS units. Default: `'200px'`
13
15
  - `translateValue`: `boolean` — Enable translation of option values through QuangTranslationService. Default: `true`
14
16
  - `scrollBehaviorOnOpen`: `ScrollBehavior` — Scroll behavior when opening dropdown ('smooth' or 'instant'). Default: `'smooth'`
15
17
  - `emitOnly`: `boolean` — Only emit selection events without updating form control. Useful for read-only suggestion display. Default: `false`
16
18
  - `searchTextDebounce`: `number` — Debounce delay in milliseconds for search input to optimize performance. Default: `300`
17
19
  - `internalFilterOptions`: `boolean` — Use built-in filtering logic. Disable for custom external filtering via searchTextChange event. Default: `true`
20
+ - `syncFormWithText`: `boolean` — **@deprecated** Use `allowFreeText` instead. Synchronize form control value with input text as user types. Default: `false`
18
21
  - `isReadonly`: `boolean` — Set component to read-only mode. Inherited from `QuangBaseComponent`
19
22
  - `componentLabel`: `string` — Label text for the component. Inherited from `QuangBaseComponent`
20
23
  - `componentPlaceholder`: `string` — Placeholder text for the input. Inherited from `QuangBaseComponent`
@@ -1,71 +1,263 @@
1
- import { Subscription } from 'rxjs';
2
1
  import { OptionListParentType, QuangBaseComponent, QuangOptionListComponent, SelectOption } from 'quang/components/shared';
3
2
  import * as i0 from "@angular/core";
3
+ /**
4
+ * Autocomplete component for providing suggestion options {@link SelectOption} as the user types.
5
+ *
6
+ * @usageNotes
7
+ * This component displays a list of filtered options based on user input.
8
+ * It allows users to select an option from the suggestions and emits the event `selectedOption` when an option is selected.
9
+ *
10
+ * `searchTextDebounce` is by default set to 300ms.
11
+ */
4
12
  export declare class QuangAutocompleteComponent extends QuangBaseComponent<string | number | string[] | number[]> {
13
+ /**
14
+ * The list of options to display in the autocomplete dropdown.
15
+ */
16
+ selectOptions: import("@angular/core").InputSignal<SelectOption[]>;
17
+ /**
18
+ * When true, allows any text input as a valid form value, not just option values.
19
+ * The form value will sync with whatever text the user types.
20
+ * When false (default), the form value must match one of the option values.
21
+ * @default false
22
+ */
23
+ allowFreeText: import("@angular/core").InputSignal<boolean>;
24
+ /**
25
+ * When true and allowFreeText is false, automatically selects an option if the user's
26
+ * input text matches an option's label exactly (case-insensitive, trimmed).
27
+ * This provides a better UX by auto-selecting when users type a complete option label.
28
+ * @default true
29
+ */
30
+ autoSelectOnExactMatch: import("@angular/core").InputSignal<boolean>;
31
+ /**
32
+ * When true, updates the form value as the user types (after debounce).
33
+ * When false (default), the form value is only updated when:
34
+ * - User selects an option from the dropdown
35
+ * - User stops typing and the input loses focus (blur)
36
+ * @default false
37
+ */
38
+ updateValueOnType: import("@angular/core").InputSignal<boolean>;
39
+ /**
40
+ * Whether the form value can be any text or must match one of the options.
41
+ * When true, the form value syncs with the input text.
42
+ * When false (default), the form value must be one of the option values.
43
+ * @default false
44
+ * @deprecated Use `allowFreeText` instead. This input will be removed in a future version.
45
+ */
5
46
  syncFormWithText: import("@angular/core").InputSignal<boolean>;
47
+ /**
48
+ * Maximum height of the option list before scrolling.
49
+ * @default '200px'
50
+ */
6
51
  optionListMaxHeight: import("@angular/core").InputSignal<string>;
7
- selectOptions: import("@angular/core").InputSignal<SelectOption[]>;
52
+ /**
53
+ * Whether to translate option labels.
54
+ * @default true
55
+ */
8
56
  translateValue: import("@angular/core").InputSignal<boolean>;
57
+ /**
58
+ * Scroll behavior when the option list opens.
59
+ * @default 'smooth'
60
+ */
9
61
  scrollBehaviorOnOpen: import("@angular/core").InputSignal<ScrollBehavior>;
10
62
  /**
11
- * Only emits the value without saving it in ngControl
63
+ * When true, only emits the value without saving it to ngControl.
64
+ * @default false
12
65
  */
13
66
  emitOnly: import("@angular/core").InputSignal<boolean>;
67
+ /**
68
+ * Enable multiple selection mode with chips.
69
+ * @default false
70
+ */
14
71
  multiple: import("@angular/core").InputSignal<boolean>;
15
72
  /**
16
- * Set the maximum length in characters of the single chip.
73
+ * Maximum length in characters for chip display text.
74
+ * When set, chips will be truncated and show a tooltip with full text.
75
+ * @default 0 (no limit)
17
76
  */
18
77
  chipMaxLength: import("@angular/core").InputSignal<number>;
78
+ /**
79
+ * Layout direction for chips in multiple selection mode.
80
+ * @default 'vertical'
81
+ */
19
82
  multiSelectDisplayMode: import("@angular/core").InputSignal<"vertical" | "horizontal">;
20
- optionList: import("@angular/core").Signal<QuangOptionListComponent | undefined>;
21
- _showOptions: import("@angular/core").WritableSignal<boolean | null>;
22
- _inputValue: import("@angular/core").WritableSignal<string>;
23
- _optionHideTimeout: import("@angular/core").WritableSignal<any>;
24
- _chipList: import("@angular/core").WritableSignal<string[]>;
25
- _selectedOptions: import("@angular/core").WritableSignal<SelectOption[]>;
26
- selectOptionsChange: Subscription;
27
- _filteredOptions: import("@angular/core").Signal<SelectOption[]>;
28
- selectedOption: import("@angular/core").OutputEmitterRef<string | number | null>;
29
- searchTextChange: import("@angular/core").OutputEmitterRef<string>;
83
+ /**
84
+ * Debounce time in milliseconds for search text changes.
85
+ * @default 300
86
+ */
30
87
  searchTextDebounce: import("@angular/core").InputSignal<number>;
88
+ /**
89
+ * Whether to filter options internally based on input text.
90
+ * When false, filtering should be handled externally via searchTextChange event.
91
+ * @default true
92
+ */
31
93
  internalFilterOptions: import("@angular/core").InputSignal<boolean>;
32
- readonly ParentType = OptionListParentType.AUTOCOMPLETE;
33
- formValueChange$: Subscription | undefined;
94
+ /**
95
+ * Emitted when an option is selected.
96
+ * Emits the selected option's value, or null when cleared.
97
+ */
98
+ selectedOption: import("@angular/core").OutputEmitterRef<string | number | null>;
99
+ /**
100
+ * Emitted when the search text changes (after debounce).
101
+ * Useful for external filtering or API calls.
102
+ */
103
+ searchTextChange: import("@angular/core").OutputEmitterRef<string>;
104
+ /** Reference to the option list component */
105
+ protected readonly optionList: import("@angular/core").Signal<QuangOptionListComponent | undefined>;
106
+ /** Reference to the input element */
34
107
  private readonly selectInput;
108
+ /** Reference to the chip container element */
35
109
  private readonly chipContainer;
110
+ /** Reference to the main autocomplete container */
36
111
  private readonly autocompleteContainer;
37
- inputHeight: import("@angular/core").WritableSignal<number>;
112
+ /** Constant for option list parent type */
113
+ readonly ParentType = OptionListParentType.AUTOCOMPLETE;
114
+ /** Height of the input element (used for positioning) */
115
+ readonly inputHeight: import("@angular/core").WritableSignal<number>;
116
+ /**
117
+ * The display text for the input field.
118
+ * - When searching: shows what the user typed
119
+ * - When allowFreeText/syncFormWithText is true and no matching option: shows the raw value
120
+ * - When not searching: shows the selected option's label (derived from _value)
121
+ */
122
+ readonly _inputValue: import("@angular/core").Signal<string>;
123
+ /** Whether the option list is currently visible */
124
+ readonly _showOptions: import("@angular/core").WritableSignal<boolean | null>;
125
+ /** List of selected chip values (for multiple mode) */
126
+ readonly _chipList: import("@angular/core").WritableSignal<string[]>;
127
+ /** List of selected option objects (for multiple mode) */
128
+ readonly _selectedOptions: import("@angular/core").WritableSignal<SelectOption[]>;
129
+ /** Filtered options based on search text and chip selection */
130
+ readonly _filteredOptions: import("@angular/core").Signal<SelectOption[]>;
131
+ /**
132
+ * The value to use for highlighting in the option list.
133
+ * When searching: shows the matched option (if any) based on exact label match
134
+ * When not searching: shows the current form value
135
+ * This keeps highlighting in sync with what will be selected on blur.
136
+ */
137
+ readonly _highlightedValue: import("@angular/core").Signal<string | number | string[] | number[] | null>;
138
+ /** Whether the user is actively typing/searching */
139
+ protected readonly _isSearching: import("@angular/core").WritableSignal<boolean>;
140
+ /** The text the user is currently typing while searching */
141
+ protected readonly _userSearchText: import("@angular/core").WritableSignal<string>;
142
+ /**
143
+ * Internal computed that returns true if free text input is allowed.
144
+ * Combines both `allowFreeText` and deprecated `syncFormWithText` inputs.
145
+ */
146
+ protected readonly _allowFreeTextInternal: import("@angular/core").Signal<boolean>;
147
+ /**
148
+ * Finds an option whose label exactly matches the given text (case-insensitive, trimmed).
149
+ * @param text The text to match against option labels
150
+ * @returns The matching option, or undefined if no match
151
+ */
152
+ protected findMatchingOption(text: string | null | undefined): SelectOption | undefined;
153
+ /** Timer for search text debounce */
38
154
  private _searchDebounceTimer;
155
+ /** Last emitted search text (for distinctUntilChanged behavior) */
39
156
  private _lastEmittedSearchText;
157
+ /** Whether the component has been destroyed */
40
158
  private _isDestroyed;
41
- private readonly onChangeSelectInput;
159
+ /** Subscription to form value changes */
160
+ private formValueChangeSubscription;
161
+ /** Effect to handle input element setup and keyboard events */
162
+ private readonly onChangeSelectInputEffect;
163
+ /** Subscription to options changes */
164
+ private readonly selectOptionsChangeSubscription;
165
+ /** Subscription to show options changes */
166
+ private readonly showOptionsChangeSubscription;
42
167
  constructor();
168
+ setupFormControl(): void;
169
+ writeValue(val: string | number | string[] | number[]): void;
170
+ onChangedHandler(value: string | number | string[] | number[]): void;
171
+ onBlurHandler(): void;
43
172
  /**
44
- * Handle debounced search text change emission
45
- * @param value The input value to emit after debounce
173
+ * Shows the option list dropdown.
46
174
  */
47
- private emitDebouncedSearchText;
48
- setupFormControl(): void;
49
175
  showOptionVisibility(): void;
50
- hideOptionVisibility(skipTimeout?: boolean): void;
176
+ /**
177
+ * Hides the option list dropdown.
178
+ */
179
+ hideOptionVisibility(): void;
180
+ /**
181
+ * Handles input text changes (typing).
182
+ * @param event The input event
183
+ */
51
184
  onChangeInput(event: Event): void;
52
- filterOptions(value: string): SelectOption[];
53
- onChangedHandler(value: string | number | string[] | number[]): void;
185
+ /**
186
+ * Handles option selection from the dropdown.
187
+ * @param value The selected option's value
188
+ * @param hideOptions Whether to hide the dropdown after selection
189
+ */
54
190
  onValueChange(value: string | number, hideOptions?: boolean): void;
55
- checkInputValue(): void;
56
- writeValue(val: string | number | string[] | number[]): void;
191
+ /**
192
+ * Handles input blur event.
193
+ * @param event The focus event
194
+ */
57
195
  onBlurInput(event: FocusEvent): void;
58
- onBlurHandler(): void;
59
- onBlurOptionList(event: any): void;
60
- setInputValue(resetOnMiss?: boolean): void;
61
- getDescription(chip: any): string;
62
- onSelectValue(value: any): void;
63
196
  /**
64
- * remove chip from chips list
65
- * @param chipValue chip to delete
197
+ * Handles blur event on the option list.
198
+ * @param event The blur event (truthy if should hide)
199
+ */
200
+ onBlurOptionList(event: FocusEvent | boolean): void;
201
+ /**
202
+ * Gets the display description for a chip value.
203
+ * @param chipValue The chip's value
204
+ * @returns The chip's display label
205
+ */
206
+ getDescription(chipValue: string | number): string;
207
+ /**
208
+ * Removes a chip from the selection (multiple mode).
209
+ * @param chipValue The chip value to remove
210
+ */
211
+ deleteChip(chipValue: string | number): void;
212
+ /**
213
+ * Filters options based on input text.
214
+ * @param value The search text
215
+ * @returns Filtered options
216
+ */
217
+ protected filterOptions(value: string): SelectOption[];
218
+ /**
219
+ * Core method that processes text input and updates form value accordingly.
220
+ *
221
+ * Matching logic:
222
+ * - If text matches an option label (case-insensitive, trimmed) and autoSelectOnExactMatch is true, select that option
223
+ * - If no match and allowFreeText is true, use the typed text as value
224
+ * - If no match and allowFreeText is false, clear the value
225
+ *
226
+ * @param text The text to process
227
+ * @param options Configuration options:
228
+ * - exitSearchMode: If true, uses onChangedHandler which exits search mode. If false, stays in search mode.
229
+ * - updateOnMatch: If true, updates form when match found. If false, only clears on no-match.
230
+ * - clearSearchText: If true, clears _userSearchText after processing.
231
+ */
232
+ private processTextToFormValue;
233
+ /**
234
+ * Handles keyboard events on the input element.
235
+ */
236
+ private handleInputKeydown;
237
+ /**
238
+ * Handles changes to the select options input.
239
+ */
240
+ private handleOptionsChange;
241
+ /**
242
+ * Handles form value changes from external sources.
243
+ */
244
+ private handleFormValueChange;
245
+ /**
246
+ * Handles selecting a value (adding to chip list in multiple mode).
247
+ */
248
+ private handleSelectValue;
249
+ /**
250
+ * Emits search text change after debounce.
251
+ * When `updateValueOnType` is true, also updates the form value using the same
252
+ * matching logic as checkInputValue (auto-select matching options, or use free text).
253
+ */
254
+ private emitDebouncedSearchText;
255
+ /**
256
+ * Updates the form value and internal _value signal without exiting search mode.
257
+ * This is used when clearing the value during typing - we want to update the form
258
+ * but keep the user in search mode so they can continue typing.
66
259
  */
67
- deleteChip(chipValue: any): void;
68
- createChipList(chip: any): void;
260
+ private updateValueWithoutExitingSearchMode;
69
261
  static ɵfac: i0.ɵɵFactoryDeclaration<QuangAutocompleteComponent, never>;
70
- static ɵcmp: i0.ɵɵComponentDeclaration<QuangAutocompleteComponent, "quang-autocomplete", never, { "syncFormWithText": { "alias": "syncFormWithText"; "required": false; "isSignal": true; }; "optionListMaxHeight": { "alias": "optionListMaxHeight"; "required": false; "isSignal": true; }; "selectOptions": { "alias": "selectOptions"; "required": true; "isSignal": true; }; "translateValue": { "alias": "translateValue"; "required": false; "isSignal": true; }; "scrollBehaviorOnOpen": { "alias": "scrollBehaviorOnOpen"; "required": false; "isSignal": true; }; "emitOnly": { "alias": "emitOnly"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "chipMaxLength": { "alias": "chipMaxLength"; "required": false; "isSignal": true; }; "multiSelectDisplayMode": { "alias": "multiSelectDisplayMode"; "required": false; "isSignal": true; }; "searchTextDebounce": { "alias": "searchTextDebounce"; "required": false; "isSignal": true; }; "internalFilterOptions": { "alias": "internalFilterOptions"; "required": false; "isSignal": true; }; }, { "selectedOption": "selectedOption"; "searchTextChange": "searchTextChange"; }, never, never, true, never>;
262
+ static ɵcmp: i0.ɵɵComponentDeclaration<QuangAutocompleteComponent, "quang-autocomplete", never, { "selectOptions": { "alias": "selectOptions"; "required": true; "isSignal": true; }; "allowFreeText": { "alias": "allowFreeText"; "required": false; "isSignal": true; }; "autoSelectOnExactMatch": { "alias": "autoSelectOnExactMatch"; "required": false; "isSignal": true; }; "updateValueOnType": { "alias": "updateValueOnType"; "required": false; "isSignal": true; }; "syncFormWithText": { "alias": "syncFormWithText"; "required": false; "isSignal": true; }; "optionListMaxHeight": { "alias": "optionListMaxHeight"; "required": false; "isSignal": true; }; "translateValue": { "alias": "translateValue"; "required": false; "isSignal": true; }; "scrollBehaviorOnOpen": { "alias": "scrollBehaviorOnOpen"; "required": false; "isSignal": true; }; "emitOnly": { "alias": "emitOnly"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "chipMaxLength": { "alias": "chipMaxLength"; "required": false; "isSignal": true; }; "multiSelectDisplayMode": { "alias": "multiSelectDisplayMode"; "required": false; "isSignal": true; }; "searchTextDebounce": { "alias": "searchTextDebounce"; "required": false; "isSignal": true; }; "internalFilterOptions": { "alias": "internalFilterOptions"; "required": false; "isSignal": true; }; }, { "selectedOption": "selectedOption"; "searchTextChange": "searchTextChange"; }, never, never, true, never>;
71
263
  }