quang 20.5.1 → 20.5.2-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.
- package/components/autocomplete/README.md +34 -0
- package/components/autocomplete/index.d.ts +2 -0
- package/components/date/index.d.ts +3 -0
- package/components/radio-group/README.md +75 -0
- package/components/radio-group/index.d.ts +31 -0
- package/components/select/README.md +34 -1
- package/components/select/index.d.ts +1 -0
- package/components/shared/index.d.ts +10 -2
- package/fesm2022/quang-components-autocomplete.mjs +9 -3
- package/fesm2022/quang-components-autocomplete.mjs.map +1 -1
- package/fesm2022/quang-components-checkbox.mjs +2 -2
- package/fesm2022/quang-components-checkbox.mjs.map +1 -1
- package/fesm2022/quang-components-date.mjs +59 -17
- package/fesm2022/quang-components-date.mjs.map +1 -1
- package/fesm2022/quang-components-input.mjs +2 -2
- package/fesm2022/quang-components-input.mjs.map +1 -1
- package/fesm2022/quang-components-radio-group.mjs +59 -0
- package/fesm2022/quang-components-radio-group.mjs.map +1 -0
- package/fesm2022/quang-components-select.mjs +6 -3
- package/fesm2022/quang-components-select.mjs.map +1 -1
- package/fesm2022/quang-components-shared.mjs +33 -12
- package/fesm2022/quang-components-shared.mjs.map +1 -1
- package/package.json +5 -1
|
@@ -82,6 +82,40 @@ The `QuangAutocompleteComponent` is a comprehensive autocomplete input with real
|
|
|
82
82
|
</quang-autocomplete>
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
### Template-based options
|
|
86
|
+
|
|
87
|
+
Each `SelectOption` can provide a `renderer` (similar to `quang-table` and `quang-radio-group`), which is used instead of the plain label in the suggestions list.
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<ng-template
|
|
91
|
+
#customOption
|
|
92
|
+
let-opt
|
|
93
|
+
let-selected="selected"
|
|
94
|
+
>
|
|
95
|
+
<span class="d-flex gap-2 align-items-center">
|
|
96
|
+
<strong>{{ opt.label }}</strong>
|
|
97
|
+
<small class="text-muted">selected: {{ selected }}</small>
|
|
98
|
+
</span>
|
|
99
|
+
</ng-template>
|
|
100
|
+
|
|
101
|
+
<quang-autocomplete
|
|
102
|
+
[selectOptions]="templatedOptions"
|
|
103
|
+
formControlName="country"
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { TemplateRef, viewChild } from '@angular/core'
|
|
109
|
+
import { SelectOption, QuangSelectOptionTemplateContext } from 'quang/components/shared'
|
|
110
|
+
|
|
111
|
+
customOptionTemplate = viewChild<TemplateRef<QuangSelectOptionTemplateContext>>('customOption')
|
|
112
|
+
|
|
113
|
+
templatedOptions: SelectOption[] = [
|
|
114
|
+
{ value: 'us', label: 'United States' },
|
|
115
|
+
{ value: 'ca', label: 'Canada', renderer: this.customOptionTemplate() },
|
|
116
|
+
]
|
|
117
|
+
```
|
|
118
|
+
|
|
85
119
|
#### TypeScript Example
|
|
86
120
|
|
|
87
121
|
```typescript
|
|
@@ -233,6 +233,8 @@ declare class QuangAutocompleteComponent extends QuangBaseComponent<string | num
|
|
|
233
233
|
* @returns The chip's display label
|
|
234
234
|
*/
|
|
235
235
|
getDescription(chipValue: string | number): string;
|
|
236
|
+
getOptionByValue(value: string | number): SelectOption | undefined;
|
|
237
|
+
getOptionIndex(option: SelectOption): number;
|
|
236
238
|
/**
|
|
237
239
|
* Removes a chip from the selection (multiple mode).
|
|
238
240
|
* @param chipValue The chip value to remove
|
|
@@ -67,6 +67,7 @@ declare class QuangDateComponent extends QuangBaseComponent<string | DateRange |
|
|
|
67
67
|
showTimepicker: _angular_core.Signal<boolean>;
|
|
68
68
|
isMouseInsideCalendar: _angular_core.WritableSignal<boolean>;
|
|
69
69
|
isMouseOutsideCalendar: _angular_core.Signal<boolean>;
|
|
70
|
+
private _shouldRefocusInputOnHide;
|
|
70
71
|
setupCalendar(): void;
|
|
71
72
|
onChangeText($event: Event): void;
|
|
72
73
|
onBlurHandler(): void;
|
|
@@ -75,8 +76,10 @@ declare class QuangDateComponent extends QuangBaseComponent<string | DateRange |
|
|
|
75
76
|
onHideCalendar(): void;
|
|
76
77
|
formatDate(val: string | DateRange | null): string;
|
|
77
78
|
openDatePicker(): void;
|
|
79
|
+
onInputKeydown(event: KeyboardEvent): void;
|
|
78
80
|
interceptInputInteraction($event: Event): void;
|
|
79
81
|
getLocale(): AirDatepickerLocale;
|
|
82
|
+
private unwrapLocaleModule;
|
|
80
83
|
onCancel(): void;
|
|
81
84
|
private dateToUtc;
|
|
82
85
|
private dateToLocal;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# QuangRadioGroupComponent
|
|
2
|
+
|
|
3
|
+
The `QuangRadioGroupComponent` renders a group of radio buttons with full Angular forms support (ControlValueAccessor).
|
|
4
|
+
|
|
5
|
+
## Input
|
|
6
|
+
|
|
7
|
+
- `radioOptions`: `RadioOption[]` - Array of options to render (required)
|
|
8
|
+
- `radioPosition`: `'left' | 'right'` - Render the radio control on the left or right of the label (default: `'left'`)
|
|
9
|
+
- `name`: `string` - Radio group name attribute. Defaults to `componentId`.
|
|
10
|
+
|
|
11
|
+
All standard inputs inherited from `QuangBaseComponent`: `isReadonly`, `componentLabel`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
|
|
12
|
+
|
|
13
|
+
## Output
|
|
14
|
+
|
|
15
|
+
All standard outputs inherited from `QuangBaseComponent`: `componentBlur`
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Standard options
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<quang-radio-group
|
|
23
|
+
[errorMap]="errors()"
|
|
24
|
+
[radioOptions]="options"
|
|
25
|
+
componentLabel="form.label.radioGroup"
|
|
26
|
+
formControlName="choice"
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { RadioOption } from 'quang/components/radio-group'
|
|
32
|
+
|
|
33
|
+
options: RadioOption[] = [
|
|
34
|
+
{ label: 'Option A', value: 'A' },
|
|
35
|
+
{ label: 'Option B', value: 'B' },
|
|
36
|
+
]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Template-based options
|
|
40
|
+
|
|
41
|
+
Each `RadioOption` can provide a `renderer` (similar to `quang-table`), which is used instead of the plain label.
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<ng-template
|
|
45
|
+
#customOption
|
|
46
|
+
let-opt
|
|
47
|
+
let-selected="selected"
|
|
48
|
+
>
|
|
49
|
+
<span class="d-flex gap-2 align-items-center">
|
|
50
|
+
<strong>{{ opt.value }}</strong>
|
|
51
|
+
<small class="text-muted">selected: {{ selected }}</small>
|
|
52
|
+
</span>
|
|
53
|
+
</ng-template>
|
|
54
|
+
|
|
55
|
+
<quang-radio-group
|
|
56
|
+
[radioOptions]="templatedOptions"
|
|
57
|
+
formControlName="choice"
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { TemplateRef, viewChild } from '@angular/core'
|
|
63
|
+
import { RadioOption, QuangRadioOptionTemplateContext } from 'quang/components/radio-group'
|
|
64
|
+
|
|
65
|
+
templatedOptions: RadioOption[] = [
|
|
66
|
+
{ value: 'A', label: 'Option A' },
|
|
67
|
+
{ value: 'B', renderer: this.customOptionTemplate() },
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
customOptionTemplate = viewChild<TemplateRef<QuangRadioOptionTemplateContext>>('customOption')
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Notes
|
|
74
|
+
|
|
75
|
+
Most components are styled based on Bootstrap v5.3 and extend `QuangBaseComponent`.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { TemplateRef } from '@angular/core';
|
|
3
|
+
import { QuangBaseComponent } from 'quang/components/shared';
|
|
4
|
+
|
|
5
|
+
type RadioPosition = 'left' | 'right';
|
|
6
|
+
interface QuangRadioOptionTemplateContext<T extends string | number | null = string | number | null> {
|
|
7
|
+
$implicit: RadioOption<T>;
|
|
8
|
+
selected: boolean;
|
|
9
|
+
index: number;
|
|
10
|
+
}
|
|
11
|
+
interface RadioOption<T extends string | number | null = string | number | null> {
|
|
12
|
+
value: T;
|
|
13
|
+
label?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
renderer?: TemplateRef<QuangRadioOptionTemplateContext<T>>;
|
|
16
|
+
}
|
|
17
|
+
declare class QuangRadioGroupComponent extends QuangBaseComponent<string | number | null> {
|
|
18
|
+
radioOptions: _angular_core.InputSignal<RadioOption<string | number | null>[]>;
|
|
19
|
+
name: _angular_core.InputSignal<string>;
|
|
20
|
+
radioPosition: _angular_core.InputSignal<RadioPosition>;
|
|
21
|
+
_radioName: _angular_core.Signal<string>;
|
|
22
|
+
getOptionId(index: number): string;
|
|
23
|
+
isOptionDisabled(option: RadioOption): boolean;
|
|
24
|
+
getOptionLabel(option: RadioOption): string;
|
|
25
|
+
onSelectOption(option: RadioOption): void;
|
|
26
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuangRadioGroupComponent, never>;
|
|
27
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuangRadioGroupComponent, "quang-radio-group", never, { "radioOptions": { "alias": "radioOptions"; "required": true; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "radioPosition": { "alias": "radioPosition"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { QuangRadioGroupComponent };
|
|
31
|
+
export type { QuangRadioOptionTemplateContext, RadioOption, RadioPosition };
|
|
@@ -55,6 +55,40 @@ All standard inputs inherited from `QuangBaseComponent`:
|
|
|
55
55
|
</quang-select>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
### Template-based options
|
|
59
|
+
|
|
60
|
+
Each `SelectOption` can provide a `renderer` (similar to `quang-table` and `quang-radio-group`), which is used instead of the plain label.
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<ng-template
|
|
64
|
+
#customOption
|
|
65
|
+
let-opt
|
|
66
|
+
let-selected="selected"
|
|
67
|
+
>
|
|
68
|
+
<span>
|
|
69
|
+
<strong>{{ opt.label }}</strong>
|
|
70
|
+
<small class="text-muted">selected: {{ selected }}</small>
|
|
71
|
+
</span>
|
|
72
|
+
</ng-template>
|
|
73
|
+
|
|
74
|
+
<quang-select
|
|
75
|
+
[selectOptions]="templatedOptions"
|
|
76
|
+
formControlName="testInput"
|
|
77
|
+
/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { TemplateRef, viewChild } from '@angular/core'
|
|
82
|
+
import { SelectOption, QuangSelectOptionTemplateContext } from 'quang/components/shared'
|
|
83
|
+
|
|
84
|
+
customOptionTemplate = viewChild<TemplateRef<QuangSelectOptionTemplateContext>>('customOption')
|
|
85
|
+
|
|
86
|
+
templatedOptions: SelectOption[] = [
|
|
87
|
+
{ value: 'IT', label: 'Italy' },
|
|
88
|
+
{ value: 'FR', label: 'France', renderer: this.customOptionTemplate() },
|
|
89
|
+
]
|
|
90
|
+
```
|
|
91
|
+
|
|
58
92
|
### Inline Help Message
|
|
59
93
|
```html
|
|
60
94
|
<quang-select
|
|
@@ -80,7 +114,6 @@ All standard inputs inherited from `QuangBaseComponent`:
|
|
|
80
114
|
</quang-select>
|
|
81
115
|
```
|
|
82
116
|
|
|
83
|
-
|
|
84
117
|
## QuangTranslationService Integration
|
|
85
118
|
|
|
86
119
|
The component supports automatic translation of all labels, help messages, and error messages through `QuangTranslationService`.
|
|
@@ -48,6 +48,7 @@ declare class QuangSelectComponent extends QuangBaseComponent<string | number |
|
|
|
48
48
|
* Sets focus to the select button element.
|
|
49
49
|
*/
|
|
50
50
|
focusButton(): void;
|
|
51
|
+
getOptionIndex(option: SelectOption): number;
|
|
51
52
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuangSelectComponent, never>;
|
|
52
53
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuangSelectComponent, "quang-select", never, { "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "optionListMaxHeight": { "alias": "optionListMaxHeight"; "required": false; "isSignal": true; }; "selectOptions": { "alias": "selectOptions"; "required": true; "isSignal": true; }; "scrollBehaviorOnOpen": { "alias": "scrollBehaviorOnOpen"; "required": false; "isSignal": true; }; "translateValue": { "alias": "translateValue"; "required": false; "isSignal": true; }; "nullOption": { "alias": "nullOption"; "required": false; "isSignal": true; }; "autoSelectSingleOption": { "alias": "autoSelectSingleOption"; "required": false; "isSignal": true; }; }, {}, never, ["[help-icon]"], true, never>;
|
|
53
54
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as rxjs from 'rxjs';
|
|
2
2
|
import { Subscription } from 'rxjs';
|
|
3
3
|
import * as _angular_core from '@angular/core';
|
|
4
|
-
import { AfterViewInit, Injector, DestroyRef, ElementRef } from '@angular/core';
|
|
4
|
+
import { AfterViewInit, Injector, DestroyRef, TemplateRef, ElementRef } from '@angular/core';
|
|
5
5
|
import { ControlValueAccessor, FormControl, NgControl } from '@angular/forms';
|
|
6
6
|
|
|
7
7
|
declare const makeId: (length: number) => string;
|
|
@@ -39,6 +39,8 @@ declare abstract class QuangBaseComponent<T = any> implements ControlValueAccess
|
|
|
39
39
|
_ngControl: _angular_core.WritableSignal<NgControl | null>;
|
|
40
40
|
_injector: _angular_core.WritableSignal<Injector>;
|
|
41
41
|
_statusChange$?: Subscription;
|
|
42
|
+
_valueChange$?: Subscription;
|
|
43
|
+
_eventsChange$?: Subscription;
|
|
42
44
|
getIsRequiredControl: _angular_core.Signal<boolean>;
|
|
43
45
|
onChange?: (value: T) => void;
|
|
44
46
|
onTouched?: () => void;
|
|
@@ -59,9 +61,15 @@ declare abstract class QuangBaseComponent<T = any> implements ControlValueAccess
|
|
|
59
61
|
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<QuangBaseComponent<any>, never, never, { "componentId": { "alias": "componentId"; "required": false; "isSignal": true; }; "isReadonly": { "alias": "isReadonly"; "required": false; "isSignal": true; }; "componentTabIndex": { "alias": "componentTabIndex"; "required": false; "isSignal": true; }; "componentClass": { "alias": "componentClass"; "required": false; "isSignal": true; }; "componentLabel": { "alias": "componentLabel"; "required": false; "isSignal": true; }; "componentPlaceholder": { "alias": "componentPlaceholder"; "required": false; "isSignal": true; }; "errorMap": { "alias": "errorMap"; "required": false; "isSignal": true; }; "successMessage": { "alias": "successMessage"; "required": false; "isSignal": true; }; "helpMessage": { "alias": "helpMessage"; "required": false; "isSignal": true; }; "formControl": { "alias": "formControl"; "required": false; "isSignal": true; }; "helpMessageTooltip": { "alias": "helpMessageTooltip"; "required": false; "isSignal": true; }; }, { "componentBlur": "componentBlur"; }, never, never, true, never>;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
interface QuangSelectOptionTemplateContext {
|
|
65
|
+
$implicit: SelectOption;
|
|
66
|
+
selected: boolean;
|
|
67
|
+
index: number;
|
|
68
|
+
}
|
|
62
69
|
interface SelectOption {
|
|
63
70
|
label: string;
|
|
64
71
|
value: string | number | null;
|
|
72
|
+
renderer?: TemplateRef<QuangSelectOptionTemplateContext>;
|
|
65
73
|
}
|
|
66
74
|
declare enum OptionListParentType {
|
|
67
75
|
SELECT = "select",
|
|
@@ -123,4 +131,4 @@ declare class QuangOptionListComponent {
|
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
export { OptionListParentType, QuangBaseComponent, QuangOptionListComponent, makeId };
|
|
126
|
-
export type { ErrorData, SelectOption };
|
|
134
|
+
export type { ErrorData, QuangSelectOptionTemplateContext, SelectOption };
|
|
@@ -513,9 +513,15 @@ class QuangAutocompleteComponent extends QuangBaseComponent {
|
|
|
513
513
|
* @returns The chip's display label
|
|
514
514
|
*/
|
|
515
515
|
getDescription(chipValue) {
|
|
516
|
-
const option = this.selectOptions().find((x) => x.value === chipValue);
|
|
516
|
+
const option = this.selectOptions().find((x) => x.value?.toString() === chipValue?.toString());
|
|
517
517
|
return option?.label?.toString() ?? '';
|
|
518
518
|
}
|
|
519
|
+
getOptionByValue(value) {
|
|
520
|
+
return this.selectOptions().find((x) => x.value?.toString() === value?.toString());
|
|
521
|
+
}
|
|
522
|
+
getOptionIndex(option) {
|
|
523
|
+
return this.selectOptions().findIndex((x) => x.value === option.value);
|
|
524
|
+
}
|
|
519
525
|
/**
|
|
520
526
|
* Removes a chip from the selection (multiple mode).
|
|
521
527
|
* @param chipValue The chip value to remove
|
|
@@ -729,7 +735,7 @@ class QuangAutocompleteComponent extends QuangBaseComponent {
|
|
|
729
735
|
provide: QuangOptionListComponent,
|
|
730
736
|
multi: false,
|
|
731
737
|
},
|
|
732
|
-
], viewQueries: [{ propertyName: "optionList", first: true, predicate: ["optionList"], descendants: true, isSignal: true }, { propertyName: "selectInput", first: true, predicate: ["selectInput"], descendants: true, isSignal: true }, { propertyName: "chipContainer", first: true, predicate: ["chipContainer"], descendants: true, isSignal: true }, { propertyName: "autocompleteContainer", first: true, predicate: ["autocompleteContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n [ngStyle]=\"{ '--chip-max-length': chipMaxLength() ? chipMaxLength() + 'ch' : 'none' }\"\n #autocompleteContainer\n class=\"autocomplete-container\"\n>\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label d-flex gap-2\"\n >\n <div>\n <span>{{ componentLabel() | transloco }}</span>\n <span [hidden]=\"!_isRequired()\">*</span>\n </div>\n @if (helpMessage() && helpMessageTooltip()) {\n <div [quangTooltip]=\"helpMessage() | transloco\">\n <ng-content select=\"[help-icon]\" />\n </div>\n }\n </label>\n }\n <div\n [ngClass]=\"{\n horizontal: multiSelectDisplayMode() === 'horizontal',\n 'form-control': multiSelectDisplayMode() === 'horizontal',\n 'chips-bottom': chipsPosition() === 'bottom',\n }\"\n #chipContainer\n class=\"container-wrap\"\n >\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n\n <input\n [attr.aria-activedescendant]=\"_showOptions() ? optionList()?.getActiveDescendantId() : null\"\n [attr.aria-controls]=\"_showOptions() ? 'optionList' : null\"\n [attr.aria-expanded]=\"_showOptions()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.form-control]=\"multiSelectDisplayMode() !== 'horizontal'\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled() || isReadonly()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_inputValue()\"\n (blur)=\"onBlurInput($event)\"\n (input)=\"onChangeInput($event)\"\n (keydown)=\"onInputKeydown($event)\"\n (mousedown)=\"showOptionVisibility()\"\n #selectInput\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n role=\"combobox\"\n type=\"text\"\n />\n\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n </div>\n @if (_showOptions()) {\n <quang-option-list\n [_isDisabled]=\"_isDisabled()\"\n [_value]=\"_highlightedValue()\"\n [componentClass]=\"componentClass()\"\n [componentLabel]=\"componentLabel()\"\n [componentTabIndex]=\"componentTabIndex()\"\n [nullOption]=\"false\"\n [optionListMaxHeight]=\"optionListMaxHeight()\"\n [parentID]=\"componentId()\"\n [parentType]=\"ParentType\"\n [scrollBehaviorOnOpen]=\"scrollBehaviorOnOpen()\"\n [selectButtonRef]=\"autocompleteContainer\"\n [selectOptions]=\"_filteredOptions()\"\n [translateValue]=\"translateValue()\"\n (blurHandler)=\"onBlurOptionList($event)\"\n (changedHandler)=\"onValueChange($event)\"\n (escapePressed)=\"onEscapePressed()\"\n (tabPressed)=\"onTabPressed($event)\"\n #optionList\n selectionMode=\"single\"\n />\n }\n <div
|
|
738
|
+
], viewQueries: [{ propertyName: "optionList", first: true, predicate: ["optionList"], descendants: true, isSignal: true }, { propertyName: "selectInput", first: true, predicate: ["selectInput"], descendants: true, isSignal: true }, { propertyName: "chipContainer", first: true, predicate: ["chipContainer"], descendants: true, isSignal: true }, { propertyName: "autocompleteContainer", first: true, predicate: ["autocompleteContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n [ngStyle]=\"{ '--chip-max-length': chipMaxLength() ? chipMaxLength() + 'ch' : 'none' }\"\n #autocompleteContainer\n class=\"autocomplete-container\"\n>\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label d-flex gap-2\"\n >\n <div>\n <span>{{ componentLabel() | transloco }}</span>\n <span [hidden]=\"!_isRequired()\">*</span>\n </div>\n @if (helpMessage() && helpMessageTooltip()) {\n <div [quangTooltip]=\"helpMessage() | transloco\">\n <ng-content select=\"[help-icon]\" />\n </div>\n }\n </label>\n }\n <div\n [ngClass]=\"{\n horizontal: multiSelectDisplayMode() === 'horizontal',\n 'form-control': multiSelectDisplayMode() === 'horizontal',\n 'chips-bottom': chipsPosition() === 'bottom',\n }\"\n #chipContainer\n class=\"container-wrap\"\n >\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n\n <input\n [attr.aria-activedescendant]=\"_showOptions() ? optionList()?.getActiveDescendantId() : null\"\n [attr.aria-controls]=\"_showOptions() ? 'optionList' : null\"\n [attr.aria-expanded]=\"_showOptions()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.form-control]=\"multiSelectDisplayMode() !== 'horizontal'\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled() || isReadonly()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_inputValue()\"\n (blur)=\"onBlurInput($event)\"\n (input)=\"onChangeInput($event)\"\n (keydown)=\"onInputKeydown($event)\"\n (mousedown)=\"showOptionVisibility()\"\n #selectInput\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n role=\"combobox\"\n type=\"text\"\n />\n\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n </div>\n @if (_showOptions()) {\n <quang-option-list\n [_isDisabled]=\"_isDisabled()\"\n [_value]=\"_highlightedValue()\"\n [componentClass]=\"componentClass()\"\n [componentLabel]=\"componentLabel()\"\n [componentTabIndex]=\"componentTabIndex()\"\n [nullOption]=\"false\"\n [optionListMaxHeight]=\"optionListMaxHeight()\"\n [parentID]=\"componentId()\"\n [parentType]=\"ParentType\"\n [scrollBehaviorOnOpen]=\"scrollBehaviorOnOpen()\"\n [selectButtonRef]=\"autocompleteContainer\"\n [selectOptions]=\"_filteredOptions()\"\n [translateValue]=\"translateValue()\"\n (blurHandler)=\"onBlurOptionList($event)\"\n (changedHandler)=\"onValueChange($event)\"\n (escapePressed)=\"onEscapePressed()\"\n (tabPressed)=\"onTabPressed($event)\"\n #optionList\n selectionMode=\"single\"\n />\n }\n <div\n [class.d-block]=\"_showSuccess()\"\n class=\"valid-feedback\"\n >\n {{ successMessage() | transloco }}\n </div>\n <div\n [class.d-block]=\"_showErrors()\"\n class=\"invalid-feedback\"\n >\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage() && !helpMessageTooltip()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n</div>\n\n<!-- Chips template for reuse in top/bottom positions -->\n<ng-template #chipsTemplate>\n <div class=\"chips-container\">\n @for (chip of _chipList(); track chip) {\n @if (getDescription(chip)) {\n <div\n [ngClass]=\"{ 'chip-truncate': chipMaxLength() }\"\n [quangTooltip]=\"chipMaxLength() ? getDescription(chip) : ''\"\n class=\"chip chip-hover\"\n >\n <p [ngClass]=\"{ 'm-0': isReadonly() || _isDisabled() }\">\n @if (getOptionByValue(chip); as opt) {\n @if (opt.renderer) {\n <ng-container\n [ngTemplateOutlet]=\"opt.renderer\"\n [ngTemplateOutletContext]=\"{ $implicit: opt, selected: true, index: getOptionIndex(opt) }\"\n ></ng-container>\n } @else {\n {{ getDescription(chip) }}\n }\n } @else {\n {{ getDescription(chip) }}\n }\n </p>\n @if (!isReadonly() && !_isDisabled()) {\n <button\n [tabIndex]=\"$index + 1\"\n (click)=\"deleteChip(chip)\"\n class=\"btn btn-chip\"\n type=\"button\"\n >\n <svg\n class=\"ionicon\"\n fill=\"currentColor\"\n height=\"24\"\n viewBox=\"0 0 512 512\"\n width=\"24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M368 368L144 144M368 144L144 368\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"32\"\n />\n </svg>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;--chip-max-length: none}.autocomplete-container{margin-bottom:1rem;position:relative}.chip:has(.btn-chip:disabled):hover{filter:unset;cursor:unset}.container-wrap,.container-wrap .chips-container{display:flex;flex-wrap:wrap;gap:.5rem}.container-wrap.chips-bottom{flex-direction:column}.container-wrap.chips-bottom input{order:-1}.container-wrap.horizontal{display:flex}.container-wrap.horizontal .chip-container{max-width:70%;margin-bottom:0;margin-left:.5rem;flex-wrap:nowrap;white-space:nowrap;overflow-x:auto;position:absolute;align-items:center}.container-wrap.horizontal .chip-container .chip{white-space:nowrap}.container-wrap.horizontal input{min-width:30%;flex:1 1 0;width:auto;border:none}.container-wrap.horizontal input:focus-visible{outline:none}.chip{display:flex;justify-content:space-between;align-items:center;gap:.25rem;padding:.25rem .5rem;border-radius:16px;color:var(--bs-btn-color);background-color:rgba(var(--bs-primary-rgb),.1);border-width:1px;border-style:solid;border-color:var(--bs-primary-border-subtle);min-height:2rem;max-width:100%}.chip p{margin:0;max-width:var(--chip-max-length);overflow:hidden;overflow-wrap:break-word;word-break:break-word}.chip.chip-truncate p{white-space:nowrap;text-overflow:ellipsis}.chip .btn-chip{text-align:end;padding:0;min-width:unset}.chip .btn-chip:hover{opacity:80%}.chip .btn-chip:active{border-color:transparent}.chip .btn-chip svg{color:var(--bs-primary);vertical-align:sub}.chip:has(.btn-chip:focus-visible){border-width:2px;filter:brightness(80%)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QuangOptionListComponent, selector: "quang-option-list", inputs: ["selectionMode", "optionListMaxHeight", "selectOptions", "selectButtonRef", "_value", "_isDisabled", "componentClass", "componentLabel", "componentTabIndex", "translateValue", "nullOption", "scrollBehaviorOnOpen", "parentType", "parentID"], outputs: ["changedHandler", "blurHandler", "escapePressed", "tabPressed"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: QuangTooltipDirective, selector: "[quangTooltip]", inputs: ["quangTooltip", "showMethod"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
733
739
|
}
|
|
734
740
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: QuangAutocompleteComponent, decorators: [{
|
|
735
741
|
type: Component,
|
|
@@ -743,7 +749,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
743
749
|
provide: QuangOptionListComponent,
|
|
744
750
|
multi: false,
|
|
745
751
|
},
|
|
746
|
-
], template: "<div\n [ngStyle]=\"{ '--chip-max-length': chipMaxLength() ? chipMaxLength() + 'ch' : 'none' }\"\n #autocompleteContainer\n class=\"autocomplete-container\"\n>\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label d-flex gap-2\"\n >\n <div>\n <span>{{ componentLabel() | transloco }}</span>\n <span [hidden]=\"!_isRequired()\">*</span>\n </div>\n @if (helpMessage() && helpMessageTooltip()) {\n <div [quangTooltip]=\"helpMessage() | transloco\">\n <ng-content select=\"[help-icon]\" />\n </div>\n }\n </label>\n }\n <div\n [ngClass]=\"{\n horizontal: multiSelectDisplayMode() === 'horizontal',\n 'form-control': multiSelectDisplayMode() === 'horizontal',\n 'chips-bottom': chipsPosition() === 'bottom',\n }\"\n #chipContainer\n class=\"container-wrap\"\n >\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n\n <input\n [attr.aria-activedescendant]=\"_showOptions() ? optionList()?.getActiveDescendantId() : null\"\n [attr.aria-controls]=\"_showOptions() ? 'optionList' : null\"\n [attr.aria-expanded]=\"_showOptions()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.form-control]=\"multiSelectDisplayMode() !== 'horizontal'\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled() || isReadonly()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_inputValue()\"\n (blur)=\"onBlurInput($event)\"\n (input)=\"onChangeInput($event)\"\n (keydown)=\"onInputKeydown($event)\"\n (mousedown)=\"showOptionVisibility()\"\n #selectInput\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n role=\"combobox\"\n type=\"text\"\n />\n\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n </div>\n @if (_showOptions()) {\n <quang-option-list\n [_isDisabled]=\"_isDisabled()\"\n [_value]=\"_highlightedValue()\"\n [componentClass]=\"componentClass()\"\n [componentLabel]=\"componentLabel()\"\n [componentTabIndex]=\"componentTabIndex()\"\n [nullOption]=\"false\"\n [optionListMaxHeight]=\"optionListMaxHeight()\"\n [parentID]=\"componentId()\"\n [parentType]=\"ParentType\"\n [scrollBehaviorOnOpen]=\"scrollBehaviorOnOpen()\"\n [selectButtonRef]=\"autocompleteContainer\"\n [selectOptions]=\"_filteredOptions()\"\n [translateValue]=\"translateValue()\"\n (blurHandler)=\"onBlurOptionList($event)\"\n (changedHandler)=\"onValueChange($event)\"\n (escapePressed)=\"onEscapePressed()\"\n (tabPressed)=\"onTabPressed($event)\"\n #optionList\n selectionMode=\"single\"\n />\n }\n <div
|
|
752
|
+
], template: "<div\n [ngStyle]=\"{ '--chip-max-length': chipMaxLength() ? chipMaxLength() + 'ch' : 'none' }\"\n #autocompleteContainer\n class=\"autocomplete-container\"\n>\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label d-flex gap-2\"\n >\n <div>\n <span>{{ componentLabel() | transloco }}</span>\n <span [hidden]=\"!_isRequired()\">*</span>\n </div>\n @if (helpMessage() && helpMessageTooltip()) {\n <div [quangTooltip]=\"helpMessage() | transloco\">\n <ng-content select=\"[help-icon]\" />\n </div>\n }\n </label>\n }\n <div\n [ngClass]=\"{\n horizontal: multiSelectDisplayMode() === 'horizontal',\n 'form-control': multiSelectDisplayMode() === 'horizontal',\n 'chips-bottom': chipsPosition() === 'bottom',\n }\"\n #chipContainer\n class=\"container-wrap\"\n >\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n\n <input\n [attr.aria-activedescendant]=\"_showOptions() ? optionList()?.getActiveDescendantId() : null\"\n [attr.aria-controls]=\"_showOptions() ? 'optionList' : null\"\n [attr.aria-expanded]=\"_showOptions()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.form-control]=\"multiSelectDisplayMode() !== 'horizontal'\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled() || isReadonly()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_inputValue()\"\n (blur)=\"onBlurInput($event)\"\n (input)=\"onChangeInput($event)\"\n (keydown)=\"onInputKeydown($event)\"\n (mousedown)=\"showOptionVisibility()\"\n #selectInput\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n role=\"combobox\"\n type=\"text\"\n />\n\n @if (multiple() && _chipList().length > 0 && chipsPosition() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"chipsTemplate\" />\n }\n </div>\n @if (_showOptions()) {\n <quang-option-list\n [_isDisabled]=\"_isDisabled()\"\n [_value]=\"_highlightedValue()\"\n [componentClass]=\"componentClass()\"\n [componentLabel]=\"componentLabel()\"\n [componentTabIndex]=\"componentTabIndex()\"\n [nullOption]=\"false\"\n [optionListMaxHeight]=\"optionListMaxHeight()\"\n [parentID]=\"componentId()\"\n [parentType]=\"ParentType\"\n [scrollBehaviorOnOpen]=\"scrollBehaviorOnOpen()\"\n [selectButtonRef]=\"autocompleteContainer\"\n [selectOptions]=\"_filteredOptions()\"\n [translateValue]=\"translateValue()\"\n (blurHandler)=\"onBlurOptionList($event)\"\n (changedHandler)=\"onValueChange($event)\"\n (escapePressed)=\"onEscapePressed()\"\n (tabPressed)=\"onTabPressed($event)\"\n #optionList\n selectionMode=\"single\"\n />\n }\n <div\n [class.d-block]=\"_showSuccess()\"\n class=\"valid-feedback\"\n >\n {{ successMessage() | transloco }}\n </div>\n <div\n [class.d-block]=\"_showErrors()\"\n class=\"invalid-feedback\"\n >\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage() && !helpMessageTooltip()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n</div>\n\n<!-- Chips template for reuse in top/bottom positions -->\n<ng-template #chipsTemplate>\n <div class=\"chips-container\">\n @for (chip of _chipList(); track chip) {\n @if (getDescription(chip)) {\n <div\n [ngClass]=\"{ 'chip-truncate': chipMaxLength() }\"\n [quangTooltip]=\"chipMaxLength() ? getDescription(chip) : ''\"\n class=\"chip chip-hover\"\n >\n <p [ngClass]=\"{ 'm-0': isReadonly() || _isDisabled() }\">\n @if (getOptionByValue(chip); as opt) {\n @if (opt.renderer) {\n <ng-container\n [ngTemplateOutlet]=\"opt.renderer\"\n [ngTemplateOutletContext]=\"{ $implicit: opt, selected: true, index: getOptionIndex(opt) }\"\n ></ng-container>\n } @else {\n {{ getDescription(chip) }}\n }\n } @else {\n {{ getDescription(chip) }}\n }\n </p>\n @if (!isReadonly() && !_isDisabled()) {\n <button\n [tabIndex]=\"$index + 1\"\n (click)=\"deleteChip(chip)\"\n class=\"btn btn-chip\"\n type=\"button\"\n >\n <svg\n class=\"ionicon\"\n fill=\"currentColor\"\n height=\"24\"\n viewBox=\"0 0 512 512\"\n width=\"24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M368 368L144 144M368 144L144 368\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"32\"\n />\n </svg>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;--chip-max-length: none}.autocomplete-container{margin-bottom:1rem;position:relative}.chip:has(.btn-chip:disabled):hover{filter:unset;cursor:unset}.container-wrap,.container-wrap .chips-container{display:flex;flex-wrap:wrap;gap:.5rem}.container-wrap.chips-bottom{flex-direction:column}.container-wrap.chips-bottom input{order:-1}.container-wrap.horizontal{display:flex}.container-wrap.horizontal .chip-container{max-width:70%;margin-bottom:0;margin-left:.5rem;flex-wrap:nowrap;white-space:nowrap;overflow-x:auto;position:absolute;align-items:center}.container-wrap.horizontal .chip-container .chip{white-space:nowrap}.container-wrap.horizontal input{min-width:30%;flex:1 1 0;width:auto;border:none}.container-wrap.horizontal input:focus-visible{outline:none}.chip{display:flex;justify-content:space-between;align-items:center;gap:.25rem;padding:.25rem .5rem;border-radius:16px;color:var(--bs-btn-color);background-color:rgba(var(--bs-primary-rgb),.1);border-width:1px;border-style:solid;border-color:var(--bs-primary-border-subtle);min-height:2rem;max-width:100%}.chip p{margin:0;max-width:var(--chip-max-length);overflow:hidden;overflow-wrap:break-word;word-break:break-word}.chip.chip-truncate p{white-space:nowrap;text-overflow:ellipsis}.chip .btn-chip{text-align:end;padding:0;min-width:unset}.chip .btn-chip:hover{opacity:80%}.chip .btn-chip:active{border-color:transparent}.chip .btn-chip svg{color:var(--bs-primary);vertical-align:sub}.chip:has(.btn-chip:focus-visible){border-width:2px;filter:brightness(80%)}\n"] }]
|
|
747
753
|
}], ctorParameters: () => [], propDecorators: { selectOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectOptions", required: true }] }], allowFreeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFreeText", required: false }] }], autoSelectOnExactMatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSelectOnExactMatch", required: false }] }], updateValueOnType: [{ type: i0.Input, args: [{ isSignal: true, alias: "updateValueOnType", required: false }] }], syncFormWithText: [{ type: i0.Input, args: [{ isSignal: true, alias: "syncFormWithText", required: false }] }], optionListMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionListMaxHeight", required: false }] }], translateValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "translateValue", required: false }] }], scrollBehaviorOnOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollBehaviorOnOpen", required: false }] }], emitOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "emitOnly", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], chipMaxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "chipMaxLength", required: false }] }], multiSelectDisplayMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSelectDisplayMode", required: false }] }], chipsPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "chipsPosition", required: false }] }], searchTextDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTextDebounce", required: false }] }], internalFilterOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "internalFilterOptions", required: false }] }], selectedOption: [{ type: i0.Output, args: ["selectedOption"] }], searchTextChange: [{ type: i0.Output, args: ["searchTextChange"] }], optionList: [{ type: i0.ViewChild, args: ['optionList', { isSignal: true }] }], selectInput: [{ type: i0.ViewChild, args: ['selectInput', { isSignal: true }] }], chipContainer: [{ type: i0.ViewChild, args: ['chipContainer', { isSignal: true }] }], autocompleteContainer: [{ type: i0.ViewChild, args: ['autocompleteContainer', { isSignal: true }] }] } });
|
|
748
754
|
|
|
749
755
|
/**
|