@i-cell/ids-angular 0.2.22 → 0.2.24
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/datepicker/index.d.ts +3 -2
- package/fesm2022/i-cell-ids-angular-datepicker.mjs +3 -2
- package/fesm2022/i-cell-ids-angular-datepicker.mjs.map +1 -1
- package/fesm2022/i-cell-ids-angular-forms.mjs +933 -709
- package/fesm2022/i-cell-ids-angular-forms.mjs.map +1 -1
- package/forms/index.d.ts +116 -96
- package/package.json +17 -17
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, InjectionToken, inject,
|
|
3
|
-
import {
|
|
2
|
+
import { Injectable, InjectionToken, inject, Injector, signal, input, effect, booleanAttribute, computed, Directive, Input, contentChildren, ChangeDetectionStrategy, ViewEncapsulation, Component, ElementRef, ChangeDetectorRef, viewChild, contentChild, output, model, untracked, forwardRef, Renderer2, afterNextRender, isDevMode } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { NgForm, FormGroupDirective, NgControl, Validators, NG_VALUE_ACCESSOR, StatusChangeEvent } from '@angular/forms';
|
|
5
|
+
import { ComponentBaseWithDefaults, IdsSize, ComponentBase, coerceBooleanAttribute, coerceNumberAttribute } from '@i-cell/ids-angular/core';
|
|
6
|
+
import { Subject, observeOn, asapScheduler, tap, switchMap, of, startWith } from 'rxjs';
|
|
4
7
|
import { IdsIconComponent } from '@i-cell/ids-angular/icon';
|
|
5
8
|
import { hasModifierKey } from '@angular/cdk/keycodes';
|
|
6
|
-
import {
|
|
7
|
-
import * as i1 from '@angular/forms';
|
|
8
|
-
import { NgForm, FormGroupDirective, NgControl, Validators, StatusChangeEvent, ValueChangeEvent, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
9
|
-
import { Subject, observeOn, asapScheduler, tap, switchMap, of, startWith, filter } from 'rxjs';
|
|
10
|
-
import { LiveAnnouncer, ActiveDescendantKeyManager } from '@angular/cdk/a11y';
|
|
11
|
-
import { SelectionModel } from '@angular/cdk/collections';
|
|
12
|
-
import { CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
13
|
-
import { IdsIconButtonComponent } from '@i-cell/ids-angular/icon-button';
|
|
9
|
+
import { IdsIconButtonAppearance, IdsIconButtonComponent } from '@i-cell/ids-angular/icon-button';
|
|
14
10
|
import { IdsOverlayPanelComponent } from '@i-cell/ids-angular/overlay-panel';
|
|
15
|
-
import { IdsSpinnerComponent } from '@i-cell/ids-angular/spinner';
|
|
11
|
+
import { IdsSpinnerVariant, IdsSpinnerComponent } from '@i-cell/ids-angular/spinner';
|
|
16
12
|
import { IdsTooltipDirective } from '@i-cell/ids-angular/tooltip';
|
|
13
|
+
import { LiveAnnouncer, ActiveDescendantKeyManager } from '@angular/cdk/a11y';
|
|
14
|
+
import { SelectionModel } from '@angular/cdk/collections';
|
|
15
|
+
import { IdsChipAppearance, IdsChipVariant, IdsChipComponent } from '@i-cell/ids-angular/chip';
|
|
17
16
|
|
|
18
17
|
class AbstractErrorStateMatcher {
|
|
19
18
|
}
|
|
@@ -95,223 +94,11 @@ const IDS_AUTOCOMPLETE_DEFAULT_CONFIG = new InjectionToken('IDS_AUTOCOMPLETE_DEF
|
|
|
95
94
|
});
|
|
96
95
|
function IDS_AUTOCOMPLETE_DEFAULT_CONFIG_FACTORY() {
|
|
97
96
|
return {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
hintNoResults: 'No results found',
|
|
101
|
-
hintMinChars: 'Please provide at least 1 characters',
|
|
102
|
-
hintMaxLength: 'Too many results, please refine your search',
|
|
103
|
-
typeaheadDebounceInterval: 300,
|
|
97
|
+
errorStateMatcher: ErrorStateMatcher,
|
|
98
|
+
successStateMatcher: SuccessStateMatcher,
|
|
104
99
|
};
|
|
105
100
|
}
|
|
106
101
|
|
|
107
|
-
const IDS_AUTOCOMPLETE_LOADER = new InjectionToken('IDS_AUTOCOMPLETE_LOADER');
|
|
108
|
-
|
|
109
|
-
const IDS_OPTION_GROUP = new InjectionToken('IdsOptionGroup');
|
|
110
|
-
|
|
111
|
-
const IDS_OPTION_PARENT_COMPONENT = new InjectionToken('IDS_OPTION_PARENT_COMPONENT');
|
|
112
|
-
|
|
113
|
-
class IdsOptionSelectionChange {
|
|
114
|
-
constructor(source, selected, isUserInput = false) {
|
|
115
|
-
this.source = source;
|
|
116
|
-
this.selected = selected;
|
|
117
|
-
this.isUserInput = isUserInput;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const IdsFormFieldVariant = {
|
|
122
|
-
SURFACE: 'surface',
|
|
123
|
-
LIGHT: 'light',
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const IDS_PSEUDO_CHECKBOX_PARENT = new InjectionToken('IDS_PSEUDO_CHECKBOX_PARENT');
|
|
127
|
-
|
|
128
|
-
const IdsPseudoCheckboxState = {
|
|
129
|
-
UNCHECKED: 'unchecked',
|
|
130
|
-
CHECKED: 'checked',
|
|
131
|
-
INDETERMINATE: 'indeterminate',
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
class PseudoCheckboxComponent extends ComponentBase {
|
|
135
|
-
constructor() {
|
|
136
|
-
super(...arguments);
|
|
137
|
-
this._parent = inject(IDS_PSEUDO_CHECKBOX_PARENT, { optional: true });
|
|
138
|
-
this.checkboxState = input(IdsPseudoCheckboxState.UNCHECKED, ...(ngDevMode ? [{ debugName: "checkboxState" }] : []));
|
|
139
|
-
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: coerceBooleanAttribute }] : [{ transform: coerceBooleanAttribute }]));
|
|
140
|
-
this._isChecked = computed(() => this.checkboxState() === IdsPseudoCheckboxState.CHECKED, ...(ngDevMode ? [{ debugName: "_isChecked" }] : []));
|
|
141
|
-
this._isIndeterminate = computed(() => this.checkboxState() === IdsPseudoCheckboxState.INDETERMINATE, ...(ngDevMode ? [{ debugName: "_isIndeterminate" }] : []));
|
|
142
|
-
this._hostClasses = computed(() => this._getHostClasses([
|
|
143
|
-
this._parent?.embeddedPseudoCheckboxSize(),
|
|
144
|
-
this._parent?.embeddedPseudoCheckboxVariant(),
|
|
145
|
-
this.disabled() ? 'disabled' : null,
|
|
146
|
-
]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
147
|
-
}
|
|
148
|
-
get _hostName() {
|
|
149
|
-
return 'pseudo-checkbox';
|
|
150
|
-
}
|
|
151
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PseudoCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
152
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: PseudoCheckboxComponent, isStandalone: true, selector: "ids-pseudo-checkbox", inputs: { checkboxState: { classPropertyName: "checkboxState", publicName: "checkboxState", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div class=\"ids-pseudo-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n [disabled]=\"disabled()\"\n [attr.aria-checked]=\"_isIndeterminate() ? 'mixed' : null\"\n [checked]=\"_isChecked()\"\n [indeterminate]=\"_isIndeterminate()\"\n (change)=\"$event.stopPropagation()\"\n />\n <div class=\"ids-pseudo-checkbox__icon\" aria-hidden=\"true\">\n @if (_isIndeterminate()) {\n <ids-icon fontIcon=\"remove\" aria-hidden=\"true\" />\n }\n @if (_isChecked()) {\n <ids-icon fontIcon=\"done\" aria-hidden=\"true\" />\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
153
|
-
}
|
|
154
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PseudoCheckboxComponent, decorators: [{
|
|
155
|
-
type: Component,
|
|
156
|
-
args: [{ selector: 'ids-pseudo-checkbox', imports: [IdsIconComponent], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ids-pseudo-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n [disabled]=\"disabled()\"\n [attr.aria-checked]=\"_isIndeterminate() ? 'mixed' : null\"\n [checked]=\"_isChecked()\"\n [indeterminate]=\"_isIndeterminate()\"\n (change)=\"$event.stopPropagation()\"\n />\n <div class=\"ids-pseudo-checkbox__icon\" aria-hidden=\"true\">\n @if (_isIndeterminate()) {\n <ids-icon fontIcon=\"remove\" aria-hidden=\"true\" />\n }\n @if (_isChecked()) {\n <ids-icon fontIcon=\"done\" aria-hidden=\"true\" />\n }\n </div>\n</div>\n" }]
|
|
157
|
-
}] });
|
|
158
|
-
|
|
159
|
-
class IdsOptionComponent extends ComponentBase {
|
|
160
|
-
get _hostName() {
|
|
161
|
-
return 'option';
|
|
162
|
-
}
|
|
163
|
-
constructor() {
|
|
164
|
-
super();
|
|
165
|
-
this._parent = inject(IDS_OPTION_PARENT_COMPONENT);
|
|
166
|
-
this._element = inject(ElementRef);
|
|
167
|
-
this.group = inject(IDS_OPTION_GROUP, { optional: true });
|
|
168
|
-
this._textElement = viewChild.required('text');
|
|
169
|
-
this.selected = signal(false, ...(ngDevMode ? [{ debugName: "selected" }] : []));
|
|
170
|
-
this._active = signal(false, ...(ngDevMode ? [{ debugName: "_active" }] : []));
|
|
171
|
-
this.size = computed(() => this._parent.parentSize(), ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
172
|
-
this.variant = computed(() => this._parent.parentVariant(), ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
173
|
-
this.value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
174
|
-
this.explicitViewValue = input(null, ...(ngDevMode ? [{ debugName: "explicitViewValue", alias: 'viewValue' }] : [{ alias: 'viewValue' }]));
|
|
175
|
-
this.disabledInput = input(false, ...(ngDevMode ? [{ debugName: "disabledInput", alias: 'disabled', transform: coerceBooleanAttribute }] : [{ alias: 'disabled', transform: coerceBooleanAttribute }]));
|
|
176
|
-
this.disabled = false; // Do not delete this class member, until ListKeyManagerOption requires: `disabled: boolean`
|
|
177
|
-
this._groupOrOptionIsDisabled = computed(() => this.group?.disabled() || this.disabledInput(), ...(ngDevMode ? [{ debugName: "_groupOrOptionIsDisabled" }] : []));
|
|
178
|
-
this._multiSelect = Boolean(this._parent?.multiSelect());
|
|
179
|
-
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
|
180
|
-
this.onSelectionChange = output();
|
|
181
|
-
this.viewValue = computed(() => this.explicitViewValue() || this._textElement().nativeElement.textContent || '', ...(ngDevMode ? [{ debugName: "viewValue" }] : []));
|
|
182
|
-
this._hostClasses = computed(() => this._getHostClasses([
|
|
183
|
-
this.selected() ? 'selected' : null,
|
|
184
|
-
this._active() ? 'active' : null,
|
|
185
|
-
this._groupOrOptionIsDisabled() ? 'disabled' : null,
|
|
186
|
-
this._multiSelect ? 'multiselect' : null,
|
|
187
|
-
this.size(),
|
|
188
|
-
this.variant(),
|
|
189
|
-
]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
190
|
-
this._pseudoCheckboxState = computed(() => (this.selected() ? IdsPseudoCheckboxState.CHECKED : IdsPseudoCheckboxState.UNCHECKED), ...(ngDevMode ? [{ debugName: "_pseudoCheckboxState" }] : []));
|
|
191
|
-
this.embeddedPseudoCheckboxSize = computed(() => this.size(), ...(ngDevMode ? [{ debugName: "embeddedPseudoCheckboxSize" }] : []));
|
|
192
|
-
this.embeddedPseudoCheckboxVariant = signal(IdsFormFieldVariant.SURFACE, ...(ngDevMode ? [{ debugName: "embeddedPseudoCheckboxVariant" }] : []));
|
|
193
|
-
effect(() => {
|
|
194
|
-
this.disabled = this.disabledInput();
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
ngOnInit() {
|
|
198
|
-
const parent = this._parent;
|
|
199
|
-
if (parent.isOptionPreSelectedByValue(this.value())) {
|
|
200
|
-
this.selected.set(true);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
_handleKeydown(event) {
|
|
204
|
-
if ((event.key === 'ENTER' || event.key === ' ') && !hasModifierKey(event)) {
|
|
205
|
-
this.selectViaInteraction();
|
|
206
|
-
event.preventDefault();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
selectViaInteraction() {
|
|
210
|
-
if (!this._groupOrOptionIsDisabled()) {
|
|
211
|
-
this._emitSelectionChangeEvent(!this.selected(), true);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
getHostElement() {
|
|
215
|
-
return this._element.nativeElement;
|
|
216
|
-
}
|
|
217
|
-
select(emitEvent = true) {
|
|
218
|
-
if (!this.selected()) {
|
|
219
|
-
if (emitEvent) {
|
|
220
|
-
this._emitSelectionChangeEvent(true);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
deselect(emitEvent = true) {
|
|
225
|
-
if (this.selected()) {
|
|
226
|
-
if (emitEvent) {
|
|
227
|
-
this._emitSelectionChangeEvent(false);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
focus(_origin, options) {
|
|
232
|
-
const element = this._element.nativeElement;
|
|
233
|
-
if (typeof element.focus === 'function') {
|
|
234
|
-
element.focus(options);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
setActiveStyles() {
|
|
238
|
-
if (!this._active()) {
|
|
239
|
-
this._active.set(true);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
setInactiveStyles() {
|
|
243
|
-
if (this._active()) {
|
|
244
|
-
this._active.set(false);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
getLabel() {
|
|
248
|
-
return this.viewValue();
|
|
249
|
-
}
|
|
250
|
-
_emitSelectionChangeEvent(selected, isUserInput = false) {
|
|
251
|
-
if (this._multiSelect || !this.selected()) {
|
|
252
|
-
this.onSelectionChange.emit(new IdsOptionSelectionChange(this, selected, isUserInput));
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
256
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: IdsOptionComponent, isStandalone: true, selector: "ids-option", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, explicitViewValue: { classPropertyName: "explicitViewValue", publicName: "viewValue", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, host: { attributes: { "role": "option" }, listeners: { "click": "selectViaInteraction()", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-selected": "selected()", "attr.aria-disabled": "disabled.toString()" } }, providers: [
|
|
257
|
-
{
|
|
258
|
-
provide: IDS_PSEUDO_CHECKBOX_PARENT,
|
|
259
|
-
useExisting: IdsOptionComponent,
|
|
260
|
-
},
|
|
261
|
-
], viewQueries: [{ propertyName: "_textElement", first: true, predicate: ["text"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (_multiSelect) {\n <ids-pseudo-checkbox aria-hidden=\"true\" [disabled]=\"_groupOrOptionIsDisabled()\" [checkboxState]=\"_pseudoCheckboxState()\" />\n}\n\n<div #text class=\"ids-option__text\"><ng-content /></div>\n\n@if (!_multiSelect && selected()) {\n <ids-icon fontIcon=\"done\" />\n}\n", dependencies: [{ kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }, { kind: "component", type: PseudoCheckboxComponent, selector: "ids-pseudo-checkbox", inputs: ["checkboxState", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
262
|
-
}
|
|
263
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsOptionComponent, decorators: [{
|
|
264
|
-
type: Component,
|
|
265
|
-
args: [{ selector: 'ids-option', imports: [
|
|
266
|
-
IdsIconComponent,
|
|
267
|
-
PseudoCheckboxComponent,
|
|
268
|
-
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
269
|
-
{
|
|
270
|
-
provide: IDS_PSEUDO_CHECKBOX_PARENT,
|
|
271
|
-
useExisting: IdsOptionComponent,
|
|
272
|
-
},
|
|
273
|
-
], host: {
|
|
274
|
-
'role': 'option',
|
|
275
|
-
'[attr.aria-selected]': 'selected()',
|
|
276
|
-
'[attr.aria-disabled]': 'disabled.toString()',
|
|
277
|
-
'(click)': 'selectViaInteraction()',
|
|
278
|
-
'(keydown)': '_handleKeydown($event)',
|
|
279
|
-
}, template: "@if (_multiSelect) {\n <ids-pseudo-checkbox aria-hidden=\"true\" [disabled]=\"_groupOrOptionIsDisabled()\" [checkboxState]=\"_pseudoCheckboxState()\" />\n}\n\n<div #text class=\"ids-option__text\"><ng-content /></div>\n\n@if (!_multiSelect && selected()) {\n <ids-icon fontIcon=\"done\" />\n}\n" }]
|
|
280
|
-
}], ctorParameters: () => [] });
|
|
281
|
-
function _countGroupLabelsBeforeOption(optionIndex, options, optionGroups) {
|
|
282
|
-
if (optionGroups.length) {
|
|
283
|
-
let groupCounter = 0;
|
|
284
|
-
for (let i = 0; i < optionIndex + 1; i++) {
|
|
285
|
-
if (options[i].group && options[i].group === optionGroups[groupCounter]) {
|
|
286
|
-
groupCounter++;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return groupCounter;
|
|
290
|
-
}
|
|
291
|
-
return 0;
|
|
292
|
-
}
|
|
293
|
-
function _getOptionScrollPosition(optionOffset, optionHeight, currentScrollPosition, panelHeight) {
|
|
294
|
-
if (optionOffset < currentScrollPosition) {
|
|
295
|
-
return optionOffset;
|
|
296
|
-
}
|
|
297
|
-
if (optionOffset + optionHeight > currentScrollPosition + panelHeight) {
|
|
298
|
-
return Math.max(0, optionOffset - panelHeight + optionHeight);
|
|
299
|
-
}
|
|
300
|
-
return currentScrollPosition;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
class IdsFormFieldActionDirective {
|
|
304
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsFormFieldActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
305
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.7", type: IdsFormFieldActionDirective, isStandalone: true, selector: "[idsFormFieldAction]", ngImport: i0 }); }
|
|
306
|
-
}
|
|
307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsFormFieldActionDirective, decorators: [{
|
|
308
|
-
type: Directive,
|
|
309
|
-
args: [{
|
|
310
|
-
selector: '[idsFormFieldAction]',
|
|
311
|
-
standalone: true,
|
|
312
|
-
}]
|
|
313
|
-
}] });
|
|
314
|
-
|
|
315
102
|
const formFieldControlClass = 'ids-form-field-control';
|
|
316
103
|
class IdsFormFieldControl extends ComponentBaseWithDefaults {
|
|
317
104
|
constructor() {
|
|
@@ -384,6 +171,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
384
171
|
type: Directive
|
|
385
172
|
}], ctorParameters: () => [] });
|
|
386
173
|
|
|
174
|
+
const IdsFormFieldVariant = {
|
|
175
|
+
SURFACE: 'surface',
|
|
176
|
+
LIGHT: 'light',
|
|
177
|
+
};
|
|
178
|
+
|
|
387
179
|
const IDS_FORM_FIELD_DEFAULT_CONFIG = new InjectionToken('IDS_FORM_FIELD_DEFAULT_CONFIG', {
|
|
388
180
|
providedIn: 'root',
|
|
389
181
|
factory: IDS_FORM_FIELD_DEFAULT_CONFIG_FACTORY,
|
|
@@ -397,6 +189,18 @@ function IDS_FORM_FIELD_DEFAULT_CONFIG_FACTORY() {
|
|
|
397
189
|
|
|
398
190
|
const IDS_FORM_FIELD_CONTROL = new InjectionToken('IDS_FORM_FIELD_CONTROL');
|
|
399
191
|
|
|
192
|
+
class IdsFormFieldActionDirective {
|
|
193
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsFormFieldActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
194
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.7", type: IdsFormFieldActionDirective, isStandalone: true, selector: "[idsFormFieldAction]", ngImport: i0 }); }
|
|
195
|
+
}
|
|
196
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsFormFieldActionDirective, decorators: [{
|
|
197
|
+
type: Directive,
|
|
198
|
+
args: [{
|
|
199
|
+
selector: '[idsFormFieldAction]',
|
|
200
|
+
standalone: true,
|
|
201
|
+
}]
|
|
202
|
+
}] });
|
|
203
|
+
|
|
400
204
|
class IdsPrefixDirective {
|
|
401
205
|
constructor() {
|
|
402
206
|
this.isLeadingIcon = false;
|
|
@@ -816,253 +620,265 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
816
620
|
args: [{ selector: 'ids-form-field', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<label class=\"ids-form-field__label\" [for]=\"_inputId()\">\n @if (hasRequiredValidator()) {\n <span class=\"ids-form-field__required-marker\"></span>\n }\n <ng-content select=\"ids-label\" />\n</label>\n\n<div #fieldWrapper class=\"ids-form-field__field-wrapper\">\n <div class=\"ids-form-field__field-wrapper__container\" (click)=\"containerClick($event)\">\n @if (_hasLeadingIcon()) {\n <div class=\"ids-form-field__leading-icon\">\n <ng-content select=\"ids-icon[idsLeadingIcon]\" />\n </div>\n }\n @if (_hasPrefix()) {\n <div class=\"ids-form-field__prefix\">\n <ng-content select=\"[idsPrefix]\" />\n </div>\n }\n <div class=\"ids-form-field__infix\">\n <ng-content />\n </div>\n @if (_hasSuffix()) {\n <div class=\"ids-form-field__suffix\">\n <ng-content select=\"[idsSuffix]\" />\n </div>\n }\n @if (_hasTrailingIcon()) {\n <div class=\"ids-form-field__trailing-icon\">\n <ng-content select=\"ids-icon[idsTrailingIcon]\" />\n </div>\n }\n </div>\n @if (_hasActions()) {\n <div class=\"ids-form-field__field-wrapper__action\">\n <ng-content select=\"[idsFormFieldAction]\" />\n </div>\n }\n</div>\n\n<div class=\"ids-form-field__subscript-wrapper\">\n @let messages = _displayedMessages();\n @if (messages) {\n <div class=\"ids-form-field__message-container\">\n @switch (messages) {\n @case (\"error\") {\n <ng-content select=\"ids-error-message\" />\n }\n @case (\"success\") {\n <ng-content select=\"ids-success-message\" />\n }\n @case (\"hint\") {\n <ng-content select=\"ids-hint-message\" />\n }\n }\n </div>\n }\n</div>\n" }]
|
|
817
621
|
}] });
|
|
818
622
|
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
623
|
+
const IDS_OPTION_GROUP = new InjectionToken('IdsOptionGroup');
|
|
624
|
+
|
|
625
|
+
const IDS_OPTION_PARENT_COMPONENT = new InjectionToken('IDS_OPTION_PARENT_COMPONENT');
|
|
626
|
+
|
|
627
|
+
class IdsOptionSelectionChange {
|
|
628
|
+
constructor(source, selected, isUserInput = false) {
|
|
629
|
+
this.source = source;
|
|
630
|
+
this.selected = selected;
|
|
631
|
+
this.isUserInput = isUserInput;
|
|
632
|
+
}
|
|
828
633
|
}
|
|
829
634
|
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
'
|
|
834
|
-
'
|
|
835
|
-
'
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
'reset',
|
|
840
|
-
'submit',
|
|
841
|
-
];
|
|
842
|
-
class IdsInputDirective extends IdsFormFieldControl {
|
|
635
|
+
const IDS_PSEUDO_CHECKBOX_PARENT = new InjectionToken('IDS_PSEUDO_CHECKBOX_PARENT');
|
|
636
|
+
|
|
637
|
+
const IdsPseudoCheckboxState = {
|
|
638
|
+
UNCHECKED: 'unchecked',
|
|
639
|
+
CHECKED: 'checked',
|
|
640
|
+
INDETERMINATE: 'indeterminate',
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
class PseudoCheckboxComponent extends ComponentBase {
|
|
843
644
|
constructor() {
|
|
844
645
|
super(...arguments);
|
|
845
|
-
this.
|
|
846
|
-
this.
|
|
847
|
-
this.
|
|
848
|
-
this.
|
|
849
|
-
this.
|
|
850
|
-
this.
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}, ...(ngDevMode ? [{ debugName: "_validateTypeEffect" }] : []));
|
|
856
|
-
/**
|
|
857
|
-
* Should be an arrow function in order to handle `this` outside of this class
|
|
858
|
-
*/
|
|
859
|
-
this.onContainerClick = () => {
|
|
860
|
-
if (!this._focused && !this.readonly() && !this.disabled) {
|
|
861
|
-
this.focus();
|
|
862
|
-
}
|
|
863
|
-
};
|
|
646
|
+
this._parent = inject(IDS_PSEUDO_CHECKBOX_PARENT, { optional: true });
|
|
647
|
+
this.checkboxState = input(IdsPseudoCheckboxState.UNCHECKED, ...(ngDevMode ? [{ debugName: "checkboxState" }] : []));
|
|
648
|
+
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: coerceBooleanAttribute }] : [{ transform: coerceBooleanAttribute }]));
|
|
649
|
+
this._isChecked = computed(() => this.checkboxState() === IdsPseudoCheckboxState.CHECKED, ...(ngDevMode ? [{ debugName: "_isChecked" }] : []));
|
|
650
|
+
this._isIndeterminate = computed(() => this.checkboxState() === IdsPseudoCheckboxState.INDETERMINATE, ...(ngDevMode ? [{ debugName: "_isIndeterminate" }] : []));
|
|
651
|
+
this._hostClasses = computed(() => this._getHostClasses([
|
|
652
|
+
this._parent?.embeddedPseudoCheckboxSize(),
|
|
653
|
+
this._parent?.embeddedPseudoCheckboxVariant(),
|
|
654
|
+
this.disabled() ? 'disabled' : null,
|
|
655
|
+
]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
864
656
|
}
|
|
865
657
|
get _hostName() {
|
|
866
|
-
return '
|
|
658
|
+
return 'pseudo-checkbox';
|
|
867
659
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
660
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PseudoCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
661
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: PseudoCheckboxComponent, isStandalone: true, selector: "ids-pseudo-checkbox", inputs: { checkboxState: { classPropertyName: "checkboxState", publicName: "checkboxState", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div class=\"ids-pseudo-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n [disabled]=\"disabled()\"\n [attr.aria-checked]=\"_isIndeterminate() ? 'mixed' : null\"\n [checked]=\"_isChecked()\"\n [indeterminate]=\"_isIndeterminate()\"\n (change)=\"$event.stopPropagation()\"\n />\n <div class=\"ids-pseudo-checkbox__icon\" aria-hidden=\"true\">\n @if (_isIndeterminate()) {\n <ids-icon fontIcon=\"remove\" aria-hidden=\"true\" />\n }\n @if (_isChecked()) {\n <ids-icon fontIcon=\"done\" aria-hidden=\"true\" />\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
662
|
+
}
|
|
663
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PseudoCheckboxComponent, decorators: [{
|
|
664
|
+
type: Component,
|
|
665
|
+
args: [{ selector: 'ids-pseudo-checkbox', imports: [IdsIconComponent], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ids-pseudo-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n [disabled]=\"disabled()\"\n [attr.aria-checked]=\"_isIndeterminate() ? 'mixed' : null\"\n [checked]=\"_isChecked()\"\n [indeterminate]=\"_isIndeterminate()\"\n (change)=\"$event.stopPropagation()\"\n />\n <div class=\"ids-pseudo-checkbox__icon\" aria-hidden=\"true\">\n @if (_isIndeterminate()) {\n <ids-icon fontIcon=\"remove\" aria-hidden=\"true\" />\n }\n @if (_isChecked()) {\n <ids-icon fontIcon=\"done\" aria-hidden=\"true\" />\n }\n </div>\n</div>\n" }]
|
|
666
|
+
}] });
|
|
667
|
+
|
|
668
|
+
class IdsOptionComponent extends ComponentBase {
|
|
669
|
+
get _hostName() {
|
|
670
|
+
return 'option';
|
|
671
|
+
}
|
|
672
|
+
constructor() {
|
|
673
|
+
super();
|
|
674
|
+
this._parent = inject(IDS_OPTION_PARENT_COMPONENT);
|
|
675
|
+
this._element = inject(ElementRef);
|
|
676
|
+
this.group = inject(IDS_OPTION_GROUP, { optional: true });
|
|
677
|
+
this._textElement = viewChild.required('text');
|
|
678
|
+
this.selected = signal(false, ...(ngDevMode ? [{ debugName: "selected" }] : []));
|
|
679
|
+
this._active = signal(false, ...(ngDevMode ? [{ debugName: "_active" }] : []));
|
|
680
|
+
this.size = computed(() => this._parent.parentSize(), ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
681
|
+
this.variant = computed(() => this._parent.parentVariant(), ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
682
|
+
this.value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
683
|
+
this.explicitViewValue = input(null, ...(ngDevMode ? [{ debugName: "explicitViewValue", alias: 'viewValue' }] : [{ alias: 'viewValue' }]));
|
|
684
|
+
this.disabledInput = input(false, ...(ngDevMode ? [{ debugName: "disabledInput", alias: 'disabled', transform: coerceBooleanAttribute }] : [{ alias: 'disabled', transform: coerceBooleanAttribute }]));
|
|
685
|
+
this.disabled = false; // Do not delete this class member, until ListKeyManagerOption requires: `disabled: boolean`
|
|
686
|
+
this._groupOrOptionIsDisabled = computed(() => this.group?.disabled() || this.disabledInput(), ...(ngDevMode ? [{ debugName: "_groupOrOptionIsDisabled" }] : []));
|
|
687
|
+
this._multiSelect = Boolean(this._parent?.multiSelect());
|
|
688
|
+
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
|
689
|
+
this.onSelectionChange = output();
|
|
690
|
+
this.viewValue = computed(() => this.explicitViewValue() || this._textElement().nativeElement.textContent || '', ...(ngDevMode ? [{ debugName: "viewValue" }] : []));
|
|
691
|
+
this._hostClasses = computed(() => this._getHostClasses([
|
|
692
|
+
this.selected() ? 'selected' : null,
|
|
693
|
+
this._active() ? 'active' : null,
|
|
694
|
+
this._groupOrOptionIsDisabled() ? 'disabled' : null,
|
|
695
|
+
this._multiSelect ? 'multiselect' : null,
|
|
696
|
+
this.size(),
|
|
697
|
+
this.variant(),
|
|
698
|
+
]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
699
|
+
this._pseudoCheckboxState = computed(() => (this.selected() ? IdsPseudoCheckboxState.CHECKED : IdsPseudoCheckboxState.UNCHECKED), ...(ngDevMode ? [{ debugName: "_pseudoCheckboxState" }] : []));
|
|
700
|
+
this.embeddedPseudoCheckboxSize = computed(() => this.size(), ...(ngDevMode ? [{ debugName: "embeddedPseudoCheckboxSize" }] : []));
|
|
701
|
+
this.embeddedPseudoCheckboxVariant = signal(IdsFormFieldVariant.SURFACE, ...(ngDevMode ? [{ debugName: "embeddedPseudoCheckboxVariant" }] : []));
|
|
702
|
+
effect(() => {
|
|
703
|
+
this.disabled = this.disabledInput();
|
|
875
704
|
});
|
|
876
705
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
706
|
+
ngOnInit() {
|
|
707
|
+
const parent = this._parent;
|
|
708
|
+
if (parent.isOptionPreSelectedByValue(this.value())) {
|
|
709
|
+
this.selected.set(true);
|
|
880
710
|
}
|
|
881
711
|
}
|
|
882
|
-
|
|
883
|
-
|
|
712
|
+
_handleKeydown(event) {
|
|
713
|
+
if ((event.key === 'ENTER' || event.key === ' ') && !hasModifierKey(event)) {
|
|
714
|
+
this.selectViaInteraction();
|
|
715
|
+
event.preventDefault();
|
|
716
|
+
}
|
|
884
717
|
}
|
|
885
|
-
|
|
886
|
-
if (
|
|
887
|
-
this.
|
|
718
|
+
selectViaInteraction() {
|
|
719
|
+
if (!this._groupOrOptionIsDisabled()) {
|
|
720
|
+
this._emitSelectionChangeEvent(!this.selected(), true);
|
|
888
721
|
}
|
|
889
722
|
}
|
|
890
|
-
|
|
891
|
-
this.
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
723
|
+
getHostElement() {
|
|
724
|
+
return this._element.nativeElement;
|
|
725
|
+
}
|
|
726
|
+
select(emitEvent = true) {
|
|
727
|
+
if (!this.selected()) {
|
|
728
|
+
if (emitEvent) {
|
|
729
|
+
this._emitSelectionChangeEvent(true);
|
|
730
|
+
}
|
|
895
731
|
}
|
|
896
732
|
}
|
|
897
|
-
|
|
898
|
-
|
|
733
|
+
deselect(emitEvent = true) {
|
|
734
|
+
if (this.selected()) {
|
|
735
|
+
if (emitEvent) {
|
|
736
|
+
this._emitSelectionChangeEvent(false);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
focus(_origin, options) {
|
|
741
|
+
const element = this._element.nativeElement;
|
|
742
|
+
if (typeof element.focus === 'function') {
|
|
743
|
+
element.focus(options);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
setActiveStyles() {
|
|
747
|
+
if (!this._active()) {
|
|
748
|
+
this._active.set(true);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
setInactiveStyles() {
|
|
752
|
+
if (this._active()) {
|
|
753
|
+
this._active.set(false);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
getLabel() {
|
|
757
|
+
return this.viewValue();
|
|
758
|
+
}
|
|
759
|
+
_emitSelectionChangeEvent(selected, isUserInput = false) {
|
|
760
|
+
if (this._multiSelect || !this.selected()) {
|
|
761
|
+
this.onSelectionChange.emit(new IdsOptionSelectionChange(this, selected, isUserInput));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
765
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: IdsOptionComponent, isStandalone: true, selector: "ids-option", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, explicitViewValue: { classPropertyName: "explicitViewValue", publicName: "viewValue", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, host: { attributes: { "role": "option" }, listeners: { "click": "selectViaInteraction()", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-selected": "selected()", "attr.aria-disabled": "disabled.toString()" } }, providers: [
|
|
899
766
|
{
|
|
900
|
-
provide:
|
|
901
|
-
useExisting:
|
|
767
|
+
provide: IDS_PSEUDO_CHECKBOX_PARENT,
|
|
768
|
+
useExisting: IdsOptionComponent,
|
|
902
769
|
},
|
|
903
|
-
],
|
|
770
|
+
], viewQueries: [{ propertyName: "_textElement", first: true, predicate: ["text"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (_multiSelect) {\n <ids-pseudo-checkbox aria-hidden=\"true\" [disabled]=\"_groupOrOptionIsDisabled()\" [checkboxState]=\"_pseudoCheckboxState()\" />\n}\n\n<div #text class=\"ids-option__text\"><ng-content /></div>\n\n@if (!_multiSelect && selected()) {\n <ids-icon fontIcon=\"done\" />\n}\n", dependencies: [{ kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }, { kind: "component", type: PseudoCheckboxComponent, selector: "ids-pseudo-checkbox", inputs: ["checkboxState", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
904
771
|
}
|
|
905
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type:
|
|
906
|
-
type:
|
|
907
|
-
args: [{
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
textarea[idsInput][ngModel]:not([formControl]):not([formControlName]),
|
|
912
|
-
textarea[idsInput][formControl]:not([ngModel]):not([formControlName]),
|
|
913
|
-
textarea[idsInput][formControlName]:not([ngModel]):not([formControl])`,
|
|
914
|
-
exportAs: 'idsInput',
|
|
915
|
-
standalone: true,
|
|
916
|
-
providers: [
|
|
772
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsOptionComponent, decorators: [{
|
|
773
|
+
type: Component,
|
|
774
|
+
args: [{ selector: 'ids-option', imports: [
|
|
775
|
+
IdsIconComponent,
|
|
776
|
+
PseudoCheckboxComponent,
|
|
777
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
917
778
|
{
|
|
918
|
-
provide:
|
|
919
|
-
useExisting:
|
|
779
|
+
provide: IDS_PSEUDO_CHECKBOX_PARENT,
|
|
780
|
+
useExisting: IdsOptionComponent,
|
|
920
781
|
},
|
|
921
|
-
],
|
|
922
|
-
|
|
923
|
-
'[attr.
|
|
924
|
-
'[attr.disabled]': 'disabled()
|
|
925
|
-
'
|
|
926
|
-
'(
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
782
|
+
], host: {
|
|
783
|
+
'role': 'option',
|
|
784
|
+
'[attr.aria-selected]': 'selected()',
|
|
785
|
+
'[attr.aria-disabled]': 'disabled.toString()',
|
|
786
|
+
'(click)': 'selectViaInteraction()',
|
|
787
|
+
'(keydown)': '_handleKeydown($event)',
|
|
788
|
+
}, template: "@if (_multiSelect) {\n <ids-pseudo-checkbox aria-hidden=\"true\" [disabled]=\"_groupOrOptionIsDisabled()\" [checkboxState]=\"_pseudoCheckboxState()\" />\n}\n\n<div #text class=\"ids-option__text\"><ng-content /></div>\n\n@if (!_multiSelect && selected()) {\n <ids-icon fontIcon=\"done\" />\n}\n" }]
|
|
789
|
+
}], ctorParameters: () => [] });
|
|
790
|
+
function _countGroupLabelsBeforeOption(optionIndex, options, optionGroups) {
|
|
791
|
+
if (optionGroups.length) {
|
|
792
|
+
let groupCounter = 0;
|
|
793
|
+
for (let i = 0; i < optionIndex + 1; i++) {
|
|
794
|
+
if (options[i].group && options[i].group === optionGroups[groupCounter]) {
|
|
795
|
+
groupCounter++;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return groupCounter;
|
|
799
|
+
}
|
|
800
|
+
return 0;
|
|
801
|
+
}
|
|
802
|
+
function _getOptionScrollPosition(optionOffset, optionHeight, currentScrollPosition, panelHeight) {
|
|
803
|
+
if (optionOffset < currentScrollPosition) {
|
|
804
|
+
return optionOffset;
|
|
805
|
+
}
|
|
806
|
+
if (optionOffset + optionHeight > currentScrollPosition + panelHeight) {
|
|
807
|
+
return Math.max(0, optionOffset - panelHeight + optionHeight);
|
|
808
|
+
}
|
|
809
|
+
return currentScrollPosition;
|
|
810
|
+
}
|
|
931
811
|
|
|
932
|
-
const defaultConfig = IDS_AUTOCOMPLETE_DEFAULT_CONFIG_FACTORY();
|
|
933
|
-
const LIVE_ANNOUNCE_DURATION_MS = 10000;
|
|
812
|
+
const defaultConfig$1 = IDS_AUTOCOMPLETE_DEFAULT_CONFIG_FACTORY();
|
|
934
813
|
class IdsAutocompleteComponent extends IdsFormFieldControl {
|
|
935
814
|
get _hostName() {
|
|
936
815
|
return 'autocomplete';
|
|
937
816
|
}
|
|
938
|
-
get _empty() {
|
|
939
|
-
return Boolean(this._selectionModel?.isEmpty());
|
|
940
|
-
}
|
|
941
|
-
get selected() {
|
|
942
|
-
return this.multiSelect() ? this._selectionModel?.selected : this._selectionModel?.selected?.[0];
|
|
943
|
-
}
|
|
944
|
-
get _triggerValue() {
|
|
945
|
-
if (this._empty) {
|
|
946
|
-
return '';
|
|
947
|
-
}
|
|
948
|
-
if (this.multiSelect()) {
|
|
949
|
-
const selectedOptions = this._selectionModel?.selected;
|
|
950
|
-
return selectedOptions?.join(', ') || '';
|
|
951
|
-
}
|
|
952
|
-
return this._selectionModel?.selected?.[0] || '';
|
|
953
|
-
}
|
|
954
817
|
constructor() {
|
|
955
818
|
super();
|
|
956
|
-
this._defaultConfig = this._getDefaultConfig(defaultConfig, IDS_AUTOCOMPLETE_DEFAULT_CONFIG);
|
|
957
|
-
this._elementRef = inject(ElementRef);
|
|
958
|
-
this._changeDetectorRef = inject(ChangeDetectorRef);
|
|
959
|
-
this._liveAnnouncer = inject(LiveAnnouncer);
|
|
960
|
-
this._parentFormField = inject(IdsFormFieldComponent);
|
|
961
|
-
this._overlayWidth = 0;
|
|
962
|
-
/**
|
|
963
|
-
* Minimum number of characters to initiate actual search.
|
|
964
|
-
* Warning is shown when input length is not met.
|
|
965
|
-
* (Resource loader/stream function needs to be adjusted accordingly!)
|
|
966
|
-
*/
|
|
967
|
-
this.minChars = input(1, ...(ngDevMode ? [{ debugName: "minChars", transform: coerceNumberAttribute }] : [{ transform: coerceNumberAttribute }]));
|
|
968
|
-
/** Max length of options allowed to show. Warning is shown when available options is higher than this number */
|
|
969
|
-
this.maxLength = input(null, ...(ngDevMode ? [{ debugName: "maxLength", transform: coerceNumberAttribute }] : [{ transform: coerceNumberAttribute }]));
|
|
970
|
-
this.multiSelect = input(false, ...(ngDevMode ? [{ debugName: "multiSelect" }] : []));
|
|
971
819
|
this.ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel", alias: 'aria-label' }] : [{ alias: 'aria-label' }]));
|
|
972
820
|
this.ariaLabelledby = input('', ...(ngDevMode ? [{ debugName: "ariaLabelledby", alias: 'aria-labelledby' }] : [{ alias: 'aria-labelledby' }]));
|
|
973
|
-
this.
|
|
974
|
-
this.
|
|
975
|
-
this.
|
|
976
|
-
this.sortCompareFn = input(...(ngDevMode ? [undefined, { debugName: "sortCompareFn" }] : []));
|
|
821
|
+
this.ariaLabelClear = input('', ...(ngDevMode ? [{ debugName: "ariaLabelClear" }] : []));
|
|
822
|
+
this.ariaLabelLoading = input('', ...(ngDevMode ? [{ debugName: "ariaLabelLoading" }] : []));
|
|
823
|
+
this.multiSelect = input(false, ...(ngDevMode ? [{ debugName: "multiSelect", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
977
824
|
this.tabIndex = input(0, ...(ngDevMode ? [{ debugName: "tabIndex", transform: coerceNumberAttribute }] : [{ transform: coerceNumberAttribute }]));
|
|
978
|
-
this.
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
this.hintLoading = input(this._defaultConfig.hintLoading, ...(ngDevMode ? [{ debugName: "hintLoading" }] : []));
|
|
982
|
-
this.hintNoResults = input(this._defaultConfig.hintNoResults, ...(ngDevMode ? [{ debugName: "hintNoResults" }] : []));
|
|
983
|
-
this.hintMinChars = input(this._defaultConfig.hintMinChars, ...(ngDevMode ? [{ debugName: "hintMinChars" }] : []));
|
|
984
|
-
this.hintMaxLength = input(this._defaultConfig.hintMaxLength, ...(ngDevMode ? [{ debugName: "hintMaxLength" }] : []));
|
|
825
|
+
this.sortCompareFn = input((a, b) => a.viewValue.localeCompare(b.viewValue), ...(ngDevMode ? [{ debugName: "sortCompareFn" }] : []));
|
|
826
|
+
this.valueCompareFn = input((o1, o2) => JSON.stringify(o1) === JSON.stringify(o2), ...(ngDevMode ? [{ debugName: "valueCompareFn" }] : []));
|
|
827
|
+
this.trigger = input.required(...(ngDevMode ? [{ debugName: "trigger" }] : []));
|
|
985
828
|
this.panelClasses = input('', ...(ngDevMode ? [{ debugName: "panelClasses" }] : []));
|
|
829
|
+
this.panelOpen = model(false, ...(ngDevMode ? [{ debugName: "panelOpen" }] : []));
|
|
830
|
+
this.options = contentChildren(IdsOptionComponent, ...(ngDevMode ? [{ debugName: "options", descendants: true }] : [{ descendants: true }]));
|
|
831
|
+
this.optionGroups = contentChildren(IDS_OPTION_GROUP, ...(ngDevMode ? [{ debugName: "optionGroups", descendants: true }] : [{ descendants: true }]));
|
|
832
|
+
this.overlayPanel = viewChild('overlayPanel', ...(ngDevMode ? [{ debugName: "overlayPanel" }] : []));
|
|
833
|
+
this.panel = viewChild('panel', ...(ngDevMode ? [{ debugName: "panel", read: (ElementRef) }] : [{ read: (ElementRef) }]));
|
|
834
|
+
this.appearance = input(IdsIconButtonAppearance.STANDARD, ...(ngDevMode ? [{ debugName: "appearance" }] : []));
|
|
986
835
|
this.parentSize = computed(() => this._parentFormField.parentOrSelfSize(), ...(ngDevMode ? [{ debugName: "parentSize" }] : []));
|
|
987
836
|
this.parentVariant = computed(() => this._parentFormField.parentOrSelfVariant(), ...(ngDevMode ? [{ debugName: "parentVariant" }] : []));
|
|
988
|
-
this.
|
|
989
|
-
this.
|
|
990
|
-
this.
|
|
991
|
-
this.
|
|
992
|
-
this.
|
|
837
|
+
this.spinnerVariant = input(IdsSpinnerVariant.SURFACE, ...(ngDevMode ? [{ debugName: "spinnerVariant" }] : []));
|
|
838
|
+
this.isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
839
|
+
this.onChange = () => { };
|
|
840
|
+
this.onTouched = () => { };
|
|
841
|
+
this._parentFormField = inject(IdsFormFieldComponent);
|
|
842
|
+
// declarations of IdsFormFieldControl variables
|
|
843
|
+
this._defaultConfig = this._getDefaultConfig(defaultConfig$1, IDS_AUTOCOMPLETE_DEFAULT_CONFIG);
|
|
844
|
+
this.errorStateMatcher = input(inject(this._defaultConfig.errorStateMatcher), ...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : []));
|
|
845
|
+
this.successStateMatcher = input(inject(this._defaultConfig.successStateMatcher), ...(ngDevMode ? [{ debugName: "successStateMatcher" }] : []));
|
|
846
|
+
this._elementRef = inject(ElementRef);
|
|
993
847
|
this._hostClasses = computed(() => this._getHostClasses([
|
|
994
848
|
this.parentSize(),
|
|
995
|
-
this.parentVariant(),
|
|
996
849
|
this.disabled() ? 'disabled' : null,
|
|
997
|
-
this.readonly() ? 'readonly' : null,
|
|
998
850
|
], [formFieldControlClass]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
999
851
|
this._panelClasses = computed(() => [
|
|
1000
|
-
'ids-overlay-
|
|
852
|
+
'ids-autocomplete-overlay-panel',
|
|
1001
853
|
this.panelClasses(),
|
|
1002
854
|
].join(' '), ...(ngDevMode ? [{ debugName: "_panelClasses" }] : []));
|
|
1003
|
-
|
|
1004
|
-
this.
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
this._onChange = () => { };
|
|
1013
|
-
this._onTouched = () => { };
|
|
1014
|
-
this._searchText = model('', ...(ngDevMode ? [{ debugName: "_searchText" }] : []));
|
|
1015
|
-
this._skipPredicate = (option) => {
|
|
1016
|
-
if (this.overlayPanel().open()) {
|
|
1017
|
-
return false;
|
|
855
|
+
// #region IdsFormFieldControl implementation
|
|
856
|
+
this.onContainerClick = (event) => {
|
|
857
|
+
if (!this.readonly() && !this.disabled()) {
|
|
858
|
+
const target = event.target;
|
|
859
|
+
// 'clear' button should not trigger focus on the input
|
|
860
|
+
if (target.parentElement?.tagName === 'BUTTON' || (target.tagName === 'IDS-ICON' && target.parentElement?.tagName === 'BUTTON')) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
this.trigger().focus();
|
|
1018
864
|
}
|
|
1019
|
-
return option.disabledInput();
|
|
1020
865
|
};
|
|
1021
866
|
effect(() => {
|
|
1022
|
-
this.
|
|
1023
|
-
});
|
|
1024
|
-
effect(() => {
|
|
1025
|
-
const options = this.options();
|
|
1026
|
-
untracked(() => {
|
|
1027
|
-
if (options.length > 0) {
|
|
1028
|
-
this._initKeyManager();
|
|
1029
|
-
this.options().forEach((option) => {
|
|
1030
|
-
if (this._selectionModel?.selected.includes(option.viewValue())) {
|
|
1031
|
-
option.selected.set(true);
|
|
1032
|
-
}
|
|
1033
|
-
});
|
|
1034
|
-
this._subscribeOptionChanges();
|
|
1035
|
-
}
|
|
1036
|
-
});
|
|
1037
|
-
});
|
|
1038
|
-
effect(() => {
|
|
1039
|
-
const searchText = this._searchText();
|
|
867
|
+
const overlayPanelOpen = this.overlayPanel()?.open() ?? false;
|
|
1040
868
|
untracked(() => {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
if (controlValue && searchText !== controlValue) {
|
|
1044
|
-
control.setValue(null);
|
|
1045
|
-
this._clearSelection();
|
|
869
|
+
if (!overlayPanelOpen && this.panelOpen()) {
|
|
870
|
+
this.panelOpen.set(false);
|
|
1046
871
|
}
|
|
1047
872
|
});
|
|
1048
873
|
});
|
|
1049
874
|
}
|
|
1050
875
|
ngOnInit() {
|
|
1051
876
|
if (!this._parentFormField) {
|
|
1052
|
-
throw this.
|
|
877
|
+
throw this.createHostError('Select must be in a form field');
|
|
1053
878
|
}
|
|
1054
|
-
this._selectionModel = new SelectionModel(this.multiSelect(), undefined, false, this.valueCompareFn());
|
|
1055
|
-
queueMicrotask(() => {
|
|
1056
|
-
const control = this.ngControl()?.control;
|
|
1057
|
-
if (control) {
|
|
1058
|
-
control.events
|
|
1059
|
-
.pipe(filter((event) => event instanceof ValueChangeEvent), takeUntilDestroyed(this._destroyRef))
|
|
1060
|
-
.subscribe(() => this._changeDetectorRef.markForCheck());
|
|
1061
|
-
}
|
|
1062
|
-
});
|
|
1063
|
-
this._initErrorStateTracker();
|
|
1064
879
|
}
|
|
1065
880
|
ngAfterViewInit() {
|
|
881
|
+
this._initErrorStateTracker();
|
|
1066
882
|
queueMicrotask(() => {
|
|
1067
883
|
const controlDir = this.ngControl();
|
|
1068
884
|
if (controlDir?.control) {
|
|
@@ -1074,276 +890,493 @@ class IdsAutocompleteComponent extends IdsFormFieldControl {
|
|
|
1074
890
|
this._errorStateTracker?.updateErrorState();
|
|
1075
891
|
this._successStateTracker?.updateSuccessState();
|
|
1076
892
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
this._keyManager = new ActiveDescendantKeyManager(this.options())
|
|
1082
|
-
.withTypeAhead(this.typeaheadDebounceInterval())
|
|
1083
|
-
.withVerticalOrientation()
|
|
1084
|
-
.withHorizontalOrientation('ltr')
|
|
1085
|
-
.withHomeAndEnd()
|
|
1086
|
-
.withPageUpDown()
|
|
1087
|
-
.withAllowedModifierKeys(['shiftKey'])
|
|
1088
|
-
.skipPredicate(this._skipPredicate);
|
|
1089
|
-
this._keyManager.change.subscribe(() => {
|
|
1090
|
-
if (this.overlayPanel().open() && this._panel()) {
|
|
1091
|
-
this._scrollOptionIntoView(this._keyManager?.activeItemIndex || 0);
|
|
1092
|
-
}
|
|
1093
|
-
});
|
|
1094
|
-
}
|
|
1095
|
-
_subscribeOptionChanges() {
|
|
1096
|
-
this.options().forEach((option) => {
|
|
1097
|
-
option.onSelectionChange.subscribe((change) => {
|
|
1098
|
-
this._handleOptionChange(change);
|
|
1099
|
-
});
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
_handleOptionChange(change) {
|
|
1103
|
-
const { source, selected, isUserInput } = change;
|
|
1104
|
-
if (!this.multiSelect()) {
|
|
1105
|
-
this._clearSelection();
|
|
1106
|
-
}
|
|
1107
|
-
source.selected.set(selected);
|
|
1108
|
-
if (isUserInput) {
|
|
1109
|
-
this._keyManager?.setActiveItem(source);
|
|
1110
|
-
}
|
|
1111
|
-
if (isUserInput && !this.multiSelect() && this.overlayPanel().open()) {
|
|
1112
|
-
this.close();
|
|
1113
|
-
}
|
|
1114
|
-
if (this.multiSelect()) {
|
|
1115
|
-
this._sortValues();
|
|
1116
|
-
}
|
|
1117
|
-
if (selected) {
|
|
1118
|
-
this._selectionModel?.select(source.viewValue());
|
|
1119
|
-
this._searchText.set(source.viewValue());
|
|
893
|
+
// #region ControlValueAccessor implementation
|
|
894
|
+
writeValue(value) {
|
|
895
|
+
if (value !== null) {
|
|
896
|
+
this._patchValue(value);
|
|
1120
897
|
}
|
|
1121
898
|
else {
|
|
1122
|
-
this.
|
|
899
|
+
this.trigger()?.clear();
|
|
1123
900
|
}
|
|
1124
|
-
this.
|
|
1125
|
-
this._onTouched();
|
|
1126
|
-
this._inputElemment()?.nativeElement.blur();
|
|
1127
|
-
this.overlayPanel().open.set(false);
|
|
901
|
+
this._value = value;
|
|
1128
902
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
this.overlayPanel().open() ? this._handleOpenedPanelKeydown(event) : this._handleClosedPanelKeydown(event);
|
|
1132
|
-
// announce number of options when a key is pressed
|
|
1133
|
-
this._liveAnnouncer.announce(this.options()
|
|
1134
|
-
.filter((option) => !option.disabled)
|
|
1135
|
-
.length.toString(), LIVE_ANNOUNCE_DURATION_MS);
|
|
1136
|
-
}
|
|
903
|
+
registerOnChange(fn) {
|
|
904
|
+
this.onChange = fn;
|
|
1137
905
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
const targetElement = event.target;
|
|
1141
|
-
const isButtonTarget = targetElement.localName === 'button';
|
|
1142
|
-
if (isButtonTarget && (key === 'Enter' || key === ' ')) {
|
|
1143
|
-
event.preventDefault();
|
|
1144
|
-
targetElement.click();
|
|
1145
|
-
targetElement.blur();
|
|
1146
|
-
return;
|
|
1147
|
-
}
|
|
1148
|
-
const manager = this._keyManager;
|
|
1149
|
-
const isArrowKey = key === 'ArrowDown' || key === 'ArrowUp' || key === 'ArrowLeft' || key === 'ArrowRight';
|
|
1150
|
-
const isOpenKey = key === 'Enter' || key === ' ';
|
|
1151
|
-
if ((!manager?.isTyping() && isOpenKey && !hasModifierKey(event)) ||
|
|
1152
|
-
isArrowKey ||
|
|
1153
|
-
this.options().length > 0 ||
|
|
1154
|
-
this._resource.value().length > 0) {
|
|
1155
|
-
if (isArrowKey || isOpenKey) {
|
|
1156
|
-
event.preventDefault();
|
|
1157
|
-
}
|
|
1158
|
-
this.open();
|
|
1159
|
-
}
|
|
1160
|
-
else if (!this.multiSelect()) {
|
|
1161
|
-
const previouslySelectedOption = this.selected;
|
|
1162
|
-
manager?.onKeydown(event);
|
|
1163
|
-
const selectedOption = this.selected;
|
|
1164
|
-
if (selectedOption && previouslySelectedOption !== selectedOption) {
|
|
1165
|
-
this._liveAnnouncer.announce(selectedOption, LIVE_ANNOUNCE_DURATION_MS);
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
906
|
+
registerOnTouched(fn) {
|
|
907
|
+
this.onTouched = fn;
|
|
1168
908
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
event.preventDefault();
|
|
1188
|
-
manager.activeItem.selectViaInteraction();
|
|
909
|
+
setDisabledState(isDisabled) {
|
|
910
|
+
this._disabled.set(isDisabled);
|
|
911
|
+
}
|
|
912
|
+
// #endregion
|
|
913
|
+
handleChange(value) {
|
|
914
|
+
this._value = value;
|
|
915
|
+
this.onChange(value);
|
|
916
|
+
}
|
|
917
|
+
// #endregion
|
|
918
|
+
// #region required as `IDS_OPTION_PARENT`, but not used here as it cannot handle option content changes.
|
|
919
|
+
// Selection is handled by `_updateCurrentSelection` method of `AutocompleteTriggerDirective`
|
|
920
|
+
isOptionPreSelectedByValue() {
|
|
921
|
+
return false;
|
|
922
|
+
}
|
|
923
|
+
// #endregion
|
|
924
|
+
setScrollTop(scrollTop) {
|
|
925
|
+
if (this.panel()) {
|
|
926
|
+
this.panel().nativeElement.scrollTop = scrollTop;
|
|
1189
927
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
928
|
+
}
|
|
929
|
+
getScrollTop() {
|
|
930
|
+
return this.panel() ? this.panel()?.nativeElement.scrollTop : 0;
|
|
931
|
+
}
|
|
932
|
+
setPanelOpen() {
|
|
933
|
+
this._overlayOrigin = this._parentFormField?.getConnectedOverlayOrigin();
|
|
934
|
+
this.overlayPanel()?.overlayDir()?.overlayRef?.updateSize({ width: this._overlayOrigin.nativeElement.getBoundingClientRect().width });
|
|
935
|
+
this._observeOverlayOrigin();
|
|
936
|
+
this.panelOpen.set(true);
|
|
937
|
+
}
|
|
938
|
+
createHostError(message) {
|
|
939
|
+
throw this._createHostError(message);
|
|
940
|
+
}
|
|
941
|
+
_observeOverlayOrigin() {
|
|
942
|
+
const observer = new ResizeObserver(() => {
|
|
943
|
+
this.overlayPanel()?.overlayDir()?.overlayRef?.updatePosition();
|
|
944
|
+
this.overlayPanel()?.overlayDir()?.overlayRef?.updateSize({ width: this._overlayOrigin.nativeElement.getBoundingClientRect().width });
|
|
945
|
+
});
|
|
946
|
+
observer.observe(this._overlayOrigin.nativeElement);
|
|
947
|
+
}
|
|
948
|
+
// "async" way to patch value to ensure options are loaded before setting selection
|
|
949
|
+
_patchValue(value) {
|
|
950
|
+
const patchEffect = effect(() => {
|
|
951
|
+
const options = this.options();
|
|
952
|
+
untracked(() => {
|
|
953
|
+
if (options.length > 0) {
|
|
954
|
+
this.trigger().setSelectionByValue(value);
|
|
955
|
+
patchEffect.destroy();
|
|
1196
956
|
}
|
|
1197
957
|
});
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
958
|
+
}, ...(ngDevMode ? [{ debugName: "patchEffect", injector: this._injector, manualCleanup: true }] : [{ injector: this._injector, manualCleanup: true }]));
|
|
959
|
+
}
|
|
960
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
961
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: IdsAutocompleteComponent, isStandalone: true, selector: "ids-autocomplete", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelClear: { classPropertyName: "ariaLabelClear", publicName: "ariaLabelClear", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelLoading: { classPropertyName: "ariaLabelLoading", publicName: "ariaLabelLoading", isSignal: true, isRequired: false, transformFunction: null }, multiSelect: { classPropertyName: "multiSelect", publicName: "multiSelect", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, sortCompareFn: { classPropertyName: "sortCompareFn", publicName: "sortCompareFn", isSignal: true, isRequired: false, transformFunction: null }, valueCompareFn: { classPropertyName: "valueCompareFn", publicName: "valueCompareFn", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: true, transformFunction: null }, panelClasses: { classPropertyName: "panelClasses", publicName: "panelClasses", isSignal: true, isRequired: false, transformFunction: null }, panelOpen: { classPropertyName: "panelOpen", publicName: "panelOpen", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, spinnerVariant: { classPropertyName: "spinnerVariant", publicName: "spinnerVariant", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, successStateMatcher: { classPropertyName: "successStateMatcher", publicName: "successStateMatcher", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { panelOpen: "panelOpenChange" }, providers: [
|
|
962
|
+
{ provide: IDS_FORM_FIELD_CONTROL, useExisting: IdsAutocompleteComponent },
|
|
963
|
+
{ provide: IDS_OPTION_PARENT_COMPONENT, useExisting: IdsAutocompleteComponent },
|
|
964
|
+
{
|
|
965
|
+
provide: NG_VALUE_ACCESSOR,
|
|
966
|
+
useExisting: forwardRef(() => IdsAutocompleteComponent),
|
|
967
|
+
multi: true,
|
|
968
|
+
},
|
|
969
|
+
], queries: [{ propertyName: "options", predicate: IdsOptionComponent, descendants: true, isSignal: true }, { propertyName: "optionGroups", predicate: IDS_OPTION_GROUP, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "overlayPanel", first: true, predicate: ["overlayPanel"], descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, read: ElementRef, isSignal: true }], exportAs: ["idsAutocomplete"], usesInheritance: true, ngImport: i0, template: `
|
|
970
|
+
@if (panelOpen()) {
|
|
971
|
+
<ids-overlay-panel
|
|
972
|
+
#overlayPanel
|
|
973
|
+
appearance="elevated"
|
|
974
|
+
[origin]="_overlayOrigin"
|
|
975
|
+
[open]="panelOpen()"
|
|
976
|
+
[size]="parentSize()"
|
|
977
|
+
[panelClasses]="_panelClasses()"
|
|
978
|
+
>
|
|
979
|
+
<div
|
|
980
|
+
#panel
|
|
981
|
+
class="ids-autocomplete-panel"
|
|
982
|
+
role="listbox"
|
|
983
|
+
[id]="id() + '-panel'"
|
|
984
|
+
[attr.aria-multiselectable]="multiSelect()"
|
|
985
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
986
|
+
[attr.aria-labelledby]="ariaLabelledby() || null"
|
|
987
|
+
>
|
|
988
|
+
<ng-content />
|
|
989
|
+
</div>
|
|
990
|
+
</ids-overlay-panel>
|
|
991
|
+
}
|
|
992
|
+
<span class="ids-autocomplete-suffix">
|
|
993
|
+
@if (trigger().selected.length > 0) {
|
|
994
|
+
<button
|
|
995
|
+
type="button"
|
|
996
|
+
idsIconButton
|
|
997
|
+
[appearance]="appearance()"
|
|
998
|
+
[variant]="parentVariant()"
|
|
999
|
+
[size]="parentSize()"
|
|
1000
|
+
[disabled]="disabled()"
|
|
1001
|
+
[ariaLabel]="ariaLabelClear()"
|
|
1002
|
+
[idsTooltip]="ariaLabelClear()"
|
|
1003
|
+
[idsTooltipDisabled]="!ariaLabelClear()"
|
|
1004
|
+
[idsTooltipIgnoreClipped]="true"
|
|
1005
|
+
(click)="trigger().clear()"
|
|
1006
|
+
>
|
|
1007
|
+
<ids-icon alt="" aria-hidden="true" fontIcon="close" />
|
|
1008
|
+
</button>
|
|
1009
|
+
}
|
|
1010
|
+
@if (isLoading()) {
|
|
1011
|
+
<ids-spinner
|
|
1012
|
+
sizeCollection="small"
|
|
1013
|
+
[size]="parentSize()"
|
|
1014
|
+
[variant]="spinnerVariant()"
|
|
1015
|
+
[isTrack]="true"
|
|
1016
|
+
[aria-label]="ariaLabelLoading()"
|
|
1017
|
+
/>
|
|
1018
|
+
} @else {
|
|
1019
|
+
<ids-icon
|
|
1020
|
+
alt=""
|
|
1021
|
+
aria-hidden="true"
|
|
1022
|
+
[size]="parentSize()"
|
|
1023
|
+
[fontIcon]="trigger().autocomplete().panelOpen() ? 'chevron-up' : 'chevron-down'"
|
|
1024
|
+
/>
|
|
1025
|
+
}
|
|
1026
|
+
</span>
|
|
1027
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }, { kind: "component", type: IdsIconButtonComponent, selector: "button[idsIconButton], a[idsIconButton]", inputs: ["appearance", "size", "variant", "disabled", "allowCustomContent"] }, { kind: "component", type: IdsOverlayPanelComponent, selector: "ids-overlay-panel", inputs: ["open", "origin", "positions", "appearance", "size", "variant", "panelClasses", "width"], outputs: ["openChange"] }, { kind: "component", type: IdsSpinnerComponent, selector: "ids-spinner", inputs: ["size", "sizeCollection", "variant", "isTrack", "aria-label"] }, { kind: "directive", type: IdsTooltipDirective, selector: "[idsTooltip]", inputs: ["idsTooltip", "idsTooltipPosition", "idsTooltipSize", "idsTooltipVariant", "idsTooltipShowDelay", "idsTooltipHideDelay", "idsTooltipDisabled", "idsTooltipTouchGestures", "idsTooltipTextAlign", "idsTooltipClass", "idsTooltipShowPointer", "idsTooltipIgnoreClipped"] }] }); }
|
|
1028
|
+
}
|
|
1029
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteComponent, decorators: [{
|
|
1030
|
+
type: Component,
|
|
1031
|
+
args: [{
|
|
1032
|
+
selector: 'ids-autocomplete',
|
|
1033
|
+
imports: [
|
|
1034
|
+
IdsIconComponent,
|
|
1035
|
+
IdsIconButtonComponent,
|
|
1036
|
+
IdsOverlayPanelComponent,
|
|
1037
|
+
IdsSpinnerComponent,
|
|
1038
|
+
IdsTooltipDirective,
|
|
1039
|
+
],
|
|
1040
|
+
template: `
|
|
1041
|
+
@if (panelOpen()) {
|
|
1042
|
+
<ids-overlay-panel
|
|
1043
|
+
#overlayPanel
|
|
1044
|
+
appearance="elevated"
|
|
1045
|
+
[origin]="_overlayOrigin"
|
|
1046
|
+
[open]="panelOpen()"
|
|
1047
|
+
[size]="parentSize()"
|
|
1048
|
+
[panelClasses]="_panelClasses()"
|
|
1049
|
+
>
|
|
1050
|
+
<div
|
|
1051
|
+
#panel
|
|
1052
|
+
class="ids-autocomplete-panel"
|
|
1053
|
+
role="listbox"
|
|
1054
|
+
[id]="id() + '-panel'"
|
|
1055
|
+
[attr.aria-multiselectable]="multiSelect()"
|
|
1056
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
1057
|
+
[attr.aria-labelledby]="ariaLabelledby() || null"
|
|
1058
|
+
>
|
|
1059
|
+
<ng-content />
|
|
1060
|
+
</div>
|
|
1061
|
+
</ids-overlay-panel>
|
|
1062
|
+
}
|
|
1063
|
+
<span class="ids-autocomplete-suffix">
|
|
1064
|
+
@if (trigger().selected.length > 0) {
|
|
1065
|
+
<button
|
|
1066
|
+
type="button"
|
|
1067
|
+
idsIconButton
|
|
1068
|
+
[appearance]="appearance()"
|
|
1069
|
+
[variant]="parentVariant()"
|
|
1070
|
+
[size]="parentSize()"
|
|
1071
|
+
[disabled]="disabled()"
|
|
1072
|
+
[ariaLabel]="ariaLabelClear()"
|
|
1073
|
+
[idsTooltip]="ariaLabelClear()"
|
|
1074
|
+
[idsTooltipDisabled]="!ariaLabelClear()"
|
|
1075
|
+
[idsTooltipIgnoreClipped]="true"
|
|
1076
|
+
(click)="trigger().clear()"
|
|
1077
|
+
>
|
|
1078
|
+
<ids-icon alt="" aria-hidden="true" fontIcon="close" />
|
|
1079
|
+
</button>
|
|
1080
|
+
}
|
|
1081
|
+
@if (isLoading()) {
|
|
1082
|
+
<ids-spinner
|
|
1083
|
+
sizeCollection="small"
|
|
1084
|
+
[size]="parentSize()"
|
|
1085
|
+
[variant]="spinnerVariant()"
|
|
1086
|
+
[isTrack]="true"
|
|
1087
|
+
[aria-label]="ariaLabelLoading()"
|
|
1088
|
+
/>
|
|
1089
|
+
} @else {
|
|
1090
|
+
<ids-icon
|
|
1091
|
+
alt=""
|
|
1092
|
+
aria-hidden="true"
|
|
1093
|
+
[size]="parentSize()"
|
|
1094
|
+
[fontIcon]="trigger().autocomplete().panelOpen() ? 'chevron-up' : 'chevron-down'"
|
|
1095
|
+
/>
|
|
1096
|
+
}
|
|
1097
|
+
</span>
|
|
1098
|
+
`,
|
|
1099
|
+
exportAs: 'idsAutocomplete',
|
|
1100
|
+
providers: [
|
|
1101
|
+
{ provide: IDS_FORM_FIELD_CONTROL, useExisting: IdsAutocompleteComponent },
|
|
1102
|
+
{ provide: IDS_OPTION_PARENT_COMPONENT, useExisting: IdsAutocompleteComponent },
|
|
1103
|
+
{
|
|
1104
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1105
|
+
useExisting: forwardRef(() => IdsAutocompleteComponent),
|
|
1106
|
+
multi: true,
|
|
1107
|
+
},
|
|
1108
|
+
],
|
|
1109
|
+
}]
|
|
1110
|
+
}], ctorParameters: () => [] });
|
|
1111
|
+
|
|
1112
|
+
const LIVE_ANNOUNCER_DURATION = 10000;
|
|
1113
|
+
class IdsAutocompleteTriggerDirective {
|
|
1114
|
+
get selected() {
|
|
1115
|
+
return this._selectionModel?.selected ?? [];
|
|
1116
|
+
}
|
|
1117
|
+
get selectedOptions() {
|
|
1118
|
+
const selectedValues = this.selected.map((option) => option.value) ?? [];
|
|
1119
|
+
return this.autocomplete()
|
|
1120
|
+
.options()
|
|
1121
|
+
.filter((option) => selectedValues.includes(option.value()));
|
|
1122
|
+
}
|
|
1123
|
+
constructor() {
|
|
1124
|
+
this.autocomplete = input.required(...(ngDevMode ? [{ debugName: "autocomplete", alias: 'idsAutocompleteTriggerFor' }] : [{ alias: 'idsAutocompleteTriggerFor' }]));
|
|
1125
|
+
this._disabled = computed(() => this.autocomplete().disabled(), ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
1126
|
+
this._readonly = computed(() => this.autocomplete().readonly(), ...(ngDevMode ? [{ debugName: "_readonly" }] : []));
|
|
1127
|
+
this._inputElement = inject((ElementRef));
|
|
1128
|
+
this._liveAnnouncer = inject(LiveAnnouncer);
|
|
1129
|
+
this._renderer = inject(Renderer2);
|
|
1130
|
+
this._injector = inject(Injector);
|
|
1131
|
+
this._skipPredicate = (option) => {
|
|
1132
|
+
if (this.autocomplete().panelOpen()) {
|
|
1133
|
+
return false;
|
|
1208
1134
|
}
|
|
1209
|
-
|
|
1135
|
+
return option.disabledInput();
|
|
1136
|
+
};
|
|
1137
|
+
effect(() => {
|
|
1138
|
+
const options = this.autocomplete().options();
|
|
1139
|
+
untracked(() => {
|
|
1140
|
+
if (options.length > 0) {
|
|
1141
|
+
this._initKeyManager();
|
|
1142
|
+
this._subscribeOptionChanges();
|
|
1143
|
+
this._liveAnnouncer.announce(options.length.toString(), LIVE_ANNOUNCER_DURATION);
|
|
1144
|
+
if (!this._selectionModel.isEmpty()) {
|
|
1145
|
+
this._updateCurrentSelection();
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
});
|
|
1210
1150
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
if (index === 0) {
|
|
1217
|
-
panel.scrollTop = 0;
|
|
1151
|
+
ngOnInit() {
|
|
1152
|
+
this._selectionModel = new SelectionModel(true, undefined, true, this.autocomplete().valueCompareFn());
|
|
1153
|
+
this._selectionModel.changed.subscribe(() => {
|
|
1154
|
+
if (this.autocomplete().multiSelect()) {
|
|
1155
|
+
this._selectionModel?.sort(this.autocomplete().sortCompareFn());
|
|
1218
1156
|
}
|
|
1219
1157
|
else {
|
|
1220
|
-
|
|
1158
|
+
this._updateInputValue(this.selected[0]?.viewValue);
|
|
1221
1159
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
if (this.multiSelect()) {
|
|
1226
|
-
const options = this.options().map((option) => option.viewValue());
|
|
1227
|
-
const sortComparator = this.sortCompareFn();
|
|
1228
|
-
this._selectionModel?.sort((a, b) => (sortComparator ? sortComparator(a, b, options) : options.indexOf(a) - options.indexOf(b)));
|
|
1229
|
-
}
|
|
1160
|
+
this.autocomplete().handleChange(this.autocomplete().multiSelect() ? this.selected.map((option) => option.value) : (this.selected[0]?.value ?? null));
|
|
1161
|
+
this.autocomplete().onTouched();
|
|
1162
|
+
});
|
|
1230
1163
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
return refToMeasure.nativeElement.getBoundingClientRect().width;
|
|
1164
|
+
ngOnDestroy() {
|
|
1165
|
+
this._keyManager?.destroy();
|
|
1234
1166
|
}
|
|
1235
1167
|
toggle() {
|
|
1236
|
-
this.
|
|
1168
|
+
this.autocomplete().panelOpen() ? this.close() : this.open();
|
|
1237
1169
|
}
|
|
1238
1170
|
open() {
|
|
1239
1171
|
if (!this._canOpen()) {
|
|
1240
1172
|
return;
|
|
1241
1173
|
}
|
|
1242
|
-
|
|
1243
|
-
this._preferredOverlayOrigin = this._parentFormField?.getConnectedOverlayOrigin();
|
|
1244
|
-
}
|
|
1245
|
-
this._overlayWidth = this._getOverlayWidth(this._preferredOverlayOrigin);
|
|
1246
|
-
this.overlayPanel().open.set(true);
|
|
1174
|
+
this.autocomplete().setPanelOpen();
|
|
1247
1175
|
this._keyManager?.withHorizontalOrientation(null);
|
|
1248
|
-
|
|
1249
|
-
|
|
1176
|
+
// wait for opening panel...
|
|
1177
|
+
afterNextRender(() => {
|
|
1178
|
+
this._scrollOptionIntoView(this._keyManager?.activeItemIndex ?? 0);
|
|
1179
|
+
this._highlightCorrectOption();
|
|
1180
|
+
}, { injector: this._injector });
|
|
1250
1181
|
}
|
|
1251
1182
|
close() {
|
|
1252
|
-
if (this.
|
|
1253
|
-
this.
|
|
1254
|
-
this.
|
|
1255
|
-
this.
|
|
1183
|
+
if (this.autocomplete().panelOpen()) {
|
|
1184
|
+
this.autocomplete().panelOpen.set(false);
|
|
1185
|
+
this._keyManager?.withHorizontalOrientation('ltr');
|
|
1186
|
+
this.autocomplete().onTouched();
|
|
1256
1187
|
}
|
|
1257
1188
|
}
|
|
1258
1189
|
clear() {
|
|
1259
|
-
this.
|
|
1260
|
-
|
|
1261
|
-
// #region ControlValueAccessor implementation
|
|
1262
|
-
writeValue(value) {
|
|
1263
|
-
this._setSelectionByValue(value);
|
|
1190
|
+
this._clearSelection();
|
|
1191
|
+
this._updateInputValue('');
|
|
1264
1192
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1193
|
+
removeOption(optionValue) {
|
|
1194
|
+
const option = this.autocomplete()
|
|
1195
|
+
.options()
|
|
1196
|
+
.find((opt) => opt.value() === optionValue.value);
|
|
1197
|
+
if (option) {
|
|
1198
|
+
this._handleOptionChange({
|
|
1199
|
+
source: option,
|
|
1200
|
+
selected: false,
|
|
1201
|
+
isUserInput: true,
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
else {
|
|
1205
|
+
// item to be removed is NOT the current option list, but present in selection model --> deselect directly
|
|
1206
|
+
this._selectionModel?.deselect(optionValue);
|
|
1207
|
+
}
|
|
1270
1208
|
}
|
|
1271
|
-
|
|
1272
|
-
this.
|
|
1273
|
-
this.
|
|
1209
|
+
focus(options) {
|
|
1210
|
+
this._inputElement.nativeElement.focus(options);
|
|
1211
|
+
this.open();
|
|
1274
1212
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
this.options().forEach((option) => {
|
|
1278
|
-
option.setInactiveStyles();
|
|
1279
|
-
option.selected.set(false);
|
|
1280
|
-
});
|
|
1281
|
-
this._selectionModel?.clear();
|
|
1282
|
-
this._rawValue = value;
|
|
1283
|
-
if (this.options().length === 0) {
|
|
1284
|
-
return;
|
|
1285
|
-
}
|
|
1286
|
-
if (this.multiSelect() && value) {
|
|
1213
|
+
setSelectionByValue(value) {
|
|
1214
|
+
if (this.autocomplete().multiSelect() && value !== null) {
|
|
1287
1215
|
if (!Array.isArray(value)) {
|
|
1288
|
-
throw this.
|
|
1216
|
+
throw this.autocomplete().createHostError('value must be an array in multiple-selection mode');
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
value.forEach((currentValue) => this._selectValue(currentValue));
|
|
1289
1220
|
}
|
|
1290
|
-
value.forEach((currentValue) => this._selectValue(currentValue));
|
|
1291
|
-
this._sortValues();
|
|
1292
1221
|
}
|
|
1293
1222
|
else {
|
|
1294
1223
|
const correspondingOption = this._selectValue(value);
|
|
1295
1224
|
if (correspondingOption) {
|
|
1296
1225
|
this._keyManager?.updateActiveItem(correspondingOption);
|
|
1297
1226
|
}
|
|
1298
|
-
else if (!this.
|
|
1227
|
+
else if (!this.autocomplete().panelOpen()) {
|
|
1299
1228
|
this._keyManager?.updateActiveItem(-1);
|
|
1300
1229
|
}
|
|
1301
1230
|
}
|
|
1302
1231
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1232
|
+
_handleKeydown(event) {
|
|
1233
|
+
if (!this._disabled() && !this._readonly()) {
|
|
1234
|
+
this.autocomplete().panelOpen() ? this._handleOpenedPanelKeydown(event) : this._handleClosedPanelKeydown(event);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
_onBlur() {
|
|
1238
|
+
if (!this._disabled()) {
|
|
1239
|
+
this.autocomplete().onTouched();
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
_getAriaActiveDescendant() {
|
|
1243
|
+
if (this.autocomplete().panelOpen() && this._keyManager?.activeItem) {
|
|
1244
|
+
return this._keyManager.activeItem.id();
|
|
1245
|
+
}
|
|
1246
|
+
return null;
|
|
1247
|
+
}
|
|
1248
|
+
_initKeyManager() {
|
|
1249
|
+
this._keyManager = new ActiveDescendantKeyManager(this.autocomplete().options())
|
|
1250
|
+
.withVerticalOrientation()
|
|
1251
|
+
.withHorizontalOrientation('ltr')
|
|
1252
|
+
.withHomeAndEnd()
|
|
1253
|
+
.withPageUpDown()
|
|
1254
|
+
.withAllowedModifierKeys(['shiftKey'])
|
|
1255
|
+
.skipPredicate(this._skipPredicate);
|
|
1256
|
+
this._keyManager.tabOut.subscribe(() => {
|
|
1257
|
+
if (this.autocomplete().panelOpen()) {
|
|
1258
|
+
if (!this.autocomplete().multiSelect() && this._keyManager?.activeItem) {
|
|
1259
|
+
this._keyManager.activeItem.selectViaInteraction();
|
|
1315
1260
|
}
|
|
1316
|
-
|
|
1261
|
+
this.focus();
|
|
1262
|
+
this.close();
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
this._keyManager.change.subscribe(() => {
|
|
1266
|
+
if (this.autocomplete().panelOpen()) {
|
|
1267
|
+
this._scrollOptionIntoView(this._keyManager?.activeItemIndex ?? 0);
|
|
1317
1268
|
}
|
|
1318
1269
|
});
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1270
|
+
}
|
|
1271
|
+
_subscribeOptionChanges() {
|
|
1272
|
+
this.autocomplete()
|
|
1273
|
+
.options()
|
|
1274
|
+
.forEach((option) => {
|
|
1275
|
+
option.onSelectionChange.subscribe((change) => {
|
|
1276
|
+
this._handleOptionChange(change);
|
|
1277
|
+
});
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
_handleOptionChange(change) {
|
|
1281
|
+
const { source, selected, isUserInput } = change;
|
|
1282
|
+
if (!this.autocomplete().multiSelect()) {
|
|
1283
|
+
this._clearSelection();
|
|
1284
|
+
}
|
|
1285
|
+
source.selected.set(selected);
|
|
1286
|
+
if (isUserInput) {
|
|
1287
|
+
this._keyManager?.setActiveItem(source);
|
|
1288
|
+
}
|
|
1289
|
+
if (isUserInput && !this.autocomplete().multiSelect() && this.autocomplete().panelOpen()) {
|
|
1290
|
+
this.close();
|
|
1291
|
+
}
|
|
1292
|
+
const optionValue = this._getAsOptionValue(source);
|
|
1293
|
+
if (selected) {
|
|
1294
|
+
this._selectionModel?.select(optionValue);
|
|
1295
|
+
}
|
|
1296
|
+
else {
|
|
1297
|
+
this._selectionModel?.deselect(optionValue);
|
|
1322
1298
|
}
|
|
1323
|
-
return correspondingOption;
|
|
1324
1299
|
}
|
|
1325
1300
|
_clearSelection() {
|
|
1326
1301
|
this._selectionModel?.clear();
|
|
1327
|
-
this.
|
|
1302
|
+
this._clearOptionsSelection();
|
|
1303
|
+
}
|
|
1304
|
+
_clearOptionsSelection() {
|
|
1305
|
+
this.autocomplete()
|
|
1306
|
+
.options()
|
|
1307
|
+
.forEach((option) => {
|
|
1308
|
+
option.setInactiveStyles();
|
|
1328
1309
|
option.selected.set(false);
|
|
1329
1310
|
});
|
|
1330
1311
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1312
|
+
_canOpen() {
|
|
1313
|
+
return !this._readonly() && !this._disabled();
|
|
1314
|
+
}
|
|
1315
|
+
_handleOpenedPanelKeydown(event) {
|
|
1316
|
+
const manager = this._keyManager;
|
|
1317
|
+
const key = event.key;
|
|
1318
|
+
const isArrowKey = key === 'ArrowDown' || key === 'ArrowUp';
|
|
1319
|
+
const isTyping = manager !== undefined && manager.isTyping();
|
|
1320
|
+
const isEscapeKey = key === 'Escape';
|
|
1321
|
+
if ((isArrowKey && event.altKey) || isEscapeKey) {
|
|
1322
|
+
event.preventDefault();
|
|
1323
|
+
this.close();
|
|
1324
|
+
}
|
|
1325
|
+
else if (!isTyping && (key === 'Enter' || key === ' ') && manager?.activeItem && !hasModifierKey(event)) {
|
|
1326
|
+
event.preventDefault();
|
|
1327
|
+
manager.activeItem.selectViaInteraction();
|
|
1328
|
+
}
|
|
1329
|
+
else if (!isTyping && this.autocomplete().multiSelect() && key === 'a' && event.ctrlKey) {
|
|
1330
|
+
event.preventDefault();
|
|
1331
|
+
const hasDeselectedOptions = this.autocomplete()
|
|
1332
|
+
.options()
|
|
1333
|
+
.some((opt) => !opt.disabled && !opt.selected());
|
|
1334
|
+
this.autocomplete()
|
|
1335
|
+
.options()
|
|
1336
|
+
.forEach((option) => {
|
|
1337
|
+
if (!option.disabled) {
|
|
1338
|
+
hasDeselectedOptions ? option.select() : option.deselect();
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1335
1341
|
}
|
|
1336
1342
|
else {
|
|
1337
|
-
|
|
1343
|
+
const previouslyFocusedIndex = manager?.activeItemIndex;
|
|
1344
|
+
manager?.onKeydown(event);
|
|
1345
|
+
this._scrollOptionIntoView(manager?.activeItemIndex ?? 0);
|
|
1346
|
+
if (this.autocomplete().multiSelect() &&
|
|
1347
|
+
isArrowKey &&
|
|
1348
|
+
event.shiftKey &&
|
|
1349
|
+
manager?.activeItem &&
|
|
1350
|
+
manager?.activeItemIndex !== previouslyFocusedIndex) {
|
|
1351
|
+
manager?.activeItem.selectViaInteraction();
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
_handleClosedPanelKeydown(event) {
|
|
1356
|
+
const manager = this._keyManager;
|
|
1357
|
+
const key = event.key;
|
|
1358
|
+
const isArrowKey = key === 'ArrowDown' || key === 'ArrowUp' || key === 'ArrowLeft' || key === 'ArrowRight';
|
|
1359
|
+
const isOpenKey = key === 'Enter' || key === ' ';
|
|
1360
|
+
const isEscapeKey = key === 'Escape';
|
|
1361
|
+
if ((manager && !manager.isTyping() && isOpenKey && !hasModifierKey(event)) || isArrowKey) {
|
|
1362
|
+
event.preventDefault();
|
|
1363
|
+
this.open();
|
|
1364
|
+
}
|
|
1365
|
+
else if (!this.autocomplete().multiSelect() && !isEscapeKey) {
|
|
1366
|
+
const previouslySelectedOption = this.selectedOptions[0];
|
|
1367
|
+
manager?.onKeydown(event);
|
|
1368
|
+
const selectedOption = this.selectedOptions[0];
|
|
1369
|
+
if (selectedOption?.viewValue() && previouslySelectedOption !== selectedOption) {
|
|
1370
|
+
this._liveAnnouncer.announce(selectedOption.viewValue(), LIVE_ANNOUNCER_DURATION);
|
|
1371
|
+
}
|
|
1338
1372
|
}
|
|
1339
|
-
this._changeDetectorRef.markForCheck();
|
|
1340
1373
|
}
|
|
1341
1374
|
_highlightCorrectOption() {
|
|
1342
1375
|
if (this._keyManager) {
|
|
1343
|
-
if (this.
|
|
1376
|
+
if (this._selectionModel?.isEmpty() ?? true) {
|
|
1344
1377
|
let firstEnabledOptionIndex = -1;
|
|
1345
|
-
for (let index = 0; index < this.options().length; index++) {
|
|
1346
|
-
const option = this.options()[index];
|
|
1378
|
+
for (let index = 0; index < this.autocomplete().options().length; index++) {
|
|
1379
|
+
const option = this.autocomplete().options()[index];
|
|
1347
1380
|
if (!option.disabled) {
|
|
1348
1381
|
firstEnabledOptionIndex = index;
|
|
1349
1382
|
break;
|
|
@@ -1353,104 +1386,182 @@ class IdsAutocompleteComponent extends IdsFormFieldControl {
|
|
|
1353
1386
|
}
|
|
1354
1387
|
else {
|
|
1355
1388
|
if (this._selectionModel) {
|
|
1356
|
-
|
|
1357
|
-
if (activeItem) {
|
|
1358
|
-
this._keyManager.setActiveItem(activeItem);
|
|
1359
|
-
}
|
|
1389
|
+
this._keyManager.setActiveItem(this.selectedOptions[0]);
|
|
1360
1390
|
}
|
|
1361
1391
|
}
|
|
1362
1392
|
}
|
|
1363
1393
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1394
|
+
_scrollOptionIntoView(index) {
|
|
1395
|
+
const option = this.autocomplete().options()[index];
|
|
1396
|
+
if (option !== undefined) {
|
|
1397
|
+
const labelCount = _countGroupLabelsBeforeOption(index, this.autocomplete().options(), this.autocomplete().optionGroups());
|
|
1398
|
+
const element = option.getHostElement();
|
|
1399
|
+
if (index === 0 || (index === 0 && labelCount === 1)) {
|
|
1400
|
+
this.autocomplete().setScrollTop(0);
|
|
1401
|
+
}
|
|
1402
|
+
else {
|
|
1403
|
+
const newScrollPosition = _getOptionScrollPosition(element.offsetTop, element.offsetHeight, this.autocomplete().getScrollTop(), this.autocomplete().panel()?.nativeElement.offsetHeight);
|
|
1404
|
+
this.autocomplete().setScrollTop(newScrollPosition);
|
|
1405
|
+
}
|
|
1376
1406
|
}
|
|
1377
1407
|
}
|
|
1378
|
-
|
|
1379
|
-
this.
|
|
1380
|
-
this.
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
this.
|
|
1408
|
+
_selectValue(value) {
|
|
1409
|
+
const valueCompareFn = this.autocomplete().valueCompareFn();
|
|
1410
|
+
const correspondingOption = this.autocomplete()
|
|
1411
|
+
.options()
|
|
1412
|
+
.find((option) => {
|
|
1413
|
+
if (this._selectionModel && this._selectionModel.isSelected(this._getAsOptionValue(option))) {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
try {
|
|
1417
|
+
return valueCompareFn?.(option.value(), value);
|
|
1418
|
+
}
|
|
1419
|
+
catch (error) {
|
|
1420
|
+
if (isDevMode()) {
|
|
1421
|
+
console.warn(error);
|
|
1422
|
+
}
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
if (correspondingOption) {
|
|
1427
|
+
correspondingOption.selected.set(true);
|
|
1428
|
+
const correspondingOptionValue = this._getAsOptionValue(correspondingOption);
|
|
1429
|
+
this._selectionModel?.select(correspondingOptionValue);
|
|
1384
1430
|
}
|
|
1431
|
+
return correspondingOption;
|
|
1385
1432
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1433
|
+
_updateCurrentSelection() {
|
|
1434
|
+
this._clearOptionsSelection();
|
|
1435
|
+
this.selectedOptions.reverse().forEach((option) => {
|
|
1436
|
+
option.selected.set(true);
|
|
1437
|
+
option.setActiveStyles();
|
|
1438
|
+
this._keyManager?.setActiveItem(option);
|
|
1439
|
+
});
|
|
1391
1440
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1441
|
+
_getAsOptionValue(option) {
|
|
1442
|
+
return { value: option.value(), viewValue: option.viewValue() };
|
|
1394
1443
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1444
|
+
_updateInputValue(value) {
|
|
1445
|
+
const input = this._inputElement.nativeElement;
|
|
1446
|
+
this._renderer.setProperty(input, 'value', value);
|
|
1447
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1399
1448
|
}
|
|
1400
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type:
|
|
1401
|
-
static { this.ɵ
|
|
1402
|
-
{ provide: IDS_FORM_FIELD_CONTROL, useExisting: IdsAutocompleteComponent },
|
|
1403
|
-
{ provide: IDS_OPTION_PARENT_COMPONENT, useExisting: IdsAutocompleteComponent },
|
|
1404
|
-
{
|
|
1405
|
-
provide: NG_VALUE_ACCESSOR,
|
|
1406
|
-
useExisting: forwardRef(() => IdsAutocompleteComponent),
|
|
1407
|
-
multi: true,
|
|
1408
|
-
},
|
|
1409
|
-
], viewQueries: [{ propertyName: "options", predicate: IdsOptionComponent, descendants: true, isSignal: true }, { propertyName: "overlayPanel", first: true, predicate: IdsOverlayPanelComponent, descendants: true, isSignal: true }, { propertyName: "_panel", first: true, predicate: ["overlay"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_inputElemment", first: true, predicate: ["fallbackOverlayOrigin"], descendants: true, read: ElementRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@let isLoading = _resource.isLoading();\n@let optionsLength = _resource.value().length;\n@let maxOptionsLength = maxLength();\n\n<input\n #fallbackOverlayOrigin=\"cdkOverlayOrigin\"\n cdkOverlayOrigin\n idsInput\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"false\"\n [(ngModel)]=\"_searchText\"\n (click)=\"_onInputClick()\"\n (blur)=\"_onBlur()\"\n/>\n@if (_searchText().length > 0) {\n <div idsFormFieldAction>\n <button\n type=\"button\"\n idsIconButton\n appearance=\"standard\"\n variant=\"surface\"\n size=\"dense\"\n [attr.aria-label]=\"ariaLabelClearButton()\"\n [idsTooltip]=\"ariaLabelClearButton()\"\n [idsTooltipDisabled]=\"!ariaLabelClearButton() || disabled()\"\n [idsTooltipIgnoreClipped]=\"true\"\n [disabled]=\"disabled()\"\n (click)=\"clear()\"\n >\n <ids-icon alt=\"\" aria-hidden=\"true\" fontIcon=\"close\" />\n </button>\n </div>\n}\n@if (!isLoading && optionsLength > 0) {\n <div idsFormFieldAction>\n <button\n type=\"button\"\n idsIconButton\n appearance=\"standard\"\n variant=\"surface\"\n size=\"dense\"\n [attr.aria-label]=\"ariaLabelToggleButton()\"\n [idsTooltip]=\"ariaLabelToggleButton()\"\n [idsTooltipDisabled]=\"!ariaLabelToggleButton() || disabled()\"\n [idsTooltipIgnoreClipped]=\"true\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n >\n <ids-icon alt=\"\" aria-hidden=\"true\" [fontIcon]=\"overlay.open() ? 'chevron-up' : 'chevron-down'\" />\n </button>\n </div>\n}\n@if (isLoading) {\n <div idsFormFieldAction>\n <ids-spinner sizeCollection=\"small\" size=\"compact\" variant=\"surface\" [isTrack]=\"true\" [aria-label]=\"hintLoading()\" />\n </div>\n}\n<ids-overlay-panel\n #overlay\n variant=\"light\"\n [id]=\"id() + '-panel'\"\n [origin]=\"_preferredOverlayOrigin || fallbackOverlayOrigin\"\n [size]=\"parentSize()\"\n [width]=\"_overlayWidth\"\n [panelClasses]=\"_panelClasses()\"\n>\n @let showHintLoading = isLoading;\n @let showHintMinChars = _searchText().length < minChars();\n @let showHintMaxLength = maxOptionsLength && optionsLength > maxOptionsLength;\n @let showHintNoResults = optionsLength === 0;\n\n @if (showHintLoading || showHintMinChars || showHintMaxLength || showHintNoResults) {\n <div class=\"ids-overlay-panel__autocomplete-message\">\n <ids-option disabled>\n @if (showHintLoading && !showHintMinChars) {\n {{ hintLoading() }}\n } @else if (showHintMinChars) {\n {{ hintMinChars() }}\n } @else if (showHintMaxLength) {\n {{ hintMaxLength() }}\n } @else if (showHintNoResults) {\n {{ hintNoResults() }}\n }\n </ids-option>\n </div>\n } @else {\n @for (option of _resource.value(); track $index) {\n <ids-option [value]=\"option\">{{ option }}</ids-option>\n }\n }\n</ids-overlay-panel>\n", dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IdsFormFieldActionDirective, selector: "[idsFormFieldAction]" }, { kind: "directive", type: IdsInputDirective, selector: "input[idsInput][ngModel]:not([formControl]):not([formControlName]),\n input[idsInput][formControl]:not([ngModel]):not([formControlName]),\n input[idsInput][formControlName]:not([ngModel]):not([formControl]),\n textarea[idsInput][ngModel]:not([formControl]):not([formControlName]),\n textarea[idsInput][formControl]:not([ngModel]):not([formControlName]),\n textarea[idsInput][formControlName]:not([ngModel]):not([formControl])", inputs: ["name", "type", "errorStateMatcher", "successStateMatcher"], exportAs: ["idsInput"] }, { kind: "component", type: IdsIconComponent, selector: "ids-icon", inputs: ["size", "sizeCollection", "variant", "fontIcon", "svgIcon", "aria-hidden"] }, { kind: "component", type: IdsIconButtonComponent, selector: "button[idsIconButton], a[idsIconButton]", inputs: ["appearance", "size", "variant", "disabled", "allowCustomContent"] }, { kind: "component", type: IdsOverlayPanelComponent, selector: "ids-overlay-panel", inputs: ["open", "origin", "positions", "appearance", "size", "variant", "panelClasses", "width"], outputs: ["openChange"] }, { kind: "component", type: IdsOptionComponent, selector: "ids-option", inputs: ["value", "viewValue", "disabled"], outputs: ["onSelectionChange"] }, { kind: "component", type: IdsSpinnerComponent, selector: "ids-spinner", inputs: ["size", "sizeCollection", "variant", "isTrack", "aria-label"] }, { kind: "directive", type: IdsTooltipDirective, selector: "[idsTooltip]", inputs: ["idsTooltip", "idsTooltipPosition", "idsTooltipSize", "idsTooltipVariant", "idsTooltipShowDelay", "idsTooltipHideDelay", "idsTooltipDisabled", "idsTooltipTouchGestures", "idsTooltipTextAlign", "idsTooltipClass", "idsTooltipShowPointer", "idsTooltipIgnoreClipped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1449
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1450
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.7", type: IdsAutocompleteTriggerDirective, isStandalone: true, selector: "input[idsAutocompleteTriggerFor]", inputs: { autocomplete: { classPropertyName: "autocomplete", publicName: "idsAutocompleteTriggerFor", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "keydown": "_handleKeydown($event)", "focus": "focus()", "blur": "_onBlur()" }, properties: { "attr.role": "_disabled() ? null : \"combobox\"", "attr.autocomplete": "_disabled() ? \"off\" : \"auto\"", "attr.aria-autocomplete": "_disabled() ? null : \"list\"", "attr.aria-activedescendant": "_getAriaActiveDescendant()", "attr.aria-owns": "autocomplete().panelOpen() ? autocomplete().id() + \"-panel\" : null", "attr.aria-expanded": "_disabled() ? null : autocomplete().panelOpen().toString()", "attr.aria-controls": "(_disabled() || !autocomplete().panelOpen()) ? null : autocomplete()?.id()", "attr.aria-haspopup": "_disabled() ? null : \"listbox\"", "attr.tabindex": "_disabled() ? -1 : autocomplete().tabIndex()", "attr.aria-required": "autocomplete().required().toString()", "attr.aria-disabled": "_disabled().toString()", "attr.aria-invalid": "autocomplete().hasErrorState()", "attr.readonly": "_readonly() ? \"true\" : null", "disabled": "_disabled()" }, classAttribute: "ids-form-field-control" }, exportAs: ["idsAutocompleteTrigger"], ngImport: i0 }); }
|
|
1410
1451
|
}
|
|
1411
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type:
|
|
1412
|
-
type:
|
|
1413
|
-
args: [{
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
IdsIconComponent,
|
|
1421
|
-
IdsIconButtonComponent,
|
|
1422
|
-
IdsOverlayPanelComponent,
|
|
1423
|
-
IdsOptionComponent,
|
|
1424
|
-
IdsSpinnerComponent,
|
|
1425
|
-
IdsTooltipDirective,
|
|
1426
|
-
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
1427
|
-
{ provide: IDS_FORM_FIELD_CONTROL, useExisting: IdsAutocompleteComponent },
|
|
1428
|
-
{ provide: IDS_OPTION_PARENT_COMPONENT, useExisting: IdsAutocompleteComponent },
|
|
1429
|
-
{
|
|
1430
|
-
provide: NG_VALUE_ACCESSOR,
|
|
1431
|
-
useExisting: forwardRef(() => IdsAutocompleteComponent),
|
|
1432
|
-
multi: true,
|
|
1433
|
-
},
|
|
1434
|
-
], host: {
|
|
1435
|
-
role: 'combobox',
|
|
1436
|
-
'aria-autocomplete': 'list',
|
|
1437
|
-
'aria-haspopup': 'listbox',
|
|
1438
|
-
'[attr.tabindex]': 'disabled() ? -1 : tabIndex()',
|
|
1439
|
-
'[attr.aria-controls]': 'overlayPanel().open() ? id() + "-panel" : null',
|
|
1440
|
-
'[attr.aria-owns]': 'overlayPanel().open() ? id() + "-panel" : null',
|
|
1441
|
-
'[attr.aria-expanded]': 'overlayPanel().open()',
|
|
1442
|
-
'[attr.aria-label]': 'ariaLabel() || null',
|
|
1443
|
-
'[attr.aria-labelledby]': 'ariaLabelledby() || null',
|
|
1444
|
-
'[attr.aria-required]': 'required().toString()',
|
|
1445
|
-
'[attr.aria-disabled]': 'disabled().toString()',
|
|
1446
|
-
'[attr.aria-invalid]': 'hasErrorState()',
|
|
1452
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteTriggerDirective, decorators: [{
|
|
1453
|
+
type: Directive,
|
|
1454
|
+
args: [{
|
|
1455
|
+
selector: 'input[idsAutocompleteTriggerFor]',
|
|
1456
|
+
host: {
|
|
1457
|
+
class: 'ids-form-field-control',
|
|
1458
|
+
'[attr.role]': '_disabled() ? null : "combobox"',
|
|
1459
|
+
'[attr.autocomplete]': '_disabled() ? "off" : "auto"',
|
|
1460
|
+
'[attr.aria-autocomplete]': '_disabled() ? null : "list"',
|
|
1447
1461
|
'[attr.aria-activedescendant]': '_getAriaActiveDescendant()',
|
|
1462
|
+
'[attr.aria-owns]': 'autocomplete().panelOpen() ? autocomplete().id() + "-panel" : null',
|
|
1463
|
+
'[attr.aria-expanded]': '_disabled() ? null : autocomplete().panelOpen().toString()',
|
|
1464
|
+
'[attr.aria-controls]': '(_disabled() || !autocomplete().panelOpen()) ? null : autocomplete()?.id()',
|
|
1465
|
+
'[attr.aria-haspopup]': '_disabled() ? null : "listbox"',
|
|
1466
|
+
'[attr.tabindex]': '_disabled() ? -1 : autocomplete().tabIndex()',
|
|
1467
|
+
'[attr.aria-required]': 'autocomplete().required().toString()',
|
|
1468
|
+
'[attr.aria-disabled]': '_disabled().toString()',
|
|
1469
|
+
'[attr.aria-invalid]': 'autocomplete().hasErrorState()',
|
|
1470
|
+
'[attr.readonly]': '_readonly() ? "true" : null',
|
|
1471
|
+
'[disabled]': '_disabled()',
|
|
1448
1472
|
'(keydown)': '_handleKeydown($event)',
|
|
1449
1473
|
'(focus)': 'focus()',
|
|
1450
1474
|
'(blur)': '_onBlur()',
|
|
1451
|
-
},
|
|
1475
|
+
},
|
|
1476
|
+
exportAs: 'idsAutocompleteTrigger',
|
|
1477
|
+
}]
|
|
1452
1478
|
}], ctorParameters: () => [] });
|
|
1453
1479
|
|
|
1480
|
+
class IdsAutocompleteChipListComponent {
|
|
1481
|
+
constructor() {
|
|
1482
|
+
this.autocompleteTrigger = input.required(...(ngDevMode ? [{ debugName: "autocompleteTrigger", alias: 'for' }] : [{ alias: 'for' }]));
|
|
1483
|
+
this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
1484
|
+
this.appearance = input(IdsChipAppearance.OUTLINED, ...(ngDevMode ? [{ debugName: "appearance" }] : []));
|
|
1485
|
+
this.size = input(IdsSize.COMPACT, ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
1486
|
+
this.variant = input(IdsChipVariant.SURFACE, ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
1487
|
+
}
|
|
1488
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteChipListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1489
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: IdsAutocompleteChipListComponent, isStandalone: true, selector: "ids-autocomplete-chip-list", inputs: { autocompleteTrigger: { classPropertyName: "autocompleteTrigger", publicName: "for", isSignal: true, isRequired: true, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ids-autocomplete-chip-list" }, ngImport: i0, template: `
|
|
1490
|
+
@for (option of autocompleteTrigger().selected; track $index) {
|
|
1491
|
+
<button
|
|
1492
|
+
idsChip
|
|
1493
|
+
type="button"
|
|
1494
|
+
[appearance]="appearance()"
|
|
1495
|
+
[size]="size()"
|
|
1496
|
+
[variant]="variant()"
|
|
1497
|
+
[disabled]="autocompleteTrigger().autocomplete().disabled()"
|
|
1498
|
+
[removable]="true"
|
|
1499
|
+
(removed)="autocompleteTrigger().removeOption(option)"
|
|
1500
|
+
>
|
|
1501
|
+
{{ option.viewValue }}
|
|
1502
|
+
</button>
|
|
1503
|
+
}
|
|
1504
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IdsChipComponent, selector: "ids-chip, button[idsChip]", inputs: ["removable", "appearance", "size", "variant", "disabled", "tabIndex"], outputs: ["removed"] }] }); }
|
|
1505
|
+
}
|
|
1506
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteChipListComponent, decorators: [{
|
|
1507
|
+
type: Component,
|
|
1508
|
+
args: [{
|
|
1509
|
+
selector: 'ids-autocomplete-chip-list',
|
|
1510
|
+
host: {
|
|
1511
|
+
class: 'ids-autocomplete-chip-list',
|
|
1512
|
+
},
|
|
1513
|
+
imports: [IdsChipComponent],
|
|
1514
|
+
template: `
|
|
1515
|
+
@for (option of autocompleteTrigger().selected; track $index) {
|
|
1516
|
+
<button
|
|
1517
|
+
idsChip
|
|
1518
|
+
type="button"
|
|
1519
|
+
[appearance]="appearance()"
|
|
1520
|
+
[size]="size()"
|
|
1521
|
+
[variant]="variant()"
|
|
1522
|
+
[disabled]="autocompleteTrigger().autocomplete().disabled()"
|
|
1523
|
+
[removable]="true"
|
|
1524
|
+
(removed)="autocompleteTrigger().removeOption(option)"
|
|
1525
|
+
>
|
|
1526
|
+
{{ option.viewValue }}
|
|
1527
|
+
</button>
|
|
1528
|
+
}
|
|
1529
|
+
`,
|
|
1530
|
+
}]
|
|
1531
|
+
}] });
|
|
1532
|
+
|
|
1533
|
+
class IdsAutocompleteHintComponent {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
this.variant = input(IdsMessageVariant.SURFACE, ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
1536
|
+
this.size = input(IdsSize.COMFORTABLE, ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
1537
|
+
}
|
|
1538
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteHintComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1539
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.7", type: IdsAutocompleteHintComponent, isStandalone: true, selector: "ids-autocomplete-hint", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ids-autocomplete-hint" }, ngImport: i0, template: `
|
|
1540
|
+
<div class="ids-autocomplete-hint__wrapper">
|
|
1541
|
+
<ids-hint-message [size]="size()" [variant]="variant()">
|
|
1542
|
+
<ng-content />
|
|
1543
|
+
</ids-hint-message>
|
|
1544
|
+
</div>
|
|
1545
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IdsHintMessageComponent, selector: "ids-hint-message" }] }); }
|
|
1546
|
+
}
|
|
1547
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsAutocompleteHintComponent, decorators: [{
|
|
1548
|
+
type: Component,
|
|
1549
|
+
args: [{
|
|
1550
|
+
selector: 'ids-autocomplete-hint',
|
|
1551
|
+
host: {
|
|
1552
|
+
class: 'ids-autocomplete-hint',
|
|
1553
|
+
},
|
|
1554
|
+
imports: [IdsHintMessageComponent],
|
|
1555
|
+
template: `
|
|
1556
|
+
<div class="ids-autocomplete-hint__wrapper">
|
|
1557
|
+
<ids-hint-message [size]="size()" [variant]="variant()">
|
|
1558
|
+
<ng-content />
|
|
1559
|
+
</ids-hint-message>
|
|
1560
|
+
</div>
|
|
1561
|
+
`,
|
|
1562
|
+
}]
|
|
1563
|
+
}] });
|
|
1564
|
+
|
|
1454
1565
|
class IdsFieldsetRowComponent extends ComponentBase {
|
|
1455
1566
|
constructor() {
|
|
1456
1567
|
super(...arguments);
|
|
@@ -1467,6 +1578,119 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
1467
1578
|
args: [{ selector: 'ids-fieldset-row', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content />\n" }]
|
|
1468
1579
|
}] });
|
|
1469
1580
|
|
|
1581
|
+
const IDS_INPUT_DEFAULT_CONFIG = new InjectionToken('IDS_INPUT_DEFAULT_CONFIG', {
|
|
1582
|
+
providedIn: 'root',
|
|
1583
|
+
factory: IDS_INPUT_DEFAULT_CONFIG_FACTORY,
|
|
1584
|
+
});
|
|
1585
|
+
function IDS_INPUT_DEFAULT_CONFIG_FACTORY() {
|
|
1586
|
+
return {
|
|
1587
|
+
errorStateMatcher: ErrorStateMatcher,
|
|
1588
|
+
successStateMatcher: SuccessStateMatcher,
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
const defaultConfig = IDS_INPUT_DEFAULT_CONFIG_FACTORY();
|
|
1593
|
+
const IDS_INPUT_INVALID_TYPES = [
|
|
1594
|
+
'button',
|
|
1595
|
+
'checkbox',
|
|
1596
|
+
'file',
|
|
1597
|
+
'hidden',
|
|
1598
|
+
'image',
|
|
1599
|
+
'radio',
|
|
1600
|
+
'range',
|
|
1601
|
+
'reset',
|
|
1602
|
+
'submit',
|
|
1603
|
+
];
|
|
1604
|
+
class IdsInputDirective extends IdsFormFieldControl {
|
|
1605
|
+
constructor() {
|
|
1606
|
+
super(...arguments);
|
|
1607
|
+
this._elementRef = inject(ElementRef);
|
|
1608
|
+
this._defaultConfig = this._getDefaultConfig(defaultConfig, IDS_INPUT_DEFAULT_CONFIG);
|
|
1609
|
+
this._focused = false;
|
|
1610
|
+
this.name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : []));
|
|
1611
|
+
this.type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
1612
|
+
this.errorStateMatcher = input(inject(this._defaultConfig.errorStateMatcher), ...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : []));
|
|
1613
|
+
this.successStateMatcher = input(inject(this._defaultConfig.successStateMatcher), ...(ngDevMode ? [{ debugName: "successStateMatcher" }] : []));
|
|
1614
|
+
this._hostClasses = computed(() => this._getHostClasses([], [formFieldControlClass]), ...(ngDevMode ? [{ debugName: "_hostClasses" }] : []));
|
|
1615
|
+
this._validateTypeEffect = effect(() => {
|
|
1616
|
+
this._validateType(this.type());
|
|
1617
|
+
}, ...(ngDevMode ? [{ debugName: "_validateTypeEffect" }] : []));
|
|
1618
|
+
/**
|
|
1619
|
+
* Should be an arrow function in order to handle `this` outside of this class
|
|
1620
|
+
*/
|
|
1621
|
+
this.onContainerClick = () => {
|
|
1622
|
+
if (!this._focused && !this.readonly() && !this.disabled) {
|
|
1623
|
+
this.focus();
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
get _hostName() {
|
|
1628
|
+
return 'input';
|
|
1629
|
+
}
|
|
1630
|
+
ngAfterViewInit() {
|
|
1631
|
+
queueMicrotask(() => {
|
|
1632
|
+
const control = this.ngControl()?.control;
|
|
1633
|
+
if (control) {
|
|
1634
|
+
this._disabled.set(control.status === 'DISABLED');
|
|
1635
|
+
control.events.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((event) => this.updateControlState(event));
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
_validateType(type) {
|
|
1640
|
+
if (isDevMode() && IDS_INPUT_INVALID_TYPES.indexOf(type) > -1) {
|
|
1641
|
+
throw this._createHostError(`Input type ${type} is not supportedby idsInput`);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
focus(options) {
|
|
1645
|
+
this._elementRef.nativeElement.focus(options);
|
|
1646
|
+
}
|
|
1647
|
+
_focusChanged(isFocused) {
|
|
1648
|
+
if (isFocused !== this._focused) {
|
|
1649
|
+
this._focused = isFocused;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
updateControlState(event) {
|
|
1653
|
+
this._errorStateTracker?.updateErrorState();
|
|
1654
|
+
this._successStateTracker?.updateSuccessState();
|
|
1655
|
+
if (event instanceof StatusChangeEvent) {
|
|
1656
|
+
this._disabled.set(event.status === 'DISABLED');
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsInputDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1660
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.7", type: IdsInputDirective, isStandalone: true, selector: "input[idsInput][ngModel]:not([formControl]):not([formControlName]),\n input[idsInput][formControl]:not([ngModel]):not([formControlName]),\n input[idsInput][formControlName]:not([ngModel]):not([formControl]),\n textarea[idsInput][ngModel]:not([formControl]):not([formControlName]),\n textarea[idsInput][formControl]:not([ngModel]):not([formControlName]),\n textarea[idsInput][formControlName]:not([ngModel]):not([formControl])", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, successStateMatcher: { classPropertyName: "successStateMatcher", publicName: "successStateMatcher", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focus": "_focusChanged(true)", "blur": "_focusChanged(false)" }, properties: { "attr.placeholder": "placeholder()", "attr.disabled": "disabled() ? \"\" : null", "attr.readonly": "readonly() ? \"\" : null" } }, providers: [
|
|
1661
|
+
{
|
|
1662
|
+
provide: IDS_FORM_FIELD_CONTROL,
|
|
1663
|
+
useExisting: IdsInputDirective,
|
|
1664
|
+
},
|
|
1665
|
+
], exportAs: ["idsInput"], usesInheritance: true, ngImport: i0 }); }
|
|
1666
|
+
}
|
|
1667
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IdsInputDirective, decorators: [{
|
|
1668
|
+
type: Directive,
|
|
1669
|
+
args: [{
|
|
1670
|
+
selector: `input[idsInput][ngModel]:not([formControl]):not([formControlName]),
|
|
1671
|
+
input[idsInput][formControl]:not([ngModel]):not([formControlName]),
|
|
1672
|
+
input[idsInput][formControlName]:not([ngModel]):not([formControl]),
|
|
1673
|
+
textarea[idsInput][ngModel]:not([formControl]):not([formControlName]),
|
|
1674
|
+
textarea[idsInput][formControl]:not([ngModel]):not([formControlName]),
|
|
1675
|
+
textarea[idsInput][formControlName]:not([ngModel]):not([formControl])`,
|
|
1676
|
+
exportAs: 'idsInput',
|
|
1677
|
+
standalone: true,
|
|
1678
|
+
providers: [
|
|
1679
|
+
{
|
|
1680
|
+
provide: IDS_FORM_FIELD_CONTROL,
|
|
1681
|
+
useExisting: IdsInputDirective,
|
|
1682
|
+
},
|
|
1683
|
+
],
|
|
1684
|
+
host: {
|
|
1685
|
+
'[attr.placeholder]': 'placeholder()',
|
|
1686
|
+
'[attr.disabled]': 'disabled() ? "" : null',
|
|
1687
|
+
'[attr.readonly]': 'readonly() ? "" : null',
|
|
1688
|
+
'(focus)': '_focusChanged(true)',
|
|
1689
|
+
'(blur)': '_focusChanged(false)',
|
|
1690
|
+
},
|
|
1691
|
+
}]
|
|
1692
|
+
}] });
|
|
1693
|
+
|
|
1470
1694
|
const Message = {
|
|
1471
1695
|
HINT: 'hint',
|
|
1472
1696
|
ERROR: 'error',
|
|
@@ -1518,5 +1742,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
1518
1742
|
* Generated bundle index. Do not edit.
|
|
1519
1743
|
*/
|
|
1520
1744
|
|
|
1521
|
-
export { AbstractErrorStateMatcher, AbstractSuccessStateMatcher, ErrorStateMatcher, ErrorStateTracker, IDS_AUTOCOMPLETE_DEFAULT_CONFIG, IDS_AUTOCOMPLETE_DEFAULT_CONFIG_FACTORY,
|
|
1745
|
+
export { AbstractErrorStateMatcher, AbstractSuccessStateMatcher, ErrorStateMatcher, ErrorStateTracker, IDS_AUTOCOMPLETE_DEFAULT_CONFIG, IDS_AUTOCOMPLETE_DEFAULT_CONFIG_FACTORY, IDS_FIELDSET_DEFAULT_CONFIG, IDS_FIELDSET_DEFAULT_CONFIG_FACTORY, IDS_FORM_FIELD_CONTROL, IDS_FORM_FIELD_DEFAULT_CONFIG, IDS_FORM_FIELD_DEFAULT_CONFIG_FACTORY, IDS_INPUT_DEFAULT_CONFIG, IDS_INPUT_DEFAULT_CONFIG_FACTORY, IDS_MESSAGE_DEFAULT_CONFIG, IDS_MESSAGE_DEFAULT_CONFIG_FACTORY, IDS_OPTION_GROUP, IDS_OPTION_PARENT_COMPONENT, IDS_PSEUDO_CHECKBOX_PARENT, IdsAutocompleteChipListComponent, IdsAutocompleteComponent, IdsAutocompleteHintComponent, IdsAutocompleteTriggerDirective, IdsErrorDefinitionDirective, IdsErrorMessageComponent, IdsFieldsetComponent, IdsFieldsetMessageDirective, IdsFieldsetRowComponent, IdsFormFieldActionDirective, IdsFormFieldComponent, IdsFormFieldControl, IdsFormFieldVariant, IdsHintMessageComponent, IdsInputDirective, IdsLabelDirective, IdsMessageDirective, IdsMessagePrefixDirective, IdsMessageSuffixDirective, IdsMessageVariant, IdsOptionComponent, IdsOptionGroupComponent, IdsOptionSelectionChange, IdsPrefixDirective, IdsPseudoCheckboxState, IdsSuccessMessageComponent, IdsSuffixDirective, IdsValidators, Message, PseudoCheckboxComponent, SuccessStateMatcher, SuccessStateTracker, _countGroupLabelsBeforeOption, _getOptionScrollPosition, formFieldControlClass, requiredFalseValidator, requiredTrueValidator, requiredValidator };
|
|
1522
1746
|
//# sourceMappingURL=i-cell-ids-angular-forms.mjs.map
|