@cute-widgets/base 20.0.1
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/CHANGELOG.md +1 -0
- package/LICENSE.md +191 -0
- package/README.md +190 -0
- package/abstract/index.d.ts +327 -0
- package/alert/index.d.ts +68 -0
- package/autocomplete/index.d.ts +442 -0
- package/badge/index.d.ts +26 -0
- package/bottom-sheet/index.d.ts +231 -0
- package/button/index.d.ts +182 -0
- package/button-toggle/index.d.ts +225 -0
- package/card/index.d.ts +163 -0
- package/checkbox/index.d.ts +174 -0
- package/chips/index.d.ts +963 -0
- package/collapse/index.d.ts +97 -0
- package/core/animation/index.d.ts +43 -0
- package/core/datetime/index.d.ts +404 -0
- package/core/directives/index.d.ts +168 -0
- package/core/error/index.d.ts +74 -0
- package/core/index.d.ts +1039 -0
- package/core/interfaces/index.d.ts +114 -0
- package/core/layout/index.d.ts +53 -0
- package/core/line/index.d.ts +37 -0
- package/core/nav/index.d.ts +321 -0
- package/core/observers/index.d.ts +124 -0
- package/core/option/index.d.ts +185 -0
- package/core/pipes/index.d.ts +53 -0
- package/core/ripple/index.d.ts +66 -0
- package/core/testing/index.d.ts +154 -0
- package/core/theming/index.d.ts +118 -0
- package/core/types/index.d.ts +53 -0
- package/core/utils/index.d.ts +129 -0
- package/cute-widgets-base-20.0.1.tgz +0 -0
- package/datepicker/index.d.ts +1817 -0
- package/dialog/index.d.ts +484 -0
- package/divider/index.d.ts +24 -0
- package/expansion/README.md +8 -0
- package/expansion/index.d.ts +308 -0
- package/fesm2022/cute-widgets-base-abstract.mjs +547 -0
- package/fesm2022/cute-widgets-base-abstract.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-alert.mjs +198 -0
- package/fesm2022/cute-widgets-base-alert.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-autocomplete.mjs +1217 -0
- package/fesm2022/cute-widgets-base-autocomplete.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-badge.mjs +75 -0
- package/fesm2022/cute-widgets-base-badge.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-bottom-sheet.mjs +416 -0
- package/fesm2022/cute-widgets-base-bottom-sheet.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-button-toggle.mjs +640 -0
- package/fesm2022/cute-widgets-base-button-toggle.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-button.mjs +546 -0
- package/fesm2022/cute-widgets-base-button.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-card.mjs +471 -0
- package/fesm2022/cute-widgets-base-card.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-checkbox.mjs +390 -0
- package/fesm2022/cute-widgets-base-checkbox.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-chips.mjs +2360 -0
- package/fesm2022/cute-widgets-base-chips.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-collapse.mjs +259 -0
- package/fesm2022/cute-widgets-base-collapse.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-animation.mjs +53 -0
- package/fesm2022/cute-widgets-base-core-animation.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-datetime.mjs +568 -0
- package/fesm2022/cute-widgets-base-core-datetime.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-directives.mjs +404 -0
- package/fesm2022/cute-widgets-base-core-directives.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-error.mjs +105 -0
- package/fesm2022/cute-widgets-base-core-error.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-interfaces.mjs +22 -0
- package/fesm2022/cute-widgets-base-core-interfaces.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-layout.mjs +74 -0
- package/fesm2022/cute-widgets-base-core-layout.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-line.mjs +87 -0
- package/fesm2022/cute-widgets-base-core-line.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-nav.mjs +863 -0
- package/fesm2022/cute-widgets-base-core-nav.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-observers.mjs +304 -0
- package/fesm2022/cute-widgets-base-core-observers.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-option.mjs +373 -0
- package/fesm2022/cute-widgets-base-core-option.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-pipes.mjs +97 -0
- package/fesm2022/cute-widgets-base-core-pipes.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-ripple.mjs +172 -0
- package/fesm2022/cute-widgets-base-core-ripple.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-testing.mjs +210 -0
- package/fesm2022/cute-widgets-base-core-testing.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-theming.mjs +314 -0
- package/fesm2022/cute-widgets-base-core-theming.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-types.mjs +22 -0
- package/fesm2022/cute-widgets-base-core-types.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core-utils.mjs +257 -0
- package/fesm2022/cute-widgets-base-core-utils.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-core.mjs +1600 -0
- package/fesm2022/cute-widgets-base-core.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-datepicker.mjs +4827 -0
- package/fesm2022/cute-widgets-base-datepicker.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-dialog.mjs +1046 -0
- package/fesm2022/cute-widgets-base-dialog.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-divider.mjs +86 -0
- package/fesm2022/cute-widgets-base-divider.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-expansion.mjs +623 -0
- package/fesm2022/cute-widgets-base-expansion.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-form-field.mjs +969 -0
- package/fesm2022/cute-widgets-base-form-field.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-grid-list.mjs +715 -0
- package/fesm2022/cute-widgets-base-grid-list.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-icon.mjs +1105 -0
- package/fesm2022/cute-widgets-base-icon.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-input.mjs +726 -0
- package/fesm2022/cute-widgets-base-input.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-layout-container.mjs +95 -0
- package/fesm2022/cute-widgets-base-layout-container.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-layout-stack.mjs +166 -0
- package/fesm2022/cute-widgets-base-layout-stack.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-layout.mjs +250 -0
- package/fesm2022/cute-widgets-base-layout.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-list.mjs +1557 -0
- package/fesm2022/cute-widgets-base-list.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-menu.mjs +1283 -0
- package/fesm2022/cute-widgets-base-menu.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-navbar.mjs +359 -0
- package/fesm2022/cute-widgets-base-navbar.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-paginator.mjs +485 -0
- package/fesm2022/cute-widgets-base-paginator.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-progress.mjs +321 -0
- package/fesm2022/cute-widgets-base-progress.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-radio.mjs +637 -0
- package/fesm2022/cute-widgets-base-radio.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-select.mjs +1208 -0
- package/fesm2022/cute-widgets-base-select.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-sidenav.mjs +1095 -0
- package/fesm2022/cute-widgets-base-sidenav.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-slider.mjs +99 -0
- package/fesm2022/cute-widgets-base-slider.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-snack-bar.mjs +897 -0
- package/fesm2022/cute-widgets-base-snack-bar.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-sort.mjs +639 -0
- package/fesm2022/cute-widgets-base-sort.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-spinner.mjs +154 -0
- package/fesm2022/cute-widgets-base-spinner.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-stepper.mjs +673 -0
- package/fesm2022/cute-widgets-base-stepper.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-table.mjs +1023 -0
- package/fesm2022/cute-widgets-base-table.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-tabs.mjs +729 -0
- package/fesm2022/cute-widgets-base-tabs.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-timepicker.mjs +965 -0
- package/fesm2022/cute-widgets-base-timepicker.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-toolbar.mjs +120 -0
- package/fesm2022/cute-widgets-base-toolbar.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-tooltip.mjs +947 -0
- package/fesm2022/cute-widgets-base-tooltip.mjs.map +1 -0
- package/fesm2022/cute-widgets-base-tree.mjs +598 -0
- package/fesm2022/cute-widgets-base-tree.mjs.map +1 -0
- package/fesm2022/cute-widgets-base.mjs +68 -0
- package/fesm2022/cute-widgets-base.mjs.map +1 -0
- package/form-field/index.d.ts +401 -0
- package/grid-list/index.d.ts +361 -0
- package/icon/index.d.ts +477 -0
- package/index.d.ts +3 -0
- package/input/index.d.ts +256 -0
- package/layout/container/index.d.ts +31 -0
- package/layout/index.d.ts +78 -0
- package/layout/stack/index.d.ts +52 -0
- package/list/index.d.ts +659 -0
- package/menu/index.d.ts +497 -0
- package/navbar/index.d.ts +91 -0
- package/package.json +279 -0
- package/paginator/index.d.ts +216 -0
- package/progress/index.d.ts +130 -0
- package/radio/index.d.ts +259 -0
- package/select/index.d.ts +426 -0
- package/sidenav/index.d.ts +369 -0
- package/slider/index.d.ts +48 -0
- package/snack-bar/index.d.ts +374 -0
- package/sort/index.d.ts +334 -0
- package/spinner/index.d.ts +70 -0
- package/stepper/index.d.ts +295 -0
- package/table/index.d.ts +395 -0
- package/tabs/index.d.ts +307 -0
- package/timepicker/index.d.ts +350 -0
- package/toolbar/index.d.ts +36 -0
- package/tooltip/index.d.ts +299 -0
- package/tree/index.d.ts +314 -0
|
@@ -0,0 +1,2360 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ElementRef, numberAttribute, booleanAttribute, Input, Directive, ChangeDetectorRef, NgZone, HOST_TAG_NAME, DOCUMENT, EventEmitter, Injector, ANIMATION_MODULE_TYPE, ViewChild, ContentChild, Output, ContentChildren, ChangeDetectionStrategy, ViewEncapsulation, Component, QueryList, isDevMode, forwardRef, NgModule } from '@angular/core';
|
|
3
|
+
import { ENTER, SPACE, BACKSPACE, DELETE, TAB, hasModifierKey } from '@angular/cdk/keycodes';
|
|
4
|
+
import { Subject, merge, EMPTY } from 'rxjs';
|
|
5
|
+
import { CuteFocusableControl } from '@cute-widgets/base/abstract';
|
|
6
|
+
import { Validators, NgControl, NgForm, FormGroupDirective, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
7
|
+
import { ErrorStateMatcher, _ErrorStateTracker } from '@cute-widgets/base/core/error';
|
|
8
|
+
import { CuteFormFieldControl, CUTE_FORM_FIELD } from '@cute-widgets/base/form-field';
|
|
9
|
+
import { takeUntil, startWith, switchMap } from 'rxjs/operators';
|
|
10
|
+
import { FocusKeyManager } from '@angular/cdk/a11y';
|
|
11
|
+
import { Directionality } from '@angular/cdk/bidi';
|
|
12
|
+
import { CuteButton } from '@cute-widgets/base/button';
|
|
13
|
+
import { CommonModule } from '@angular/common';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @license Apache-2.0
|
|
17
|
+
*
|
|
18
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
19
|
+
*
|
|
20
|
+
* You may not use this file except in compliance with the License
|
|
21
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
22
|
+
*
|
|
23
|
+
* This code is a modification of the `@angular/material` original
|
|
24
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
25
|
+
*/
|
|
26
|
+
/** Injection token to be used to override the default options for the chips module. */
|
|
27
|
+
const CUTE_CHIPS_DEFAULT_OPTIONS = new InjectionToken('cute-chips-default-options', {
|
|
28
|
+
providedIn: 'root',
|
|
29
|
+
factory: () => ({
|
|
30
|
+
separatorKeyCodes: [ENTER],
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Injection token that can be used to reference instances of `CuteChipAvatar`. It serves as
|
|
35
|
+
* an alternative token to the actual `CuteChipAvatar` class which could cause unnecessary
|
|
36
|
+
* retention of the class and its directive metadata.
|
|
37
|
+
*/
|
|
38
|
+
const CUTE_CHIP_AVATAR = new InjectionToken('CuteChipAvatar');
|
|
39
|
+
/**
|
|
40
|
+
* Injection token that can be used to reference instances of `CuteChipTrailingIcon`. It serves as
|
|
41
|
+
* an alternative token to the actual `CuteChipTrailingIcon` class, which could cause unnecessary
|
|
42
|
+
* retention of the class and its directive metadata.
|
|
43
|
+
*/
|
|
44
|
+
const CUTE_CHIP_TRAILING_ICON = new InjectionToken('CuteChipTrailingIcon');
|
|
45
|
+
/**
|
|
46
|
+
* Injection token that can be used to reference instances of `CuteChipEdit`. It serves as
|
|
47
|
+
* alternative token to the actual `CuteChipEdit` class which could cause unnecessary
|
|
48
|
+
* retention of the class and its directive metadata.
|
|
49
|
+
*/
|
|
50
|
+
const CUTE_CHIP_EDIT = new InjectionToken('CuteChipEdit');
|
|
51
|
+
/**
|
|
52
|
+
* Injection token that can be used to reference instances of `CuteChipRemove`. It serves as
|
|
53
|
+
* an alternative token to the actual `CuteChipRemove` class, which could cause unnecessary
|
|
54
|
+
* retention of the class and its directive metadata.
|
|
55
|
+
*/
|
|
56
|
+
const CUTE_CHIP_REMOVE = new InjectionToken('CuteChipRemove');
|
|
57
|
+
/**
|
|
58
|
+
* Injection token used to avoid a circular dependency between the `CuteChip` and `CuteChipAction`.
|
|
59
|
+
*/
|
|
60
|
+
const CUTE_CHIP = new InjectionToken('CuteChip');
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @license Apache-2.0
|
|
64
|
+
*
|
|
65
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
66
|
+
*
|
|
67
|
+
* You may not use this file except in compliance with the License
|
|
68
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
69
|
+
*
|
|
70
|
+
* This code is a modification of the `@angular/material` original
|
|
71
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Section within a chip.
|
|
75
|
+
* @docs-private
|
|
76
|
+
*/
|
|
77
|
+
class CuteChipAction {
|
|
78
|
+
/** Whether the action is disabled. */
|
|
79
|
+
get disabled() { return this._disabled || this._parentChip.disabled; }
|
|
80
|
+
set disabled(value) { this._disabled = value; }
|
|
81
|
+
/**
|
|
82
|
+
* Determine the value of the disabled attribute for this chip action.
|
|
83
|
+
*/
|
|
84
|
+
_getDisabledAttribute() {
|
|
85
|
+
// When this chip action is disabled and focusing disabled chips is not permitted, return empty
|
|
86
|
+
// string to indicate that disabled attribute should be included.
|
|
87
|
+
return this.disabled && !this._allowFocusWhenDisabled ? '' : null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Determine the value of the tabindex attribute for this chip action.
|
|
91
|
+
*/
|
|
92
|
+
_getTabindex() {
|
|
93
|
+
return (this.disabled && !this._allowFocusWhenDisabled) || !this.isInteractive
|
|
94
|
+
? null
|
|
95
|
+
: this.tabIndex.toString();
|
|
96
|
+
}
|
|
97
|
+
constructor() {
|
|
98
|
+
this._elementRef = inject(ElementRef);
|
|
99
|
+
this._parentChip = inject(CUTE_CHIP);
|
|
100
|
+
/** Whether the action is interactive. */
|
|
101
|
+
this.isInteractive = true;
|
|
102
|
+
/** Whether this is the primary action in the chip. */
|
|
103
|
+
this._isPrimary = true;
|
|
104
|
+
/** Whether this is the leading action in the chip. */
|
|
105
|
+
this._isLeading = false; // TODO(adolgachev): consolidate usage to secondary css class
|
|
106
|
+
this._disabled = false;
|
|
107
|
+
/** Tab index of the action. */
|
|
108
|
+
this.tabIndex = -1;
|
|
109
|
+
/**
|
|
110
|
+
* Private API to allow focusing this chip when it is disabled.
|
|
111
|
+
*/
|
|
112
|
+
this._allowFocusWhenDisabled = false;
|
|
113
|
+
if (this._elementRef.nativeElement.nodeName === 'BUTTON') {
|
|
114
|
+
this._elementRef.nativeElement.setAttribute('type', 'button');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
focus() {
|
|
118
|
+
this._elementRef.nativeElement.focus();
|
|
119
|
+
}
|
|
120
|
+
_handleClick(event) {
|
|
121
|
+
if (!this.disabled && this.isInteractive && this._isPrimary) {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
this._parentChip._handlePrimaryActionInteraction();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
_handleKeydown(event) {
|
|
127
|
+
if ((event.keyCode === ENTER || event.keyCode === SPACE) &&
|
|
128
|
+
!this.disabled &&
|
|
129
|
+
this.isInteractive &&
|
|
130
|
+
this._isPrimary &&
|
|
131
|
+
!this._parentChip._isEditing) {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
this._parentChip._handlePrimaryActionInteraction();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipAction, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
137
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.15", type: CuteChipAction, isStandalone: true, selector: "[cuteChipAction]", inputs: { isInteractive: "isInteractive", disabled: ["disabled", "disabled", booleanAttribute], tabIndex: ["tabIndex", "tabIndex", (value) => (value == null ? -1 : numberAttribute(value))], _allowFocusWhenDisabled: "_allowFocusWhenDisabled" }, host: { listeners: { "click": "_handleClick($event)", "keydown": "_handleKeydown($event)" }, properties: { "class.cute-chip__action--primary": "_isPrimary", "class.cute-chip__action--presentational": "!isInteractive", "class.cute-chip__action--secondary": "!_isPrimary", "class.cute-chip__action--trailing": "!_isPrimary && !_isLeading", "attr.tabindex": "_getTabindex()", "attr.disabled": "_getDisabledAttribute()", "attr.aria-disabled": "disabled" }, classAttribute: "cute-chip__action cute-chip-action" }, ngImport: i0 }); }
|
|
138
|
+
}
|
|
139
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipAction, decorators: [{
|
|
140
|
+
type: Directive,
|
|
141
|
+
args: [{
|
|
142
|
+
selector: '[cuteChipAction]',
|
|
143
|
+
host: {
|
|
144
|
+
'class': 'cute-chip__action cute-chip-action',
|
|
145
|
+
'[class.cute-chip__action--primary]': '_isPrimary',
|
|
146
|
+
'[class.cute-chip__action--presentational]': '!isInteractive',
|
|
147
|
+
'[class.cute-chip__action--secondary]': '!_isPrimary',
|
|
148
|
+
'[class.cute-chip__action--trailing]': '!_isPrimary && !_isLeading',
|
|
149
|
+
'[attr.tabindex]': '_getTabindex()',
|
|
150
|
+
'[attr.disabled]': '_getDisabledAttribute()',
|
|
151
|
+
'[attr.aria-disabled]': 'disabled',
|
|
152
|
+
'(click)': '_handleClick($event)',
|
|
153
|
+
'(keydown)': '_handleKeydown($event)',
|
|
154
|
+
},
|
|
155
|
+
standalone: true,
|
|
156
|
+
}]
|
|
157
|
+
}], ctorParameters: () => [], propDecorators: { isInteractive: [{
|
|
158
|
+
type: Input
|
|
159
|
+
}], disabled: [{
|
|
160
|
+
type: Input,
|
|
161
|
+
args: [{ transform: booleanAttribute }]
|
|
162
|
+
}], tabIndex: [{
|
|
163
|
+
type: Input,
|
|
164
|
+
args: [{
|
|
165
|
+
transform: (value) => (value == null ? -1 : numberAttribute(value)),
|
|
166
|
+
}]
|
|
167
|
+
}], _allowFocusWhenDisabled: [{
|
|
168
|
+
type: Input
|
|
169
|
+
}] } });
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @license Apache-2.0
|
|
173
|
+
*
|
|
174
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
175
|
+
*
|
|
176
|
+
* You may not use this file except in compliance with the License
|
|
177
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
178
|
+
*
|
|
179
|
+
* This code is a modification of the `@angular/material` original
|
|
180
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
181
|
+
*/
|
|
182
|
+
let uid = 0;
|
|
183
|
+
/**
|
|
184
|
+
* A Chip base component used inside the `CuteChipSet` component.
|
|
185
|
+
* Extended by `CuteChipOption` and `CuteChipRow` for different interaction patterns.
|
|
186
|
+
*/
|
|
187
|
+
class CuteChip extends CuteFocusableControl {
|
|
188
|
+
_hasFocus() {
|
|
189
|
+
return this._hasFocusInternal;
|
|
190
|
+
}
|
|
191
|
+
/** A unique id for the chip. If none is supplied, it will be auto-generated. */
|
|
192
|
+
generateId() {
|
|
193
|
+
return `cute-chip-${uid++}`;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The value of the chip. Defaults to the content inside
|
|
197
|
+
* the `cute-chip-action-label` element.
|
|
198
|
+
*/
|
|
199
|
+
get value() {
|
|
200
|
+
return this._value !== undefined ? this._value : this._textElement?.textContent.trim();
|
|
201
|
+
}
|
|
202
|
+
set value(value) {
|
|
203
|
+
this._value = value;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Handles the lazy creation of the CuteChip ripple.
|
|
207
|
+
* Used to improve initial load time of large applications.
|
|
208
|
+
*/
|
|
209
|
+
//_rippleLoader: MatRippleLoader = inject(MatRippleLoader);
|
|
210
|
+
getDisabledState() {
|
|
211
|
+
return super.getDisabledState() || this._chipListDisabled;
|
|
212
|
+
}
|
|
213
|
+
constructor() {
|
|
214
|
+
super();
|
|
215
|
+
this._changeDetectorRef = inject(ChangeDetectorRef);
|
|
216
|
+
this._ngZone = inject(NgZone);
|
|
217
|
+
this._tagName = inject(HOST_TAG_NAME);
|
|
218
|
+
//private _globalRippleOptions = inject<RippleGlobalOptions>(MAT_RIPPLE_GLOBAL_OPTIONS, {
|
|
219
|
+
// optional: true,
|
|
220
|
+
//});
|
|
221
|
+
this._document = inject(DOCUMENT);
|
|
222
|
+
/** Emits when the chip is focused. */
|
|
223
|
+
this._onFocus = new Subject();
|
|
224
|
+
/** Emits when the chip is blurred. */
|
|
225
|
+
this._onBlur = new Subject();
|
|
226
|
+
/** Whether the chip has focus. */
|
|
227
|
+
this._hasFocusInternal = false;
|
|
228
|
+
/** The `id` of a span that contains this chip's aria description. */
|
|
229
|
+
this._ariaDescriptionId = `${this.id}-aria-description`;
|
|
230
|
+
/** Whether the chip list is disabled. */
|
|
231
|
+
this._chipListDisabled = false;
|
|
232
|
+
/** Whether the chip was focused when it was removed. */
|
|
233
|
+
this._hadFocusOnRemove = false;
|
|
234
|
+
/**
|
|
235
|
+
* Determines whether the chip displays the remove styling and emits (removed) events.
|
|
236
|
+
*/
|
|
237
|
+
this.removable = true;
|
|
238
|
+
/**
|
|
239
|
+
* Colors the chip for emphasis as if it were selected.
|
|
240
|
+
*/
|
|
241
|
+
this.highlighted = false;
|
|
242
|
+
/** Whether the ripple effect is disabled or not. */
|
|
243
|
+
this.disableRipple = false;
|
|
244
|
+
/** Emitted when a chip is to be removed. */
|
|
245
|
+
this.removed = new EventEmitter();
|
|
246
|
+
/** Emitted when the chip is destroyed. */
|
|
247
|
+
this.destroyed = new EventEmitter();
|
|
248
|
+
/** The unstyled chip selector for this component. */
|
|
249
|
+
this.basicChipAttrName = 'cute-basic-chip';
|
|
250
|
+
this._injector = inject(Injector);
|
|
251
|
+
const animationMode = inject(ANIMATION_MODULE_TYPE, { optional: true });
|
|
252
|
+
this._animationsDisabled = animationMode === 'NoopAnimations';
|
|
253
|
+
const tabIndex = this.getAttribute("tabindex");
|
|
254
|
+
if (tabIndex) {
|
|
255
|
+
this.tabIndex = parseInt(tabIndex) ?? -1;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
this.tabIndex = undefined;
|
|
259
|
+
}
|
|
260
|
+
this._monitorFocus();
|
|
261
|
+
}
|
|
262
|
+
ngOnInit() {
|
|
263
|
+
super.ngOnInit();
|
|
264
|
+
// This check needs to happen in `ngOnInit` so the overridden value of
|
|
265
|
+
// `basicChipAttrName` coming from base classes can be picked up.
|
|
266
|
+
const element = this._elementRef.nativeElement;
|
|
267
|
+
this._isBasicChip =
|
|
268
|
+
element.hasAttribute(this.basicChipAttrName) ||
|
|
269
|
+
element.tagName.toLowerCase() === this.basicChipAttrName;
|
|
270
|
+
this._isStandardStaticChip = !this._isBasicChip &&
|
|
271
|
+
(element.tagName.toLowerCase() === "cute-chip" ||
|
|
272
|
+
element.tagName.toLowerCase() === "cute-chip-row");
|
|
273
|
+
}
|
|
274
|
+
ngAfterViewInit() {
|
|
275
|
+
super.ngAfterViewInit();
|
|
276
|
+
this._textElement = this._elementRef.nativeElement.querySelector('.cute-chip-action-label');
|
|
277
|
+
if (this._pendingFocus) {
|
|
278
|
+
this._pendingFocus = false;
|
|
279
|
+
this.focus();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
ngAfterContentInit() {
|
|
283
|
+
super.ngAfterContentInit();
|
|
284
|
+
// Since the styling depends on the presence of some
|
|
285
|
+
// actions, we have to mark for check on changes.
|
|
286
|
+
this._actionChanges = merge(this._allLeadingIcons?.changes, this._allTrailingIcons?.changes, this._allEditIcons?.changes, this._allRemoveIcons?.changes).subscribe(() => this._changeDetectorRef.markForCheck());
|
|
287
|
+
}
|
|
288
|
+
ngDoCheck() {
|
|
289
|
+
//this._rippleLoader.setDisabled(this._elementRef.nativeElement, this._isRippleDisabled());
|
|
290
|
+
}
|
|
291
|
+
ngOnDestroy() {
|
|
292
|
+
super.ngOnDestroy();
|
|
293
|
+
this._actionChanges?.unsubscribe();
|
|
294
|
+
this.destroyed.emit({ chip: this });
|
|
295
|
+
this.destroyed.complete();
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Allows for programmatic removal of the chip.
|
|
299
|
+
*
|
|
300
|
+
* Informs any listeners of the removal request. Does not remove the chip from the DOM.
|
|
301
|
+
*/
|
|
302
|
+
remove() {
|
|
303
|
+
if (this.removable) {
|
|
304
|
+
this._hadFocusOnRemove = this._hasFocus();
|
|
305
|
+
this.removed.emit({ chip: this });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/** Whether the ripple should be disabled. */
|
|
309
|
+
/*
|
|
310
|
+
_isRippleDisabled(): boolean {
|
|
311
|
+
return (
|
|
312
|
+
this.disabled ||
|
|
313
|
+
this.disableRipple ||
|
|
314
|
+
this._animationsDisabled ||
|
|
315
|
+
this._isBasicChip ||
|
|
316
|
+
!!this._globalRippleOptions?.disabled
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
*/
|
|
320
|
+
/** Returns whether the chip has a trailing icon. */
|
|
321
|
+
_hasTrailingIcon() {
|
|
322
|
+
return !!(this.trailingIcon || this.removeIcon);
|
|
323
|
+
}
|
|
324
|
+
/** Handles keyboard events on the chip. */
|
|
325
|
+
_handleKeydown(event) {
|
|
326
|
+
// Ignore backspace events where the user is holding down the key
|
|
327
|
+
// so that we don't accidentally remove too many chips.
|
|
328
|
+
if ((event.keyCode === BACKSPACE && !event.repeat) || event.keyCode === DELETE) {
|
|
329
|
+
event.preventDefault();
|
|
330
|
+
this.remove();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/** Allows for programmatic focusing of the chip. */
|
|
334
|
+
focus() {
|
|
335
|
+
super.focus();
|
|
336
|
+
if (!this.disabled) {
|
|
337
|
+
// If `focus` is called before `ngAfterViewInit`, we won't have access to the primary action.
|
|
338
|
+
// This can happen if the consumer tries to focus a chip immediately after it is added.
|
|
339
|
+
// Queue the method to be called again on init.
|
|
340
|
+
if (this.primaryAction) {
|
|
341
|
+
this.primaryAction.focus();
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
this._pendingFocus = true;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/** Gets the action that contains a specific target node. */
|
|
349
|
+
_getSourceAction(target) {
|
|
350
|
+
return this._getActions().find(action => {
|
|
351
|
+
const element = action._elementRef.nativeElement;
|
|
352
|
+
return element === target || element.contains(target);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
/** Gets all the actions within the chip. */
|
|
356
|
+
_getActions() {
|
|
357
|
+
const result = [];
|
|
358
|
+
if (this.editIcon) {
|
|
359
|
+
result.push(this.editIcon);
|
|
360
|
+
}
|
|
361
|
+
if (this.primaryAction) {
|
|
362
|
+
result.push(this.primaryAction);
|
|
363
|
+
}
|
|
364
|
+
if (this.removeIcon) {
|
|
365
|
+
result.push(this.removeIcon);
|
|
366
|
+
}
|
|
367
|
+
if (this.trailingIcon) {
|
|
368
|
+
result.push(this.trailingIcon);
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
/** Handles interactions with the primary action of the chip. */
|
|
373
|
+
_handlePrimaryActionInteraction() {
|
|
374
|
+
// Empty here, but is overwritten in child classes.
|
|
375
|
+
}
|
|
376
|
+
/** Handles interactions with the edit action of the chip. */
|
|
377
|
+
_edit(event) {
|
|
378
|
+
// Empty here, but is overwritten in child classes.
|
|
379
|
+
}
|
|
380
|
+
/** Gets the tabindex of the chip. */
|
|
381
|
+
_getTabIndex() {
|
|
382
|
+
if (!this.role) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
return this.disabled ? -1 : this.tabIndex;
|
|
386
|
+
}
|
|
387
|
+
/** Starts the focus monitoring process on the chip. */
|
|
388
|
+
_monitorFocus() {
|
|
389
|
+
this._focusMonitor.monitor(this._elementRef, true).subscribe(origin => {
|
|
390
|
+
const hasFocus = origin !== null;
|
|
391
|
+
if (hasFocus !== this._hasFocusInternal) {
|
|
392
|
+
this._hasFocusInternal = hasFocus;
|
|
393
|
+
if (hasFocus) {
|
|
394
|
+
this._onFocus.next({ chip: this });
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
// When animations are enabled, Angular may end up removing the chip from the DOM a little
|
|
398
|
+
// earlier than usual, causing it to be blurred and throwing off the logic in the chip list
|
|
399
|
+
// that moves focus not the next item. To work around the issue, we defer marking the chip
|
|
400
|
+
// as not focused until after the next render.
|
|
401
|
+
this.markForCheck();
|
|
402
|
+
setTimeout(() => this._ngZone.run(() => this._onBlur.next({ chip: this })));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChip, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
408
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CuteChip, isStandalone: true, selector: "cute-basic-chip, [cute-basic-chip], cute-chip, [cute-chip]", inputs: { value: "value", removable: ["removable", "removable", booleanAttribute], highlighted: ["highlighted", "highlighted", booleanAttribute], disableRipple: ["disableRipple", "disableRipple", booleanAttribute] }, outputs: { removed: "removed", destroyed: "destroyed" }, host: { listeners: { "keydown": "_handleKeydown($event)" }, properties: { "class.btn": "_isStandardStaticChip", "class.btn-sm": "_isStandardStaticChip", "class.border": "_isStandardStaticChip", "class.rounded-pill": "_isStandardStaticChip", "class.cute-static-chip": "_isStandardStaticChip", "class.cute-chip-with-avatar": "leadingIcon", "class.cute-chip-highlighted": "highlighted", "class.disabled": "_isStandardStaticChip && disabled", "class.cute-basic-chip": "_isBasicChip", "class.cute-standard-chip": "!_isBasicChip", "class.cute-chip-with-trailing-icon": "_hasTrailingIcon()", "class._cute-animation-noopable": "_animationsDisabled", "id": "id", "attr.role": "role", "attr.tabindex": "_getTabIndex()", "attr.aria-label": "ariaLabel" }, classAttribute: "cute-chip" }, providers: [{ provide: CUTE_CHIP, useExisting: CuteChip }], queries: [{ propertyName: "leadingIcon", first: true, predicate: CUTE_CHIP_AVATAR, descendants: true }, { propertyName: "editIcon", first: true, predicate: CUTE_CHIP_EDIT, descendants: true }, { propertyName: "trailingIcon", first: true, predicate: CUTE_CHIP_TRAILING_ICON, descendants: true }, { propertyName: "removeIcon", first: true, predicate: CUTE_CHIP_REMOVE, descendants: true }, { propertyName: "_allLeadingIcons", predicate: CUTE_CHIP_AVATAR, descendants: true }, { propertyName: "_allTrailingIcons", predicate: CUTE_CHIP_TRAILING_ICON, descendants: true }, { propertyName: "_allEditIcons", predicate: CUTE_CHIP_EDIT, descendants: true }, { propertyName: "_allRemoveIcons", predicate: CUTE_CHIP_REMOVE, descendants: true }], viewQueries: [{ propertyName: "primaryAction", first: true, predicate: CuteChipAction, descendants: true }], exportAs: ["cuteChip"], usesInheritance: true, ngImport: i0, template: "<span class=\"cute-chip-focus-overlay\"></span>\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <span cuteChipAction [isInteractive]=\"false\">\r\n @if (leadingIcon) {\r\n <span class=\"cute-chip__graphic cute-chip-graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n </span>\r\n }\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n <ng-content></ng-content>\r\n <span class=\"cute-chip-primary-focus-indicator cute-focus-indicator\"></span>\r\n </span>\r\n </span>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span class=\"cute-chip__cell cute-chip__cell--trailing\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"], dependencies: [{ kind: "directive", type: CuteChipAction, selector: "[cuteChipAction]", inputs: ["isInteractive", "disabled", "tabIndex", "_allowFocusWhenDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
409
|
+
}
|
|
410
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChip, decorators: [{
|
|
411
|
+
type: Component,
|
|
412
|
+
args: [{ selector: 'cute-basic-chip, [cute-basic-chip], cute-chip, [cute-chip]', exportAs: 'cuteChip', host: {
|
|
413
|
+
'class': 'cute-chip',
|
|
414
|
+
'[class.btn]': '_isStandardStaticChip',
|
|
415
|
+
'[class.btn-sm]': '_isStandardStaticChip',
|
|
416
|
+
'[class.border]': '_isStandardStaticChip',
|
|
417
|
+
'[class.rounded-pill]': '_isStandardStaticChip',
|
|
418
|
+
'[class.cute-static-chip]': '_isStandardStaticChip',
|
|
419
|
+
/*
|
|
420
|
+
'[class]': '"text-bg-"+color||"tertiary"',
|
|
421
|
+
'[class.mdc-evolution-chip]': '!_isBasicChip',
|
|
422
|
+
'[class.mdc-evolution-chip--disabled]': 'disabled',
|
|
423
|
+
'[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',
|
|
424
|
+
'[class.mdc-evolution-chip--with-primary-graphic]': 'leadingIcon',
|
|
425
|
+
'[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',
|
|
426
|
+
'[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',
|
|
427
|
+
*/
|
|
428
|
+
'[class.cute-chip-with-avatar]': 'leadingIcon',
|
|
429
|
+
'[class.cute-chip-highlighted]': 'highlighted',
|
|
430
|
+
'[class.disabled]': '_isStandardStaticChip && disabled',
|
|
431
|
+
'[class.cute-basic-chip]': '_isBasicChip',
|
|
432
|
+
'[class.cute-standard-chip]': '!_isBasicChip',
|
|
433
|
+
'[class.cute-chip-with-trailing-icon]': '_hasTrailingIcon()',
|
|
434
|
+
'[class._cute-animation-noopable]': '_animationsDisabled',
|
|
435
|
+
'[id]': 'id',
|
|
436
|
+
'[attr.role]': 'role',
|
|
437
|
+
'[attr.tabindex]': '_getTabIndex()',
|
|
438
|
+
'[attr.aria-label]': 'ariaLabel',
|
|
439
|
+
'(keydown)': '_handleKeydown($event)',
|
|
440
|
+
}, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: CUTE_CHIP, useExisting: CuteChip }], imports: [CuteChipAction], template: "<span class=\"cute-chip-focus-overlay\"></span>\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <span cuteChipAction [isInteractive]=\"false\">\r\n @if (leadingIcon) {\r\n <span class=\"cute-chip__graphic cute-chip-graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n </span>\r\n }\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n <ng-content></ng-content>\r\n <span class=\"cute-chip-primary-focus-indicator cute-focus-indicator\"></span>\r\n </span>\r\n </span>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span class=\"cute-chip__cell cute-chip__cell--trailing\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"] }]
|
|
441
|
+
}], ctorParameters: () => [], propDecorators: { _allLeadingIcons: [{
|
|
442
|
+
type: ContentChildren,
|
|
443
|
+
args: [CUTE_CHIP_AVATAR, { descendants: true }]
|
|
444
|
+
}], _allTrailingIcons: [{
|
|
445
|
+
type: ContentChildren,
|
|
446
|
+
args: [CUTE_CHIP_TRAILING_ICON, { descendants: true }]
|
|
447
|
+
}], _allEditIcons: [{
|
|
448
|
+
type: ContentChildren,
|
|
449
|
+
args: [CUTE_CHIP_EDIT, { descendants: true }]
|
|
450
|
+
}], _allRemoveIcons: [{
|
|
451
|
+
type: ContentChildren,
|
|
452
|
+
args: [CUTE_CHIP_REMOVE, { descendants: true }]
|
|
453
|
+
}], value: [{
|
|
454
|
+
type: Input
|
|
455
|
+
}], removable: [{
|
|
456
|
+
type: Input,
|
|
457
|
+
args: [{ transform: booleanAttribute }]
|
|
458
|
+
}], highlighted: [{
|
|
459
|
+
type: Input,
|
|
460
|
+
args: [{ transform: booleanAttribute }]
|
|
461
|
+
}], disableRipple: [{
|
|
462
|
+
type: Input,
|
|
463
|
+
args: [{ transform: booleanAttribute }]
|
|
464
|
+
}], removed: [{
|
|
465
|
+
type: Output
|
|
466
|
+
}], destroyed: [{
|
|
467
|
+
type: Output
|
|
468
|
+
}], leadingIcon: [{
|
|
469
|
+
type: ContentChild,
|
|
470
|
+
args: [CUTE_CHIP_AVATAR]
|
|
471
|
+
}], editIcon: [{
|
|
472
|
+
type: ContentChild,
|
|
473
|
+
args: [CUTE_CHIP_EDIT]
|
|
474
|
+
}], trailingIcon: [{
|
|
475
|
+
type: ContentChild,
|
|
476
|
+
args: [CUTE_CHIP_TRAILING_ICON]
|
|
477
|
+
}], removeIcon: [{
|
|
478
|
+
type: ContentChild,
|
|
479
|
+
args: [CUTE_CHIP_REMOVE]
|
|
480
|
+
}], primaryAction: [{
|
|
481
|
+
type: ViewChild,
|
|
482
|
+
args: [CuteChipAction]
|
|
483
|
+
}] } });
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @license Apache-2.0
|
|
487
|
+
*
|
|
488
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
489
|
+
*
|
|
490
|
+
* You may not use this file except in compliance with the License
|
|
491
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
492
|
+
*
|
|
493
|
+
* This code is a modification of the `@angular/material` original
|
|
494
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
495
|
+
*/
|
|
496
|
+
/**
|
|
497
|
+
* A directive that makes a <span> editable and exposes functions to modify and retrieve the
|
|
498
|
+
* element's contents.
|
|
499
|
+
*/
|
|
500
|
+
class CuteChipEditInput {
|
|
501
|
+
constructor() {
|
|
502
|
+
this._elementRef = inject(ElementRef);
|
|
503
|
+
this._document = inject(DOCUMENT);
|
|
504
|
+
}
|
|
505
|
+
initialize(initialValue) {
|
|
506
|
+
this.getNativeElement().focus();
|
|
507
|
+
this.setValue(initialValue);
|
|
508
|
+
}
|
|
509
|
+
getNativeElement() {
|
|
510
|
+
return this._elementRef.nativeElement;
|
|
511
|
+
}
|
|
512
|
+
setValue(value) {
|
|
513
|
+
this.getNativeElement().textContent = value;
|
|
514
|
+
this._moveCursorToEndOfInput();
|
|
515
|
+
}
|
|
516
|
+
getValue() {
|
|
517
|
+
return this.getNativeElement().textContent || '';
|
|
518
|
+
}
|
|
519
|
+
_moveCursorToEndOfInput() {
|
|
520
|
+
const range = this._document.createRange();
|
|
521
|
+
range.selectNodeContents(this.getNativeElement());
|
|
522
|
+
range.collapse(false);
|
|
523
|
+
const sel = window.getSelection();
|
|
524
|
+
sel.removeAllRanges();
|
|
525
|
+
sel.addRange(range);
|
|
526
|
+
}
|
|
527
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipEditInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
528
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteChipEditInput, isStandalone: true, selector: "span[cuteChipEditInput]", host: { attributes: { "role": "textbox", "tabindex": "-1", "contenteditable": "true" }, classAttribute: "cute-chip-edit-input" }, ngImport: i0 }); }
|
|
529
|
+
}
|
|
530
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipEditInput, decorators: [{
|
|
531
|
+
type: Directive,
|
|
532
|
+
args: [{
|
|
533
|
+
selector: 'span[cuteChipEditInput]',
|
|
534
|
+
host: {
|
|
535
|
+
'class': 'cute-chip-edit-input',
|
|
536
|
+
'role': 'textbox',
|
|
537
|
+
'tabindex': '-1',
|
|
538
|
+
'contenteditable': 'true',
|
|
539
|
+
},
|
|
540
|
+
standalone: true,
|
|
541
|
+
}]
|
|
542
|
+
}], ctorParameters: () => [] });
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* @license Apache-2.0
|
|
546
|
+
*
|
|
547
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
548
|
+
*
|
|
549
|
+
* You may not use this file except in compliance with the License
|
|
550
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
551
|
+
*
|
|
552
|
+
* This code is a modification of the `@angular/material` original
|
|
553
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
554
|
+
*/
|
|
555
|
+
/**
|
|
556
|
+
* An extension of the CuteChip component used with CuteChipGrid and
|
|
557
|
+
* the cuteChipInputFor directive.
|
|
558
|
+
*/
|
|
559
|
+
class CuteChipRow extends CuteChip {
|
|
560
|
+
constructor() {
|
|
561
|
+
super();
|
|
562
|
+
this.basicChipAttrName = 'cute-basic-chip-row';
|
|
563
|
+
/**
|
|
564
|
+
* The editing action has to be triggered in a timeout. While we're waiting on it, a blur
|
|
565
|
+
* event might occur which will interrupt the editing. This flag is used to avoid interruptions
|
|
566
|
+
* while the editing action is being initialized.
|
|
567
|
+
*/
|
|
568
|
+
this._editStartPending = false;
|
|
569
|
+
this.editable = false;
|
|
570
|
+
/** Emitted when the chip is edited. */
|
|
571
|
+
this.edited = new EventEmitter();
|
|
572
|
+
this._isEditing = false;
|
|
573
|
+
this.role = 'row';
|
|
574
|
+
this._onBlur.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
575
|
+
if (this._isEditing && !this._editStartPending) {
|
|
576
|
+
this._onEditFinish();
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
_hasTrailingIcon() {
|
|
581
|
+
// The trailing icon is hidden while editing.
|
|
582
|
+
return !this._isEditing && super._hasTrailingIcon();
|
|
583
|
+
}
|
|
584
|
+
/** Sends focus to the first gridcell when the user clicks anywhere inside the chip. */
|
|
585
|
+
_handleFocus() {
|
|
586
|
+
if (!this._isEditing && !this.disabled) {
|
|
587
|
+
this.focus();
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
_handleKeydown(event) {
|
|
591
|
+
if (event.keyCode === ENTER && !this.disabled) {
|
|
592
|
+
if (this._isEditing) {
|
|
593
|
+
event.preventDefault();
|
|
594
|
+
this._onEditFinish();
|
|
595
|
+
}
|
|
596
|
+
else if (this.editable) {
|
|
597
|
+
this._startEditing(event);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
else if (this._isEditing) {
|
|
601
|
+
// Stop the event from reaching the chip set in order to avoid navigating.
|
|
602
|
+
event.stopPropagation();
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
super._handleKeydown(event);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
_handleDoubleclick(event) {
|
|
609
|
+
if (!this.disabled && this.editable) {
|
|
610
|
+
this._startEditing(event);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
_startEditing(event) {
|
|
614
|
+
if (!this.primaryAction ||
|
|
615
|
+
(this.removeIcon && this._getSourceAction(event.target) === this.removeIcon)) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
// The value depends on the DOM so we need to extract it before we flip the flag.
|
|
619
|
+
const value = this.value;
|
|
620
|
+
this._isEditing = this._editStartPending = true;
|
|
621
|
+
// Starting the editing sequence below depends on the edit input
|
|
622
|
+
// query resolving on time. Trigger a synchronous change detection to
|
|
623
|
+
// ensure that it happens by the time we hit the timeout below.
|
|
624
|
+
this._changeDetectorRef.detectChanges();
|
|
625
|
+
// TODO(crisbeto): this timeout shouldn't be necessary given the `detectChange` call above.
|
|
626
|
+
// Defer initializing the input so it has time to be added to the DOM.
|
|
627
|
+
setTimeout(() => {
|
|
628
|
+
this._getEditInput().initialize(value);
|
|
629
|
+
this._editStartPending = false;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
_onEditFinish() {
|
|
633
|
+
this._isEditing = this._editStartPending = false;
|
|
634
|
+
this.edited.emit({ chip: this, value: this._getEditInput().getValue() });
|
|
635
|
+
// If the edit input is still focused or focus was returned to the body after it was destroyed,
|
|
636
|
+
// return focus to the chip contents.
|
|
637
|
+
if (this._document.activeElement === this._getEditInput().getNativeElement() ||
|
|
638
|
+
this._document.activeElement === this._document.body) {
|
|
639
|
+
this.primaryAction?.focus();
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/*
|
|
643
|
+
override _isRippleDisabled(): boolean {
|
|
644
|
+
return super._isRippleDisabled() || this._isEditing;
|
|
645
|
+
}
|
|
646
|
+
*/
|
|
647
|
+
/**
|
|
648
|
+
* Gets the projected chip edit input, or the default input if none is projected in. One of these
|
|
649
|
+
* two values is guaranteed to be defined.
|
|
650
|
+
*/
|
|
651
|
+
_getEditInput() {
|
|
652
|
+
return this.contentEditInput || this.defaultEditInput;
|
|
653
|
+
}
|
|
654
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipRow, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
655
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CuteChipRow, isStandalone: true, selector: "cute-chip-row, [cute-chip-row], cute-basic-chip-row, [cute-basic-chip-row]", inputs: { editable: "editable" }, outputs: { edited: "edited" }, host: { listeners: { "focus": "_handleFocus($event)", "dblclick": "_handleDoubleclick($event)" }, properties: { "class.cute-chip-with-avatar": "leadingIcon", "class.cute-chip-disabled": "disabled", "class.cute-chip-editing": "_isEditing", "class.cute-chip-editable": "editable", "class.cute-chip-highlighted": "highlighted", "class.cute-chip-with-trailing-icon": "_hasTrailingIcon()", "id": "id", "attr.tabindex": "disabled ? null : -1", "attr.aria-label": "null", "attr.aria-description": "null", "attr.role": "role" }, classAttribute: "cute-chip-row" }, providers: [
|
|
656
|
+
{ provide: CuteChip, useExisting: CuteChipRow },
|
|
657
|
+
{ provide: CUTE_CHIP, useExisting: CuteChipRow },
|
|
658
|
+
], queries: [{ propertyName: "contentEditInput", first: true, predicate: CuteChipEditInput, descendants: true }], viewQueries: [{ propertyName: "defaultEditInput", first: true, predicate: CuteChipEditInput, descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (!_isEditing) {\r\n <span class=\"cute-chip-focus-overlay\"></span>\r\n}\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <span class=\"cute-chip-action\" role=\"gridcell\"\r\n cuteChipAction\r\n [tabIndex]=\"tabIndex\"\r\n [disabled]=\"disabled\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"_ariaDescriptionId\">\r\n @if (leadingIcon) {\r\n <span class=\"cute-chip-graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n </span>\r\n }\r\n\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n @if (_isEditing) {\r\n @if (contentEditInput) {\r\n <ng-content select=\"[cuteChipEditInput]\"></ng-content>\r\n } @else {\r\n <span cuteChipEditInput></span>\r\n }\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n\r\n <span class=\"cute-chip-primary-focus-indicator cute-focus-indicator\" aria-hidden=\"true\"></span>\r\n </span>\r\n </span>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span\r\n class=\"cute-chip__cell cute-chip__cell--trailing\"\r\n role=\"gridcell\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n\r\n<span class=\"visually-hidden\" [id]=\"_ariaDescriptionId\">{{ariaDescription}}</span>\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"], dependencies: [{ kind: "directive", type: CuteChipAction, selector: "[cuteChipAction]", inputs: ["isInteractive", "disabled", "tabIndex", "_allowFocusWhenDisabled"] }, { kind: "directive", type: CuteChipEditInput, selector: "span[cuteChipEditInput]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
659
|
+
}
|
|
660
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipRow, decorators: [{
|
|
661
|
+
type: Component,
|
|
662
|
+
args: [{ selector: 'cute-chip-row, [cute-chip-row], cute-basic-chip-row, [cute-basic-chip-row]', host: {
|
|
663
|
+
'class': 'cute-chip-row',
|
|
664
|
+
'[class.cute-chip-with-avatar]': 'leadingIcon',
|
|
665
|
+
'[class.cute-chip-disabled]': 'disabled',
|
|
666
|
+
'[class.cute-chip-editing]': '_isEditing',
|
|
667
|
+
'[class.cute-chip-editable]': 'editable',
|
|
668
|
+
'[class.cute-chip-highlighted]': 'highlighted',
|
|
669
|
+
'[class.cute-chip-with-trailing-icon]': '_hasTrailingIcon()',
|
|
670
|
+
/*
|
|
671
|
+
'[class.mdc-evolution-chip--disabled]': 'disabled',
|
|
672
|
+
'[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',
|
|
673
|
+
'[class.mdc-evolution-chip--with-primary-graphic]': 'leadingIcon',
|
|
674
|
+
'[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',
|
|
675
|
+
'[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',
|
|
676
|
+
*/
|
|
677
|
+
'[id]': 'id',
|
|
678
|
+
// Has to have a negative tabindex to capture
|
|
679
|
+
// focus and redirect it to the primary action.
|
|
680
|
+
'[attr.tabindex]': 'disabled ? null : -1',
|
|
681
|
+
'[attr.aria-label]': 'null',
|
|
682
|
+
'[attr.aria-description]': 'null',
|
|
683
|
+
'[attr.role]': 'role',
|
|
684
|
+
'(focus)': '_handleFocus($event)',
|
|
685
|
+
'(dblclick)': '_handleDoubleclick($event)',
|
|
686
|
+
}, providers: [
|
|
687
|
+
{ provide: CuteChip, useExisting: CuteChipRow },
|
|
688
|
+
{ provide: CUTE_CHIP, useExisting: CuteChipRow },
|
|
689
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CuteChipAction, CuteChipEditInput], template: "@if (!_isEditing) {\r\n <span class=\"cute-chip-focus-overlay\"></span>\r\n}\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <span class=\"cute-chip-action\" role=\"gridcell\"\r\n cuteChipAction\r\n [tabIndex]=\"tabIndex\"\r\n [disabled]=\"disabled\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"_ariaDescriptionId\">\r\n @if (leadingIcon) {\r\n <span class=\"cute-chip-graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n </span>\r\n }\r\n\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n @if (_isEditing) {\r\n @if (contentEditInput) {\r\n <ng-content select=\"[cuteChipEditInput]\"></ng-content>\r\n } @else {\r\n <span cuteChipEditInput></span>\r\n }\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n\r\n <span class=\"cute-chip-primary-focus-indicator cute-focus-indicator\" aria-hidden=\"true\"></span>\r\n </span>\r\n </span>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span\r\n class=\"cute-chip__cell cute-chip__cell--trailing\"\r\n role=\"gridcell\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n\r\n<span class=\"visually-hidden\" [id]=\"_ariaDescriptionId\">{{ariaDescription}}</span>\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"] }]
|
|
690
|
+
}], ctorParameters: () => [], propDecorators: { editable: [{
|
|
691
|
+
type: Input
|
|
692
|
+
}], edited: [{
|
|
693
|
+
type: Output
|
|
694
|
+
}], defaultEditInput: [{
|
|
695
|
+
type: ViewChild,
|
|
696
|
+
args: [CuteChipEditInput]
|
|
697
|
+
}], contentEditInput: [{
|
|
698
|
+
type: ContentChild,
|
|
699
|
+
args: [CuteChipEditInput]
|
|
700
|
+
}] } });
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* @license Apache-2.0
|
|
704
|
+
*
|
|
705
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
706
|
+
*
|
|
707
|
+
* You may not use this file except in compliance with the License
|
|
708
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
709
|
+
*
|
|
710
|
+
* This code is a modification of the `@angular/material` original
|
|
711
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
712
|
+
*/
|
|
713
|
+
/**
|
|
714
|
+
* Basic container component for the `CuteChip` component.
|
|
715
|
+
* Extended by `CuteChipListbox` and `CuteChipGrid` for different interaction patterns.
|
|
716
|
+
*/
|
|
717
|
+
class CuteChipSet {
|
|
718
|
+
/** Combined stream of all the child chips' focus events. */
|
|
719
|
+
get chipFocusChanges() {
|
|
720
|
+
return this._getChipStream(chip => chip._onFocus);
|
|
721
|
+
}
|
|
722
|
+
/** Combined stream of all the child chips' destroy events. */
|
|
723
|
+
get chipDestroyedChanges() {
|
|
724
|
+
return this._getChipStream(chip => chip.destroyed);
|
|
725
|
+
}
|
|
726
|
+
/** Combined stream of all the child chips' remove events. */
|
|
727
|
+
get chipRemovedChanges() {
|
|
728
|
+
return this._getChipStream(chip => chip.removed);
|
|
729
|
+
}
|
|
730
|
+
/** Whether the chip set is disabled. */
|
|
731
|
+
get disabled() { return this._disabled; }
|
|
732
|
+
set disabled(value) {
|
|
733
|
+
this._disabled = value;
|
|
734
|
+
this._syncChipsState();
|
|
735
|
+
}
|
|
736
|
+
/** Whether the chip list contains chips or not. */
|
|
737
|
+
get empty() {
|
|
738
|
+
return !this._chips || this._chips.length === 0;
|
|
739
|
+
}
|
|
740
|
+
/** The ARIA role applied to the chip set. */
|
|
741
|
+
get role() {
|
|
742
|
+
if (this._explicitRole) {
|
|
743
|
+
return this._explicitRole;
|
|
744
|
+
}
|
|
745
|
+
return this.empty ? null : this._defaultRole;
|
|
746
|
+
}
|
|
747
|
+
set role(value) {
|
|
748
|
+
this._explicitRole = value;
|
|
749
|
+
}
|
|
750
|
+
/** Whether any of the chips inside this chip-set has focus. */
|
|
751
|
+
get focused() {
|
|
752
|
+
return this._hasFocusedChip();
|
|
753
|
+
}
|
|
754
|
+
constructor() {
|
|
755
|
+
this._elementRef = inject(ElementRef);
|
|
756
|
+
this._changeDetectorRef = inject(ChangeDetectorRef);
|
|
757
|
+
this._dir = inject(Directionality, { optional: true });
|
|
758
|
+
/** Index of the last destroyed chip that had focus. */
|
|
759
|
+
this._lastDestroyedFocusedChipIndex = null;
|
|
760
|
+
/** Subject that emits when the component has been destroyed. */
|
|
761
|
+
this._destroyed = new Subject();
|
|
762
|
+
/** Role to use if it hasn't been overwritten by the user. */
|
|
763
|
+
this._defaultRole = 'presentation';
|
|
764
|
+
this._disabled = false;
|
|
765
|
+
this._explicitRole = null;
|
|
766
|
+
/** Tabindex of the chip set. */
|
|
767
|
+
this.tabIndex = 0;
|
|
768
|
+
/** Flat list of all the actions contained within the chips. */
|
|
769
|
+
this._chipActions = new QueryList();
|
|
770
|
+
}
|
|
771
|
+
ngAfterViewInit() {
|
|
772
|
+
this._setUpFocusManagement();
|
|
773
|
+
this._trackChipSetChanges();
|
|
774
|
+
this._trackDestroyedFocusedChip();
|
|
775
|
+
}
|
|
776
|
+
ngOnDestroy() {
|
|
777
|
+
this._keyManager?.destroy();
|
|
778
|
+
this._chipActions.destroy();
|
|
779
|
+
this._destroyed.next();
|
|
780
|
+
this._destroyed.complete();
|
|
781
|
+
}
|
|
782
|
+
/** Checks whether any of the chips is focused. */
|
|
783
|
+
_hasFocusedChip() {
|
|
784
|
+
return (this._chips && this._chips.some(chip => chip._hasFocus())) || false;
|
|
785
|
+
}
|
|
786
|
+
/** Syncs the chip-set's state with the individual chips. */
|
|
787
|
+
_syncChipsState() {
|
|
788
|
+
if (this._chips) {
|
|
789
|
+
this._chips.forEach(chip => {
|
|
790
|
+
chip._chipListDisabled = this._disabled;
|
|
791
|
+
chip._changeDetectorRef.markForCheck();
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
/** The dummy method for subclasses to override. Base chip set cannot be focused. */
|
|
796
|
+
focus() { }
|
|
797
|
+
/** Handles keyboard events on the chip set. */
|
|
798
|
+
_handleKeydown(event) {
|
|
799
|
+
if (this._originatesFromChip(event)) {
|
|
800
|
+
this._keyManager?.onKeydown(event);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Utility to ensure all indexes are valid.
|
|
805
|
+
*
|
|
806
|
+
* @param index The index to be checked.
|
|
807
|
+
* @returns True if the index is valid for our list of chips.
|
|
808
|
+
*/
|
|
809
|
+
_isValidIndex(index) {
|
|
810
|
+
if (this._chips) {
|
|
811
|
+
return index >= 0 && index < this._chips.length;
|
|
812
|
+
}
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Removes the `tabindex` from the chip set and resets it back afterward, allowing the
|
|
817
|
+
* user to tab out of it. This prevents the set from capturing focus and redirecting
|
|
818
|
+
* it back to the first chip, creating a focus trap if its user tries to tab away.
|
|
819
|
+
*/
|
|
820
|
+
_allowFocusEscape() {
|
|
821
|
+
const previous = this._elementRef.nativeElement.tabIndex;
|
|
822
|
+
if (previous !== -1) {
|
|
823
|
+
// Set the tabindex directly on the element, instead of going through
|
|
824
|
+
// the data binding, because we aren't guaranteed that change detection
|
|
825
|
+
// will run quickly enough to allow focus to escape.
|
|
826
|
+
this._elementRef.nativeElement.tabIndex = -1;
|
|
827
|
+
// Note that this needs to be a `setTimeout`, because a `Promise.resolve`
|
|
828
|
+
// doesn't allow enough time for the focus to escape.
|
|
829
|
+
setTimeout(() => (this._elementRef.nativeElement.tabIndex = previous));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Gets a stream of events from all the chips within the set.
|
|
834
|
+
* The stream will automatically incorporate any newly added chips.
|
|
835
|
+
*/
|
|
836
|
+
_getChipStream(mappingFunction) {
|
|
837
|
+
if (this._chips) {
|
|
838
|
+
return this._chips.changes.pipe(startWith(null), switchMap(() => merge(...this._chips.map(mappingFunction))));
|
|
839
|
+
}
|
|
840
|
+
return EMPTY;
|
|
841
|
+
}
|
|
842
|
+
/** Checks whether an event comes from inside a chip element. */
|
|
843
|
+
_originatesFromChip(event) {
|
|
844
|
+
let currentElement = event.target;
|
|
845
|
+
while (currentElement && currentElement !== this._elementRef.nativeElement) {
|
|
846
|
+
if (currentElement.classList.contains('cute-chip')) {
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
currentElement = currentElement.parentElement;
|
|
850
|
+
}
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
/** Sets up the chip set's focus management logic. */
|
|
854
|
+
_setUpFocusManagement() {
|
|
855
|
+
// Create a flat `QueryList` containing the actions of all the chips.
|
|
856
|
+
// This allows us to navigate both within the chip and move to the next/previous
|
|
857
|
+
// one using the existing `ListKeyManager`.
|
|
858
|
+
this._chips?.changes.pipe(startWith(this._chips)).subscribe((chips) => {
|
|
859
|
+
const actions = [];
|
|
860
|
+
chips.forEach(chip => chip._getActions().forEach(action => actions.push(action)));
|
|
861
|
+
this._chipActions.reset(actions);
|
|
862
|
+
this._chipActions.notifyOnChanges();
|
|
863
|
+
});
|
|
864
|
+
this._keyManager = new FocusKeyManager(this._chipActions)
|
|
865
|
+
.withVerticalOrientation()
|
|
866
|
+
.withHorizontalOrientation(this._dir ? this._dir.value : 'ltr')
|
|
867
|
+
.withHomeAndEnd()
|
|
868
|
+
.skipPredicate(action => this._skipPredicate(action));
|
|
869
|
+
// Keep the manager active index in sync so that navigation picks
|
|
870
|
+
// up from the current chip if the user clicks into the list directly.
|
|
871
|
+
this.chipFocusChanges.pipe(takeUntil(this._destroyed)).subscribe(({ chip }) => {
|
|
872
|
+
const action = chip._getSourceAction(document.activeElement);
|
|
873
|
+
if (action) {
|
|
874
|
+
this._keyManager?.updateActiveItem(action);
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
this._dir?.change
|
|
878
|
+
.pipe(takeUntil(this._destroyed))
|
|
879
|
+
.subscribe(direction => this._keyManager?.withHorizontalOrientation(direction));
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Determines if key manager should avoid putting a given chip action in the tab index. Skip
|
|
883
|
+
* non-interactive and disabled actions since the user can't do anything with them.
|
|
884
|
+
*/
|
|
885
|
+
_skipPredicate(action) {
|
|
886
|
+
// Skip chips that the user cannot interact with.
|
|
887
|
+
// The `cute-chip-set` does not permit focusing on disabled chips.
|
|
888
|
+
return !action.isInteractive || action.disabled;
|
|
889
|
+
}
|
|
890
|
+
/** Listens to changes in the chip set and syncs up the state of the individual chips. */
|
|
891
|
+
_trackChipSetChanges() {
|
|
892
|
+
this._chips?.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
|
|
893
|
+
if (this.disabled) {
|
|
894
|
+
// Since this happens after the content has been
|
|
895
|
+
// checked, we need to defer it to the next tick.
|
|
896
|
+
Promise.resolve().then(() => this._syncChipsState());
|
|
897
|
+
}
|
|
898
|
+
this._redirectDestroyedChipFocus();
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
/** Starts tracking the destroyed chips to capture the focused one. */
|
|
902
|
+
_trackDestroyedFocusedChip() {
|
|
903
|
+
this.chipDestroyedChanges.pipe(takeUntil(this._destroyed)).subscribe((event) => {
|
|
904
|
+
// If the focused chip is destroyed, save its index so that we can move focus to the next
|
|
905
|
+
// chip. We only save the index here, rather than move the focus immediately, because we want
|
|
906
|
+
// to wait until the chip is removed from the chip list before focusing the next one. This
|
|
907
|
+
// allows us to keep focus on the same index if the chip gets swapped out.
|
|
908
|
+
const chipArray = this._chips?.toArray() || [];
|
|
909
|
+
const chipIndex = chipArray.indexOf(event.chip);
|
|
910
|
+
const hasFocus = event.chip._hasFocus();
|
|
911
|
+
const wasLastFocused = event.chip._hadFocusOnRemove &&
|
|
912
|
+
this._keyManager?.activeItem &&
|
|
913
|
+
event.chip._getActions().includes(this._keyManager.activeItem);
|
|
914
|
+
// Note that depending on the timing, the chip might've already lost focus by the
|
|
915
|
+
// time we check this. We need the `wasLastFocused` as a fallback to detect such cases.
|
|
916
|
+
// In `wasLastFocused` we also need to ensure that the chip actually had focus when it was
|
|
917
|
+
// deleted so that we don't steal away the user's focus after they've moved on from the chip.
|
|
918
|
+
const shouldMoveFocus = hasFocus || wasLastFocused;
|
|
919
|
+
if (this._isValidIndex(chipIndex) && shouldMoveFocus) {
|
|
920
|
+
this._lastDestroyedFocusedChipIndex = chipIndex;
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Finds the next appropriate chip to move focus to
|
|
926
|
+
* if the currently focused chip is destroyed.
|
|
927
|
+
*/
|
|
928
|
+
_redirectDestroyedChipFocus() {
|
|
929
|
+
if (this._lastDestroyedFocusedChipIndex == null) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
if (this._chips && this._chips.length) {
|
|
933
|
+
const newIndex = Math.min(this._lastDestroyedFocusedChipIndex, this._chips.length - 1);
|
|
934
|
+
const chipToFocus = this._chips.toArray()[newIndex];
|
|
935
|
+
if (chipToFocus.disabled) {
|
|
936
|
+
// If we're down to one disabled chip, move focus back to the set.
|
|
937
|
+
if (this._chips.length === 1) {
|
|
938
|
+
this.focus();
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
this._keyManager?.setPreviousItemActive();
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
chipToFocus.focus();
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
this.focus();
|
|
950
|
+
}
|
|
951
|
+
this._lastDestroyedFocusedChipIndex = null;
|
|
952
|
+
}
|
|
953
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipSet, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
954
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.15", type: CuteChipSet, isStandalone: true, selector: "cute-chip-set", inputs: { disabled: ["disabled", "disabled", booleanAttribute], role: "role", tabIndex: ["tabIndex", "tabIndex", (value) => (value == null ? 0 : numberAttribute(value))] }, host: { listeners: { "keydown": "_handleKeydown($event)" }, properties: { "attr.role": "role" }, classAttribute: "cute-chip-set" }, queries: [{ propertyName: "_chips", predicate: CuteChip, descendants: true }], ngImport: i0, template: `
|
|
955
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
956
|
+
<ng-content></ng-content>
|
|
957
|
+
</div>
|
|
958
|
+
`, isInline: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
959
|
+
}
|
|
960
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipSet, decorators: [{
|
|
961
|
+
type: Component,
|
|
962
|
+
args: [{ selector: 'cute-chip-set', template: `
|
|
963
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
964
|
+
<ng-content></ng-content>
|
|
965
|
+
</div>
|
|
966
|
+
`, host: {
|
|
967
|
+
'class': 'cute-chip-set',
|
|
968
|
+
'(keydown)': '_handleKeydown($event)',
|
|
969
|
+
'[attr.role]': 'role',
|
|
970
|
+
}, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"] }]
|
|
971
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{
|
|
972
|
+
type: Input,
|
|
973
|
+
args: [{ transform: booleanAttribute }]
|
|
974
|
+
}], role: [{
|
|
975
|
+
type: Input
|
|
976
|
+
}], tabIndex: [{
|
|
977
|
+
type: Input,
|
|
978
|
+
args: [{
|
|
979
|
+
transform: (value) => (value == null ? 0 : numberAttribute(value)),
|
|
980
|
+
}]
|
|
981
|
+
}], _chips: [{
|
|
982
|
+
type: ContentChildren,
|
|
983
|
+
args: [CuteChip, {
|
|
984
|
+
// We need to use `descendants: true`, because Ivy will no longer match
|
|
985
|
+
// indirect descendants if it's left as false.
|
|
986
|
+
descendants: true,
|
|
987
|
+
}]
|
|
988
|
+
}] } });
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* @license Apache-2.0
|
|
992
|
+
*
|
|
993
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
994
|
+
*
|
|
995
|
+
* You may not use this file except in compliance with the License
|
|
996
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
997
|
+
*
|
|
998
|
+
* This code is a modification of the `@angular/material` original
|
|
999
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
1000
|
+
*/
|
|
1001
|
+
/** Change event object that is emitted when the chip grid value has changed. */
|
|
1002
|
+
class CuteChipGridChange {
|
|
1003
|
+
constructor(
|
|
1004
|
+
/** Chip grid that emitted the event. */
|
|
1005
|
+
source,
|
|
1006
|
+
/** Value of the chip grid when the event was emitted. */
|
|
1007
|
+
value) {
|
|
1008
|
+
this.source = source;
|
|
1009
|
+
this.value = value;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* An extension of the CuteChipSet component used with CuteChipRow chips and
|
|
1014
|
+
* the cuteChipInputFor directive.
|
|
1015
|
+
*/
|
|
1016
|
+
class CuteChipGrid extends CuteChipSet {
|
|
1017
|
+
/**
|
|
1018
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1019
|
+
* @docs-private
|
|
1020
|
+
*/
|
|
1021
|
+
get disabled() {
|
|
1022
|
+
return this.ngControl ? !!this.ngControl.disabled : this._disabled;
|
|
1023
|
+
}
|
|
1024
|
+
set disabled(value) {
|
|
1025
|
+
this._disabled = value;
|
|
1026
|
+
this._syncChipsState();
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1030
|
+
* @docs-private
|
|
1031
|
+
*/
|
|
1032
|
+
get id() {
|
|
1033
|
+
return this._chipInput?.id || "";
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1037
|
+
* @docs-private
|
|
1038
|
+
*/
|
|
1039
|
+
get empty() {
|
|
1040
|
+
return ((!this._chipInput || this._chipInput.empty) && (!this._chips || this._chips.length === 0));
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1044
|
+
* @docs-private
|
|
1045
|
+
*/
|
|
1046
|
+
get placeholder() {
|
|
1047
|
+
return (this._chipInput ? this._chipInput.placeholder : this._placeholder) || "";
|
|
1048
|
+
}
|
|
1049
|
+
set placeholder(value) {
|
|
1050
|
+
this._placeholder = value;
|
|
1051
|
+
this.stateChanges.next();
|
|
1052
|
+
}
|
|
1053
|
+
/** Whether any chips or the `cuteChipInput` inside this <chip-grid> has focus. */
|
|
1054
|
+
get focused() {
|
|
1055
|
+
return this._chipInput?.focused || this._hasFocusedChip();
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1059
|
+
* @docs-private
|
|
1060
|
+
*/
|
|
1061
|
+
get required() {
|
|
1062
|
+
return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
|
|
1063
|
+
}
|
|
1064
|
+
set required(value) {
|
|
1065
|
+
this._required = value;
|
|
1066
|
+
this.stateChanges.next();
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1070
|
+
* @docs-private
|
|
1071
|
+
*/
|
|
1072
|
+
get shouldLabelFloat() {
|
|
1073
|
+
return !this.empty || this.focused;
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1077
|
+
* @docs-private
|
|
1078
|
+
*/
|
|
1079
|
+
get value() { return this._value; }
|
|
1080
|
+
set value(value) { this._value = value; }
|
|
1081
|
+
/** An object used to control when error messages are shown. */
|
|
1082
|
+
get errorStateMatcher() { return this._errorStateTracker.matcher; }
|
|
1083
|
+
set errorStateMatcher(value) {
|
|
1084
|
+
this._errorStateTracker.matcher = value;
|
|
1085
|
+
}
|
|
1086
|
+
/** Combined stream of all of the child chips' blur events. */
|
|
1087
|
+
get chipBlurChanges() {
|
|
1088
|
+
return this._getChipStream(chip => chip._onBlur);
|
|
1089
|
+
}
|
|
1090
|
+
/** Whether the chip grid is in an error state. */
|
|
1091
|
+
get errorState() { return this._errorStateTracker.errorState; }
|
|
1092
|
+
set errorState(value) {
|
|
1093
|
+
this._errorStateTracker.errorState = value;
|
|
1094
|
+
}
|
|
1095
|
+
get controlElementRef() {
|
|
1096
|
+
return this._elementRef;
|
|
1097
|
+
}
|
|
1098
|
+
constructor() {
|
|
1099
|
+
super();
|
|
1100
|
+
this.ngControl = inject(NgControl, { optional: true, self: true });
|
|
1101
|
+
/**
|
|
1102
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1103
|
+
* @docs-private
|
|
1104
|
+
*/
|
|
1105
|
+
this.controlType = 'cute-chip-grid';
|
|
1106
|
+
this._defaultRole = 'grid';
|
|
1107
|
+
/**
|
|
1108
|
+
* List of element ids to propagate to the chipInput's `aria-describedby` attribute.
|
|
1109
|
+
*/
|
|
1110
|
+
this._ariaDescribedbyIds = [];
|
|
1111
|
+
/**
|
|
1112
|
+
* Function when touched. Set as part of ControlValueAccessor implementation.
|
|
1113
|
+
* @docs-private
|
|
1114
|
+
*/
|
|
1115
|
+
this._onTouched = () => { };
|
|
1116
|
+
/**
|
|
1117
|
+
* Function when changed. Set as part of ControlValueAccessor implementation.
|
|
1118
|
+
* @docs-private
|
|
1119
|
+
*/
|
|
1120
|
+
this._onChange = () => { };
|
|
1121
|
+
this._value = [];
|
|
1122
|
+
/** Emits when the user has changed the chip grid value. */
|
|
1123
|
+
this.change = new EventEmitter();
|
|
1124
|
+
/**
|
|
1125
|
+
* Emits whenever the raw value of the <chip-grid> changes. This is here primarily
|
|
1126
|
+
* to facilitate the two-way binding for the `value` input.
|
|
1127
|
+
*/
|
|
1128
|
+
this.valueChange = new EventEmitter();
|
|
1129
|
+
this._chips = undefined;
|
|
1130
|
+
/**
|
|
1131
|
+
* Emits whenever the component state changes and should cause the parent
|
|
1132
|
+
* form-field to update. Implemented as part of `CuteFormFieldControl`.
|
|
1133
|
+
*/
|
|
1134
|
+
this.stateChanges = new Subject();
|
|
1135
|
+
const parentForm = inject(NgForm, { optional: true });
|
|
1136
|
+
const parentFormGroup = inject(FormGroupDirective, { optional: true });
|
|
1137
|
+
const defaultErrorStateMatcher = inject(ErrorStateMatcher);
|
|
1138
|
+
if (this.ngControl) {
|
|
1139
|
+
this.ngControl.valueAccessor = this;
|
|
1140
|
+
}
|
|
1141
|
+
this._errorStateTracker = new _ErrorStateTracker(defaultErrorStateMatcher, this.ngControl, parentFormGroup, parentForm, this.stateChanges);
|
|
1142
|
+
}
|
|
1143
|
+
ngAfterContentInit() {
|
|
1144
|
+
this.chipBlurChanges.pipe(takeUntil(this._destroyed)).subscribe(() => {
|
|
1145
|
+
this._blur();
|
|
1146
|
+
this.stateChanges.next();
|
|
1147
|
+
});
|
|
1148
|
+
merge(this.chipFocusChanges, this._chips.changes)
|
|
1149
|
+
.pipe(takeUntil(this._destroyed))
|
|
1150
|
+
.subscribe(() => this.stateChanges.next());
|
|
1151
|
+
}
|
|
1152
|
+
ngAfterViewInit() {
|
|
1153
|
+
super.ngAfterViewInit();
|
|
1154
|
+
if (!this._chipInput && isDevMode()) {
|
|
1155
|
+
throw Error('cute-chip-grid must be used in combination with cuteChipInputFor.');
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
ngDoCheck() {
|
|
1159
|
+
if (this.ngControl) {
|
|
1160
|
+
// We need to re-evaluate this on every change detection cycle, because there are some
|
|
1161
|
+
// error triggers that we can't subscribe to (e.g. parent form submissions). This means
|
|
1162
|
+
// that whatever logic is in here has to be super lean, or we risk destroying the performance.
|
|
1163
|
+
this.updateErrorState();
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
ngOnDestroy() {
|
|
1167
|
+
super.ngOnDestroy();
|
|
1168
|
+
this.stateChanges.complete();
|
|
1169
|
+
}
|
|
1170
|
+
/** Associates an HTML input element with this chip grid. */
|
|
1171
|
+
registerInput(inputElement) {
|
|
1172
|
+
this._chipInput = inputElement;
|
|
1173
|
+
this._chipInput.setDescribedByIds(this._ariaDescribedbyIds);
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1177
|
+
*/
|
|
1178
|
+
onContainerClick(event) {
|
|
1179
|
+
if (!this.disabled && !this._originatesFromChip(event)) {
|
|
1180
|
+
this.focus();
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
_toggleFocusedStyle(force) {
|
|
1184
|
+
if (this._elementRef.nativeElement.classList.contains("input-group-text")) {
|
|
1185
|
+
this._elementRef.nativeElement.classList.toggle("cute-chip-grid-focused", force);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Focuses the first chip in this chip grid, or the associated input when there
|
|
1190
|
+
* are no eligible chips.
|
|
1191
|
+
*/
|
|
1192
|
+
focus() {
|
|
1193
|
+
if (this.disabled || this._chipInput?.focused) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (!this._chips.length || this._chips.first.disabled) {
|
|
1197
|
+
// Delay until the next tick, because this can cause a "changed after checked"
|
|
1198
|
+
// error if the input does something on focus (e.g., opens an autocomplete).
|
|
1199
|
+
Promise.resolve().then(() => this._chipInput?.focus());
|
|
1200
|
+
}
|
|
1201
|
+
else {
|
|
1202
|
+
const activeItem = this._keyManager?.activeItem;
|
|
1203
|
+
if (activeItem) {
|
|
1204
|
+
activeItem.focus();
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
this._keyManager?.setFirstItemActive();
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
this.stateChanges.next();
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Implemented as part of CuteFormFieldControl.
|
|
1214
|
+
*/
|
|
1215
|
+
setDescribedByIds(ids) {
|
|
1216
|
+
// We must keep this up to date to handle the case where ids are set
|
|
1217
|
+
// before the chip input is registered.
|
|
1218
|
+
this._ariaDescribedbyIds = ids;
|
|
1219
|
+
this._chipInput?.setDescribedByIds(ids);
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Implemented as part of ControlValueAccessor.
|
|
1223
|
+
*/
|
|
1224
|
+
writeValue(value) {
|
|
1225
|
+
// The user is responsible for creating the child chips, so we just store the value.
|
|
1226
|
+
this._value = value;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Implemented as part of ControlValueAccessor.
|
|
1230
|
+
*/
|
|
1231
|
+
registerOnChange(fn) {
|
|
1232
|
+
this._onChange = fn;
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Implemented as part of ControlValueAccessor.
|
|
1236
|
+
*/
|
|
1237
|
+
registerOnTouched(fn) {
|
|
1238
|
+
this._onTouched = fn;
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Implemented as part of ControlValueAccessor.
|
|
1242
|
+
*/
|
|
1243
|
+
setDisabledState(isDisabled) {
|
|
1244
|
+
this.disabled = isDisabled;
|
|
1245
|
+
this.stateChanges.next();
|
|
1246
|
+
}
|
|
1247
|
+
/** Refreshes the error state of the chip grid. */
|
|
1248
|
+
updateErrorState() {
|
|
1249
|
+
this._errorStateTracker.updateErrorState();
|
|
1250
|
+
}
|
|
1251
|
+
/** When blurred, mark the field as touched when focus moved outside the chip grid. */
|
|
1252
|
+
_blur() {
|
|
1253
|
+
if (!this.disabled) {
|
|
1254
|
+
this._toggleFocusedStyle(false);
|
|
1255
|
+
// Check whether the focus moved to chip input.
|
|
1256
|
+
// If the focus is not moved to chip input, mark the field as touched. If the focus moved
|
|
1257
|
+
// to chip input, do nothing.
|
|
1258
|
+
// Timeout is needed to wait for the focus() event trigger on chip input.
|
|
1259
|
+
setTimeout(() => {
|
|
1260
|
+
if (!this.focused) {
|
|
1261
|
+
this._propagateChanges();
|
|
1262
|
+
this._markAsTouched();
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* Removes the `tabindex` from the chip grid and resets it back afterward, allowing the
|
|
1269
|
+
* user to tab out of it. This prevents the grid from capturing focus and redirecting
|
|
1270
|
+
* it back to the first chip, creating a focus trap if its user tries to tab away.
|
|
1271
|
+
*/
|
|
1272
|
+
_allowFocusEscape() {
|
|
1273
|
+
if (!this._chipInput?.focused) {
|
|
1274
|
+
super._allowFocusEscape();
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/** Handles custom keyboard events. */
|
|
1278
|
+
_handleKeydown(event) {
|
|
1279
|
+
if (event.keyCode === TAB) {
|
|
1280
|
+
if (this._chipInput?.focused &&
|
|
1281
|
+
hasModifierKey(event, 'shiftKey') &&
|
|
1282
|
+
this._chips.length &&
|
|
1283
|
+
!this._chips.last.disabled) {
|
|
1284
|
+
event.preventDefault();
|
|
1285
|
+
if (this._keyManager?.activeItem) {
|
|
1286
|
+
this._keyManager?.setActiveItem(this._keyManager.activeItem);
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
this._focusLastChip();
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
else {
|
|
1293
|
+
// Use the super method here since it doesn't check for the input
|
|
1294
|
+
// focused state. This allows focus to escape if there's only one
|
|
1295
|
+
// disabled chip left in the list.
|
|
1296
|
+
super._allowFocusEscape();
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
else if (!this._chipInput?.focused) {
|
|
1300
|
+
super._handleKeydown(event);
|
|
1301
|
+
}
|
|
1302
|
+
this.stateChanges.next();
|
|
1303
|
+
}
|
|
1304
|
+
_focusLastChip() {
|
|
1305
|
+
if (this._chips.length) {
|
|
1306
|
+
this._chips.last.focus();
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
/** Emits change event to set the model value. */
|
|
1310
|
+
_propagateChanges() {
|
|
1311
|
+
const valueToEmit = this._chips.length ? this._chips.toArray().map(chip => chip.value) : [];
|
|
1312
|
+
this._value = valueToEmit;
|
|
1313
|
+
this.change.emit(new CuteChipGridChange(this, valueToEmit));
|
|
1314
|
+
this.valueChange.emit(valueToEmit);
|
|
1315
|
+
this._onChange(valueToEmit);
|
|
1316
|
+
this._changeDetectorRef.markForCheck();
|
|
1317
|
+
}
|
|
1318
|
+
/** Mark the field as touched */
|
|
1319
|
+
_markAsTouched() {
|
|
1320
|
+
this._onTouched();
|
|
1321
|
+
this._changeDetectorRef.markForCheck();
|
|
1322
|
+
this.stateChanges.next();
|
|
1323
|
+
}
|
|
1324
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipGrid, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1325
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.15", type: CuteChipGrid, isStandalone: true, selector: "cute-chip-grid", inputs: { disabled: ["disabled", "disabled", booleanAttribute], placeholder: "placeholder", required: ["required", "required", booleanAttribute], value: "value", errorStateMatcher: "errorStateMatcher" }, outputs: { change: "change", valueChange: "valueChange" }, host: { listeners: { "focus": "focus()", "blur": "_blur()" }, properties: { "attr.role": "role", "attr.tabindex": "(disabled || (_chips && _chips.length === 0)) ? -1 : tabIndex", "attr.aria-disabled": "disabled", "attr.aria-invalid": "errorState", "class.cute-chip-list-disabled": "disabled", "class.cute-chip-list-invalid": "errorState", "class.cute-chip-list-required": "required" }, classAttribute: "cute-chip-grid input-group-text" }, providers: [{ provide: CuteFormFieldControl, useExisting: CuteChipGrid }], queries: [{ propertyName: "_chips", predicate: CuteChipRow, descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1326
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
1327
|
+
<ng-content></ng-content>
|
|
1328
|
+
</div>
|
|
1329
|
+
`, isInline: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1330
|
+
}
|
|
1331
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipGrid, decorators: [{
|
|
1332
|
+
type: Component,
|
|
1333
|
+
args: [{ selector: 'cute-chip-grid', template: `
|
|
1334
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
1335
|
+
<ng-content></ng-content>
|
|
1336
|
+
</div>
|
|
1337
|
+
`, host: {
|
|
1338
|
+
'class': 'cute-chip-grid input-group-text',
|
|
1339
|
+
'[attr.role]': 'role',
|
|
1340
|
+
'[attr.tabindex]': '(disabled || (_chips && _chips.length === 0)) ? -1 : tabIndex',
|
|
1341
|
+
'[attr.aria-disabled]': 'disabled',
|
|
1342
|
+
'[attr.aria-invalid]': 'errorState',
|
|
1343
|
+
'[class.cute-chip-list-disabled]': 'disabled',
|
|
1344
|
+
'[class.cute-chip-list-invalid]': 'errorState',
|
|
1345
|
+
'[class.cute-chip-list-required]': 'required',
|
|
1346
|
+
'(focus)': 'focus()',
|
|
1347
|
+
'(blur)': '_blur()',
|
|
1348
|
+
}, providers: [{ provide: CuteFormFieldControl, useExisting: CuteChipGrid }], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"] }]
|
|
1349
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{
|
|
1350
|
+
type: Input,
|
|
1351
|
+
args: [{ transform: booleanAttribute }]
|
|
1352
|
+
}], placeholder: [{
|
|
1353
|
+
type: Input
|
|
1354
|
+
}], required: [{
|
|
1355
|
+
type: Input,
|
|
1356
|
+
args: [{ transform: booleanAttribute }]
|
|
1357
|
+
}], value: [{
|
|
1358
|
+
type: Input
|
|
1359
|
+
}], errorStateMatcher: [{
|
|
1360
|
+
type: Input
|
|
1361
|
+
}], change: [{
|
|
1362
|
+
type: Output
|
|
1363
|
+
}], valueChange: [{
|
|
1364
|
+
type: Output
|
|
1365
|
+
}], _chips: [{
|
|
1366
|
+
type: ContentChildren,
|
|
1367
|
+
args: [CuteChipRow, {
|
|
1368
|
+
// We need to use `descendants: true`, because Ivy will no longer match
|
|
1369
|
+
// indirect descendants if it's left as false.
|
|
1370
|
+
descendants: true,
|
|
1371
|
+
}]
|
|
1372
|
+
}] } });
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* @license Apache-2.0
|
|
1376
|
+
*
|
|
1377
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
1378
|
+
*
|
|
1379
|
+
* You may not use this file except in compliance with the License
|
|
1380
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
1381
|
+
*
|
|
1382
|
+
* This code is a modification of the `@angular/material` original
|
|
1383
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
1384
|
+
*/
|
|
1385
|
+
/** Avatar image within a chip. */
|
|
1386
|
+
class CuteChipAvatar {
|
|
1387
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipAvatar, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1388
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteChipAvatar, isStandalone: true, selector: "cute-chip-avatar, [cuteChipAvatar]", host: { attributes: { "role": "img" }, classAttribute: "cute-chip-avatar cute-chip__icon cute-chip__icon--primary" }, providers: [{ provide: CUTE_CHIP_AVATAR, useExisting: CuteChipAvatar }], ngImport: i0 }); }
|
|
1389
|
+
}
|
|
1390
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipAvatar, decorators: [{
|
|
1391
|
+
type: Directive,
|
|
1392
|
+
args: [{
|
|
1393
|
+
selector: 'cute-chip-avatar, [cuteChipAvatar]',
|
|
1394
|
+
host: {
|
|
1395
|
+
'class': 'cute-chip-avatar cute-chip__icon cute-chip__icon--primary',
|
|
1396
|
+
'role': 'img',
|
|
1397
|
+
},
|
|
1398
|
+
providers: [{ provide: CUTE_CHIP_AVATAR, useExisting: CuteChipAvatar }],
|
|
1399
|
+
standalone: true,
|
|
1400
|
+
}]
|
|
1401
|
+
}] });
|
|
1402
|
+
/** Non-interactive trailing icon in a chip. */
|
|
1403
|
+
class CuteChipTrailingIcon extends CuteChipAction {
|
|
1404
|
+
constructor() {
|
|
1405
|
+
super(...arguments);
|
|
1406
|
+
/**
|
|
1407
|
+
* MDC considers all trailing actions as a remove icon,
|
|
1408
|
+
* but we support non-interactive trailing icons.
|
|
1409
|
+
*/
|
|
1410
|
+
this.isInteractive = false;
|
|
1411
|
+
this._isPrimary = false;
|
|
1412
|
+
}
|
|
1413
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipTrailingIcon, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1414
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteChipTrailingIcon, isStandalone: true, selector: "cute-chip-trailing-icon, [cuteChipTrailingIcon]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "cute-chip-trailing-icon cute-chip__icon cute-chip__icon--trailing" }, providers: [{ provide: CUTE_CHIP_TRAILING_ICON, useExisting: CuteChipTrailingIcon }], usesInheritance: true, ngImport: i0 }); }
|
|
1415
|
+
}
|
|
1416
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipTrailingIcon, decorators: [{
|
|
1417
|
+
type: Directive,
|
|
1418
|
+
args: [{
|
|
1419
|
+
selector: 'cute-chip-trailing-icon, [cuteChipTrailingIcon]',
|
|
1420
|
+
host: {
|
|
1421
|
+
'class': 'cute-chip-trailing-icon cute-chip__icon cute-chip__icon--trailing',
|
|
1422
|
+
'aria-hidden': 'true',
|
|
1423
|
+
},
|
|
1424
|
+
providers: [{ provide: CUTE_CHIP_TRAILING_ICON, useExisting: CuteChipTrailingIcon }],
|
|
1425
|
+
standalone: true,
|
|
1426
|
+
}]
|
|
1427
|
+
}] });
|
|
1428
|
+
/**
|
|
1429
|
+
* Directive to edit the parent chip when the leading action icon is clicked or
|
|
1430
|
+
* when the ENTER key is pressed on it.
|
|
1431
|
+
*
|
|
1432
|
+
* Recommended for use with the Material Design "edit" icon
|
|
1433
|
+
* available at https://material.io/icons/#ic_edit.
|
|
1434
|
+
*
|
|
1435
|
+
* Example:
|
|
1436
|
+
*
|
|
1437
|
+
* ```
|
|
1438
|
+
* <cute-chip>
|
|
1439
|
+
* <button cuteChipEdit aria-label="Edit">
|
|
1440
|
+
* <cute-icon>edit</cute-icon>
|
|
1441
|
+
* </button>
|
|
1442
|
+
* </cute-chip>
|
|
1443
|
+
* ```
|
|
1444
|
+
*/
|
|
1445
|
+
class CuteChipEdit extends CuteChipAction {
|
|
1446
|
+
constructor() {
|
|
1447
|
+
super(...arguments);
|
|
1448
|
+
this._isPrimary = false;
|
|
1449
|
+
this._isLeading = true;
|
|
1450
|
+
}
|
|
1451
|
+
_handleClick(event) {
|
|
1452
|
+
if (!this.disabled) {
|
|
1453
|
+
event.stopPropagation();
|
|
1454
|
+
event.preventDefault();
|
|
1455
|
+
this._parentChip._edit();
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
_handleKeydown(event) {
|
|
1459
|
+
if ((event.keyCode === ENTER || event.keyCode === SPACE) && !this.disabled) {
|
|
1460
|
+
event.stopPropagation();
|
|
1461
|
+
event.preventDefault();
|
|
1462
|
+
this._parentChip._edit();
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipEdit, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1466
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteChipEdit, isStandalone: true, selector: "[cuteChipEdit]", host: { attributes: { "role": "button" }, properties: { "attr.aria-hidden": "null" }, classAttribute: "cute-chip-edit cute-chip-avatar cute-focus-indicator cute-chip__icon cute-chip__icon--primary" }, providers: [{ provide: CUTE_CHIP_EDIT, useExisting: CuteChipEdit }], usesInheritance: true, ngImport: i0 }); }
|
|
1467
|
+
}
|
|
1468
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipEdit, decorators: [{
|
|
1469
|
+
type: Directive,
|
|
1470
|
+
args: [{
|
|
1471
|
+
selector: '[cuteChipEdit]',
|
|
1472
|
+
host: {
|
|
1473
|
+
'class': 'cute-chip-edit cute-chip-avatar cute-focus-indicator ' +
|
|
1474
|
+
'cute-chip__icon cute-chip__icon--primary',
|
|
1475
|
+
'role': 'button',
|
|
1476
|
+
'[attr.aria-hidden]': 'null',
|
|
1477
|
+
},
|
|
1478
|
+
providers: [{ provide: CUTE_CHIP_EDIT, useExisting: CuteChipEdit }],
|
|
1479
|
+
}]
|
|
1480
|
+
}] });
|
|
1481
|
+
/**
|
|
1482
|
+
* Directive to remove the parent chip when the trailing icon is clicked or
|
|
1483
|
+
* when the ENTER key is pressed on it.
|
|
1484
|
+
*
|
|
1485
|
+
* Recommended for use with the Material Design "cancel" icon
|
|
1486
|
+
* available at https://material.io/icons/#ic_cancel.
|
|
1487
|
+
*
|
|
1488
|
+
* Example:
|
|
1489
|
+
*
|
|
1490
|
+
* ```
|
|
1491
|
+
* <cute-chip>
|
|
1492
|
+
* <cute-icon cuteChipRemove>cancel</cute-icon>
|
|
1493
|
+
* </cute-chip>
|
|
1494
|
+
* ```
|
|
1495
|
+
*/
|
|
1496
|
+
class CuteChipRemove extends CuteChipAction {
|
|
1497
|
+
constructor() {
|
|
1498
|
+
super(...arguments);
|
|
1499
|
+
this._isPrimary = false;
|
|
1500
|
+
}
|
|
1501
|
+
_handleClick(event) {
|
|
1502
|
+
if (!this.disabled) {
|
|
1503
|
+
event.stopPropagation();
|
|
1504
|
+
event.preventDefault();
|
|
1505
|
+
this._parentChip.remove();
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
_handleKeydown(event) {
|
|
1509
|
+
if ((event.keyCode === ENTER || event.keyCode === SPACE) && !this.disabled) {
|
|
1510
|
+
event.stopPropagation();
|
|
1511
|
+
event.preventDefault();
|
|
1512
|
+
this._parentChip.remove();
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipRemove, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1516
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteChipRemove, isStandalone: true, selector: "[cuteChipRemove]", host: { attributes: { "role": "button" }, properties: { "attr.aria-hidden": "null" }, classAttribute: "cute-chip-remove cute-chip-trailing-icon cute-focus-indicator cute-chip__icon cute-chip__icon--trailing cute-chip__action" }, providers: [{ provide: CUTE_CHIP_REMOVE, useExisting: CuteChipRemove }], usesInheritance: true, ngImport: i0 }); }
|
|
1517
|
+
}
|
|
1518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipRemove, decorators: [{
|
|
1519
|
+
type: Directive,
|
|
1520
|
+
args: [{
|
|
1521
|
+
selector: '[cuteChipRemove]',
|
|
1522
|
+
host: {
|
|
1523
|
+
'class': 'cute-chip-remove cute-chip-trailing-icon cute-focus-indicator ' +
|
|
1524
|
+
'cute-chip__icon cute-chip__icon--trailing cute-chip__action',
|
|
1525
|
+
'role': 'button',
|
|
1526
|
+
'[attr.aria-hidden]': 'null',
|
|
1527
|
+
},
|
|
1528
|
+
providers: [{ provide: CUTE_CHIP_REMOVE, useExisting: CuteChipRemove }],
|
|
1529
|
+
standalone: true,
|
|
1530
|
+
}]
|
|
1531
|
+
}] });
|
|
1532
|
+
|
|
1533
|
+
/**
|
|
1534
|
+
* @license Apache-2.0
|
|
1535
|
+
*
|
|
1536
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
1537
|
+
*
|
|
1538
|
+
* You may not use this file except in compliance with the License
|
|
1539
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
1540
|
+
*
|
|
1541
|
+
* This code is a modification of the `@angular/material` original
|
|
1542
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
1543
|
+
*/
|
|
1544
|
+
// Increasing integer for generating unique ids.
|
|
1545
|
+
let nextUniqueId = 0;
|
|
1546
|
+
/**
|
|
1547
|
+
* Directive that adds chip-specific behaviors to an input element inside `<cute-form-field>`.
|
|
1548
|
+
* May be placed inside or outside a `<cute-chip-grid>`.
|
|
1549
|
+
*/
|
|
1550
|
+
class CuteChipInput {
|
|
1551
|
+
/** Register input for a chip list */
|
|
1552
|
+
get chipGrid() { return this._chipGrid; }
|
|
1553
|
+
set chipGrid(value) {
|
|
1554
|
+
if (value) {
|
|
1555
|
+
this._chipGrid = value;
|
|
1556
|
+
this._chipGrid.registerInput(this);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
/** Whether the input is disabled. */
|
|
1560
|
+
get disabled() {
|
|
1561
|
+
return (this._disabled || (this._chipGrid && this._chipGrid.disabled)) ?? false;
|
|
1562
|
+
}
|
|
1563
|
+
set disabled(value) {
|
|
1564
|
+
this._disabled = value;
|
|
1565
|
+
}
|
|
1566
|
+
/** Whether the input is empty. */
|
|
1567
|
+
get empty() {
|
|
1568
|
+
return !this.inputElement.value;
|
|
1569
|
+
}
|
|
1570
|
+
constructor() {
|
|
1571
|
+
this._elementRef = inject(ElementRef);
|
|
1572
|
+
/** Used to prevent focus moving to chips while user is holding backspace */
|
|
1573
|
+
this._focusLastChipOnBackspace = false;
|
|
1574
|
+
/** Whether the control is focused. */
|
|
1575
|
+
this.focused = false;
|
|
1576
|
+
/**
|
|
1577
|
+
* Whether the `chipEnd` event will be emitted when the input is blurred.
|
|
1578
|
+
*/
|
|
1579
|
+
this.addOnBlur = false;
|
|
1580
|
+
/** Emitted when a chip is to be added. */
|
|
1581
|
+
this.chipEnd = new EventEmitter();
|
|
1582
|
+
/** The input's placeholder text. */
|
|
1583
|
+
this.placeholder = '';
|
|
1584
|
+
/** Unique id for the input. */
|
|
1585
|
+
this.id = `cute-chip-list-input-${nextUniqueId++}`;
|
|
1586
|
+
this._disabled = false;
|
|
1587
|
+
/** Whether the input is readonly. */
|
|
1588
|
+
this.readonly = false;
|
|
1589
|
+
/** Whether the input should remain interactive when it is disabled. */
|
|
1590
|
+
this.disabledInteractive = false;
|
|
1591
|
+
const defaultOptions = inject(CUTE_CHIPS_DEFAULT_OPTIONS);
|
|
1592
|
+
const formField = inject(CUTE_FORM_FIELD, { optional: true });
|
|
1593
|
+
this.inputElement = this._elementRef.nativeElement;
|
|
1594
|
+
this.separatorKeyCodes = defaultOptions.separatorKeyCodes;
|
|
1595
|
+
this.disabledInteractive = defaultOptions.inputDisabledInteractive ?? false;
|
|
1596
|
+
if (formField) {
|
|
1597
|
+
this.inputElement.classList.add('cute-form-field-input-control');
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
ngOnChanges() {
|
|
1601
|
+
this._chipGrid?.stateChanges.next();
|
|
1602
|
+
}
|
|
1603
|
+
ngOnDestroy() {
|
|
1604
|
+
this.chipEnd.complete();
|
|
1605
|
+
}
|
|
1606
|
+
/** Utility method to make host definition/tests more clear. */
|
|
1607
|
+
_keydown(event) {
|
|
1608
|
+
if (this.empty && event.keyCode === BACKSPACE) {
|
|
1609
|
+
// Ignore events where the user is holding down backspace
|
|
1610
|
+
// so that we don't accidentally remove too many chips.
|
|
1611
|
+
if (!event.repeat) {
|
|
1612
|
+
this._chipGrid?._focusLastChip();
|
|
1613
|
+
}
|
|
1614
|
+
event.preventDefault();
|
|
1615
|
+
}
|
|
1616
|
+
else {
|
|
1617
|
+
this._emitChipEnd(event);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
/** Checks to see if the blur should emit the (chipEnd) event. */
|
|
1621
|
+
_blur() {
|
|
1622
|
+
if (this.addOnBlur) {
|
|
1623
|
+
this._emitChipEnd();
|
|
1624
|
+
}
|
|
1625
|
+
this.focused = false;
|
|
1626
|
+
// Blur the chip list if it is not focused
|
|
1627
|
+
if (this._chipGrid) {
|
|
1628
|
+
if (!this._chipGrid.focused) {
|
|
1629
|
+
this._chipGrid._blur();
|
|
1630
|
+
}
|
|
1631
|
+
this._chipGrid.stateChanges.next();
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
_focus() {
|
|
1635
|
+
this.focused = true;
|
|
1636
|
+
this._focusLastChipOnBackspace = this.empty;
|
|
1637
|
+
this._chipGrid?._toggleFocusedStyle(true);
|
|
1638
|
+
this._chipGrid?.stateChanges.next();
|
|
1639
|
+
}
|
|
1640
|
+
/** Checks to see if the (chipEnd) event needs to be emitted. */
|
|
1641
|
+
_emitChipEnd(event) {
|
|
1642
|
+
if (!event || this._isSeparatorKey(event)) {
|
|
1643
|
+
this.chipEnd.emit({
|
|
1644
|
+
input: this.inputElement,
|
|
1645
|
+
value: this.inputElement.value,
|
|
1646
|
+
chipInput: this,
|
|
1647
|
+
});
|
|
1648
|
+
event?.preventDefault();
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
_onInput() {
|
|
1652
|
+
// Let the chip list know whenever the value changes.
|
|
1653
|
+
this._chipGrid?.stateChanges.next();
|
|
1654
|
+
}
|
|
1655
|
+
/** Focuses the input. */
|
|
1656
|
+
focus() {
|
|
1657
|
+
this.inputElement.focus();
|
|
1658
|
+
}
|
|
1659
|
+
/** Clears the input */
|
|
1660
|
+
clear() {
|
|
1661
|
+
this.inputElement.value = '';
|
|
1662
|
+
this._focusLastChipOnBackspace = true;
|
|
1663
|
+
}
|
|
1664
|
+
setDescribedByIds(ids) {
|
|
1665
|
+
const element = this._elementRef.nativeElement;
|
|
1666
|
+
// Set the value directly in the DOM since this binding
|
|
1667
|
+
// is prone to "changed after checked" errors.
|
|
1668
|
+
if (ids.length) {
|
|
1669
|
+
element.setAttribute('aria-describedby', ids.join(' '));
|
|
1670
|
+
}
|
|
1671
|
+
else {
|
|
1672
|
+
element.removeAttribute('aria-describedby');
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
/** Checks whether a keycode is one of the configured separators. */
|
|
1676
|
+
_isSeparatorKey(event) {
|
|
1677
|
+
return !hasModifierKey(event) && new Set(this.separatorKeyCodes).has(event.keyCode);
|
|
1678
|
+
}
|
|
1679
|
+
/** Gets the value to set on the `readonly` attribute. */
|
|
1680
|
+
_getReadonlyAttribute() {
|
|
1681
|
+
return this.readonly || (this.disabled && this.disabledInteractive) ? 'true' : null;
|
|
1682
|
+
}
|
|
1683
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1684
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.15", type: CuteChipInput, isStandalone: true, selector: "input[cuteChipInputFor]", inputs: { chipGrid: ["cuteChipInputFor", "chipGrid"], addOnBlur: ["cuteChipInputAddOnBlur", "addOnBlur", booleanAttribute], separatorKeyCodes: ["cuteChipInputSeparatorKeyCodes", "separatorKeyCodes"], placeholder: "placeholder", id: "id", disabled: ["disabled", "disabled", booleanAttribute], readonly: ["readonly", "readonly", booleanAttribute], disabledInteractive: ["cuteChipInputDisabledInteractive", "disabledInteractive", booleanAttribute] }, outputs: { chipEnd: "cuteChipInputTokenEnd" }, host: { listeners: { "keydown": "_keydown($event)", "blur": "_blur()", "focus": "_focus()", "input": "_onInput()" }, properties: { "id": "id", "attr.disabled": "disabled && !disabledInteractive ? \"\" : null", "attr.placeholder": "placeholder || null", "attr.aria-invalid": "chipGrid && chipGrid.ngControl ? chipGrid.ngControl.invalid : null", "attr.aria-required": "(chipGrid && chipGrid.required) || null", "attr.aria-disabled": "disabled && disabledInteractive ? \"true\" : null", "attr.readonly": "_getReadonlyAttribute()", "attr.required": "(chipGrid && chipGrid.required) || null" }, classAttribute: "cute-chip-input" }, exportAs: ["cuteChipInput", "cuteChipInputFor"], usesOnChanges: true, ngImport: i0 }); }
|
|
1685
|
+
}
|
|
1686
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipInput, decorators: [{
|
|
1687
|
+
type: Directive,
|
|
1688
|
+
args: [{
|
|
1689
|
+
selector: 'input[cuteChipInputFor]',
|
|
1690
|
+
exportAs: 'cuteChipInput, cuteChipInputFor',
|
|
1691
|
+
host: {
|
|
1692
|
+
'class': 'cute-chip-input',
|
|
1693
|
+
'(keydown)': '_keydown($event)',
|
|
1694
|
+
'(blur)': '_blur()',
|
|
1695
|
+
'(focus)': '_focus()',
|
|
1696
|
+
'(input)': '_onInput()',
|
|
1697
|
+
'[id]': 'id',
|
|
1698
|
+
'[attr.disabled]': 'disabled && !disabledInteractive ? "" : null',
|
|
1699
|
+
'[attr.placeholder]': 'placeholder || null',
|
|
1700
|
+
'[attr.aria-invalid]': 'chipGrid && chipGrid.ngControl ? chipGrid.ngControl.invalid : null',
|
|
1701
|
+
'[attr.aria-required]': '(chipGrid && chipGrid.required) || null',
|
|
1702
|
+
'[attr.aria-disabled]': 'disabled && disabledInteractive ? "true" : null',
|
|
1703
|
+
'[attr.readonly]': '_getReadonlyAttribute()',
|
|
1704
|
+
'[attr.required]': '(chipGrid && chipGrid.required) || null',
|
|
1705
|
+
},
|
|
1706
|
+
standalone: true,
|
|
1707
|
+
}]
|
|
1708
|
+
}], ctorParameters: () => [], propDecorators: { chipGrid: [{
|
|
1709
|
+
type: Input,
|
|
1710
|
+
args: ['cuteChipInputFor']
|
|
1711
|
+
}], addOnBlur: [{
|
|
1712
|
+
type: Input,
|
|
1713
|
+
args: [{ alias: 'cuteChipInputAddOnBlur', transform: booleanAttribute }]
|
|
1714
|
+
}], separatorKeyCodes: [{
|
|
1715
|
+
type: Input,
|
|
1716
|
+
args: ['cuteChipInputSeparatorKeyCodes']
|
|
1717
|
+
}], chipEnd: [{
|
|
1718
|
+
type: Output,
|
|
1719
|
+
args: ['cuteChipInputTokenEnd']
|
|
1720
|
+
}], placeholder: [{
|
|
1721
|
+
type: Input
|
|
1722
|
+
}], id: [{
|
|
1723
|
+
type: Input
|
|
1724
|
+
}], disabled: [{
|
|
1725
|
+
type: Input,
|
|
1726
|
+
args: [{ transform: booleanAttribute }]
|
|
1727
|
+
}], readonly: [{
|
|
1728
|
+
type: Input,
|
|
1729
|
+
args: [{ transform: booleanAttribute }]
|
|
1730
|
+
}], disabledInteractive: [{
|
|
1731
|
+
type: Input,
|
|
1732
|
+
args: [{ alias: 'cuteChipInputDisabledInteractive', transform: booleanAttribute }]
|
|
1733
|
+
}] } });
|
|
1734
|
+
|
|
1735
|
+
/**
|
|
1736
|
+
* @license Apache-2.0
|
|
1737
|
+
*
|
|
1738
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
1739
|
+
*
|
|
1740
|
+
* You may not use this file except in compliance with the License
|
|
1741
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
1742
|
+
*
|
|
1743
|
+
* This code is a modification of the `@angular/material` original
|
|
1744
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
1745
|
+
*/
|
|
1746
|
+
/** Event object emitted by CuteChipOption when selected or deselected. */
|
|
1747
|
+
class CuteChipSelectionChange {
|
|
1748
|
+
constructor(
|
|
1749
|
+
/** Reference to the chip that emitted the event. */
|
|
1750
|
+
source,
|
|
1751
|
+
/** Whether the chip that emitted the event is selected. */
|
|
1752
|
+
selected,
|
|
1753
|
+
/** Whether the selection change was a result of a user interaction. */
|
|
1754
|
+
isUserInput = false) {
|
|
1755
|
+
this.source = source;
|
|
1756
|
+
this.selected = selected;
|
|
1757
|
+
this.isUserInput = isUserInput;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* An extension of the CuteChip component that supports chip selection. Used with CuteChipListbox.
|
|
1762
|
+
*
|
|
1763
|
+
* Unlike other chips, the user can focus on disabled chip options inside a CuteChipListbox. The
|
|
1764
|
+
* user cannot click disabled chips.
|
|
1765
|
+
*/
|
|
1766
|
+
class CuteChipOption extends CuteChip {
|
|
1767
|
+
constructor() {
|
|
1768
|
+
super(...arguments);
|
|
1769
|
+
/** Default chip options. */
|
|
1770
|
+
this._defaultOptions = inject(CUTE_CHIPS_DEFAULT_OPTIONS, { optional: true });
|
|
1771
|
+
/** Whether the chip list is selectable. */
|
|
1772
|
+
this.chipListSelectable = true;
|
|
1773
|
+
/** Whether the chip list is in multi-selection mode. */
|
|
1774
|
+
this._chipListMultiple = false;
|
|
1775
|
+
/** Whether the chip list hides single-selection indicator. */
|
|
1776
|
+
this._chipListHideSingleSelectionIndicator = this._defaultOptions?.hideSingleSelectionIndicator ?? false;
|
|
1777
|
+
this._selectable = true;
|
|
1778
|
+
this._selected = false;
|
|
1779
|
+
/** The unstyled chip selector for this component. */
|
|
1780
|
+
this.basicChipAttrName = 'cute-basic-chip-option';
|
|
1781
|
+
/** Emitted when the chip is selected or deselected. */
|
|
1782
|
+
this.selectionChange = new EventEmitter();
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Whether the chip is selectable.
|
|
1786
|
+
*
|
|
1787
|
+
* When a chip is not selectable, changes to its selected state are always
|
|
1788
|
+
* ignored. By default, an option chip is selectable, and it becomes
|
|
1789
|
+
* non-selectable if its parent chip list is not selectable.
|
|
1790
|
+
*/
|
|
1791
|
+
get selectable() { return this._selectable && this.chipListSelectable; }
|
|
1792
|
+
set selectable(value) {
|
|
1793
|
+
this._selectable = value;
|
|
1794
|
+
this.markForCheck();
|
|
1795
|
+
}
|
|
1796
|
+
/** Whether the chip is selected. */
|
|
1797
|
+
get selected() { return this._selected; }
|
|
1798
|
+
set selected(value) { this._setSelectedState(value, false, true); }
|
|
1799
|
+
/**
|
|
1800
|
+
* The ARIA selected applied to the chip. Conforms to WAI ARIA best practices for listbox
|
|
1801
|
+
* interaction patterns.
|
|
1802
|
+
*
|
|
1803
|
+
* From [WAI ARIA Listbox authoring practices guide](
|
|
1804
|
+
* https://www.w3.org/WAI/ARIA/apg/patterns/listbox/):
|
|
1805
|
+
* "If any options are selected, each selected option has either aria-selected or aria-checked
|
|
1806
|
+
* set to true. All options that are selectable but not selected have either aria-selected or
|
|
1807
|
+
* aria-checked set to false."
|
|
1808
|
+
*
|
|
1809
|
+
* Set `aria-selected="false"` on not-selected listbox options that are selectable to fix
|
|
1810
|
+
* VoiceOver reading every option as "selected" (#25736).
|
|
1811
|
+
*/
|
|
1812
|
+
get ariaSelected() {
|
|
1813
|
+
return this.selectable ? this.selected.toString() : null;
|
|
1814
|
+
}
|
|
1815
|
+
ngOnInit() {
|
|
1816
|
+
super.ngOnInit();
|
|
1817
|
+
this.role = 'presentation';
|
|
1818
|
+
}
|
|
1819
|
+
/** Selects the chip. */
|
|
1820
|
+
select() { this._setSelectedState(true, false, true); }
|
|
1821
|
+
/** Deselects the chip. */
|
|
1822
|
+
deselect() { this._setSelectedState(false, false, true); }
|
|
1823
|
+
/** Selects this chip and emits userInputSelection event */
|
|
1824
|
+
selectViaInteraction() { this._setSelectedState(true, true, true); }
|
|
1825
|
+
/** Toggles the current selected state of this chip. */
|
|
1826
|
+
toggleSelected(isUserInput = false) {
|
|
1827
|
+
this._setSelectedState(!this.selected, isUserInput, true);
|
|
1828
|
+
return this.selected;
|
|
1829
|
+
}
|
|
1830
|
+
_handlePrimaryActionInteraction() {
|
|
1831
|
+
if (!this.disabled) {
|
|
1832
|
+
// Interacting with the primary action implies that the chip already has focus, however,
|
|
1833
|
+
// there's a bug in Safari where focus ends up lingering on the previous chip (see #27544).
|
|
1834
|
+
// We work around it by explicitly focusing the primary action of the current chip.
|
|
1835
|
+
this.focus();
|
|
1836
|
+
if (this.selectable) {
|
|
1837
|
+
this.toggleSelected(true);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
_hasLeadingGraphic() {
|
|
1842
|
+
if (this.leadingIcon) {
|
|
1843
|
+
return true;
|
|
1844
|
+
}
|
|
1845
|
+
// The checkmark graphic communicates selected state for both single-select and multi-select.
|
|
1846
|
+
// Include checkmark in single-select to fix a11y issue where the selected state is communicated
|
|
1847
|
+
// visually only using color (#25886).
|
|
1848
|
+
return !this._chipListHideSingleSelectionIndicator || this._chipListMultiple;
|
|
1849
|
+
}
|
|
1850
|
+
_setSelectedState(isSelected, isUserInput, emitEvent) {
|
|
1851
|
+
if (isSelected !== this.selected) {
|
|
1852
|
+
this._selected = isSelected;
|
|
1853
|
+
if (emitEvent) {
|
|
1854
|
+
this.selectionChange.emit({
|
|
1855
|
+
source: this,
|
|
1856
|
+
isUserInput,
|
|
1857
|
+
selected: this.selected,
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
this.markForCheck();
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipOption, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1864
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CuteChipOption, isStandalone: true, selector: "cute-basic-chip-option, [cute-basic-chip-option], cute-chip-option, [cute-chip-option]", inputs: { selectable: ["selectable", "selectable", booleanAttribute], selected: ["selected", "selected", booleanAttribute] }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "class.cute-chip-disabled": "disabled", "class.cute-chip-highlighted": "highlighted", "class.cute-chip-with-trailing-icon": "_hasTrailingIcon()", "class.cute-chip-selected": "selected", "class.cute-chip-multiple": "_chipListMultiple", "class.cute-chip-with-avatar": "leadingIcon", "attr.tabindex": "null", "attr.aria-label": "null", "attr.aria-description": "null", "attr.role": "role", "id": "id" }, classAttribute: "cute-chip-option" }, providers: [
|
|
1865
|
+
{ provide: CuteChip, useExisting: CuteChipOption },
|
|
1866
|
+
{ provide: CUTE_CHIP, useExisting: CuteChipOption },
|
|
1867
|
+
], usesInheritance: true, ngImport: i0, template: "<span class=\"cute-chip-focus-overlay\"></span>\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <button\r\n cuteButton=\"outline-button\"\r\n class=\"cute-chip-action rounded-pill text-nowrap\"\r\n [class.active]=\"selected\"\r\n magnitude=\"small\"\r\n [color]=\"color\"\r\n [tabIndex]=\"tabIndex\"\r\n [disabled]=\"disabled\"\r\n [attr.aria-selected]=\"ariaSelected\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"_ariaDescriptionId\"\r\n data-bs-toggle=\"button\"\r\n role=\"option\"\r\n (click)=\"_handlePrimaryActionInteraction()\">\r\n @if (_hasLeadingGraphic()) {\r\n <span cuteButtonIcon class=\"cute-chip-graphic cute-chip__graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n @if (selected && !leadingIcon ) {\r\n <span class=\"cute-chip__checkmark\">\r\n <svg\r\n class=\"cute-chip__checkmark-svg\"\r\n viewBox=\"-2 2 24 24\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\">\r\n <path class=\"cute-chip__checkmark-path\"\r\n fill=\"none\" stroke=\"currentColor\" d=\"M1.73,12.91 8.1,19.28 22.79,4.59\" />\r\n </svg>\r\n </span>\r\n }\r\n </span>\r\n }\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n <ng-content></ng-content>\r\n <span class=\"cute-chip-primary-focus-indicator\"></span>\r\n </span>\r\n </button>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span class=\"cute-chip__cell cute-chip__cell--trailing\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n\r\n<span class=\"visually-hidden\" [id]=\"_ariaDescriptionId\">{{ariaDescription}}</span>\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"], dependencies: [{ kind: "component", type: CuteButton, selector: "button[cuteButton], button[cute-button], a[cuteButton], a[cute-button], ", exportAs: ["cuteButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1868
|
+
}
|
|
1869
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipOption, decorators: [{
|
|
1870
|
+
type: Component,
|
|
1871
|
+
args: [{ selector: 'cute-basic-chip-option, [cute-basic-chip-option], cute-chip-option, [cute-chip-option]', host: {
|
|
1872
|
+
'class': 'cute-chip-option',
|
|
1873
|
+
'[class.cute-chip-disabled]': 'disabled',
|
|
1874
|
+
'[class.cute-chip-highlighted]': 'highlighted',
|
|
1875
|
+
'[class.cute-chip-with-trailing-icon]': '_hasTrailingIcon()',
|
|
1876
|
+
'[class.cute-chip-selected]': 'selected',
|
|
1877
|
+
'[class.cute-chip-multiple]': '_chipListMultiple',
|
|
1878
|
+
'[class.cute-chip-with-avatar]': 'leadingIcon',
|
|
1879
|
+
/*
|
|
1880
|
+
'[class.mdc-evolution-chip]': '!_isBasicChip',
|
|
1881
|
+
'[class.mdc-evolution-chip--filter]': '!_isBasicChip',
|
|
1882
|
+
'[class.mdc-evolution-chip--selectable]': '!_isBasicChip',
|
|
1883
|
+
'[class.mdc-evolution-chip--disabled]': 'disabled',
|
|
1884
|
+
'[class.mdc-evolution-chip--selected]': 'selected',
|
|
1885
|
+
// This class enables the transition on the checkmark. Usually MDC adds it when selection
|
|
1886
|
+
// starts and removes it once the animation is finished. We don't need to go through all
|
|
1887
|
+
// the trouble, because we only care about the selection animation. MDC needs to do it,
|
|
1888
|
+
// because they also have an exit animation that we don't care about.
|
|
1889
|
+
'[class.mdc-evolution-chip--selecting]': '!_animationsDisabled',
|
|
1890
|
+
'[class.mdc-evolution-chip--with-trailing-action]': '_hasTrailingIcon()',
|
|
1891
|
+
'[class.mdc-evolution-chip--with-primary-icon]': 'leadingIcon',
|
|
1892
|
+
'[class.mdc-evolution-chip--with-primary-graphic]': '_hasLeadingGraphic()',
|
|
1893
|
+
'[class.mdc-evolution-chip--with-avatar]': 'leadingIcon',
|
|
1894
|
+
*/
|
|
1895
|
+
'[attr.tabindex]': 'null',
|
|
1896
|
+
'[attr.aria-label]': 'null',
|
|
1897
|
+
'[attr.aria-description]': 'null',
|
|
1898
|
+
'[attr.role]': 'role',
|
|
1899
|
+
'[id]': 'id',
|
|
1900
|
+
}, providers: [
|
|
1901
|
+
{ provide: CuteChip, useExisting: CuteChipOption },
|
|
1902
|
+
{ provide: CUTE_CHIP, useExisting: CuteChipOption },
|
|
1903
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CuteChipAction, CuteButton], template: "<span class=\"cute-chip-focus-overlay\"></span>\r\n\r\n<span class=\"cute-chip__cell cute-chip__cell--primary\">\r\n <button\r\n cuteButton=\"outline-button\"\r\n class=\"cute-chip-action rounded-pill text-nowrap\"\r\n [class.active]=\"selected\"\r\n magnitude=\"small\"\r\n [color]=\"color\"\r\n [tabIndex]=\"tabIndex\"\r\n [disabled]=\"disabled\"\r\n [attr.aria-selected]=\"ariaSelected\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"_ariaDescriptionId\"\r\n data-bs-toggle=\"button\"\r\n role=\"option\"\r\n (click)=\"_handlePrimaryActionInteraction()\">\r\n @if (_hasLeadingGraphic()) {\r\n <span cuteButtonIcon class=\"cute-chip-graphic cute-chip__graphic\">\r\n <ng-content select=\"cute-avatar, cute-chip-avatar, [cuteChipAvatar]\"></ng-content>\r\n @if (selected && !leadingIcon ) {\r\n <span class=\"cute-chip__checkmark\">\r\n <svg\r\n class=\"cute-chip__checkmark-svg\"\r\n viewBox=\"-2 2 24 24\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\">\r\n <path class=\"cute-chip__checkmark-path\"\r\n fill=\"none\" stroke=\"currentColor\" d=\"M1.73,12.91 8.1,19.28 22.79,4.59\" />\r\n </svg>\r\n </span>\r\n }\r\n </span>\r\n }\r\n <span class=\"cute-chip__text-label cute-chip-action-label\">\r\n <ng-content></ng-content>\r\n <span class=\"cute-chip-primary-focus-indicator\"></span>\r\n </span>\r\n </button>\r\n</span>\r\n\r\n@if (_hasTrailingIcon()) {\r\n <span class=\"cute-chip__cell cute-chip__cell--trailing\">\r\n <ng-content select=\"cute-chip-trailing-icon,[cuteChipRemove],[cuteChipTrailingIcon]\"></ng-content>\r\n </span>\r\n}\r\n\r\n<span class=\"visually-hidden\" [id]=\"_ariaDescriptionId\">{{ariaDescription}}</span>\r\n", styles: [".cute-chip,.cute-chip-option,cute-chip-row{position:relative;display:inline-flex;align-items:center}.cute-chip.cute-static-chip,.cute-chip-option.cute-static-chip,cute-chip-row.cute-static-chip{--bs-btn-bg: rgba(var(--bs-body-color-rgb), .06);cursor:auto}.cute-chip:hover,.cute-chip-option:hover,cute-chip-row:hover{--bs-btn-hover-bg: rgba(var(--bs-body-color-rgb), .1)}.cute-chip:active,.cute-chip-option:active,cute-chip-row:active{--bs-btn-active-bg: rgba(var(--bs-body-color-rgb), .14)}.cute-chip__cell [cuteChipAction],.cute-chip__cell .cute-chip-action{display:inline-flex;align-items:center;cursor:pointer;outline:none}.cute-chip__cell [cuteChipAction].cute-chip__action--presentational,.cute-chip__cell .cute-chip-action.cute-chip__action--presentational{cursor:auto}.cute-chip__cell [cuteChipAction]:not(button),.cute-chip__cell .cute-chip-action:not(button){gap:.5rem}.cute-chip__cell [cuteChipAction] .cute-chip__graphic,.cute-chip__cell .cute-chip-action .cute-chip__graphic{align-items:center;display:inline-flex;justify-content:center;overflow:hidden;pointer-events:none;position:relative}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark{padding-left:2px;padding-right:4px}.cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,.cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{width:1.2rem}[dir=rtl] .cute-chip__cell [cuteChipAction] .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg,[dir=rtl] .cute-chip__cell .cute-chip-action .cute-chip__graphic .cute-chip__checkmark .cute-chip__checkmark-svg{transform:rotateY(180deg)}.cute-chip__cell [cuteChipAction].disabled,.cute-chip__cell .cute-chip-action.disabled{cursor:auto}.cute-chip__cell [cuteChipAction].cute-chip__icon--trailing,.cute-chip__cell .cute-chip-action.cute-chip__icon--trailing{padding-left:4px;padding-right:4px;border:none;background:none}.cute-standard-chip{-webkit-tap-highlight-color:transparent}@media (forced-colors: active){.cute-standard-chip{outline:solid 1px}.cute-standard-chip .cute-chip__checkmark-path{stroke:CanvasText!important}}.cute-standard-chip .cute-chip__icon--primary{--size: 18px;height:var(--size);width:var(--size);font-size:var(--size);border-radius:calc(var(--size) * 1.3);min-height:fit-content;background:none}.cute-standard-chip .cute-chip__cell--primary{display:flex}.cute-standard-chip .cute-chip__cell--trailing{display:inline-flex;background-color:transparent;padding-left:.5rem;padding-right:0}[dir=rtl] .cute-standard-chip .cute-chip__cell--trailing{padding-left:0;padding-right:.5rem}.cute-standard-chip._cute-animation-noopable,.cute-standard-chip._cute-animation-noopable .cute-chip__graphic,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark,.cute-standard-chip._cute-animation-noopable .cute-chip__checkmark-path{transition-duration:1ms;animation-duration:1ms}.cute-chip-focus-overlay{inset:0;position:absolute;pointer-events:none;opacity:0;border-radius:inherit;transition:opacity .15s linear}._cute-animation-noopable .cute-chip-focus-overlay{transition:none}.cute-basic-chip .cute-chip-focus-overlay{display:none}.cute-chip-action-label{text-align:left;white-space:nowrap}[dir=rtl] .cute-chip-action-label{text-align:right}.cute-chip-primary-focus-indicator{position:absolute;inset:0;pointer-events:none}.cute-chip-edit-input{cursor:text;display:inline-block;color:inherit;outline:0}@media (forced-colors: active){.cute-chip-selected:not(.cute-chip-multiple){outline-width:3px}}\n"] }]
|
|
1904
|
+
}], propDecorators: { selectable: [{
|
|
1905
|
+
type: Input,
|
|
1906
|
+
args: [{ transform: booleanAttribute }]
|
|
1907
|
+
}], selected: [{
|
|
1908
|
+
type: Input,
|
|
1909
|
+
args: [{ transform: booleanAttribute }]
|
|
1910
|
+
}], selectionChange: [{
|
|
1911
|
+
type: Output
|
|
1912
|
+
}] } });
|
|
1913
|
+
|
|
1914
|
+
/**
|
|
1915
|
+
* @license Apache-2.0
|
|
1916
|
+
*
|
|
1917
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
1918
|
+
*
|
|
1919
|
+
* You may not use this file except in compliance with the License
|
|
1920
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
1921
|
+
*
|
|
1922
|
+
* This code is a modification of the `@angular/material` original
|
|
1923
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
1924
|
+
*/
|
|
1925
|
+
/** Change event object that is emitted when the chip listbox value has changed. */
|
|
1926
|
+
class CuteChipListboxChange {
|
|
1927
|
+
constructor(
|
|
1928
|
+
/** Chip listbox that emitted the event. */
|
|
1929
|
+
source,
|
|
1930
|
+
/** Value of the chip listbox when the event was emitted. */
|
|
1931
|
+
value) {
|
|
1932
|
+
this.source = source;
|
|
1933
|
+
this.value = value;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1937
|
+
* Provider Expression that allows cute-chip-listbox to register as a ControlValueAccessor.
|
|
1938
|
+
* This allows it to support [(ngModel)].
|
|
1939
|
+
* @docs-private
|
|
1940
|
+
*/
|
|
1941
|
+
const CUTE_CHIP_LISTBOX_CONTROL_VALUE_ACCESSOR = {
|
|
1942
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1943
|
+
useExisting: forwardRef(() => CuteChipListbox),
|
|
1944
|
+
multi: true,
|
|
1945
|
+
};
|
|
1946
|
+
/**
|
|
1947
|
+
* An extension of the CuteChipSet component that supports chip selection.
|
|
1948
|
+
* Used with CuteChipOption chips.
|
|
1949
|
+
*/
|
|
1950
|
+
class CuteChipListbox extends CuteChipSet {
|
|
1951
|
+
constructor() {
|
|
1952
|
+
super(...arguments);
|
|
1953
|
+
/**
|
|
1954
|
+
* Function when touched. Set as part of ControlValueAccessor implementation.
|
|
1955
|
+
* @docs-private
|
|
1956
|
+
*/
|
|
1957
|
+
this._onTouched = () => { };
|
|
1958
|
+
/**
|
|
1959
|
+
* Function when changed. Set as part of ControlValueAccessor implementation.
|
|
1960
|
+
* @docs-private
|
|
1961
|
+
*/
|
|
1962
|
+
this._onChange = () => { };
|
|
1963
|
+
// TODO: MDC uses `grid` here
|
|
1964
|
+
this._defaultRole = 'listbox';
|
|
1965
|
+
/** Default chip options. */
|
|
1966
|
+
this._defaultOptions = inject(CUTE_CHIPS_DEFAULT_OPTIONS, { optional: true });
|
|
1967
|
+
this._multiple = false;
|
|
1968
|
+
/** Orientation of the chip list. */
|
|
1969
|
+
this.ariaOrientation = 'horizontal';
|
|
1970
|
+
this._selectable = true;
|
|
1971
|
+
/**
|
|
1972
|
+
* A function to compare the option values with the selected values. The first argument
|
|
1973
|
+
* is a value from an option. The second is a value from the selection. A boolean
|
|
1974
|
+
* should be returned.
|
|
1975
|
+
*/
|
|
1976
|
+
this.compareWith = (o1, o2) => o1 === o2;
|
|
1977
|
+
/** Whether this chip listbox is required. */
|
|
1978
|
+
this.required = false;
|
|
1979
|
+
this._hideSingleSelectionIndicator = this._defaultOptions?.hideSingleSelectionIndicator ?? false;
|
|
1980
|
+
/** Event emitted when the user has changed the selected chip listbox value. */
|
|
1981
|
+
this.change = new EventEmitter();
|
|
1982
|
+
this._chips = undefined;
|
|
1983
|
+
}
|
|
1984
|
+
/** Whether the user should be allowed to select multiple chips. */
|
|
1985
|
+
get multiple() { return this._multiple; }
|
|
1986
|
+
set multiple(value) {
|
|
1987
|
+
this._multiple = value;
|
|
1988
|
+
this._syncListboxProperties();
|
|
1989
|
+
}
|
|
1990
|
+
/** The array of selected chips inside the chip listbox. */
|
|
1991
|
+
get selected() {
|
|
1992
|
+
const selectedChips = this._chips.toArray().filter(chip => chip.selected);
|
|
1993
|
+
return this.multiple ? selectedChips : selectedChips[0];
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Whether this chip listbox is selectable.
|
|
1997
|
+
*
|
|
1998
|
+
* When a chip listbox is not selectable, the selected states for all
|
|
1999
|
+
* the chips inside the chip listbox are always ignored.
|
|
2000
|
+
*/
|
|
2001
|
+
get selectable() { return this._selectable; }
|
|
2002
|
+
set selectable(value) {
|
|
2003
|
+
this._selectable = value;
|
|
2004
|
+
this._syncListboxProperties();
|
|
2005
|
+
}
|
|
2006
|
+
/** Whether the checkmark indicator for single-selection options is hidden. */
|
|
2007
|
+
get hideSingleSelectionIndicator() { return this._hideSingleSelectionIndicator; }
|
|
2008
|
+
set hideSingleSelectionIndicator(value) {
|
|
2009
|
+
this._hideSingleSelectionIndicator = value;
|
|
2010
|
+
this._syncListboxProperties();
|
|
2011
|
+
}
|
|
2012
|
+
/** The combined stream of all of the child chips' selection change events. */
|
|
2013
|
+
get chipSelectionChanges() {
|
|
2014
|
+
return this._getChipStream(chip => chip.selectionChange);
|
|
2015
|
+
}
|
|
2016
|
+
/** Combined stream of all of the child chips' blur events. */
|
|
2017
|
+
get chipBlurChanges() {
|
|
2018
|
+
return this._getChipStream(chip => chip._onBlur);
|
|
2019
|
+
}
|
|
2020
|
+
/** The value of the listbox, which is the combined value of the selected chips. */
|
|
2021
|
+
get value() { return this._value; }
|
|
2022
|
+
set value(value) {
|
|
2023
|
+
this.writeValue(value);
|
|
2024
|
+
this._value = value;
|
|
2025
|
+
}
|
|
2026
|
+
ngAfterContentInit() {
|
|
2027
|
+
if (this._pendingInitialValue !== undefined) {
|
|
2028
|
+
Promise.resolve().then(() => {
|
|
2029
|
+
this._setSelectionByValue(this._pendingInitialValue, false);
|
|
2030
|
+
this._pendingInitialValue = undefined;
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
this._chips.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
|
|
2034
|
+
// Update listbox selectable/multiple properties on chips
|
|
2035
|
+
this._syncListboxProperties();
|
|
2036
|
+
});
|
|
2037
|
+
this.chipBlurChanges.pipe(takeUntil(this._destroyed)).subscribe(() => this._blur());
|
|
2038
|
+
this.chipSelectionChanges.pipe(takeUntil(this._destroyed)).subscribe(event => {
|
|
2039
|
+
if (!this.multiple) {
|
|
2040
|
+
this._chips.forEach(chip => {
|
|
2041
|
+
if (chip !== event.source) {
|
|
2042
|
+
chip._setSelectedState(false, false, false);
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
if (event.isUserInput) {
|
|
2047
|
+
this._propagateChanges();
|
|
2048
|
+
}
|
|
2049
|
+
});
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Focuses the first selected chip in this chip listbox, or the first non-disabled chip when there
|
|
2053
|
+
* are no selected chips.
|
|
2054
|
+
*/
|
|
2055
|
+
focus() {
|
|
2056
|
+
if (this.disabled) {
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
const firstSelectedChip = this._getFirstSelectedChip();
|
|
2060
|
+
if (firstSelectedChip && !firstSelectedChip.disabled) {
|
|
2061
|
+
firstSelectedChip.focus();
|
|
2062
|
+
}
|
|
2063
|
+
else if (this._chips.length > 0) {
|
|
2064
|
+
this._keyManager?.setFirstItemActive();
|
|
2065
|
+
}
|
|
2066
|
+
else {
|
|
2067
|
+
this._elementRef.nativeElement.focus();
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Implemented as part of ControlValueAccessor.
|
|
2072
|
+
* @docs-private
|
|
2073
|
+
*/
|
|
2074
|
+
writeValue(value) {
|
|
2075
|
+
if (this._chips) {
|
|
2076
|
+
this._setSelectionByValue(value, false);
|
|
2077
|
+
}
|
|
2078
|
+
else if (value != null) {
|
|
2079
|
+
this._pendingInitialValue = value;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Implemented as part of ControlValueAccessor.
|
|
2084
|
+
* @docs-private
|
|
2085
|
+
*/
|
|
2086
|
+
registerOnChange(fn) {
|
|
2087
|
+
this._onChange = fn;
|
|
2088
|
+
}
|
|
2089
|
+
/**
|
|
2090
|
+
* Implemented as part of ControlValueAccessor.
|
|
2091
|
+
* @docs-private
|
|
2092
|
+
*/
|
|
2093
|
+
registerOnTouched(fn) {
|
|
2094
|
+
this._onTouched = fn;
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Implemented as part of ControlValueAccessor.
|
|
2098
|
+
* @docs-private
|
|
2099
|
+
*/
|
|
2100
|
+
setDisabledState(isDisabled) {
|
|
2101
|
+
this.disabled = isDisabled;
|
|
2102
|
+
}
|
|
2103
|
+
/** Selects all chips with value. */
|
|
2104
|
+
_setSelectionByValue(value, isUserInput = true) {
|
|
2105
|
+
this._clearSelection();
|
|
2106
|
+
if (Array.isArray(value)) {
|
|
2107
|
+
value.forEach(currentValue => this._selectValue(currentValue, isUserInput));
|
|
2108
|
+
}
|
|
2109
|
+
else {
|
|
2110
|
+
this._selectValue(value, isUserInput);
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
/** When blurred, marks the field as touched when focus moved outside the chip listbox. */
|
|
2114
|
+
_blur() {
|
|
2115
|
+
if (!this.disabled) {
|
|
2116
|
+
// Wait to see if focus moves to an individual chip.
|
|
2117
|
+
setTimeout(() => {
|
|
2118
|
+
if (!this.focused) {
|
|
2119
|
+
this._markAsTouched();
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
_keydown(event) {
|
|
2125
|
+
if (event.keyCode === TAB) {
|
|
2126
|
+
super._allowFocusEscape();
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
/** Marks the field as touched */
|
|
2130
|
+
_markAsTouched() {
|
|
2131
|
+
this._onTouched();
|
|
2132
|
+
this._changeDetectorRef.markForCheck();
|
|
2133
|
+
}
|
|
2134
|
+
/** Emits change event to set the model value. */
|
|
2135
|
+
_propagateChanges() {
|
|
2136
|
+
let valueToEmit = null;
|
|
2137
|
+
if (Array.isArray(this.selected)) {
|
|
2138
|
+
valueToEmit = this.selected.map(chip => chip.value);
|
|
2139
|
+
}
|
|
2140
|
+
else {
|
|
2141
|
+
valueToEmit = this.selected ? this.selected.value : undefined;
|
|
2142
|
+
}
|
|
2143
|
+
this._value = valueToEmit;
|
|
2144
|
+
this.change.emit(new CuteChipListboxChange(this, valueToEmit));
|
|
2145
|
+
this._onChange(valueToEmit);
|
|
2146
|
+
this._changeDetectorRef.markForCheck();
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Deselects every chip in the listbox.
|
|
2150
|
+
* @param skip Chip that should not be deselected.
|
|
2151
|
+
*/
|
|
2152
|
+
_clearSelection(skip) {
|
|
2153
|
+
this._chips.forEach(chip => {
|
|
2154
|
+
if (chip !== skip) {
|
|
2155
|
+
chip.deselect();
|
|
2156
|
+
}
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Finds and selects the chip based on its value.
|
|
2161
|
+
* @returns Chip that has the corresponding value.
|
|
2162
|
+
*/
|
|
2163
|
+
_selectValue(value, isUserInput) {
|
|
2164
|
+
const correspondingChip = this._chips.find(chip => {
|
|
2165
|
+
return chip.value != null && this.compareWith(chip.value, value);
|
|
2166
|
+
});
|
|
2167
|
+
if (correspondingChip) {
|
|
2168
|
+
isUserInput ? correspondingChip.selectViaInteraction() : correspondingChip.select();
|
|
2169
|
+
}
|
|
2170
|
+
return correspondingChip;
|
|
2171
|
+
}
|
|
2172
|
+
/** Syncs the chip-listbox selection state with the individual chips. */
|
|
2173
|
+
_syncListboxProperties() {
|
|
2174
|
+
if (this._chips) {
|
|
2175
|
+
// Defers setting the value to avoid the "Expression
|
|
2176
|
+
// has changed after it was checked" errors from Angular.
|
|
2177
|
+
Promise.resolve().then(() => {
|
|
2178
|
+
this._chips.forEach(chip => {
|
|
2179
|
+
chip._chipListMultiple = this.multiple;
|
|
2180
|
+
chip.chipListSelectable = this._selectable;
|
|
2181
|
+
chip._chipListHideSingleSelectionIndicator = this.hideSingleSelectionIndicator;
|
|
2182
|
+
chip._changeDetectorRef.markForCheck();
|
|
2183
|
+
});
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
/** Returns the first selected chip in this listbox, or undefined if no chips are selected. */
|
|
2188
|
+
_getFirstSelectedChip() {
|
|
2189
|
+
if (Array.isArray(this.selected)) {
|
|
2190
|
+
return this.selected.length ? this.selected[0] : undefined;
|
|
2191
|
+
}
|
|
2192
|
+
else {
|
|
2193
|
+
return this.selected;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Determines if key manager should avoid putting a given chip action in the tab index. Skip
|
|
2198
|
+
* non-interactive actions since the user can't do anything with them.
|
|
2199
|
+
*/
|
|
2200
|
+
_skipPredicate(action) {
|
|
2201
|
+
// Override the skip predicate in the base class to avoid skipping disabled chips. Allow
|
|
2202
|
+
// disabled chip options to receive focus to align with WAI ARIA recommendation. Normally WAI
|
|
2203
|
+
// ARIA's instructions are to exclude disabled items from the tab order, but it makes a few
|
|
2204
|
+
// exceptions for compound widgets.
|
|
2205
|
+
//
|
|
2206
|
+
// From [Developing a Keyboard Interface](
|
|
2207
|
+
// https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/):
|
|
2208
|
+
// "For the following composite widget elements, keep them focusable when disabled: Options in a
|
|
2209
|
+
// Listbox..."
|
|
2210
|
+
return !action.isInteractive;
|
|
2211
|
+
}
|
|
2212
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipListbox, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2213
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.15", type: CuteChipListbox, isStandalone: true, selector: "cute-chip-listbox", inputs: { multiple: ["multiple", "multiple", booleanAttribute], ariaOrientation: ["aria-orientation", "ariaOrientation"], selectable: ["selectable", "selectable", booleanAttribute], compareWith: "compareWith", required: ["required", "required", booleanAttribute], hideSingleSelectionIndicator: ["hideSingleSelectionIndicator", "hideSingleSelectionIndicator", booleanAttribute], value: "value" }, outputs: { change: "change" }, host: { listeners: { "focus": "focus()", "blur": "_blur()", "keydown": "_keydown($event)" }, properties: { "attr.role": "role", "tabIndex": "(disabled || empty) ? -1 : tabIndex", "attr.aria-required": "role ? required : null", "attr.aria-disabled": "disabled", "attr.aria-multiselectable": "multiple", "attr.aria-orientation": "ariaOrientation", "class.cute-chip-list-disabled": "disabled", "class.cute-chip-list-required": "required" }, classAttribute: "cute-chip-listbox" }, providers: [CUTE_CHIP_LISTBOX_CONTROL_VALUE_ACCESSOR], queries: [{ propertyName: "_chips", predicate: CuteChipOption, descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
2214
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
2215
|
+
<ng-content></ng-content>
|
|
2216
|
+
</div>
|
|
2217
|
+
`, isInline: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2218
|
+
}
|
|
2219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipListbox, decorators: [{
|
|
2220
|
+
type: Component,
|
|
2221
|
+
args: [{ selector: 'cute-chip-listbox', template: `
|
|
2222
|
+
<div class="cute-chip-set__chips" role="presentation">
|
|
2223
|
+
<ng-content></ng-content>
|
|
2224
|
+
</div>
|
|
2225
|
+
`, host: {
|
|
2226
|
+
'class': 'cute-chip-listbox',
|
|
2227
|
+
'[attr.role]': 'role',
|
|
2228
|
+
'[tabIndex]': '(disabled || empty) ? -1 : tabIndex',
|
|
2229
|
+
// TODO: replace this binding with use of AriaDescriber
|
|
2230
|
+
//'[attr.aria-describedby]': '_ariaDescribedby || null',
|
|
2231
|
+
'[attr.aria-required]': 'role ? required : null',
|
|
2232
|
+
'[attr.aria-disabled]': 'disabled',
|
|
2233
|
+
'[attr.aria-multiselectable]': 'multiple',
|
|
2234
|
+
'[attr.aria-orientation]': 'ariaOrientation',
|
|
2235
|
+
'[class.cute-chip-list-disabled]': 'disabled',
|
|
2236
|
+
'[class.cute-chip-list-required]': 'required',
|
|
2237
|
+
'(focus)': 'focus()',
|
|
2238
|
+
'(blur)': '_blur()',
|
|
2239
|
+
'(keydown)': '_keydown($event)',
|
|
2240
|
+
}, providers: [CUTE_CHIP_LISTBOX_CONTROL_VALUE_ACCESSOR], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, styles: [".cute-chip-listbox,.cute-chip-grid,.cute-chip-set{display:flex;width:100%;background-color:var(--bs-body-bg)}.cute-chip-listbox .cute-chip-set__chips,.cute-chip-grid .cute-chip-set__chips,.cute-chip-set .cute-chip-set__chips{display:flex;flex-flow:wrap;gap:.375rem;min-width:100%}.cute-form-field .cute-chip-listbox,.cute-form-field .cute-chip-grid,.cute-form-field .cute-chip-set{min-height:58px}.cute-chip-grid-focused{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.cute-chip-set-stacked .cute-chip-set__chips{flex-direction:column;align-items:flex-start}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip{display:block;width:100%}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__graphic{flex-grow:0}.cute-chip-set-stacked .cute-chip-set__chips .cute-chip-action,.cute-chip-set-stacked .cute-chip-set__chips .cute-chip__action--primary{flex-basis:100%;justify-content:start;width:100%}input.cute-chip-input{flex:1 0 150px;margin-left:.25rem;border:none;outline:none;background:none;transition:opacity .15s 0ms cubic-bezier(.4,0,.2,1)}input.cute-chip-input:not(:focus){opacity:.75}[dir=rtl] input.cute-chip-input{margin-left:0;margin-right:.25rem}\n"] }]
|
|
2241
|
+
}], propDecorators: { multiple: [{
|
|
2242
|
+
type: Input,
|
|
2243
|
+
args: [{ transform: booleanAttribute }]
|
|
2244
|
+
}], ariaOrientation: [{
|
|
2245
|
+
type: Input,
|
|
2246
|
+
args: ['aria-orientation']
|
|
2247
|
+
}], selectable: [{
|
|
2248
|
+
type: Input,
|
|
2249
|
+
args: [{ transform: booleanAttribute }]
|
|
2250
|
+
}], compareWith: [{
|
|
2251
|
+
type: Input
|
|
2252
|
+
}], required: [{
|
|
2253
|
+
type: Input,
|
|
2254
|
+
args: [{ transform: booleanAttribute }]
|
|
2255
|
+
}], hideSingleSelectionIndicator: [{
|
|
2256
|
+
type: Input,
|
|
2257
|
+
args: [{ transform: booleanAttribute }]
|
|
2258
|
+
}], value: [{
|
|
2259
|
+
type: Input
|
|
2260
|
+
}], change: [{
|
|
2261
|
+
type: Output
|
|
2262
|
+
}], _chips: [{
|
|
2263
|
+
type: ContentChildren,
|
|
2264
|
+
args: [CuteChipOption, {
|
|
2265
|
+
// We need to use `descendants: true`, because Ivy will no longer match
|
|
2266
|
+
// indirect descendants if it's left as false.
|
|
2267
|
+
descendants: true,
|
|
2268
|
+
}]
|
|
2269
|
+
}] } });
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* @license Apache-2.0
|
|
2273
|
+
*
|
|
2274
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
2275
|
+
*
|
|
2276
|
+
* You may not use this file except in compliance with the License
|
|
2277
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
2278
|
+
*
|
|
2279
|
+
* This code is a modification of the `@angular/material` original
|
|
2280
|
+
* code licensed under MIT-style License (https://angular.dev/license).
|
|
2281
|
+
*/
|
|
2282
|
+
|
|
2283
|
+
/**
|
|
2284
|
+
* @license Apache-2.0
|
|
2285
|
+
*
|
|
2286
|
+
* Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
|
|
2287
|
+
*
|
|
2288
|
+
* You may not use this file except in compliance with the License
|
|
2289
|
+
* that can be found at http://www.apache.org/licenses/LICENSE-2.0
|
|
2290
|
+
*/
|
|
2291
|
+
const TYPES = [
|
|
2292
|
+
CuteChip,
|
|
2293
|
+
CuteChipAvatar,
|
|
2294
|
+
CuteChipEditInput,
|
|
2295
|
+
CuteChipGrid,
|
|
2296
|
+
CuteChipInput,
|
|
2297
|
+
CuteChipListbox,
|
|
2298
|
+
CuteChipOption,
|
|
2299
|
+
CuteChipRemove,
|
|
2300
|
+
CuteChipRow,
|
|
2301
|
+
CuteChipSet,
|
|
2302
|
+
CuteChipTrailingIcon,
|
|
2303
|
+
];
|
|
2304
|
+
class CuteChipsModule {
|
|
2305
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2306
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: CuteChipsModule, imports: [CommonModule, CuteChip,
|
|
2307
|
+
CuteChipAvatar,
|
|
2308
|
+
CuteChipEditInput,
|
|
2309
|
+
CuteChipGrid,
|
|
2310
|
+
CuteChipInput,
|
|
2311
|
+
CuteChipListbox,
|
|
2312
|
+
CuteChipOption,
|
|
2313
|
+
CuteChipRemove,
|
|
2314
|
+
CuteChipRow,
|
|
2315
|
+
CuteChipSet,
|
|
2316
|
+
CuteChipTrailingIcon], exports: [CuteChip,
|
|
2317
|
+
CuteChipAvatar,
|
|
2318
|
+
CuteChipEditInput,
|
|
2319
|
+
CuteChipGrid,
|
|
2320
|
+
CuteChipInput,
|
|
2321
|
+
CuteChipListbox,
|
|
2322
|
+
CuteChipOption,
|
|
2323
|
+
CuteChipRemove,
|
|
2324
|
+
CuteChipRow,
|
|
2325
|
+
CuteChipSet,
|
|
2326
|
+
CuteChipTrailingIcon] }); }
|
|
2327
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipsModule, providers: [
|
|
2328
|
+
ErrorStateMatcher,
|
|
2329
|
+
{
|
|
2330
|
+
provide: CUTE_CHIPS_DEFAULT_OPTIONS,
|
|
2331
|
+
useValue: {
|
|
2332
|
+
separatorKeyCodes: [ENTER],
|
|
2333
|
+
},
|
|
2334
|
+
},
|
|
2335
|
+
], imports: [CommonModule, CuteChipOption] }); }
|
|
2336
|
+
}
|
|
2337
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteChipsModule, decorators: [{
|
|
2338
|
+
type: NgModule,
|
|
2339
|
+
args: [{
|
|
2340
|
+
imports: [CommonModule, ...TYPES],
|
|
2341
|
+
exports: TYPES,
|
|
2342
|
+
declarations: [],
|
|
2343
|
+
providers: [
|
|
2344
|
+
ErrorStateMatcher,
|
|
2345
|
+
{
|
|
2346
|
+
provide: CUTE_CHIPS_DEFAULT_OPTIONS,
|
|
2347
|
+
useValue: {
|
|
2348
|
+
separatorKeyCodes: [ENTER],
|
|
2349
|
+
},
|
|
2350
|
+
},
|
|
2351
|
+
],
|
|
2352
|
+
}]
|
|
2353
|
+
}] });
|
|
2354
|
+
|
|
2355
|
+
/**
|
|
2356
|
+
* Generated bundle index. Do not edit.
|
|
2357
|
+
*/
|
|
2358
|
+
|
|
2359
|
+
export { CUTE_CHIP_LISTBOX_CONTROL_VALUE_ACCESSOR, CuteChip, CuteChipAvatar, CuteChipEdit, CuteChipEditInput, CuteChipGrid, CuteChipGridChange, CuteChipInput, CuteChipListbox, CuteChipListboxChange, CuteChipOption, CuteChipRemove, CuteChipRow, CuteChipSelectionChange, CuteChipSet, CuteChipTrailingIcon, CuteChipsModule };
|
|
2360
|
+
//# sourceMappingURL=cute-widgets-base-chips.mjs.map
|