@clr/angular 18.0.0-beta.1 → 18.0.0-beta.11
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/fesm2022/clr-angular-accordion.mjs +1 -1
- package/fesm2022/clr-angular-accordion.mjs.map +1 -1
- package/fesm2022/clr-angular-button.mjs +6 -6
- package/fesm2022/clr-angular-button.mjs.map +1 -1
- package/fesm2022/clr-angular-data-datagrid.mjs +45 -35
- package/fesm2022/clr-angular-data-datagrid.mjs.map +1 -1
- package/fesm2022/clr-angular-data-tree-view.mjs +3 -3
- package/fesm2022/clr-angular-data-tree-view.mjs.map +1 -1
- package/fesm2022/clr-angular-data.mjs +11 -9116
- package/fesm2022/clr-angular-data.mjs.map +1 -1
- package/fesm2022/clr-angular-emphasis-alert.mjs +2 -2
- package/fesm2022/clr-angular-emphasis-alert.mjs.map +1 -1
- package/fesm2022/clr-angular-emphasis.mjs +12 -778
- package/fesm2022/clr-angular-emphasis.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-checkbox.mjs +13 -44
- package/fesm2022/clr-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-combobox.mjs +420 -90
- package/fesm2022/clr-angular-forms-combobox.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-common.mjs +62 -57
- package/fesm2022/clr-angular-forms-common.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-datalist.mjs +2 -14
- package/fesm2022/clr-angular-forms-datalist.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-datepicker.mjs +20 -28
- package/fesm2022/clr-angular-forms-datepicker.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-file-input.mjs +78 -62
- package/fesm2022/clr-angular-forms-file-input.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-input.mjs +4 -18
- package/fesm2022/clr-angular-forms-input.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-number-input.mjs +2 -14
- package/fesm2022/clr-angular-forms-number-input.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-password.mjs +2 -14
- package/fesm2022/clr-angular-forms-password.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-radio.mjs +13 -44
- package/fesm2022/clr-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-range.mjs +3 -16
- package/fesm2022/clr-angular-forms-range.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-select.mjs +3 -16
- package/fesm2022/clr-angular-forms-select.mjs.map +1 -1
- package/fesm2022/clr-angular-forms-textarea.mjs +4 -17
- package/fesm2022/clr-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/clr-angular-forms.mjs +68 -8560
- package/fesm2022/clr-angular-forms.mjs.map +1 -1
- package/fesm2022/clr-angular-icon.mjs +10 -0
- package/fesm2022/clr-angular-icon.mjs.map +1 -1
- package/fesm2022/clr-angular-layout-nav.mjs +27 -25
- package/fesm2022/clr-angular-layout-nav.mjs.map +1 -1
- package/fesm2022/clr-angular-layout-tabs.mjs +1 -1
- package/fesm2022/clr-angular-layout-tabs.mjs.map +1 -1
- package/fesm2022/clr-angular-layout.mjs +15 -2057
- package/fesm2022/clr-angular-layout.mjs.map +1 -1
- package/fesm2022/clr-angular-modal.mjs +4 -5
- package/fesm2022/clr-angular-modal.mjs.map +1 -1
- package/fesm2022/clr-angular-popover-common.mjs +151 -85
- package/fesm2022/clr-angular-popover-common.mjs.map +1 -1
- package/fesm2022/clr-angular-popover-dropdown.mjs +7 -4
- package/fesm2022/clr-angular-popover-dropdown.mjs.map +1 -1
- package/fesm2022/clr-angular-popover-signpost.mjs +30 -15
- package/fesm2022/clr-angular-popover-signpost.mjs.map +1 -1
- package/fesm2022/clr-angular-popover-tooltip.mjs +7 -7
- package/fesm2022/clr-angular-popover-tooltip.mjs.map +1 -1
- package/fesm2022/clr-angular-popover.mjs +12 -2242
- package/fesm2022/clr-angular-popover.mjs.map +1 -1
- package/fesm2022/clr-angular-stepper.mjs +5 -5
- package/fesm2022/clr-angular-stepper.mjs.map +1 -1
- package/fesm2022/clr-angular-utils.mjs +20 -485
- package/fesm2022/clr-angular-utils.mjs.map +1 -1
- package/fesm2022/clr-angular-wizard.mjs +434 -223
- package/fesm2022/clr-angular-wizard.mjs.map +1 -1
- package/fesm2022/clr-angular.mjs +94 -38740
- package/fesm2022/clr-angular.mjs.map +1 -1
- package/package.json +10 -5
- package/popover/common/README.md +14 -12
- package/schematics/collection.json +14 -0
- package/schematics/ng-update/index.d.ts +2 -0
- package/schematics/ng-update/index.js +69 -0
- package/schematics/ng-update/index.js.map +1 -0
- package/schematics/ng-update/migrations/css-migration.d.ts +6 -0
- package/schematics/ng-update/migrations/css-migration.js +177 -0
- package/schematics/ng-update/migrations/css-migration.js.map +1 -0
- package/schematics/ng-update/migrations/import-migration.d.ts +4 -0
- package/schematics/ng-update/migrations/import-migration.js +187 -0
- package/schematics/ng-update/migrations/import-migration.js.map +1 -0
- package/schematics/ng-update/migrations/template-migration.d.ts +6 -0
- package/schematics/ng-update/migrations/template-migration.js +261 -0
- package/schematics/ng-update/migrations/template-migration.js.map +1 -0
- package/schematics/ng-update/replacements/css-replacements.d.ts +17 -0
- package/schematics/ng-update/replacements/css-replacements.js +74 -0
- package/schematics/ng-update/replacements/css-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/import-replacements.d.ts +13 -0
- package/schematics/ng-update/replacements/import-replacements.js +108 -0
- package/schematics/ng-update/replacements/import-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/symbol-replacements.d.ts +12 -0
- package/schematics/ng-update/replacements/symbol-replacements.js +67 -0
- package/schematics/ng-update/replacements/symbol-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/template-replacements.d.ts +19 -0
- package/schematics/ng-update/replacements/template-replacements.js +57 -0
- package/schematics/ng-update/replacements/template-replacements.js.map +1 -0
- package/schematics/ng-update/tests/test-helpers.d.ts +6 -0
- package/schematics/ng-update/tests/test-helpers.js +34 -0
- package/schematics/ng-update/tests/test-helpers.js.map +1 -0
- package/schematics/ng-update/utils/file-visitor.d.ts +8 -0
- package/schematics/ng-update/utils/file-visitor.js +44 -0
- package/schematics/ng-update/utils/file-visitor.js.map +1 -0
- package/schematics/ng-update/utils/regexp-utils.d.ts +16 -0
- package/schematics/ng-update/utils/regexp-utils.js +34 -0
- package/schematics/ng-update/utils/regexp-utils.js.map +1 -0
- package/schematics/vitest.config.d.ts +2 -0
- package/schematics/vitest.config.js +17 -0
- package/schematics/vitest.config.js.map +1 -0
- package/types/clr-angular-accordion.d.ts +1 -1
- package/types/clr-angular-button.d.ts +1 -1
- package/types/clr-angular-data-datagrid.d.ts +23 -33
- package/types/clr-angular-data-tree-view.d.ts +10 -1
- package/types/clr-angular-data.d.ts +4 -2136
- package/types/clr-angular-emphasis.d.ts +4 -220
- package/types/clr-angular-forms-combobox.d.ts +64 -11
- package/types/clr-angular-forms-common.d.ts +9 -9
- package/types/clr-angular-forms-datepicker.d.ts +8 -1
- package/types/clr-angular-forms-file-input.d.ts +6 -3
- package/types/clr-angular-forms.d.ts +26 -2062
- package/types/clr-angular-layout-nav.d.ts +6 -2
- package/types/clr-angular-layout-tabs.d.ts +1 -1
- package/types/clr-angular-layout.d.ts +6 -463
- package/types/clr-angular-popover-common.d.ts +38 -13
- package/types/clr-angular-popover-dropdown.d.ts +2 -1
- package/types/clr-angular-popover-signpost.d.ts +15 -7
- package/types/clr-angular-popover-tooltip.d.ts +1 -1
- package/types/clr-angular-popover.d.ts +7 -559
- package/types/clr-angular-stepper.d.ts +1 -1
- package/types/clr-angular-utils.d.ts +13 -175
- package/types/clr-angular-wizard.d.ts +92 -35
- package/types/clr-angular.d.ts +22 -10238
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as i8 from '@angular/common';
|
|
2
2
|
import { isPlatformBrowser, NgForOf, CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Injectable, ViewChild, Optional, Component, Input, Directive, PLATFORM_ID, Inject, HostListener, HostBinding, DOCUMENT, ContentChildren, EventEmitter, ContentChild, Output, Self, NgModule } from '@angular/core';
|
|
4
|
+
import { Injectable, ViewChild, Optional, Component, Input, Directive, PLATFORM_ID, Inject, HostListener, HostBinding, DOCUMENT, ContentChildren, EventEmitter, booleanAttribute, ContentChild, ViewChildren, Output, Self, Host, NgModule } from '@angular/core';
|
|
5
5
|
import * as i1$1 from '@angular/forms';
|
|
6
6
|
import { FormsModule } from '@angular/forms';
|
|
7
7
|
import * as i1 from '@clr/angular/forms/common';
|
|
8
8
|
import { ClrAbstractContainer, NgControlService, ControlIdService, ControlClassService, WrappedFormControl, ClrCommonFormsModule } from '@clr/angular/forms/common';
|
|
9
|
-
import * as
|
|
10
|
-
import { ClarityIcons,
|
|
11
|
-
import * as i4
|
|
12
|
-
import {
|
|
9
|
+
import * as i9 from '@clr/angular/icon';
|
|
10
|
+
import { ClarityIcons, successStandardIcon, errorStandardIcon, angleIcon, windowCloseIcon, ClrIcon } from '@clr/angular/icon';
|
|
11
|
+
import * as i4 from '@clr/angular/popover/common';
|
|
12
|
+
import { POPOVER_HOST_ORIGIN, ClrPopoverPosition, ClrPopoverType, ClrPopoverHostDirective, ClrPopoverModuleNext } from '@clr/angular/popover/common';
|
|
13
13
|
import * as i5 from '@clr/angular/progress/spinner';
|
|
14
14
|
import { ClrSpinnerModule } from '@clr/angular/progress/spinner';
|
|
15
|
-
import * as i3
|
|
16
|
-
import { ArrowKeyDirection,
|
|
15
|
+
import * as i3 from '@clr/angular/utils';
|
|
16
|
+
import { ArrowKeyDirection, Keys, customFocusableItemProvider, uniqueIdFactory, ClrLoadingState, IF_ACTIVE_ID, LoadingListener, IF_ACTIVE_ID_PROVIDER, FOCUS_SERVICE_PROVIDER, ClrConditionalModule, ClrKeyFocusModule } from '@clr/angular/utils';
|
|
17
|
+
import { BehaviorSubject, ReplaySubject, Subject, debounceTime } from 'rxjs';
|
|
17
18
|
import { take } from 'rxjs/operators';
|
|
18
|
-
import { BehaviorSubject, ReplaySubject } from 'rxjs';
|
|
19
19
|
|
|
20
20
|
/*
|
|
21
21
|
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
@@ -63,12 +63,6 @@ class ClrComboboxContainer extends ClrAbstractContainer {
|
|
|
63
63
|
}
|
|
64
64
|
<div class="clr-control-container" [ngClass]="controlClass()" #controlContainer>
|
|
65
65
|
<ng-content select="clr-combobox"></ng-content>
|
|
66
|
-
@if (showInvalid) {
|
|
67
|
-
<cds-icon class="clr-validate-icon" shape="exclamation-circle" status="danger" aria-hidden="true"></cds-icon>
|
|
68
|
-
}
|
|
69
|
-
@if (showValid) {
|
|
70
|
-
<cds-icon class="clr-validate-icon" shape="check-circle" status="success" aria-hidden="true"></cds-icon>
|
|
71
|
-
}
|
|
72
66
|
@if (showHelper) {
|
|
73
67
|
<ng-content select="clr-control-helper"></ng-content>
|
|
74
68
|
}
|
|
@@ -79,7 +73,7 @@ class ClrComboboxContainer extends ClrAbstractContainer {
|
|
|
79
73
|
<ng-content select="clr-control-success"></ng-content>
|
|
80
74
|
}
|
|
81
75
|
</div>
|
|
82
|
-
`, isInline: true, dependencies: [{ kind: "directive", type:
|
|
76
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.ClrControlLabel, selector: "label", inputs: ["id", "for"] }] }); }
|
|
83
77
|
}
|
|
84
78
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrComboboxContainer, decorators: [{
|
|
85
79
|
type: Component,
|
|
@@ -92,12 +86,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
92
86
|
}
|
|
93
87
|
<div class="clr-control-container" [ngClass]="controlClass()" #controlContainer>
|
|
94
88
|
<ng-content select="clr-combobox"></ng-content>
|
|
95
|
-
@if (showInvalid) {
|
|
96
|
-
<cds-icon class="clr-validate-icon" shape="exclamation-circle" status="danger" aria-hidden="true"></cds-icon>
|
|
97
|
-
}
|
|
98
|
-
@if (showValid) {
|
|
99
|
-
<cds-icon class="clr-validate-icon" shape="check-circle" status="success" aria-hidden="true"></cds-icon>
|
|
100
|
-
}
|
|
101
89
|
@if (showHelper) {
|
|
102
90
|
<ng-content select="clr-control-helper"></ng-content>
|
|
103
91
|
}
|
|
@@ -131,20 +119,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
131
119
|
* This software is released under MIT license.
|
|
132
120
|
* The full license information can be found in LICENSE in the root directory of this project.
|
|
133
121
|
*/
|
|
134
|
-
class
|
|
122
|
+
class ComboboxModel {
|
|
123
|
+
constructor() {
|
|
124
|
+
this.identityFn = (item) => item;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
130
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
131
|
+
* This software is released under MIT license.
|
|
132
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
133
|
+
*/
|
|
134
|
+
class MultiSelectComboboxModel extends ComboboxModel {
|
|
135
135
|
containsItem(item) {
|
|
136
|
-
if (this.model) {
|
|
137
|
-
|
|
138
|
-
const includes = this.model.some(modelItem => {
|
|
139
|
-
return modelItem[this.displayField] === item[this.displayField];
|
|
140
|
-
});
|
|
141
|
-
return includes;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
return this.model.includes(item);
|
|
145
|
-
}
|
|
136
|
+
if (this.model === null || this.model === undefined) {
|
|
137
|
+
return false;
|
|
146
138
|
}
|
|
147
|
-
return
|
|
139
|
+
return this.model.some(m => this.identityFn(m) === this.identityFn(item));
|
|
148
140
|
}
|
|
149
141
|
select(item) {
|
|
150
142
|
this.addItem(item);
|
|
@@ -207,7 +199,7 @@ class MultiSelectComboboxModel {
|
|
|
207
199
|
if (this.model === null || this.model === undefined) {
|
|
208
200
|
return;
|
|
209
201
|
}
|
|
210
|
-
const index = this.model.
|
|
202
|
+
const index = this.model.findIndex(m => this.identityFn(m) === this.identityFn(item));
|
|
211
203
|
if (index > -1) {
|
|
212
204
|
this.model.splice(index, 1);
|
|
213
205
|
}
|
|
@@ -224,9 +216,12 @@ class MultiSelectComboboxModel {
|
|
|
224
216
|
* This software is released under MIT license.
|
|
225
217
|
* The full license information can be found in LICENSE in the root directory of this project.
|
|
226
218
|
*/
|
|
227
|
-
class SingleSelectComboboxModel {
|
|
219
|
+
class SingleSelectComboboxModel extends ComboboxModel {
|
|
228
220
|
containsItem(item) {
|
|
229
|
-
|
|
221
|
+
if (this.model === null || this.model === undefined) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
return this.identityFn(this.model) === this.identityFn(item);
|
|
230
225
|
}
|
|
231
226
|
select(item) {
|
|
232
227
|
this.model = item;
|
|
@@ -313,13 +308,16 @@ class OptionSelectionService {
|
|
|
313
308
|
constructor() {
|
|
314
309
|
this.loading = false;
|
|
315
310
|
this.editable = false;
|
|
316
|
-
this.
|
|
311
|
+
this.showSelectAll = false;
|
|
317
312
|
// Display all options on first open, even if filter text exists.
|
|
318
313
|
// https://github.com/vmware-clarity/ng-clarity/issues/386
|
|
319
314
|
this.showAllOptions = true;
|
|
320
315
|
this._currentInput = '';
|
|
321
316
|
this._inputChanged = new BehaviorSubject('');
|
|
322
317
|
this._selectionChanged = new ReplaySubject(1);
|
|
318
|
+
this._selectAllRequested = new Subject();
|
|
319
|
+
this.editableResolver = (input) => input;
|
|
320
|
+
this._identityFn = (item) => item;
|
|
323
321
|
this.inputChanged = this._inputChanged.asObservable();
|
|
324
322
|
}
|
|
325
323
|
get displayField() {
|
|
@@ -350,6 +348,21 @@ class OptionSelectionService {
|
|
|
350
348
|
get multiselectable() {
|
|
351
349
|
return this.selectionModel instanceof MultiSelectComboboxModel;
|
|
352
350
|
}
|
|
351
|
+
get identityFn() {
|
|
352
|
+
return this._identityFn;
|
|
353
|
+
}
|
|
354
|
+
set identityFn(value) {
|
|
355
|
+
this._identityFn = value || ((item) => item);
|
|
356
|
+
if (this.selectionModel) {
|
|
357
|
+
this.selectionModel.identityFn = this._identityFn;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
get selectAllRequested() {
|
|
361
|
+
return this._selectAllRequested.asObservable();
|
|
362
|
+
}
|
|
363
|
+
requestSelectAll() {
|
|
364
|
+
this._selectAllRequested.next();
|
|
365
|
+
}
|
|
353
366
|
select(item) {
|
|
354
367
|
if (item === null || item === undefined || this.selectionModel.containsItem(item)) {
|
|
355
368
|
return;
|
|
@@ -369,6 +382,33 @@ class OptionSelectionService {
|
|
|
369
382
|
}
|
|
370
383
|
this._selectionChanged.next(this.selectionModel);
|
|
371
384
|
}
|
|
385
|
+
selectMany(items) {
|
|
386
|
+
let changed = false;
|
|
387
|
+
for (const item of items) {
|
|
388
|
+
if (!this.selectionModel.containsItem(item)) {
|
|
389
|
+
this.selectionModel.select(item);
|
|
390
|
+
changed = true;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (changed) {
|
|
394
|
+
this._selectionChanged.next(this.selectionModel);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
unselectMany(items) {
|
|
398
|
+
if (!this.selectionModel || this.selectionModel.isEmpty()) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
let changed = false;
|
|
402
|
+
for (const item of items) {
|
|
403
|
+
if (this.selectionModel.containsItem(item)) {
|
|
404
|
+
this.selectionModel.unselect(item);
|
|
405
|
+
changed = true;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (changed) {
|
|
409
|
+
this._selectionChanged.next(this.selectionModel);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
372
412
|
unselect(item) {
|
|
373
413
|
if (item === null || item === undefined || !this.selectionModel.containsItem(item)) {
|
|
374
414
|
return;
|
|
@@ -376,25 +416,58 @@ class OptionSelectionService {
|
|
|
376
416
|
this.selectionModel.unselect(item);
|
|
377
417
|
this._selectionChanged.next(this.selectionModel);
|
|
378
418
|
}
|
|
379
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Checks whether all given items are currently selected, using identityFn for comparison.
|
|
421
|
+
*/
|
|
422
|
+
containsAll(items) {
|
|
423
|
+
if (!items.length || this.selectionModel.isEmpty()) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
return items.every(item => this.selectionModel.containsItem(item));
|
|
427
|
+
}
|
|
380
428
|
setSelectionValue(value) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if (
|
|
429
|
+
if (!this.selectionModel) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const current = this.selectionModel.model;
|
|
433
|
+
if (this.valuesEqualByIdentity(current, value)) {
|
|
386
434
|
return;
|
|
387
435
|
}
|
|
388
436
|
this.selectionModel.model = value;
|
|
389
437
|
this._selectionChanged.next(this.selectionModel);
|
|
390
438
|
}
|
|
391
|
-
|
|
392
|
-
if (
|
|
393
|
-
return
|
|
394
|
-
|
|
395
|
-
|
|
439
|
+
valuesEqualByIdentity(current, value) {
|
|
440
|
+
if (current === value) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
// Check if both are null or undefined or empty string.
|
|
444
|
+
if ((current === null || current === undefined || current === '') &&
|
|
445
|
+
(value === null || value === undefined || value === '')) {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
// Check if one is null or undefined or empty string and the other is not.
|
|
449
|
+
if (current === null ||
|
|
450
|
+
current === undefined ||
|
|
451
|
+
current === '' ||
|
|
452
|
+
value === null ||
|
|
453
|
+
value === undefined ||
|
|
454
|
+
value === '') {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
if (this.multiselectable) {
|
|
458
|
+
const cur = current;
|
|
459
|
+
const val = value;
|
|
460
|
+
if (cur.length !== val.length) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
// We only consider values equal if they are ordered the same way.
|
|
464
|
+
const curIds = cur.map(this._identityFn);
|
|
465
|
+
const valIds = val.map(this._identityFn);
|
|
466
|
+
return curIds.every((id, i) => id === valIds[i]);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
return this._identityFn(current) === this._identityFn(value);
|
|
396
470
|
}
|
|
397
|
-
return value;
|
|
398
471
|
}
|
|
399
472
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: OptionSelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
400
473
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: OptionSelectionService }); }
|
|
@@ -476,6 +549,9 @@ class ComboboxFocusHandler {
|
|
|
476
549
|
addOptionValues(options) {
|
|
477
550
|
this.optionData = options;
|
|
478
551
|
}
|
|
552
|
+
focusOption(option) {
|
|
553
|
+
this.pseudoFocus.select(option);
|
|
554
|
+
}
|
|
479
555
|
handleFocusSubscription() {
|
|
480
556
|
this.popoverService.openChange.subscribe(open => {
|
|
481
557
|
if (!open) {
|
|
@@ -520,13 +596,18 @@ class ComboboxFocusHandler {
|
|
|
520
596
|
// this service is only interested in keys that may move the focus
|
|
521
597
|
handleTextInput(event) {
|
|
522
598
|
let preventDefault = false;
|
|
523
|
-
const key =
|
|
599
|
+
const key = event.key;
|
|
524
600
|
if (event) {
|
|
525
601
|
switch (key) {
|
|
526
602
|
case Keys.Enter:
|
|
527
603
|
if (this.popoverService.open && this.pseudoFocus.model) {
|
|
528
604
|
if (this.selectionService.multiselectable) {
|
|
529
|
-
|
|
605
|
+
if (this.pseudoFocus.model.id === SELECT_ALL_ID) {
|
|
606
|
+
this.selectionService.requestSelectAll();
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
this.selectionService.toggle(this.pseudoFocus.model.value);
|
|
610
|
+
}
|
|
530
611
|
}
|
|
531
612
|
else {
|
|
532
613
|
this.selectionService.select(this.pseudoFocus.model.value);
|
|
@@ -577,26 +658,20 @@ class ComboboxFocusHandler {
|
|
|
577
658
|
this.renderer.listen(el, 'blur', event => {
|
|
578
659
|
if (this.focusOutOfComponent(event)) {
|
|
579
660
|
this.popoverService.open = false;
|
|
580
|
-
// Workaround for popover close-on-outside-click timing issues in Edge browser
|
|
581
|
-
if (this.componentCdRef) {
|
|
582
|
-
this.componentCdRef.detectChanges();
|
|
583
|
-
}
|
|
584
661
|
}
|
|
585
662
|
});
|
|
586
663
|
}
|
|
587
664
|
}
|
|
588
665
|
focusOutOfComponent(event) {
|
|
589
|
-
|
|
590
|
-
// which points to the element that becomes active as the blur event occurs on the input.
|
|
591
|
-
const target = (event.relatedTarget || document.activeElement);
|
|
666
|
+
const target = event.relatedTarget;
|
|
592
667
|
return !(this.textInput.contains(target) || this.trigger.contains(target) || this.listbox.contains(target));
|
|
593
668
|
}
|
|
594
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ComboboxFocusHandler, deps: [{ token: i0.RendererFactory2 }, { token: i4
|
|
669
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ComboboxFocusHandler, deps: [{ token: i0.RendererFactory2 }, { token: i4.ClrPopoverService }, { token: OptionSelectionService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
595
670
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ComboboxFocusHandler }); }
|
|
596
671
|
}
|
|
597
672
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ComboboxFocusHandler, decorators: [{
|
|
598
673
|
type: Injectable
|
|
599
|
-
}], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: i4
|
|
674
|
+
}], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: i4.ClrPopoverService }, { type: OptionSelectionService }, { type: undefined, decorators: [{
|
|
600
675
|
type: Inject,
|
|
601
676
|
args: [PLATFORM_ID]
|
|
602
677
|
}] }] });
|
|
@@ -668,9 +743,10 @@ class ClrOption {
|
|
|
668
743
|
// This way we achieve two things:
|
|
669
744
|
// - do not lose focus
|
|
670
745
|
// - we're still able to use onBlur for "outside-click" handling
|
|
746
|
+
this.focusHandler.focusOption(this.optionProxy);
|
|
671
747
|
this.focusHandler.focusInput();
|
|
672
748
|
}
|
|
673
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrOption, deps: [{ token: i0.ElementRef }, { token: i3
|
|
749
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrOption, deps: [{ token: i0.ElementRef }, { token: i3.ClrCommonStringsService }, { token: ComboboxFocusHandler }, { token: OptionSelectionService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
674
750
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrOption, isStandalone: false, selector: "clr-option", inputs: { optionId: ["id", "optionId"], value: ["clrValue", "value"] }, host: { listeners: { "click": "onClick($event)" }, properties: { "class.clr-combobox-option": "true", "attr.role": "\"option\"", "attr.tabindex": "-1", "attr.id": "optionId", "class.active": "this.selected", "class.clr-focus": "this.focusClass" } }, ngImport: i0, template: `
|
|
675
751
|
<ng-content></ng-content>
|
|
676
752
|
@if (selected) {
|
|
@@ -697,7 +773,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
697
773
|
},
|
|
698
774
|
standalone: false,
|
|
699
775
|
}]
|
|
700
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i3
|
|
776
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i3.ClrCommonStringsService }, { type: ComboboxFocusHandler }, { type: OptionSelectionService }], propDecorators: { optionId: [{
|
|
701
777
|
type: Input,
|
|
702
778
|
args: ['id']
|
|
703
779
|
}], value: [{
|
|
@@ -721,6 +797,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
721
797
|
* The full license information can be found in LICENSE in the root directory of this project.
|
|
722
798
|
*/
|
|
723
799
|
let nbOptionsComponents = 0;
|
|
800
|
+
const SELECT_ALL_ID = 'select-all-id';
|
|
724
801
|
class ClrOptions {
|
|
725
802
|
constructor(optionSelectionService, id, el, commonStrings, focusHandler, popoverService, parentHost, document) {
|
|
726
803
|
this.optionSelectionService = optionSelectionService;
|
|
@@ -739,12 +816,22 @@ class ClrOptions {
|
|
|
739
816
|
this.optionsId = 'clr-options-' + nbOptionsComponents++;
|
|
740
817
|
}
|
|
741
818
|
}
|
|
819
|
+
set selectAllBtn(value) {
|
|
820
|
+
if (value) {
|
|
821
|
+
this._selectAllOption = new OptionData(SELECT_ALL_ID, null);
|
|
822
|
+
this._selectAllOption.el = value.nativeElement;
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
this._selectAllOption = null;
|
|
826
|
+
}
|
|
827
|
+
this.updateFocusableItems();
|
|
828
|
+
}
|
|
742
829
|
get items() {
|
|
743
830
|
return this._items;
|
|
744
831
|
}
|
|
745
832
|
set items(items) {
|
|
746
833
|
this._items = items;
|
|
747
|
-
this.
|
|
834
|
+
this.updateFocusableItems();
|
|
748
835
|
}
|
|
749
836
|
/**
|
|
750
837
|
* Tests if the list of options is empty, meaning it doesn't contain any items
|
|
@@ -758,6 +845,34 @@ class ClrOptions {
|
|
|
758
845
|
get noResultsElementId() {
|
|
759
846
|
return `${this.optionsId}-no-results`;
|
|
760
847
|
}
|
|
848
|
+
get showSelectAll() {
|
|
849
|
+
return (this.optionSelectionService.showSelectAll &&
|
|
850
|
+
this.optionSelectionService.multiselectable &&
|
|
851
|
+
!this.optionSelectionService.loading &&
|
|
852
|
+
this.items.length > 0);
|
|
853
|
+
}
|
|
854
|
+
get allVisibleSelected() {
|
|
855
|
+
if (!this.items || this.items.length === 0) {
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
return this.optionSelectionService.containsAll(this.items.map(option => option.value));
|
|
859
|
+
}
|
|
860
|
+
get isSelectAllFocused() {
|
|
861
|
+
return this.focusHandler.pseudoFocus.model?.id === SELECT_ALL_ID;
|
|
862
|
+
}
|
|
863
|
+
toggleSelectAll(event = null) {
|
|
864
|
+
if (event) {
|
|
865
|
+
event.stopPropagation();
|
|
866
|
+
this.focusHandler.focusInput();
|
|
867
|
+
}
|
|
868
|
+
const visibleValues = this.items.map(option => option.value);
|
|
869
|
+
if (this.allVisibleSelected) {
|
|
870
|
+
this.optionSelectionService.unselectMany(visibleValues);
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
this.optionSelectionService.selectMany(visibleValues);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
761
876
|
ngAfterViewInit() {
|
|
762
877
|
this.focusHandler.listbox = this.el.nativeElement;
|
|
763
878
|
this.subscriptions.push(this.items.changes.subscribe(items => {
|
|
@@ -769,6 +884,8 @@ class ClrOptions {
|
|
|
769
884
|
else {
|
|
770
885
|
this.focusHandler.pseudoFocus.pop();
|
|
771
886
|
}
|
|
887
|
+
}), this.optionSelectionService.selectAllRequested.subscribe(() => {
|
|
888
|
+
this.toggleSelectAll();
|
|
772
889
|
}));
|
|
773
890
|
}
|
|
774
891
|
ngOnDestroy() {
|
|
@@ -780,8 +897,19 @@ class ClrOptions {
|
|
|
780
897
|
loadingStateChange(state) {
|
|
781
898
|
this.loading = state === ClrLoadingState.LOADING;
|
|
782
899
|
}
|
|
783
|
-
|
|
784
|
-
|
|
900
|
+
updateFocusableItems() {
|
|
901
|
+
const focusList = [];
|
|
902
|
+
if (this._selectAllOption) {
|
|
903
|
+
focusList.push(this._selectAllOption);
|
|
904
|
+
}
|
|
905
|
+
if (this._items) {
|
|
906
|
+
const itemOptions = this._items.map(option => option.optionProxy);
|
|
907
|
+
focusList.push(...itemOptions);
|
|
908
|
+
}
|
|
909
|
+
this.focusHandler.addOptionValues(focusList);
|
|
910
|
+
}
|
|
911
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrOptions, deps: [{ token: OptionSelectionService }, { token: IF_ACTIVE_ID }, { token: i0.ElementRef }, { token: i3.ClrCommonStringsService }, { token: ComboboxFocusHandler }, { token: i4.ClrPopoverService }, { token: POPOVER_HOST_ORIGIN, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
912
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrOptions, isStandalone: false, selector: "clr-options", inputs: { optionsId: ["id", "optionsId"] }, host: { properties: { "class.clr-combobox-options": "true", "class.clr-combobox-options-multi": "optionSelectionService.multiselectable", "class.clr-combobox-options-hidden": "emptyOptions && editable", "attr.role": "\"listbox\"", "id": "optionsId" } }, providers: [{ provide: LoadingListener, useExisting: ClrOptions }], queries: [{ propertyName: "items", predicate: ClrOption, descendants: true }], viewQueries: [{ propertyName: "selectAllBtn", first: true, predicate: ["selectAllBtn"], descendants: true }], ngImport: i0, template: `
|
|
785
913
|
@if (optionSelectionService.loading) {
|
|
786
914
|
<div class="clr-combobox-options-loading">
|
|
787
915
|
<clr-spinner clrInline>
|
|
@@ -793,6 +921,21 @@ class ClrOptions {
|
|
|
793
921
|
</div>
|
|
794
922
|
}
|
|
795
923
|
|
|
924
|
+
@if (showSelectAll) {
|
|
925
|
+
<div class="clr-combobox-select-all">
|
|
926
|
+
<button
|
|
927
|
+
#selectAllBtn
|
|
928
|
+
type="button"
|
|
929
|
+
tabindex="-1"
|
|
930
|
+
class="btn btn-link clr-combobox-select-all-btn clr-combobox-option"
|
|
931
|
+
[class.clr-focus]="isSelectAllFocused"
|
|
932
|
+
(click)="toggleSelectAll($event)"
|
|
933
|
+
>
|
|
934
|
+
{{ allVisibleSelected ? commonStrings.keys.comboboxUnselectAll : commonStrings.keys.comboboxSelectAll }}
|
|
935
|
+
</button>
|
|
936
|
+
</div>
|
|
937
|
+
}
|
|
938
|
+
|
|
796
939
|
<!-- Rendered if data set is empty -->
|
|
797
940
|
@if (emptyOptions) {
|
|
798
941
|
<div [id]="noResultsElementId" role="option">
|
|
@@ -822,6 +965,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
822
965
|
</div>
|
|
823
966
|
}
|
|
824
967
|
|
|
968
|
+
@if (showSelectAll) {
|
|
969
|
+
<div class="clr-combobox-select-all">
|
|
970
|
+
<button
|
|
971
|
+
#selectAllBtn
|
|
972
|
+
type="button"
|
|
973
|
+
tabindex="-1"
|
|
974
|
+
class="btn btn-link clr-combobox-select-all-btn clr-combobox-option"
|
|
975
|
+
[class.clr-focus]="isSelectAllFocused"
|
|
976
|
+
(click)="toggleSelectAll($event)"
|
|
977
|
+
>
|
|
978
|
+
{{ allVisibleSelected ? commonStrings.keys.comboboxUnselectAll : commonStrings.keys.comboboxSelectAll }}
|
|
979
|
+
</button>
|
|
980
|
+
</div>
|
|
981
|
+
}
|
|
982
|
+
|
|
825
983
|
<!-- Rendered if data set is empty -->
|
|
826
984
|
@if (emptyOptions) {
|
|
827
985
|
<div [id]="noResultsElementId" role="option">
|
|
@@ -837,6 +995,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
837
995
|
providers: [{ provide: LoadingListener, useExisting: ClrOptions }],
|
|
838
996
|
host: {
|
|
839
997
|
'[class.clr-combobox-options]': 'true',
|
|
998
|
+
'[class.clr-combobox-options-multi]': 'optionSelectionService.multiselectable',
|
|
840
999
|
'[class.clr-combobox-options-hidden]': 'emptyOptions && editable',
|
|
841
1000
|
'[attr.role]': '"listbox"',
|
|
842
1001
|
'[id]': 'optionsId',
|
|
@@ -846,17 +1005,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
846
1005
|
}], ctorParameters: () => [{ type: OptionSelectionService }, { type: undefined, decorators: [{
|
|
847
1006
|
type: Inject,
|
|
848
1007
|
args: [IF_ACTIVE_ID]
|
|
849
|
-
}] }, { type: i0.ElementRef }, { type: i3
|
|
1008
|
+
}] }, { type: i0.ElementRef }, { type: i3.ClrCommonStringsService }, { type: ComboboxFocusHandler }, { type: i4.ClrPopoverService }, { type: i0.ElementRef, decorators: [{
|
|
850
1009
|
type: Optional
|
|
851
1010
|
}, {
|
|
852
1011
|
type: Inject,
|
|
853
|
-
args: [
|
|
1012
|
+
args: [POPOVER_HOST_ORIGIN]
|
|
854
1013
|
}] }, { type: undefined, decorators: [{
|
|
855
1014
|
type: Inject,
|
|
856
1015
|
args: [DOCUMENT]
|
|
857
1016
|
}] }], propDecorators: { optionsId: [{
|
|
858
1017
|
type: Input,
|
|
859
1018
|
args: ['id']
|
|
1019
|
+
}], selectAllBtn: [{
|
|
1020
|
+
type: ViewChild,
|
|
1021
|
+
args: ['selectAllBtn']
|
|
860
1022
|
}], items: [{
|
|
861
1023
|
type: ContentChildren,
|
|
862
1024
|
args: [ClrOption, { descendants: true }]
|
|
@@ -869,7 +1031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
869
1031
|
* The full license information can be found in LICENSE in the root directory of this project.
|
|
870
1032
|
*/
|
|
871
1033
|
class ClrCombobox extends WrappedFormControl {
|
|
872
|
-
constructor(vcr, injector, control, renderer, el, optionSelectionService, commonStrings, popoverService, containerService, platformId, focusHandler, cdr) {
|
|
1034
|
+
constructor(vcr, injector, control, renderer, el, optionSelectionService, commonStrings, popoverService, containerService, platformId, focusHandler, cdr, zone, container) {
|
|
873
1035
|
super(vcr, ClrComboboxContainer, injector, control, renderer, el);
|
|
874
1036
|
this.control = control;
|
|
875
1037
|
this.renderer = renderer;
|
|
@@ -881,6 +1043,8 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
881
1043
|
this.platformId = platformId;
|
|
882
1044
|
this.focusHandler = focusHandler;
|
|
883
1045
|
this.cdr = cdr;
|
|
1046
|
+
this.zone = zone;
|
|
1047
|
+
this.container = container;
|
|
884
1048
|
this.placeholder = '';
|
|
885
1049
|
this.clrInputChange = new EventEmitter(false);
|
|
886
1050
|
this.clrOpenChange = this.popoverService.openChange;
|
|
@@ -892,13 +1056,23 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
892
1056
|
this.popoverPosition = ClrPopoverPosition.BOTTOM_LEFT;
|
|
893
1057
|
this.index = 1;
|
|
894
1058
|
this.popoverType = ClrPopoverType.DROPDOWN;
|
|
1059
|
+
this.containerWidth = null;
|
|
1060
|
+
this.selectionExpanded = false;
|
|
1061
|
+
this.shouldCalculate = true;
|
|
1062
|
+
this.isTotalSelection = false;
|
|
1063
|
+
this.containerWidthChange = new Subject();
|
|
895
1064
|
this._searchText = '';
|
|
896
1065
|
if (control) {
|
|
897
1066
|
control.valueAccessor = this;
|
|
898
1067
|
}
|
|
899
1068
|
// default to SingleSelectComboboxModel, in case the optional input [ClrMulti] isn't used
|
|
900
|
-
|
|
901
|
-
|
|
1069
|
+
this.multiSelect = false;
|
|
1070
|
+
}
|
|
1071
|
+
get showSelectAll() {
|
|
1072
|
+
return this.optionSelectionService.showSelectAll;
|
|
1073
|
+
}
|
|
1074
|
+
set showSelectAll(value) {
|
|
1075
|
+
this.optionSelectionService.showSelectAll = value;
|
|
902
1076
|
}
|
|
903
1077
|
get editable() {
|
|
904
1078
|
return this.optionSelectionService.editable;
|
|
@@ -906,6 +1080,12 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
906
1080
|
set editable(value) {
|
|
907
1081
|
this.optionSelectionService.editable = value;
|
|
908
1082
|
}
|
|
1083
|
+
set editableResolver(value) {
|
|
1084
|
+
this.optionSelectionService.editableResolver = value;
|
|
1085
|
+
}
|
|
1086
|
+
set identityFn(value) {
|
|
1087
|
+
this.optionSelectionService.identityFn = value;
|
|
1088
|
+
}
|
|
909
1089
|
get multiSelect() {
|
|
910
1090
|
return this.optionSelectionService.multiselectable;
|
|
911
1091
|
}
|
|
@@ -918,6 +1098,7 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
918
1098
|
// since the initial call to writeValue (caused by [ngModel] input) should happen after this
|
|
919
1099
|
this.optionSelectionService.selectionModel = new SingleSelectComboboxModel();
|
|
920
1100
|
}
|
|
1101
|
+
this.optionSelectionService.selectionModel.identityFn = this.optionSelectionService.identityFn;
|
|
921
1102
|
this.updateControlValue();
|
|
922
1103
|
}
|
|
923
1104
|
// Override the id of WrappedFormControl, as we want to move it to the embedded input.
|
|
@@ -966,6 +1147,24 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
966
1147
|
get displayField() {
|
|
967
1148
|
return this.optionSelectionService.displayField;
|
|
968
1149
|
}
|
|
1150
|
+
get showAllText() {
|
|
1151
|
+
return this.commonStrings.parse(this.commonStrings.keys.comboboxShowAll, {
|
|
1152
|
+
ITEMS: this.multiSelectModel?.length.toString(),
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
get allSelectedText() {
|
|
1156
|
+
return this.commonStrings.parse(this.commonStrings.keys.comboboxAllSelected, {
|
|
1157
|
+
ITEMS: this.multiSelectModel?.length.toString(),
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
get showIndividualPills() {
|
|
1161
|
+
return !this.isTotalSelection || this.selectionExpanded;
|
|
1162
|
+
}
|
|
1163
|
+
get showTruncationToggle() {
|
|
1164
|
+
return (this.selectionExpanded ||
|
|
1165
|
+
this.isTotalSelection ||
|
|
1166
|
+
(this.calculatedLimit !== null && this.calculatedLimit < this.multiSelectModel.length));
|
|
1167
|
+
}
|
|
969
1168
|
get disabled() {
|
|
970
1169
|
return this.control?.disabled;
|
|
971
1170
|
}
|
|
@@ -977,13 +1176,30 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
977
1176
|
}
|
|
978
1177
|
}
|
|
979
1178
|
ngAfterViewInit() {
|
|
980
|
-
this.focusHandler.componentCdRef = this.cdr;
|
|
981
1179
|
this.focusHandler.textInput = this.textbox.nativeElement;
|
|
982
1180
|
this.focusHandler.trigger = this.trigger.nativeElement;
|
|
983
1181
|
// The text input is the actual element we are wrapping
|
|
984
1182
|
// This assignment is needed by the wrapper, so it can set
|
|
985
1183
|
// the aria properties on the input element, not on the component.
|
|
1184
|
+
// We calculate on the initial load to prevent flickering
|
|
986
1185
|
this.el = this.textbox;
|
|
1186
|
+
if (this.showSelectAll) {
|
|
1187
|
+
if (this.multiSelect && this.multiSelectModel?.length > 0) {
|
|
1188
|
+
this.calculateLimit();
|
|
1189
|
+
}
|
|
1190
|
+
this.initialiseObserver();
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
ngOnDestroy() {
|
|
1194
|
+
super.ngOnDestroy();
|
|
1195
|
+
if (this.resizeObserver) {
|
|
1196
|
+
this.resizeObserver.disconnect();
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
clearSelection() {
|
|
1200
|
+
this.focusHandler.focusInput();
|
|
1201
|
+
// Clear the array model directly
|
|
1202
|
+
this.optionSelectionService.setSelectionValue([]);
|
|
987
1203
|
}
|
|
988
1204
|
onKeyUp(event) {
|
|
989
1205
|
// if BACKSPACE in multiselect mode, delete the last pill if text is empty
|
|
@@ -1001,7 +1217,7 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
1001
1217
|
break;
|
|
1002
1218
|
case Keys.Enter:
|
|
1003
1219
|
if (this.editable && this._searchText.length > 0 && this.options.emptyOptions) {
|
|
1004
|
-
const parsedInput = this.optionSelectionService.
|
|
1220
|
+
const parsedInput = this.optionSelectionService.editableResolver(this._searchText);
|
|
1005
1221
|
this.control?.control.markAsTouched();
|
|
1006
1222
|
this.optionSelectionService.select(parsedInput);
|
|
1007
1223
|
this.searchText = '';
|
|
@@ -1042,7 +1258,7 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
1042
1258
|
}
|
|
1043
1259
|
onChange() {
|
|
1044
1260
|
if (this.editable && !this.multiSelect && this.options.emptyOptions) {
|
|
1045
|
-
const parsedInput = this.optionSelectionService.
|
|
1261
|
+
const parsedInput = this.optionSelectionService.editableResolver(this._searchText);
|
|
1046
1262
|
this.optionSelectionService.setSelectionValue(parsedInput);
|
|
1047
1263
|
}
|
|
1048
1264
|
}
|
|
@@ -1083,13 +1299,103 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
1083
1299
|
this.popoverService.toggleWithEvent(event);
|
|
1084
1300
|
}
|
|
1085
1301
|
}
|
|
1302
|
+
toggleSelectionExpand() {
|
|
1303
|
+
this.selectionExpanded = !this.selectionExpanded;
|
|
1304
|
+
if (this.selectionExpanded) {
|
|
1305
|
+
this.applyLimit(this.multiSelectModel.length);
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
this.containerWidthChange.next(this.containerWidth);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
initialiseObserver() {
|
|
1312
|
+
const container = this.container ? this.container.el.nativeElement : this.el.nativeElement.parentElement;
|
|
1313
|
+
this.containerWidth = container.offsetWidth;
|
|
1314
|
+
this.resizeObserver = new ResizeObserver(entries => {
|
|
1315
|
+
this.zone.runOutsideAngular(() => {
|
|
1316
|
+
entries.forEach(entry => {
|
|
1317
|
+
const entryWidth = entry.contentRect.width;
|
|
1318
|
+
switch (entry.target) {
|
|
1319
|
+
case container:
|
|
1320
|
+
if (this.containerWidth !== entryWidth) {
|
|
1321
|
+
this.containerWidth = entryWidth;
|
|
1322
|
+
this.containerWidthChange.next(entryWidth);
|
|
1323
|
+
}
|
|
1324
|
+
break;
|
|
1325
|
+
case this.wrapper.nativeElement:
|
|
1326
|
+
this.containerWidthChange.next(null);
|
|
1327
|
+
break;
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
});
|
|
1331
|
+
});
|
|
1332
|
+
this.resizeObserver.observe(container);
|
|
1333
|
+
this.resizeObserver.observe(this.wrapper.nativeElement);
|
|
1334
|
+
}
|
|
1335
|
+
calculateLimit() {
|
|
1336
|
+
this.shouldCalculate = true;
|
|
1337
|
+
this.cdr.detectChanges();
|
|
1338
|
+
if (!this.calculationPills || this.calculationPills.length === 0) {
|
|
1339
|
+
this.applyLimit();
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const pillDimensions = this.calculationPills.map(p => ({
|
|
1343
|
+
top: p.nativeElement.offsetTop,
|
|
1344
|
+
width: p.nativeElement.offsetWidth,
|
|
1345
|
+
left: p.nativeElement.offsetLeft,
|
|
1346
|
+
}));
|
|
1347
|
+
const firstPill = pillDimensions[0];
|
|
1348
|
+
const buttonWidth = this.truncationButton?.nativeElement?.offsetWidth || 100;
|
|
1349
|
+
const textboxWidth = this.textbox.nativeElement.offsetWidth;
|
|
1350
|
+
const expectedWidth = this.containerWidth - textboxWidth - buttonWidth;
|
|
1351
|
+
let fitCount = 0;
|
|
1352
|
+
for (const pill of pillDimensions) {
|
|
1353
|
+
if (pill.top > firstPill.top || pill.left + pill.width > expectedWidth) {
|
|
1354
|
+
break;
|
|
1355
|
+
}
|
|
1356
|
+
fitCount++;
|
|
1357
|
+
}
|
|
1358
|
+
this.applyLimit(fitCount);
|
|
1359
|
+
}
|
|
1360
|
+
applyLimit(limit = undefined) {
|
|
1361
|
+
this.zone.run(() => {
|
|
1362
|
+
this.calculatedLimit = limit === 0 ? 1 : limit;
|
|
1363
|
+
this.shouldCalculate = false;
|
|
1364
|
+
this.cdr.markForCheck();
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
updateTotalSelection() {
|
|
1368
|
+
if (!this.multiSelect || !this.multiSelectModel?.length) {
|
|
1369
|
+
this.isTotalSelection = false;
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
// Skip recalculation when items are filtered to zero (e.g. "no results")
|
|
1373
|
+
// to prevent pills from flashing while typing in the search input.
|
|
1374
|
+
if (!this.options?.items?.length) {
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
this.isTotalSelection = this.optionSelectionService.containsAll(this.options.items.map(option => option.value));
|
|
1378
|
+
}
|
|
1086
1379
|
initializeSubscriptions() {
|
|
1087
1380
|
this.subscriptions.push(this.optionSelectionService.selectionChanged.subscribe((newSelection) => {
|
|
1088
1381
|
this.updateInputValue(newSelection);
|
|
1089
|
-
if (
|
|
1090
|
-
this.
|
|
1382
|
+
if (newSelection.isEmpty()) {
|
|
1383
|
+
this.selectionExpanded = false;
|
|
1384
|
+
this.isTotalSelection = false;
|
|
1385
|
+
}
|
|
1386
|
+
else {
|
|
1387
|
+
if (!this.multiSelect) {
|
|
1388
|
+
this.popoverService.open = false;
|
|
1389
|
+
}
|
|
1390
|
+
this.updateTotalSelection();
|
|
1091
1391
|
}
|
|
1092
1392
|
this.updateControlValue();
|
|
1393
|
+
if (this.selectionExpanded) {
|
|
1394
|
+
this.applyLimit(this.multiSelectModel.length);
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
this.calculateLimit();
|
|
1398
|
+
}
|
|
1093
1399
|
if (this.multiSelect) {
|
|
1094
1400
|
setTimeout(() => {
|
|
1095
1401
|
this.popoverService?.updatePosition();
|
|
@@ -1116,6 +1422,10 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
1116
1422
|
else {
|
|
1117
1423
|
this.searchText = this.getDisplayNames(this.optionSelectionService.selectionModel.model)[0] || '';
|
|
1118
1424
|
}
|
|
1425
|
+
}), this.containerWidthChange.pipe(debounceTime(0)).subscribe(() => {
|
|
1426
|
+
if (!this.selectionExpanded && !this.isTotalSelection) {
|
|
1427
|
+
this.calculateLimit();
|
|
1428
|
+
}
|
|
1119
1429
|
}));
|
|
1120
1430
|
}
|
|
1121
1431
|
updateInputValue(model) {
|
|
@@ -1140,14 +1450,14 @@ class ClrCombobox extends WrappedFormControl {
|
|
|
1140
1450
|
}
|
|
1141
1451
|
return [this.optionSelectionService.selectionModel.model];
|
|
1142
1452
|
}
|
|
1143
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrCombobox, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1$1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: OptionSelectionService }, { token: i3
|
|
1144
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrCombobox, isStandalone: false, selector: "clr-combobox", inputs: { placeholder: "placeholder", editable: ["clrEditable", "editable"], multiSelect: ["clrMulti", "multiSelect"] }, outputs: { clrInputChange: "clrInputChange", clrOpenChange: "clrOpenChange", clrSelectionChange: "clrSelectionChange" }, host: { listeners: { "keydown": "onKeyUp($event)" }, properties: { "class.aria-required": "true", "class.clr-combobox": "true", "class.clr-combobox-disabled": "control?.disabled" } }, providers: [
|
|
1453
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrCombobox, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1$1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: OptionSelectionService }, { token: i3.ClrCommonStringsService }, { token: i4.ClrPopoverService }, { token: ComboboxContainerService, optional: true }, { token: PLATFORM_ID }, { token: ComboboxFocusHandler }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: ClrComboboxContainer, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1454
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrCombobox, isStandalone: false, selector: "clr-combobox", inputs: { placeholder: "placeholder", showSelectAll: ["showSelectAll", "showSelectAll", booleanAttribute], editable: ["clrEditable", "editable"], editableResolver: ["clrEditableResolverFn", "editableResolver"], identityFn: ["clrComboboxIdentityFn", "identityFn"], multiSelect: ["clrMulti", "multiSelect"] }, outputs: { clrInputChange: "clrInputChange", clrOpenChange: "clrOpenChange", clrSelectionChange: "clrSelectionChange" }, host: { listeners: { "keydown": "onKeyUp($event)" }, properties: { "class.aria-required": "true", "class.clr-combobox": "true", "class.clr-combobox-disabled": "control?.disabled" } }, providers: [
|
|
1145
1455
|
OptionSelectionService,
|
|
1146
1456
|
{ provide: LoadingListener, useExisting: ClrCombobox },
|
|
1147
1457
|
IF_ACTIVE_ID_PROVIDER,
|
|
1148
1458
|
FOCUS_SERVICE_PROVIDER,
|
|
1149
1459
|
COMBOBOX_FOCUS_HANDLER_PROVIDER,
|
|
1150
|
-
], queries: [{ propertyName: "optionSelected", first: true, predicate: ClrOptionSelected, descendants: true }, { propertyName: "options", first: true, predicate: ClrOptions, descendants: true }], viewQueries: [{ propertyName: "textbox", first: true, predicate: ["textboxInput"], descendants: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }], usesInheritance: true, hostDirectives: [{ directive: i4
|
|
1460
|
+
], queries: [{ propertyName: "optionSelected", first: true, predicate: ClrOptionSelected, descendants: true }, { propertyName: "options", first: true, predicate: ClrOptions, descendants: true }], viewQueries: [{ propertyName: "textbox", first: true, predicate: ["textboxInput"], descendants: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "truncationButton", first: true, predicate: ["truncationButton"], descendants: true }, { propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true, static: true }, { propertyName: "calculationPills", predicate: ["pill"], descendants: true }], usesInheritance: true, hostDirectives: [{ directive: i4.ClrPopoverHostDirective }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<!-- The (click) handler is needed to auto-focus on input field which can not currently occupy the whole\nwidth of the component, after being wrapped to a new line -->\n<div\n #wrapper\n class=\"clr-combobox-wrapper\"\n clrPopoverOrigin\n (click)=\"onWrapperClick($event)\"\n [class.multi]=\"multiSelect\"\n [class.invalid]=\"(control?.control.touched && control?.invalid)\"\n [class.disabled]=\"control?.disabled\"\n>\n @if (multiSelect && multiSelectModel && multiSelectModel.length > 0) {\n <span\n role=\"grid\"\n clrRovingTabindex\n [clrRovingTabindexDisabled]=\"control?.disabled\"\n clrDirection=\"both\"\n [attr.aria-label]=\"getSelectionAriaLabel()\"\n [attr.aria-disabled]=\"control?.disabled? true: null\"\n class=\"clr-combobox-pills\"\n >\n <ng-template #pillTemplate let-item let-i=\"index\">\n <span class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>\n @if (optionSelected) {\n <ng-container\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: item}\"\n ></ng-container>\n }\n </span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n [disabled]=\"control?.disabled ? true : null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxDelete + ' ' + optionSelectionService.selectionModel.toString(displayField, i)\"\n (click)=\"unselect(item)\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n </ng-template>\n\n @if (showSelectAll) { @if (isTotalSelection && !selectionExpanded) {\n <span class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>{{ allSelectedText }}</span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n (click)=\"clearSelection()\"\n [attr.aria-label]=\"commonStrings.keys.comboboxUnselectAll\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n } @if (showIndividualPills) { @for (item of multiSelectModel | slice:0:calculatedLimit; track item; let i = $index)\n {\n <ng-container\n [ngTemplateOutlet]=\"pillTemplate\"\n [ngTemplateOutletContext]=\"{$implicit: item, index: i}\"\n ></ng-container>\n } } @if (showTruncationToggle) {\n <span role=\"row\" class=\"label label-combobox-pill clr-combobox-truncation-row\">\n <span role=\"gridcell\" class=\"clr-combobox-truncation-cell\">\n <span class=\"clr-combobox-pill-content\">\n <button\n #truncationButton\n clrKeyFocusItem\n type=\"button\"\n class=\"btn btn-link clr-combobox-show-more-btn\"\n (click)=\"toggleSelectionExpand()\"\n [attr.aria-expanded]=\"selectionExpanded\"\n [attr.aria-controls]=\"'expanded-selection-' + id\"\n >\n @if (!selectionExpanded) { {{ showAllText }} } @else { {{ commonStrings.keys.comboboxShowLess }} }\n </button>\n </span>\n </span>\n </span>\n } } @else { @for (item of multiSelectModel; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"pillTemplate\"\n [ngTemplateOutletContext]=\"{$implicit: item, index: i}\"\n ></ng-container>\n } }\n </span>\n\n @if (showSelectAll && shouldCalculate) {\n <span class=\"clr-combobox-pills-calculation\" aria-hidden=\"true\">\n @for (item of multiSelectModel; track item) {\n <span class=\"label label-combobox-pill\" #pill>\n <span class=\"clr-combobox-pill-content\">\n @if (optionSelected) {\n <ng-container\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: item}\"\n ></ng-container>\n }\n </span>\n <button type=\"button\" class=\"clr-combobox-remove-btn\" tabindex=\"-1\">\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n }\n </span>\n } }\n\n <input\n #textboxInput\n type=\"text\"\n role=\"combobox\"\n [id]=\"inputId()\"\n class=\"clr-input clr-combobox-input\"\n [(ngModel)]=\"searchText\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus()\"\n (change)=\"onChange()\"\n [attr.aria-expanded]=\"openState\"\n [attr.aria-owns]=\"ariaOwns\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [attr.aria-invalid]=\"control?.invalid? true: null\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-activedescendant]=\"getActiveDescendant()\"\n [attr.placeholder]=\"placeholder\"\n />\n\n <!-- No click handler, as it uses the handler on the .clr-combobox-wrapper -->\n <button\n #trigger\n type=\"button\"\n class=\"clr-combobox-trigger\"\n tabindex=\"-1\"\n [disabled]=\"control?.disabled || null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxOpen\"\n >\n <cds-icon shape=\"angle\" direction=\"down\"></cds-icon>\n </button>\n\n <div class=\"clr-focus-indicator\" [class.clr-focus]=\"focused\"></div>\n</div>\n\n<!-- Both close handlers are handled manually.\n'outsideClickToClose' has complex handling that's necessary\nto be manual due to the component architecture -->\n<div role=\"dialog\" *clrPopoverContent=\"openState; at popoverPosition; type: popoverType;\">\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }, { kind: "component", type: i3.ClrRovingTabindex, selector: "[clrRovingTabindex]", inputs: ["clrRovingTabindex", "clrRovingTabindexDisabled"] }, { kind: "directive", type: i3.ClrKeyFocusItem, selector: "[clrKeyFocusItem]" }, { kind: "directive", type: i4.ClrPopoverOrigin, selector: "[clrPopoverOrigin]" }, { kind: "directive", type: i4.ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentAvailablePositions", "clrPopoverContentType", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose", "clrPopoverContentOrigin"] }, { kind: "pipe", type: i8.SlicePipe, name: "slice" }] }); }
|
|
1151
1461
|
}
|
|
1152
1462
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrCombobox, decorators: [{
|
|
1153
1463
|
type: Component,
|
|
@@ -1161,17 +1471,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1161
1471
|
'[class.aria-required]': 'true',
|
|
1162
1472
|
'[class.clr-combobox]': 'true',
|
|
1163
1473
|
'[class.clr-combobox-disabled]': 'control?.disabled',
|
|
1164
|
-
}, standalone: false, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<!-- The (click) handler is needed to auto-focus on input field which can not currently occupy the whole\nwidth of the component, after being wrapped to a new line -->\n<div\n class=\"clr-combobox-wrapper\"\n
|
|
1474
|
+
}, standalone: false, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<!-- The (click) handler is needed to auto-focus on input field which can not currently occupy the whole\nwidth of the component, after being wrapped to a new line -->\n<div\n #wrapper\n class=\"clr-combobox-wrapper\"\n clrPopoverOrigin\n (click)=\"onWrapperClick($event)\"\n [class.multi]=\"multiSelect\"\n [class.invalid]=\"(control?.control.touched && control?.invalid)\"\n [class.disabled]=\"control?.disabled\"\n>\n @if (multiSelect && multiSelectModel && multiSelectModel.length > 0) {\n <span\n role=\"grid\"\n clrRovingTabindex\n [clrRovingTabindexDisabled]=\"control?.disabled\"\n clrDirection=\"both\"\n [attr.aria-label]=\"getSelectionAriaLabel()\"\n [attr.aria-disabled]=\"control?.disabled? true: null\"\n class=\"clr-combobox-pills\"\n >\n <ng-template #pillTemplate let-item let-i=\"index\">\n <span class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>\n @if (optionSelected) {\n <ng-container\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: item}\"\n ></ng-container>\n }\n </span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n [disabled]=\"control?.disabled ? true : null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxDelete + ' ' + optionSelectionService.selectionModel.toString(displayField, i)\"\n (click)=\"unselect(item)\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n </ng-template>\n\n @if (showSelectAll) { @if (isTotalSelection && !selectionExpanded) {\n <span class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>{{ allSelectedText }}</span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n (click)=\"clearSelection()\"\n [attr.aria-label]=\"commonStrings.keys.comboboxUnselectAll\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n } @if (showIndividualPills) { @for (item of multiSelectModel | slice:0:calculatedLimit; track item; let i = $index)\n {\n <ng-container\n [ngTemplateOutlet]=\"pillTemplate\"\n [ngTemplateOutletContext]=\"{$implicit: item, index: i}\"\n ></ng-container>\n } } @if (showTruncationToggle) {\n <span role=\"row\" class=\"label label-combobox-pill clr-combobox-truncation-row\">\n <span role=\"gridcell\" class=\"clr-combobox-truncation-cell\">\n <span class=\"clr-combobox-pill-content\">\n <button\n #truncationButton\n clrKeyFocusItem\n type=\"button\"\n class=\"btn btn-link clr-combobox-show-more-btn\"\n (click)=\"toggleSelectionExpand()\"\n [attr.aria-expanded]=\"selectionExpanded\"\n [attr.aria-controls]=\"'expanded-selection-' + id\"\n >\n @if (!selectionExpanded) { {{ showAllText }} } @else { {{ commonStrings.keys.comboboxShowLess }} }\n </button>\n </span>\n </span>\n </span>\n } } @else { @for (item of multiSelectModel; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"pillTemplate\"\n [ngTemplateOutletContext]=\"{$implicit: item, index: i}\"\n ></ng-container>\n } }\n </span>\n\n @if (showSelectAll && shouldCalculate) {\n <span class=\"clr-combobox-pills-calculation\" aria-hidden=\"true\">\n @for (item of multiSelectModel; track item) {\n <span class=\"label label-combobox-pill\" #pill>\n <span class=\"clr-combobox-pill-content\">\n @if (optionSelected) {\n <ng-container\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: item}\"\n ></ng-container>\n }\n </span>\n <button type=\"button\" class=\"clr-combobox-remove-btn\" tabindex=\"-1\">\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n }\n </span>\n } }\n\n <input\n #textboxInput\n type=\"text\"\n role=\"combobox\"\n [id]=\"inputId()\"\n class=\"clr-input clr-combobox-input\"\n [(ngModel)]=\"searchText\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus()\"\n (change)=\"onChange()\"\n [attr.aria-expanded]=\"openState\"\n [attr.aria-owns]=\"ariaOwns\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [attr.aria-invalid]=\"control?.invalid? true: null\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-activedescendant]=\"getActiveDescendant()\"\n [attr.placeholder]=\"placeholder\"\n />\n\n <!-- No click handler, as it uses the handler on the .clr-combobox-wrapper -->\n <button\n #trigger\n type=\"button\"\n class=\"clr-combobox-trigger\"\n tabindex=\"-1\"\n [disabled]=\"control?.disabled || null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxOpen\"\n >\n <cds-icon shape=\"angle\" direction=\"down\"></cds-icon>\n </button>\n\n <div class=\"clr-focus-indicator\" [class.clr-focus]=\"focused\"></div>\n</div>\n\n<!-- Both close handlers are handled manually.\n'outsideClickToClose' has complex handling that's necessary\nto be manual due to the component architecture -->\n<div role=\"dialog\" *clrPopoverContent=\"openState; at popoverPosition; type: popoverType;\">\n <ng-content></ng-content>\n</div>\n" }]
|
|
1165
1475
|
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1$1.NgControl, decorators: [{
|
|
1166
1476
|
type: Self
|
|
1167
1477
|
}, {
|
|
1168
1478
|
type: Optional
|
|
1169
|
-
}] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: OptionSelectionService }, { type: i3
|
|
1479
|
+
}] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: OptionSelectionService }, { type: i3.ClrCommonStringsService }, { type: i4.ClrPopoverService }, { type: ComboboxContainerService, decorators: [{
|
|
1170
1480
|
type: Optional
|
|
1171
1481
|
}] }, { type: undefined, decorators: [{
|
|
1172
1482
|
type: Inject,
|
|
1173
1483
|
args: [PLATFORM_ID]
|
|
1174
|
-
}] }, { type: ComboboxFocusHandler }, { type: i0.ChangeDetectorRef }
|
|
1484
|
+
}] }, { type: ComboboxFocusHandler }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: ClrComboboxContainer, decorators: [{
|
|
1485
|
+
type: Optional
|
|
1486
|
+
}, {
|
|
1487
|
+
type: Host
|
|
1488
|
+
}] }], propDecorators: { placeholder: [{
|
|
1175
1489
|
type: Input,
|
|
1176
1490
|
args: ['placeholder']
|
|
1177
1491
|
}], clrInputChange: [{
|
|
@@ -1192,12 +1506,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1192
1506
|
}], optionSelected: [{
|
|
1193
1507
|
type: ContentChild,
|
|
1194
1508
|
args: [ClrOptionSelected]
|
|
1509
|
+
}], truncationButton: [{
|
|
1510
|
+
type: ViewChild,
|
|
1511
|
+
args: ['truncationButton']
|
|
1512
|
+
}], wrapper: [{
|
|
1513
|
+
type: ViewChild,
|
|
1514
|
+
args: ['wrapper', { static: true }]
|
|
1515
|
+
}], calculationPills: [{
|
|
1516
|
+
type: ViewChildren,
|
|
1517
|
+
args: ['pill']
|
|
1195
1518
|
}], options: [{
|
|
1196
1519
|
type: ContentChild,
|
|
1197
1520
|
args: [ClrOptions]
|
|
1521
|
+
}], showSelectAll: [{
|
|
1522
|
+
type: Input,
|
|
1523
|
+
args: [{ alias: 'showSelectAll', transform: booleanAttribute }]
|
|
1198
1524
|
}], editable: [{
|
|
1199
1525
|
type: Input,
|
|
1200
1526
|
args: ['clrEditable']
|
|
1527
|
+
}], editableResolver: [{
|
|
1528
|
+
type: Input,
|
|
1529
|
+
args: ['clrEditableResolverFn']
|
|
1530
|
+
}], identityFn: [{
|
|
1531
|
+
type: Input,
|
|
1532
|
+
args: ['clrComboboxIdentityFn']
|
|
1201
1533
|
}], multiSelect: [{
|
|
1202
1534
|
type: Input,
|
|
1203
1535
|
args: ['clrMulti']
|
|
@@ -1223,9 +1555,7 @@ class ClrOptionItems {
|
|
|
1223
1555
|
this.iterableProxy = new NgForOf(vcr, template, differs);
|
|
1224
1556
|
this.subscriptions.push(optionService.inputChanged.subscribe(filter => {
|
|
1225
1557
|
this.filter = filter;
|
|
1226
|
-
|
|
1227
|
-
this.updateItems();
|
|
1228
|
-
}
|
|
1558
|
+
this.updateItems();
|
|
1229
1559
|
}));
|
|
1230
1560
|
}
|
|
1231
1561
|
set rawItems(items) {
|
|
@@ -1359,7 +1689,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1359
1689
|
*/
|
|
1360
1690
|
class ClrComboboxModule {
|
|
1361
1691
|
constructor() {
|
|
1362
|
-
ClarityIcons.addIcons(
|
|
1692
|
+
ClarityIcons.addIcons(successStandardIcon, errorStandardIcon, angleIcon, windowCloseIcon);
|
|
1363
1693
|
}
|
|
1364
1694
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrComboboxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1365
1695
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ClrComboboxModule, declarations: [ClrCombobox,
|
|
@@ -1374,7 +1704,7 @@ class ClrComboboxModule {
|
|
|
1374
1704
|
ClrKeyFocusModule,
|
|
1375
1705
|
ClrCommonFormsModule,
|
|
1376
1706
|
ClrConditionalModule,
|
|
1377
|
-
|
|
1707
|
+
ClrPopoverModuleNext,
|
|
1378
1708
|
ClrSpinnerModule], exports: [ClrCommonFormsModule,
|
|
1379
1709
|
ClrCombobox,
|
|
1380
1710
|
ClrComboboxContainer,
|
|
@@ -1390,7 +1720,7 @@ class ClrComboboxModule {
|
|
|
1390
1720
|
ClrKeyFocusModule,
|
|
1391
1721
|
ClrCommonFormsModule,
|
|
1392
1722
|
ClrConditionalModule,
|
|
1393
|
-
|
|
1723
|
+
ClrPopoverModuleNext,
|
|
1394
1724
|
ClrSpinnerModule, ClrCommonFormsModule,
|
|
1395
1725
|
ClrConditionalModule] }); }
|
|
1396
1726
|
}
|
|
@@ -1404,7 +1734,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1404
1734
|
ClrKeyFocusModule,
|
|
1405
1735
|
ClrCommonFormsModule,
|
|
1406
1736
|
ClrConditionalModule,
|
|
1407
|
-
|
|
1737
|
+
ClrPopoverModuleNext,
|
|
1408
1738
|
ClrSpinnerModule,
|
|
1409
1739
|
],
|
|
1410
1740
|
declarations: [
|
|
@@ -1441,5 +1771,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1441
1771
|
* Generated bundle index. Do not edit.
|
|
1442
1772
|
*/
|
|
1443
1773
|
|
|
1444
|
-
export { ClrCombobox, ClrComboboxContainer, ClrComboboxModule, ClrOption, ClrOptionGroup, ClrOptionItems, ClrOptionSelected, ClrOptions };
|
|
1774
|
+
export { ClrCombobox, ClrComboboxContainer, ClrComboboxModule, ClrOption, ClrOptionGroup, ClrOptionItems, ClrOptionSelected, ClrOptions, SELECT_ALL_ID };
|
|
1445
1775
|
//# sourceMappingURL=clr-angular-forms-combobox.mjs.map
|