@ifsworld/granite-components 6.0.4 → 6.1.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, Input, HostBinding, ContentChildren, NgModule, InjectionToken, Attribute, Inject, Optional, EventEmitter, QueryList, TemplateRef, Directive, ViewChild, Output, Self, HostListener, Pipe } from '@angular/core';
2
+ import { Component, ChangeDetectionStrategy, Input, HostBinding, ContentChildren, NgModule, InjectionToken, Attribute, Inject, Optional, EventEmitter, QueryList, TemplateRef, Directive, ViewChild, Output, Self, HostListener, ViewEncapsulation, Pipe } from '@angular/core';
3
3
  import * as i3 from '@angular/common';
4
4
  import { CommonModule, DOCUMENT } from '@angular/common';
5
5
  import { coerceNumberProperty, coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -13,10 +13,13 @@ import { TemplatePortal, PortalModule } from '@angular/cdk/portal';
13
13
  import { trigger, state, style, transition, group, query, animate, sequence } from '@angular/animations';
14
14
  import * as i1 from '@angular/cdk/a11y';
15
15
  import { FocusKeyManager, isFakeMousedownFromScreenReader } from '@angular/cdk/a11y';
16
- import { hasModifierKey } from '@angular/cdk/keycodes';
16
+ import { hasModifierKey, SPACE, BACKSPACE, DELETE, ENTER, TAB } from '@angular/cdk/keycodes';
17
17
  import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
18
18
  import * as i3$1 from '@angular/cdk/bidi';
19
19
  import * as i2 from '@angular/cdk/collections';
20
+ import { SelectionModel } from '@angular/cdk/collections';
21
+ import * as i2$1 from '@angular/forms';
22
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
20
23
 
21
24
  class GraniteArrangeGridItemComponent {
22
25
  constructor(element) {
@@ -2847,6 +2850,1058 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
2847
2850
  }]
2848
2851
  }] });
2849
2852
 
2853
+ /** Event object emitted by GraniteChip when selected or deselected. */
2854
+ class GraniteChipSelectionChangeEvent {
2855
+ constructor() {
2856
+ /** Whether the selection change was a result of a user interaction. */
2857
+ this.isUserInput = false;
2858
+ }
2859
+ }
2860
+ class GraniteChipComponent {
2861
+ constructor(_elementRef, _ngZone, _changeDetectorRef, tabIndex) {
2862
+ this._elementRef = _elementRef;
2863
+ this._ngZone = _ngZone;
2864
+ this._changeDetectorRef = _changeDetectorRef;
2865
+ /** Whether the chip has focus. */
2866
+ this._hasFocus = false;
2867
+ /** Whether the chip list is selectable */
2868
+ this._chipListSelectable = true;
2869
+ /** Whether the chip list is in multi-selection mode. */
2870
+ this._chipListMultiple = false;
2871
+ /** Whether the chip list as a whole is disabled. */
2872
+ this._chipListDisabled = false;
2873
+ /** ARIA role that should be applied to the chip. */
2874
+ this.role = 'option';
2875
+ this._selected = false;
2876
+ this._selectable = true;
2877
+ this._disabled = false;
2878
+ this._removable = false;
2879
+ this._invalid = false;
2880
+ this.ariaLabel = null;
2881
+ this.ariaLabelledby = null;
2882
+ /** Emitted when the chip is selected or deselected. */
2883
+ this.selectionChange = new EventEmitter();
2884
+ /** Emitted when a chip is to be removed. */
2885
+ this.removed = new EventEmitter();
2886
+ /** Emitted when the chip is destroyed. */
2887
+ this.destroyed = new EventEmitter();
2888
+ this.tabIndex = -1;
2889
+ this.inputChip = false;
2890
+ /** Emits when the chip is focused. */
2891
+ this.chipFocus = new EventEmitter();
2892
+ /** Emits when the chip is blurred. */
2893
+ this.chipBlur = new EventEmitter();
2894
+ const inputChipAttrName = 'granite-input-chip';
2895
+ const element = this._elementRef.nativeElement;
2896
+ if (element.hasAttribute(inputChipAttrName) ||
2897
+ element.tagName.toLowerCase() === inputChipAttrName) {
2898
+ this.inputChip = true;
2899
+ }
2900
+ this.tabIndex = tabIndex != null ? parseInt(tabIndex) || -1 : -1;
2901
+ }
2902
+ /** Whether the chip is selected. */
2903
+ get selected() {
2904
+ return this._selected;
2905
+ }
2906
+ set selected(value) {
2907
+ const coercedValue = coerceBooleanProperty(value);
2908
+ if (coercedValue !== this._selected) {
2909
+ this._selected = coercedValue;
2910
+ }
2911
+ }
2912
+ /** The value of the chip. Defaults to the text content inside `<granite-chip>` tags. */
2913
+ get value() {
2914
+ return this._value != null
2915
+ ? this._value
2916
+ : this._elementRef.nativeElement.textContent;
2917
+ }
2918
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
2919
+ set value(val) {
2920
+ this._value = val;
2921
+ }
2922
+ /**
2923
+ * Whether or not the chip is selectable. When a chip is not selectable,
2924
+ * changes to its selected state are always ignored. By default a chip is
2925
+ * selectable, and it becomes non-selectable if its parent chip list is
2926
+ * not selectable.
2927
+ */
2928
+ get selectable() {
2929
+ return this._selectable && this._chipListSelectable;
2930
+ }
2931
+ set selectable(value) {
2932
+ this._selectable = coerceBooleanProperty(value);
2933
+ }
2934
+ /** Whether the chip is disabled. Also the individual chips are disabled when chip list is disabled */
2935
+ get disabled() {
2936
+ return this._chipListDisabled || this._disabled;
2937
+ }
2938
+ set disabled(value) {
2939
+ this._disabled = coerceBooleanProperty(value);
2940
+ }
2941
+ /**
2942
+ * Whether the chip can be removed from the list
2943
+ */
2944
+ get removable() {
2945
+ return this._removable;
2946
+ }
2947
+ set removable(value) {
2948
+ this._removable = coerceBooleanProperty(value);
2949
+ }
2950
+ /** Whether the chip is in an invalid state. */
2951
+ get invalid() {
2952
+ return this._invalid;
2953
+ }
2954
+ set invalid(value) {
2955
+ this._invalid = coerceBooleanProperty(value);
2956
+ }
2957
+ ngOnDestroy() {
2958
+ this.destroyed.emit({ chip: this });
2959
+ }
2960
+ /** Selects the chip. */
2961
+ select(isUserInput = false) {
2962
+ if (!this._selected) {
2963
+ this._selected = true;
2964
+ this._dispatchSelectionChange(isUserInput);
2965
+ this._changeDetectorRef.markForCheck();
2966
+ }
2967
+ }
2968
+ /** Deselects the chip. */
2969
+ deselect() {
2970
+ if (this._selected) {
2971
+ this._selected = false;
2972
+ this._dispatchSelectionChange();
2973
+ this._changeDetectorRef.markForCheck();
2974
+ }
2975
+ }
2976
+ /** Toggles the current selected state of this chip. */
2977
+ toggleSelected(isUserInput = false) {
2978
+ this._selected = !this.selected;
2979
+ this._dispatchSelectionChange(isUserInput);
2980
+ this._changeDetectorRef.markForCheck();
2981
+ return this.selected;
2982
+ }
2983
+ /** Allows for programmatic focusing of the chip unless it's disabled. */
2984
+ focus() {
2985
+ if (!this.disabled) {
2986
+ if (!this._hasFocus) {
2987
+ this._elementRef.nativeElement.focus();
2988
+ this.chipFocus.next({ chip: this });
2989
+ }
2990
+ this._hasFocus = true;
2991
+ }
2992
+ }
2993
+ /**
2994
+ * Allows for programmatic removal of the chip.
2995
+ * Called by the GraniteChipList when the DELETE or BACKSPACE keys are pressed.
2996
+ * Informs any listeners of the removal request. Does not remove the chip from the DOM.
2997
+ */
2998
+ remove() {
2999
+ if (this.removable || this.inputChip) {
3000
+ this.removed.emit({ chip: this });
3001
+ }
3002
+ }
3003
+ /** Handles click events on the chip. */
3004
+ _handleClick(event) {
3005
+ if (this.disabled) {
3006
+ event.preventDefault();
3007
+ return;
3008
+ }
3009
+ if (this.selectable) {
3010
+ this.toggleSelected(true);
3011
+ }
3012
+ }
3013
+ /** Handle custom key presses. */
3014
+ _handleKeydown(event) {
3015
+ if (this.disabled) {
3016
+ return;
3017
+ }
3018
+ switch (event.keyCode) {
3019
+ case DELETE:
3020
+ case BACKSPACE:
3021
+ // If the chip is removable, remove the focused chip
3022
+ this.remove();
3023
+ // Always prevent so page navigation does not occur
3024
+ event.preventDefault();
3025
+ break;
3026
+ case SPACE:
3027
+ // If we are selectable, toggle the focused chip
3028
+ if (this.selectable) {
3029
+ this.toggleSelected(true);
3030
+ }
3031
+ // Always prevent space from scrolling the page since the list has focus
3032
+ event.preventDefault();
3033
+ break;
3034
+ }
3035
+ }
3036
+ _handleRemoveClick(event) {
3037
+ this.remove();
3038
+ // We need to stop event propagation because otherwise the event will bubble up to the
3039
+ // form field and cause the `onContainerClick` method to be invoked. This method would then
3040
+ // reset the focused chip that has been focused after chip removal.
3041
+ event.stopPropagation();
3042
+ event.preventDefault();
3043
+ }
3044
+ _blur() {
3045
+ // When animations are enabled, Angular may end up removing the chip from the DOM a little
3046
+ // earlier than usual, causing it to be blurred and throwing off the logic in the chip list
3047
+ // that moves focus not the next item. To work around the issue, we defer marking the chip
3048
+ // as not focused until the next time the zone stabilizes.
3049
+ this._ngZone.onStable.pipe(take(1)).subscribe(() => {
3050
+ this._ngZone.run(() => {
3051
+ this._hasFocus = false;
3052
+ this.chipBlur.next({ chip: this });
3053
+ });
3054
+ });
3055
+ }
3056
+ _dispatchSelectionChange(isUserInput = false) {
3057
+ this.selectionChange.emit({
3058
+ source: this,
3059
+ isUserInput,
3060
+ selected: this._selected,
3061
+ });
3062
+ }
3063
+ /** The ARIA selected applied to the chip. */
3064
+ get ariaSelected() {
3065
+ // Remove the `aria-selected` when the chip is deselected in single-selection mode, because
3066
+ // it adds noise to NVDA users where "not selected" will be read out for each chip.
3067
+ return this.selectable && (this._chipListMultiple || this.selected)
3068
+ ? this.selected.toString()
3069
+ : null;
3070
+ }
3071
+ }
3072
+ GraniteChipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef, optional: true }, { token: 'tabindex', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
3073
+ GraniteChipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: GraniteChipComponent, selector: "granite-chip, granite-input-chip", inputs: { tabIndex: "tabIndex", role: "role", selected: "selected", value: "value", selectable: "selectable", disabled: "disabled", removable: "removable", invalid: "invalid", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"] }, outputs: { selectionChange: "selectionChange", removed: "removed", destroyed: "destroyed", chipFocus: "chipFocus", chipBlur: "chipBlur" }, host: { listeners: { "click": "_handleClick($event)", "keydown": "_handleKeydown($event)", "blur": "_blur()", "focus": "focus()" }, properties: { "class.granite-chip-input": "inputChip", "class.granite-chip-selectable": "selectable", "class.granite-chip-selected": "selected", "class.granite-chip-disabled": "disabled", "class.granite-chip-invalid": "invalid", "attr.tabindex": "disabled ? null : tabIndex", "attr.role": "role", "attr.disabled": "disabled || null", "attr.aria-label": "ariaLabel", "attr.aria-labelledby": "ariaLabelledby", "attr.aria-disabled": "disabled.toString()", "attr.aria-selected": "ariaSelected" }, classAttribute: "granite-chip" }, exportAs: ["graniteChip"], ngImport: i0, template: "<ng-content></ng-content>\n<button\n *ngIf=\"!disabled && (removable || inputChip)\"\n class=\"granite-chip-remove\"\n (click)=\"_handleRemoveClick($event)\"\n>\n <granite-icon\n fontIcon=\"icon-error-solid\"\n class=\"granite-chip-remove-icon\"\n [class.granite-chip-remove-icon-invalid]=\"invalid\"\n ></granite-icon>\n</button>\n", styles: [":host.granite-chip{display:-moz-inline-flex;display:inline-flex;flex-direction:row;flex-wrap:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;position:relative;box-sizing:border-box;-webkit-tap-highlight-color:transparent;border:none;-webkit-appearance:none;-moz-appearance:none;justify-content:center;align-items:center;padding-inline:var(--granite-spacing-m);padding-top:var(--granite-spacing-xs);padding-bottom:var(--granite-spacing-xs);margin:var(--granite-spacing-xxs);height:inherit;color:var(--granite-color-text-weak);background-color:var(--granite-color-background);border-radius:var(--granite-radius-l);border-style:solid;border-width:var(--granite-border-width-regular);border-color:var(--granite-color-border-hard);min-width:48px}:host.granite-chip:hover{background-color:var(--granite-color-background-hover);cursor:pointer}:host.granite-chip.granite-chip-disabled{background-color:var(--granite-color-background);color:var(--granite-color-text-hint)}:host.granite-chip.granite-chip-disabled:hover{background-color:var(--granite-color-background);cursor:auto}:host.granite-chip:not(.granite-chip-selectable):hover{background-color:var(--granite-color-background);cursor:auto}:host.granite-chip.granite-chip-invalid{background-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-invalid{background-color:var(--granite-color-background-failure);border-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-invalid:hover{border-color:var(--granite-color-signal-failure)}:host.granite-chip.granite-chip-selected:not(.granite-chip-disabled):not(.granite-chip-input){border-color:var(--granite-color-background-active);background-color:var(--granite-color-background-info)}:host.granite-chip.granite-chip-selected:not(.granite-chip-disabled):not(.granite-chip-input):hover{background-color:var(--granite-color-background-hover)}:host.granite-chip.granite-chip-input{padding-inline:var(--granite-spacing-s)}:host.granite-chip.granite-chip-input:hover{background-color:var(--granite-color-background-hover)}:host.granite-chip.granite-chip-input:hover.granite-chip-invalid{background-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-input:hover.granite-chip-invalid:hover{border-color:var(--granite-color-signal-failure)}.granite-chip-remove{display:flex;justify-content:center;align-items:center;background-color:transparent;outline:none;border:none;cursor:pointer;margin-inline-start:var(--granite-spacing-xs);margin-inline-end:0;padding:0}[dir=rtl] .granite-chip-remove{margin-inline-end:var(--granite-spacing-xs);margin-inline-start:0}.granite-chip-remove .granite-chip-remove-icon{position:relative;top:0;font-size:var(--granite-font-size-body-medium);line-height:var(--granite-line-height-regular);overflow:hidden;background-repeat:no-repeat;color:var(--granite-color-text-hint)}.granite-chip-remove .granite-chip-remove-icon:hover{color:var(--granite-color-text)}.granite-chip-remove .granite-chip-remove-icon.granite-chip-remove-icon-invalid{color:var(--granite-color-signal-failure)}\n"], components: [{ type: GraniteIconComponent, selector: "granite-icon", inputs: ["fontIcon"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
3074
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipComponent, decorators: [{
3075
+ type: Component,
3076
+ args: [{ selector: `granite-chip, granite-input-chip`, inputs: ['tabIndex'], exportAs: 'graniteChip', host: {
3077
+ class: 'granite-chip',
3078
+ '[class.granite-chip-input]': 'inputChip',
3079
+ '[class.granite-chip-selectable]': 'selectable',
3080
+ '[class.granite-chip-selected]': 'selected',
3081
+ '[class.granite-chip-disabled]': 'disabled',
3082
+ '[class.granite-chip-invalid]': 'invalid',
3083
+ '[attr.tabindex]': 'disabled ? null : tabIndex',
3084
+ '[attr.role]': 'role',
3085
+ '[attr.disabled]': 'disabled || null',
3086
+ '[attr.aria-label]': 'ariaLabel',
3087
+ '[attr.aria-labelledby]': 'ariaLabelledby',
3088
+ '[attr.aria-disabled]': 'disabled.toString()',
3089
+ '[attr.aria-selected]': 'ariaSelected',
3090
+ '(click)': '_handleClick($event)',
3091
+ '(keydown)': '_handleKeydown($event)',
3092
+ '(blur)': '_blur()',
3093
+ '(focus)': 'focus()',
3094
+ }, template: "<ng-content></ng-content>\n<button\n *ngIf=\"!disabled && (removable || inputChip)\"\n class=\"granite-chip-remove\"\n (click)=\"_handleRemoveClick($event)\"\n>\n <granite-icon\n fontIcon=\"icon-error-solid\"\n class=\"granite-chip-remove-icon\"\n [class.granite-chip-remove-icon-invalid]=\"invalid\"\n ></granite-icon>\n</button>\n", styles: [":host.granite-chip{display:-moz-inline-flex;display:inline-flex;flex-direction:row;flex-wrap:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;position:relative;box-sizing:border-box;-webkit-tap-highlight-color:transparent;border:none;-webkit-appearance:none;-moz-appearance:none;justify-content:center;align-items:center;padding-inline:var(--granite-spacing-m);padding-top:var(--granite-spacing-xs);padding-bottom:var(--granite-spacing-xs);margin:var(--granite-spacing-xxs);height:inherit;color:var(--granite-color-text-weak);background-color:var(--granite-color-background);border-radius:var(--granite-radius-l);border-style:solid;border-width:var(--granite-border-width-regular);border-color:var(--granite-color-border-hard);min-width:48px}:host.granite-chip:hover{background-color:var(--granite-color-background-hover);cursor:pointer}:host.granite-chip.granite-chip-disabled{background-color:var(--granite-color-background);color:var(--granite-color-text-hint)}:host.granite-chip.granite-chip-disabled:hover{background-color:var(--granite-color-background);cursor:auto}:host.granite-chip:not(.granite-chip-selectable):hover{background-color:var(--granite-color-background);cursor:auto}:host.granite-chip.granite-chip-invalid{background-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-invalid{background-color:var(--granite-color-background-failure);border-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-invalid:hover{border-color:var(--granite-color-signal-failure)}:host.granite-chip.granite-chip-selected:not(.granite-chip-disabled):not(.granite-chip-input){border-color:var(--granite-color-background-active);background-color:var(--granite-color-background-info)}:host.granite-chip.granite-chip-selected:not(.granite-chip-disabled):not(.granite-chip-input):hover{background-color:var(--granite-color-background-hover)}:host.granite-chip.granite-chip-input{padding-inline:var(--granite-spacing-s)}:host.granite-chip.granite-chip-input:hover{background-color:var(--granite-color-background-hover)}:host.granite-chip.granite-chip-input:hover.granite-chip-invalid{background-color:var(--granite-color-background-failure)}:host.granite-chip.granite-chip-input:hover.granite-chip-invalid:hover{border-color:var(--granite-color-signal-failure)}.granite-chip-remove{display:flex;justify-content:center;align-items:center;background-color:transparent;outline:none;border:none;cursor:pointer;margin-inline-start:var(--granite-spacing-xs);margin-inline-end:0;padding:0}[dir=rtl] .granite-chip-remove{margin-inline-end:var(--granite-spacing-xs);margin-inline-start:0}.granite-chip-remove .granite-chip-remove-icon{position:relative;top:0;font-size:var(--granite-font-size-body-medium);line-height:var(--granite-line-height-regular);overflow:hidden;background-repeat:no-repeat;color:var(--granite-color-text-hint)}.granite-chip-remove .granite-chip-remove-icon:hover{color:var(--granite-color-text)}.granite-chip-remove .granite-chip-remove-icon.granite-chip-remove-icon-invalid{color:var(--granite-color-signal-failure)}\n"] }]
3095
+ }], ctorParameters: function () {
3096
+ return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef, decorators: [{
3097
+ type: Optional
3098
+ }] }, { type: undefined, decorators: [{
3099
+ type: Attribute,
3100
+ args: ['tabindex']
3101
+ }] }];
3102
+ }, propDecorators: { role: [{
3103
+ type: Input
3104
+ }], selected: [{
3105
+ type: Input
3106
+ }], value: [{
3107
+ type: Input
3108
+ }], selectable: [{
3109
+ type: Input
3110
+ }], disabled: [{
3111
+ type: Input
3112
+ }], removable: [{
3113
+ type: Input
3114
+ }], invalid: [{
3115
+ type: Input
3116
+ }], ariaLabel: [{
3117
+ type: Input,
3118
+ args: ['aria-label']
3119
+ }], ariaLabelledby: [{
3120
+ type: Input,
3121
+ args: ['aria-labelledby']
3122
+ }], selectionChange: [{
3123
+ type: Output
3124
+ }], removed: [{
3125
+ type: Output
3126
+ }], destroyed: [{
3127
+ type: Output
3128
+ }], chipFocus: [{
3129
+ type: Output
3130
+ }], chipBlur: [{
3131
+ type: Output
3132
+ }] } });
3133
+
3134
+ class GraniteChipListBase {
3135
+ constructor(_parentForm, _parentFormGroup, ngControl) {
3136
+ this._parentForm = _parentForm;
3137
+ this._parentFormGroup = _parentFormGroup;
3138
+ this.ngControl = ngControl;
3139
+ this.stateChanges = new EventEmitter();
3140
+ }
3141
+ }
3142
+ // Increasing integer for generating unique ids for chip-list components.
3143
+ let nextUniqueId$1 = 0;
3144
+ class GraniteChipListComponent extends GraniteChipListBase {
3145
+ constructor(_elementRef, _changeDetectorRef, _dir, _parentForm, _parentFormGroup, ngControl) {
3146
+ super(_parentForm, _parentFormGroup, ngControl);
3147
+ this._elementRef = _elementRef;
3148
+ this._changeDetectorRef = _changeDetectorRef;
3149
+ this._dir = _dir;
3150
+ this.controlType = 'granite-chip-list';
3151
+ /**
3152
+ * When a chip is destroyed, we store the index of the destroyed chip until the chips
3153
+ * query list notifies about the update. This is necessary because we cannot determine an
3154
+ * appropriate chip that should receive focus until the array of chips updated completely.
3155
+ */
3156
+ this._lastDestroyedChipIndex = null;
3157
+ /** Subject that emits when the component has been destroyed. */
3158
+ this._destroyed = new Subject();
3159
+ /** Uid of the chip list */
3160
+ this._uid = `granite-chip-list-${nextUniqueId$1++}`;
3161
+ /** Tab index for the chip list. */
3162
+ this._tabIndex = 0;
3163
+ /**
3164
+ * User defined tab index.
3165
+ * When it is not null, use user defined tab index. Otherwise use _tabIndex
3166
+ */
3167
+ this._userTabIndex = null;
3168
+ this._multiple = false;
3169
+ this._disabled = false;
3170
+ this._selectable = true;
3171
+ this.ariaLabel = null;
3172
+ this.ariaLabelledby = null;
3173
+ this.ariaOrientation = 'horizontal';
3174
+ /** Function when changed */
3175
+ this._onChange = () => {
3176
+ // Implemented as part of ControlValueAccessor
3177
+ };
3178
+ /** Function when changed */
3179
+ this._onTouched = () => {
3180
+ // Implemented as part of ControlValueAccessor
3181
+ };
3182
+ this._compareWith = (o1, o2) => o1 === o2;
3183
+ if (this.ngControl) {
3184
+ this.ngControl.valueAccessor = this;
3185
+ }
3186
+ }
3187
+ /** The ARIA role applied to the chip list. */
3188
+ get role() {
3189
+ if (this._explicitRole) {
3190
+ return this._explicitRole;
3191
+ }
3192
+ return this.empty ? null : 'listbox';
3193
+ }
3194
+ set role(role) {
3195
+ this._explicitRole = role;
3196
+ }
3197
+ /** Whether the user should be allowed to select multiselect chips. */
3198
+ get multiselect() {
3199
+ return this._multiple;
3200
+ }
3201
+ set multiselect(value) {
3202
+ this._multiple = coerceBooleanProperty(value);
3203
+ this._syncChipsState();
3204
+ }
3205
+ /**
3206
+ * Whether the chip list is disabled.
3207
+ */
3208
+ get disabled() {
3209
+ return this.ngControl ? !!this.ngControl.disabled : this._disabled;
3210
+ }
3211
+ set disabled(value) {
3212
+ this._disabled = coerceBooleanProperty(value);
3213
+ this._syncChipsState();
3214
+ }
3215
+ /**
3216
+ * Whether or not this chip list is selectable. When a chip list is not selectable,
3217
+ * the selected states for all the chips inside the chip list are always ignored.
3218
+ */
3219
+ get selectable() {
3220
+ return this._selectable;
3221
+ }
3222
+ set selectable(value) {
3223
+ this._selectable = coerceBooleanProperty(value);
3224
+ if (this.chips) {
3225
+ this.chips.forEach((chip) => (chip._chipListSelectable = this._selectable));
3226
+ }
3227
+ }
3228
+ set tabindex(value) {
3229
+ this._userTabIndex = value;
3230
+ this._tabIndex = value;
3231
+ }
3232
+ /** Unique identifier for the chip list. */
3233
+ get id() {
3234
+ return this._chipInput ? this._chipInput.id : this._uid;
3235
+ }
3236
+ /** Whether any chips or the matChipInput inside of this chip-list has focus. */
3237
+ get focused() {
3238
+ return ((this._chipInput && this._chipInput.focused) || this._hasFocusedChip());
3239
+ }
3240
+ /** Whether the chip list is empty. */
3241
+ get empty() {
3242
+ return ((!this._chipInput || this._chipInput.empty) &&
3243
+ (!this.chips || this.chips.length === 0));
3244
+ }
3245
+ /** The array of selected chips inside chip list. */
3246
+ get selected() {
3247
+ var _a, _b;
3248
+ return this.multiselect
3249
+ ? ((_a = this._selectionModel) === null || _a === void 0 ? void 0 : _a.selected) || []
3250
+ : (_b = this._selectionModel) === null || _b === void 0 ? void 0 : _b.selected[0];
3251
+ }
3252
+ /** Combined stream of all of the child chips' selection change events. */
3253
+ get chipSelectionChanges() {
3254
+ return merge(...this.chips.map((chip) => chip.selectionChange));
3255
+ }
3256
+ /** Combined stream of all of the child chips' focus change events. */
3257
+ get chipFocusChanges() {
3258
+ return merge(...this.chips.map((chip) => chip.chipFocus));
3259
+ }
3260
+ /** Combined stream of all of the child chips' blur change events. */
3261
+ get chipBlurChanges() {
3262
+ return merge(...this.chips.map((chip) => chip.chipBlur));
3263
+ }
3264
+ /** Combined stream of all of the child chips' remove change events. */
3265
+ get chipRemoveChanges() {
3266
+ return merge(...this.chips.map((chip) => chip.destroyed));
3267
+ }
3268
+ ngAfterContentInit() {
3269
+ this._keyManager = new FocusKeyManager(this.chips)
3270
+ .withWrap()
3271
+ .withVerticalOrientation()
3272
+ .withHomeAndEnd()
3273
+ .withHorizontalOrientation(this._dir ? this._dir.value : 'ltr');
3274
+ if (this._dir) {
3275
+ this._dir.change
3276
+ .pipe(takeUntil(this._destroyed))
3277
+ .subscribe((dir) => this._keyManager.withHorizontalOrientation(dir));
3278
+ }
3279
+ this._keyManager.tabOut.pipe(takeUntil(this._destroyed)).subscribe(() => {
3280
+ this._allowFocusEscape();
3281
+ });
3282
+ // When the list changes, re-subscribe
3283
+ this.chips.changes
3284
+ .pipe(startWith(null), takeUntil(this._destroyed))
3285
+ .subscribe(() => {
3286
+ if (this.disabled) {
3287
+ // Since this happens after the content has been
3288
+ // checked, we need to defer it to the next tick.
3289
+ Promise.resolve().then(() => {
3290
+ this._syncChipsState();
3291
+ });
3292
+ }
3293
+ this._resetChips();
3294
+ // Reset chips selected/deselected status
3295
+ this._initializeSelection();
3296
+ // Check to see if we need to update our tab index
3297
+ this._updateTabIndex();
3298
+ // Check to see if we have a destroyed chip and need to refocus
3299
+ this._updateFocusForDestroyedChips();
3300
+ this.stateChanges.next();
3301
+ });
3302
+ }
3303
+ ngOnInit() {
3304
+ this._selectionModel = new SelectionModel(this.multiselect, undefined, false);
3305
+ this.stateChanges.next();
3306
+ }
3307
+ ngDoCheck() {
3308
+ if (this.ngControl) {
3309
+ // We need to re-evaluate this on every change detection cycle, because there are some
3310
+ // error triggers that we can't subscribe to (e.g. parent form submissions). This means
3311
+ // that whatever logic is in here has to be super lean or we risk destroying the performance.
3312
+ if (this.ngControl.disabled !== this._disabled) {
3313
+ this.disabled = !!this.ngControl.disabled;
3314
+ }
3315
+ }
3316
+ }
3317
+ ngOnDestroy() {
3318
+ this._destroyed.next();
3319
+ this._destroyed.complete();
3320
+ this.stateChanges.complete();
3321
+ this._dropSubscriptions();
3322
+ }
3323
+ /** Associates an HTML input element with this chip list. */
3324
+ registerInput(inputElement) {
3325
+ this._chipInput = inputElement;
3326
+ // We use this attribute to match the chip list to its input in test harnesses.
3327
+ // Set the attribute directly here to avoid "changed after checked" errors.
3328
+ this._elementRef.nativeElement.setAttribute('data-granite-chip-input', inputElement.id);
3329
+ }
3330
+ // Implemented as part of ControlValueAccessor.
3331
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
3332
+ writeValue(value) {
3333
+ if (this.chips) {
3334
+ this._setSelectionByValue(value, false);
3335
+ }
3336
+ }
3337
+ // Implemented as part of ControlValueAccessor.
3338
+ registerOnChange(fn) {
3339
+ this._onChange = fn;
3340
+ }
3341
+ // Implemented as part of ControlValueAccessor.
3342
+ registerOnTouched(fn) {
3343
+ this._onTouched = fn;
3344
+ }
3345
+ // Implemented as part of ControlValueAccessor.
3346
+ setDisabledState(isDisabled) {
3347
+ this.disabled = isDisabled;
3348
+ this.stateChanges.next();
3349
+ }
3350
+ /**
3351
+ * Focus chip list when click on the container.
3352
+ */
3353
+ onContainerClick(event) {
3354
+ if (!this._originatesFromChip(event)) {
3355
+ this.focus();
3356
+ }
3357
+ }
3358
+ /**
3359
+ * Focuses the first non-disabled chip in this chip list, or the associated input when there
3360
+ * are no eligible chips.
3361
+ */
3362
+ focus(options) {
3363
+ if (this.disabled) {
3364
+ return;
3365
+ }
3366
+ // Focus on first element if there's no chipInput inside chip-list
3367
+ if (this._chipInput && this._chipInput.focused) {
3368
+ // do nothing
3369
+ }
3370
+ else if (this.chips.length > 0) {
3371
+ this._keyManager.setFirstItemActive();
3372
+ this.stateChanges.next();
3373
+ }
3374
+ else {
3375
+ this._focusInput(options);
3376
+ this.stateChanges.next();
3377
+ }
3378
+ }
3379
+ /** Attempt to focus an input if we have one. */
3380
+ _focusInput(options) {
3381
+ if (this._chipInput) {
3382
+ this._chipInput.setFocus(options);
3383
+ }
3384
+ }
3385
+ /**
3386
+ * Pass events to the keyboard manager. Available here for tests.
3387
+ */
3388
+ _keydown(event) {
3389
+ const target = event.target;
3390
+ if (target && target.classList.contains('granite-chip')) {
3391
+ this._keyManager.onKeydown(event);
3392
+ this.stateChanges.next();
3393
+ }
3394
+ }
3395
+ /**
3396
+ * Check the tab index as you should not be allowed to focus an empty list.
3397
+ */
3398
+ _updateTabIndex() {
3399
+ // If we have 0 chips, we should not allow keyboard focus
3400
+ this._tabIndex = this._userTabIndex || (this.chips.length === 0 ? -1 : 0);
3401
+ }
3402
+ /**
3403
+ * If the amount of chips changed, we need to update the
3404
+ * key manager state and focus the next closest chip.
3405
+ */
3406
+ _updateFocusForDestroyedChips() {
3407
+ // Move focus to the closest chip. If no other chips remain, focus the chip-list itself.
3408
+ if (this._lastDestroyedChipIndex != null) {
3409
+ if (this.chips.length) {
3410
+ const newChipIndex = Math.min(this._lastDestroyedChipIndex, this.chips.length - 1);
3411
+ this._keyManager.setActiveItem(newChipIndex);
3412
+ }
3413
+ else {
3414
+ this.focus();
3415
+ }
3416
+ }
3417
+ this._lastDestroyedChipIndex = null;
3418
+ }
3419
+ /**
3420
+ * Utility to ensure all indexes are valid.
3421
+ *
3422
+ * @param index The index to be checked.
3423
+ * @returns True if the index is valid for our list of chips.
3424
+ */
3425
+ _isValidIndex(index) {
3426
+ return index >= 0 && index < this.chips.length;
3427
+ }
3428
+ _setSelectionByValue(value, isUserInput = true) {
3429
+ this._clearSelection();
3430
+ this.chips.forEach((chip) => chip.deselect());
3431
+ if (Array.isArray(value)) {
3432
+ value.forEach((currentValue) => this._selectValue(currentValue, isUserInput));
3433
+ this._sortValues();
3434
+ }
3435
+ else {
3436
+ const correspondingChip = this._selectValue(value, isUserInput);
3437
+ // Shift focus to the active item. Note that we shouldn't do this in multiselect
3438
+ // mode, because we don't know what chip the user interacted with last.
3439
+ if (correspondingChip) {
3440
+ if (isUserInput) {
3441
+ this._keyManager.setActiveItem(correspondingChip);
3442
+ }
3443
+ }
3444
+ }
3445
+ }
3446
+ /**
3447
+ * Finds and selects the chip based on its value.
3448
+ * @returns Chip that has the corresponding value.
3449
+ */
3450
+ _selectValue(value, isUserInput = true) {
3451
+ const correspondingChip = this.chips.find((chip) => {
3452
+ return chip.value != null && this._compareWith(chip.value, value);
3453
+ });
3454
+ if (correspondingChip) {
3455
+ correspondingChip.select(isUserInput);
3456
+ this._selectionModel.select(correspondingChip);
3457
+ }
3458
+ return correspondingChip;
3459
+ }
3460
+ _initializeSelection() {
3461
+ // Defer setting the value in order to avoid the "Expression
3462
+ // has changed after it was checked" errors from Angular.
3463
+ Promise.resolve().then(() => {
3464
+ if (this.ngControl) {
3465
+ this._setSelectionByValue(this.ngControl.value, false);
3466
+ this.stateChanges.next();
3467
+ }
3468
+ });
3469
+ }
3470
+ /**
3471
+ * Deselects every chip in the list.
3472
+ * @param skip Chip that should not be deselected.
3473
+ */
3474
+ _clearSelection(skip) {
3475
+ this._selectionModel.clear();
3476
+ this.chips.forEach((chip) => {
3477
+ if (chip !== skip) {
3478
+ chip.deselect();
3479
+ }
3480
+ });
3481
+ this.stateChanges.next();
3482
+ }
3483
+ /**
3484
+ * Sorts the model values, ensuring that they keep the same
3485
+ * order that they have in the panel.
3486
+ */
3487
+ _sortValues() {
3488
+ if (this._multiple) {
3489
+ this._selectionModel.clear();
3490
+ this.chips.forEach((chip) => {
3491
+ if (chip.selected) {
3492
+ this._selectionModel.select(chip);
3493
+ }
3494
+ });
3495
+ this.stateChanges.next();
3496
+ }
3497
+ }
3498
+ /** When blurred, mark the field as touched when focus moved outside the chip list. */
3499
+ _blur() {
3500
+ if (!this._hasFocusedChip()) {
3501
+ this._keyManager.setActiveItem(-1);
3502
+ }
3503
+ if (!this.disabled) {
3504
+ if (this._chipInput) {
3505
+ // If there's a chip input, we should check whether the focus moved to chip input.
3506
+ // If the focus is not moved to chip input, mark the field as touched. If the focus moved
3507
+ // to chip input, do nothing.
3508
+ // Timeout is needed to wait for the focus() event trigger on chip input.
3509
+ setTimeout(() => {
3510
+ if (!this.focused) {
3511
+ this._markAsTouched();
3512
+ }
3513
+ });
3514
+ }
3515
+ else {
3516
+ // If there's no chip input, then mark the field as touched.
3517
+ this._markAsTouched();
3518
+ }
3519
+ }
3520
+ }
3521
+ /** Mark the field as touched */
3522
+ _markAsTouched() {
3523
+ this._onTouched();
3524
+ this._changeDetectorRef.markForCheck();
3525
+ this.stateChanges.next();
3526
+ }
3527
+ /**
3528
+ * Removes the `tabindex` from the chip list and resets it back afterwards, allowing the
3529
+ * user to tab out of it. This prevents the list from capturing focus and redirecting
3530
+ * it back to the first chip, creating a focus trap, if it user tries to tab away.
3531
+ */
3532
+ _allowFocusEscape() {
3533
+ if (this._tabIndex !== -1) {
3534
+ this._tabIndex = -1;
3535
+ setTimeout(() => {
3536
+ this._tabIndex = this._userTabIndex || 0;
3537
+ this._changeDetectorRef.markForCheck();
3538
+ });
3539
+ }
3540
+ }
3541
+ _resetChips() {
3542
+ this._dropSubscriptions();
3543
+ this._listenToChipsFocus();
3544
+ this._listenToChipsSelection();
3545
+ this._listenToChipsRemoved();
3546
+ }
3547
+ _dropSubscriptions() {
3548
+ if (this._chipFocusSubscription) {
3549
+ this._chipFocusSubscription.unsubscribe();
3550
+ this._chipFocusSubscription = null;
3551
+ }
3552
+ if (this._chipBlurSubscription) {
3553
+ this._chipBlurSubscription.unsubscribe();
3554
+ this._chipBlurSubscription = null;
3555
+ }
3556
+ if (this._chipSelectionSubscription) {
3557
+ this._chipSelectionSubscription.unsubscribe();
3558
+ this._chipSelectionSubscription = null;
3559
+ }
3560
+ if (this._chipRemoveSubscription) {
3561
+ this._chipRemoveSubscription.unsubscribe();
3562
+ this._chipRemoveSubscription = null;
3563
+ }
3564
+ }
3565
+ /** Listens to user-generated selection events on each chip. */
3566
+ _listenToChipsSelection() {
3567
+ this._chipSelectionSubscription = this.chipSelectionChanges.subscribe((event) => {
3568
+ event.source.selected
3569
+ ? this._selectionModel.select(event.source)
3570
+ : this._selectionModel.deselect(event.source);
3571
+ // For single selection chip list, make sure the deselected value is unselected.
3572
+ if (!this.multiselect) {
3573
+ this.chips.forEach((chip) => {
3574
+ if (!this._selectionModel.isSelected(chip) && chip.selected) {
3575
+ chip.deselect();
3576
+ }
3577
+ });
3578
+ }
3579
+ });
3580
+ }
3581
+ /** Listens to user-generated selection events on each chip. */
3582
+ _listenToChipsFocus() {
3583
+ this._chipFocusSubscription = this.chipFocusChanges.subscribe((event) => {
3584
+ const chipIndex = this.chips.toArray().indexOf(event.chip);
3585
+ if (this._isValidIndex(chipIndex)) {
3586
+ this._keyManager.updateActiveItem(chipIndex);
3587
+ }
3588
+ this.stateChanges.next();
3589
+ });
3590
+ this._chipBlurSubscription = this.chipBlurChanges.subscribe(() => {
3591
+ this._blur();
3592
+ this.stateChanges.next();
3593
+ });
3594
+ }
3595
+ _listenToChipsRemoved() {
3596
+ this._chipRemoveSubscription = this.chipRemoveChanges.subscribe((event) => {
3597
+ const chip = event.chip;
3598
+ const chipIndex = this.chips.toArray().indexOf(event.chip);
3599
+ // In case the chip that will be removed is currently focused, we temporarily store
3600
+ // the index in order to be able to determine an appropriate sibling chip that will
3601
+ // receive focus.
3602
+ if (this._isValidIndex(chipIndex) && chip._hasFocus) {
3603
+ this._lastDestroyedChipIndex = chipIndex;
3604
+ }
3605
+ });
3606
+ }
3607
+ /** Checks whether an event comes from inside a chip element. */
3608
+ _originatesFromChip(event) {
3609
+ let currentElement = event.target;
3610
+ while (currentElement &&
3611
+ currentElement !== this._elementRef.nativeElement) {
3612
+ if (currentElement.classList.contains('granite-chip')) {
3613
+ return true;
3614
+ }
3615
+ currentElement = currentElement.parentElement;
3616
+ }
3617
+ return false;
3618
+ }
3619
+ /** Checks whether any of the chips is focused. */
3620
+ _hasFocusedChip() {
3621
+ return this.chips && this.chips.some((chip) => chip._hasFocus);
3622
+ }
3623
+ /** Syncs the list's state with the individual chips. */
3624
+ _syncChipsState() {
3625
+ if (this.chips) {
3626
+ this.chips.forEach((chip) => {
3627
+ chip._chipListDisabled = this._disabled;
3628
+ chip._chipListMultiple = this.multiselect;
3629
+ });
3630
+ }
3631
+ }
3632
+ }
3633
+ GraniteChipListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipListComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i3$1.Directionality, optional: true }, { token: i2$1.NgForm, optional: true }, { token: i2$1.FormGroupDirective, optional: true }, { token: i2$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
3634
+ GraniteChipListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: GraniteChipListComponent, selector: "granite-chip-list", inputs: { role: "role", multiselect: "multiselect", disabled: "disabled", selectable: "selectable", tabindex: "tabindex", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], ariaOrientation: ["aria-orientation", "ariaOrientation"] }, host: { listeners: { "focus": "focus()", "blur": "_blur()", "keydown": "_keydown($event)" }, properties: { "class.granite-chip-list-disabled": "disabled", "attr.tabindex": "disabled ? null : _tabIndex", "attr.role": "role", "attr.aria-label": "ariaLabel", "attr.aria-labelledby": "ariaLabelledby", "attr.aria-disabled": "disabled.toString()", "attr.aria-multiselectable": "multiselect", "attr.aria-orientation": "ariaOrientation", "id": "_uid" }, classAttribute: "granite-chip-list" }, queries: [{ propertyName: "chips", predicate: GraniteChipComponent, descendants: true }], exportAs: ["graniteChipList"], usesInheritance: true, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [".granite-chip-list{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-items:center;align-content:center;font-weight:400;font-size:var(--granite-font-size-body-small);line-height:var(--granite-line-height-flowing);overflow:auto;padding:0;margin:0}input.granite-chip-input{outline:none;border:none;background-color:transparent;color:var(--granite-color-text);margin-top:var(--granite-spacing-s);margin-bottom:var(--granite-spacing-s);margin-inline:var(--granite-spacing-xs)}granite-icon{color:var(--granite-color-text);background-color:transparent}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipListComponent, decorators: [{
3636
+ type: Component,
3637
+ args: [{ selector: 'granite-chip-list', template: `<ng-content></ng-content>`, exportAs: 'graniteChipList', host: {
3638
+ class: 'granite-chip-list',
3639
+ '[class.granite-chip-list-disabled]': 'disabled',
3640
+ '[attr.tabindex]': 'disabled ? null : _tabIndex',
3641
+ '[attr.role]': 'role',
3642
+ '[attr.aria-label]': 'ariaLabel',
3643
+ '[attr.aria-labelledby]': 'ariaLabelledby',
3644
+ '[attr.aria-disabled]': 'disabled.toString()',
3645
+ '[attr.aria-multiselectable]': 'multiselect',
3646
+ '[attr.aria-orientation]': 'ariaOrientation',
3647
+ '[id]': '_uid',
3648
+ '(focus)': 'focus()',
3649
+ '(blur)': '_blur()',
3650
+ '(keydown)': '_keydown($event)',
3651
+ }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".granite-chip-list{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-items:center;align-content:center;font-weight:400;font-size:var(--granite-font-size-body-small);line-height:var(--granite-line-height-flowing);overflow:auto;padding:0;margin:0}input.granite-chip-input{outline:none;border:none;background-color:transparent;color:var(--granite-color-text);margin-top:var(--granite-spacing-s);margin-bottom:var(--granite-spacing-s);margin-inline:var(--granite-spacing-xs)}granite-icon{color:var(--granite-color-text);background-color:transparent}\n"] }]
3652
+ }], ctorParameters: function () {
3653
+ return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i3$1.Directionality, decorators: [{
3654
+ type: Optional
3655
+ }] }, { type: i2$1.NgForm, decorators: [{
3656
+ type: Optional
3657
+ }] }, { type: i2$1.FormGroupDirective, decorators: [{
3658
+ type: Optional
3659
+ }] }, { type: i2$1.NgControl, decorators: [{
3660
+ type: Optional
3661
+ }, {
3662
+ type: Self
3663
+ }] }];
3664
+ }, propDecorators: { role: [{
3665
+ type: Input
3666
+ }], multiselect: [{
3667
+ type: Input
3668
+ }], disabled: [{
3669
+ type: Input
3670
+ }], selectable: [{
3671
+ type: Input
3672
+ }], tabindex: [{
3673
+ type: Input
3674
+ }], ariaLabel: [{
3675
+ type: Input,
3676
+ args: ['aria-label']
3677
+ }], ariaLabelledby: [{
3678
+ type: Input,
3679
+ args: ['aria-labelledby']
3680
+ }], ariaOrientation: [{
3681
+ type: Input,
3682
+ args: ['aria-orientation']
3683
+ }], chips: [{
3684
+ type: ContentChildren,
3685
+ args: [GraniteChipComponent, {
3686
+ // We need to use `descendants: true`, because Ivy will no longer match
3687
+ // indirect descendants if it's left as false.
3688
+ descendants: true,
3689
+ }]
3690
+ }] } });
3691
+
3692
+ let nextUniqueId = 0;
3693
+ class GraniteChipInputDirective {
3694
+ constructor(_elementRef) {
3695
+ this._elementRef = _elementRef;
3696
+ /** Unique id for the input. */
3697
+ this.id = `granite-chip-list-input-${nextUniqueId++}`;
3698
+ /** The input's placeholder text. */
3699
+ this.placeholder = '';
3700
+ /**
3701
+ * The list of key codes that will trigger a chipEnd event.
3702
+ *
3703
+ * Defaults to `[ENTER]`.
3704
+ */
3705
+ this.graniteChipInputSeparatorKeyCodes = [
3706
+ ENTER,
3707
+ ];
3708
+ this._addOnBlur = true;
3709
+ this._disabled = false;
3710
+ /** Emitted when a chip is to be added. */
3711
+ this.graniteChipInputTokenEnd = new EventEmitter();
3712
+ this.focused = false;
3713
+ this.inputElement = this._elementRef.nativeElement;
3714
+ }
3715
+ /** Register input for chip list */
3716
+ set graniteChipInputFor(value) {
3717
+ if (value) {
3718
+ this._chipList = value;
3719
+ this._chipList.registerInput(this);
3720
+ }
3721
+ }
3722
+ /**
3723
+ * Whether or not the chipEnd event will be emitted when the input is blurred.
3724
+ */
3725
+ get graniteChipInputAddOnBlur() {
3726
+ return this._addOnBlur;
3727
+ }
3728
+ set graniteChipInputAddOnBlur(value) {
3729
+ this._addOnBlur = coerceBooleanProperty(value);
3730
+ }
3731
+ /**
3732
+ * Whether this is a required field, currently we use it only for setting aria-required.
3733
+ */
3734
+ get required() {
3735
+ return this._required;
3736
+ }
3737
+ set required(value) {
3738
+ this._required = coerceBooleanProperty(value);
3739
+ }
3740
+ /** Whether the input is disabled. */
3741
+ get disabled() {
3742
+ return this._disabled || (this._chipList && this._chipList.disabled);
3743
+ }
3744
+ set disabled(value) {
3745
+ this._disabled = coerceBooleanProperty(value);
3746
+ }
3747
+ ngOnChanges() {
3748
+ this._chipList.stateChanges.next();
3749
+ }
3750
+ ngOnDestroy() {
3751
+ this.graniteChipInputTokenEnd.complete();
3752
+ }
3753
+ ngAfterContentInit() {
3754
+ this._focusLastChipOnBackspace = this.empty;
3755
+ }
3756
+ /** Utility method to make host definition/tests more clear. */
3757
+ _keydown(event) {
3758
+ if (event) {
3759
+ // Allow the user's focus to escape when they're tabbing forward. Note that we don't
3760
+ // want to do this when going backwards, because focus should go back to the first chip.
3761
+ if (event.keyCode === TAB && !hasModifierKey(event, 'shiftKey')) {
3762
+ this._chipList._allowFocusEscape();
3763
+ }
3764
+ // To prevent the user from accidentally deleting chips when pressing BACKSPACE continuously,
3765
+ // We focus the last chip on backspace only after the user has released the backspace button,
3766
+ // and the input is empty (see behaviour in _keyup)
3767
+ if (event.keyCode === BACKSPACE && this._focusLastChipOnBackspace) {
3768
+ this._chipList._keyManager.setLastItemActive();
3769
+ event.preventDefault();
3770
+ return;
3771
+ }
3772
+ else {
3773
+ this._focusLastChipOnBackspace = false;
3774
+ }
3775
+ }
3776
+ this._emitChipEnd(event);
3777
+ }
3778
+ /**
3779
+ * Pass events to the keyboard manager. Available here for tests.
3780
+ */
3781
+ _keyup(event) {
3782
+ // Allow user to move focus to chips next time he presses backspace
3783
+ if (!this._focusLastChipOnBackspace &&
3784
+ event.keyCode === BACKSPACE &&
3785
+ this.empty) {
3786
+ this._focusLastChipOnBackspace = true;
3787
+ event.preventDefault();
3788
+ }
3789
+ }
3790
+ /** Checks to see if the blur should emit the (chipEnd) event. */
3791
+ _blur() {
3792
+ if (this.graniteChipInputAddOnBlur) {
3793
+ this._emitChipEnd();
3794
+ }
3795
+ this.focused = false;
3796
+ // Blur the chip list if it is not focused
3797
+ if (!this._chipList.focused) {
3798
+ this._chipList._blur();
3799
+ }
3800
+ this._chipList.stateChanges.next();
3801
+ }
3802
+ _focus() {
3803
+ this.focused = true;
3804
+ this._focusLastChipOnBackspace = this.empty;
3805
+ this._chipList.stateChanges.next();
3806
+ }
3807
+ /** Checks to see if the (chipEnd) event needs to be emitted. */
3808
+ _emitChipEnd(event) {
3809
+ if (!this.inputElement.value && !!event) {
3810
+ this._chipList._keydown(event);
3811
+ }
3812
+ if (!event || this._isSeparatorKey(event)) {
3813
+ this.graniteChipInputTokenEnd.emit({
3814
+ input: this.inputElement,
3815
+ value: this.inputElement.value,
3816
+ chipInput: this,
3817
+ });
3818
+ event === null || event === void 0 ? void 0 : event.preventDefault();
3819
+ }
3820
+ }
3821
+ _onInput() {
3822
+ // Let chip list know whenever the value changes.
3823
+ this._chipList.stateChanges.next();
3824
+ }
3825
+ /** Focuses the input (called from parent level). */
3826
+ setFocus(options) {
3827
+ this.inputElement.focus(options);
3828
+ }
3829
+ /** Clears the input */
3830
+ clear() {
3831
+ this.inputElement.value = '';
3832
+ this._focusLastChipOnBackspace = true;
3833
+ }
3834
+ /** Whether the input is empty. */
3835
+ get empty() {
3836
+ return !this.inputElement.value;
3837
+ }
3838
+ /** Checks whether a keycode is one of the configured separators. */
3839
+ _isSeparatorKey(event) {
3840
+ return (!hasModifierKey(event) &&
3841
+ new Set(this.graniteChipInputSeparatorKeyCodes).has(event.keyCode));
3842
+ }
3843
+ }
3844
+ GraniteChipInputDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipInputDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
3845
+ GraniteChipInputDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: GraniteChipInputDirective, selector: "input[graniteChipInputFor]", inputs: { id: "id", placeholder: "placeholder", graniteChipInputFor: "graniteChipInputFor", graniteChipInputSeparatorKeyCodes: "graniteChipInputSeparatorKeyCodes", graniteChipInputAddOnBlur: "graniteChipInputAddOnBlur", required: "required", disabled: "disabled" }, outputs: { graniteChipInputTokenEnd: "graniteChipInputTokenEnd" }, host: { listeners: { "keydown": "_keydown($event)", "keyup": "_keyup($event)", "blur": "_blur()", "focus": "_focus()", "input": "_onInput()" }, properties: { "id": "id", "attr.disabled": "disabled || null", "attr.placeholder": "placeholder || null", "attr.aria-required": "required || null" }, classAttribute: "granite-chip-input" }, exportAs: ["graniteChipInput", "graniteChipInputFor"], usesOnChanges: true, ngImport: i0 });
3846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipInputDirective, decorators: [{
3847
+ type: Directive,
3848
+ args: [{
3849
+ selector: 'input[graniteChipInputFor]',
3850
+ exportAs: 'graniteChipInput, graniteChipInputFor',
3851
+ host: {
3852
+ class: 'granite-chip-input',
3853
+ '[id]': 'id',
3854
+ '[attr.disabled]': 'disabled || null',
3855
+ '[attr.placeholder]': 'placeholder || null',
3856
+ '[attr.aria-required]': 'required || null',
3857
+ '(keydown)': '_keydown($event)',
3858
+ '(keyup)': '_keyup($event)',
3859
+ '(blur)': '_blur()',
3860
+ '(focus)': '_focus()',
3861
+ '(input)': '_onInput()',
3862
+ },
3863
+ }]
3864
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { id: [{
3865
+ type: Input
3866
+ }], placeholder: [{
3867
+ type: Input
3868
+ }], graniteChipInputFor: [{
3869
+ type: Input
3870
+ }], graniteChipInputSeparatorKeyCodes: [{
3871
+ type: Input
3872
+ }], graniteChipInputAddOnBlur: [{
3873
+ type: Input
3874
+ }], required: [{
3875
+ type: Input
3876
+ }], disabled: [{
3877
+ type: Input
3878
+ }], graniteChipInputTokenEnd: [{
3879
+ type: Output
3880
+ }] } });
3881
+
3882
+ const CHIP_DECLARATIONS = [
3883
+ GraniteChipListComponent,
3884
+ GraniteChipComponent,
3885
+ GraniteChipInputDirective,
3886
+ ];
3887
+ class GraniteChipsModule {
3888
+ }
3889
+ GraniteChipsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3890
+ GraniteChipsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipsModule, declarations: [GraniteChipListComponent,
3891
+ GraniteChipComponent,
3892
+ GraniteChipInputDirective], imports: [CommonModule, FormsModule, ReactiveFormsModule, GraniteIconModule], exports: [GraniteChipListComponent,
3893
+ GraniteChipComponent,
3894
+ GraniteChipInputDirective] });
3895
+ GraniteChipsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipsModule, imports: [[CommonModule, FormsModule, ReactiveFormsModule, GraniteIconModule]] });
3896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: GraniteChipsModule, decorators: [{
3897
+ type: NgModule,
3898
+ args: [{
3899
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, GraniteIconModule],
3900
+ declarations: CHIP_DECLARATIONS,
3901
+ exports: CHIP_DECLARATIONS,
3902
+ }]
3903
+ }] });
3904
+
2850
3905
  class GraniteLabelComponent {
2851
3906
  constructor() {
2852
3907
  this.for = null;
@@ -3062,5 +4117,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
3062
4117
  * Generated bundle index. Do not edit.
3063
4118
  */
3064
4119
 
3065
- export { ButtonSelectors, ClientInputDesktopDirective, ClientInputTouchDirective, ClientOutputDesktopDirective, ClientOutputTouchDirective, GRANITE_CLIENT_INPUT, GRANITE_CLIENT_OUTPUT, GraniteAnchorComponent, GraniteArrangeGridComponent, GraniteArrangeGridItemComponent, GraniteArrangeGridModule, GraniteArrangeGridOrientation, GraniteBadgeComponent, GraniteBadgeHarness, GraniteBadgeModule, GraniteButtonComponent, GraniteButtonModule, GraniteCheckboxComponent, GraniteCheckboxGroupComponent, GraniteCheckboxModule, GraniteCoreModule, GraniteDividerDirective, GraniteGridComponent, GraniteGridItemComponent, GraniteGridModule, GraniteIconComponent, GraniteIconModule, GraniteInputFieldComponent, GraniteInputFieldModule, GraniteLabelComponent, GraniteLabelModule, GraniteMenuComponent, GraniteMenuHarness, GraniteMenuItemComponent, GraniteMenuItemHarness, GraniteMenuModule, GraniteMenuTouchCloseComponent, GraniteMenuTouchTitleItemComponent, GraniteMenuTriggerForDirective, GraniteRadioButtonComponent, GraniteRadioButtonModule, GraniteRadioGroupComponent, GraniteTitleDirective, GraniteTitlePipe, GraniteToggleSwitchComponent, GraniteToggleSwitchModule, PurePipesModule, deviceDesktop, deviceTouch, disabledMixin, graniteMenuDesktopAnimations, graniteMenuTouchAnimations };
4120
+ export { ButtonSelectors, ClientInputDesktopDirective, ClientInputTouchDirective, ClientOutputDesktopDirective, ClientOutputTouchDirective, GRANITE_CLIENT_INPUT, GRANITE_CLIENT_OUTPUT, GraniteAnchorComponent, GraniteArrangeGridComponent, GraniteArrangeGridItemComponent, GraniteArrangeGridModule, GraniteArrangeGridOrientation, GraniteBadgeComponent, GraniteBadgeHarness, GraniteBadgeModule, GraniteButtonComponent, GraniteButtonModule, GraniteCheckboxComponent, GraniteCheckboxGroupComponent, GraniteCheckboxModule, GraniteChipComponent, GraniteChipInputDirective, GraniteChipListComponent, GraniteChipSelectionChangeEvent, GraniteChipsModule, GraniteCoreModule, GraniteDividerDirective, GraniteGridComponent, GraniteGridItemComponent, GraniteGridModule, GraniteIconComponent, GraniteIconModule, GraniteInputFieldComponent, GraniteInputFieldModule, GraniteLabelComponent, GraniteLabelModule, GraniteMenuComponent, GraniteMenuHarness, GraniteMenuItemComponent, GraniteMenuItemHarness, GraniteMenuModule, GraniteMenuTouchCloseComponent, GraniteMenuTouchTitleItemComponent, GraniteMenuTriggerForDirective, GraniteRadioButtonComponent, GraniteRadioButtonModule, GraniteRadioGroupComponent, GraniteTitleDirective, GraniteTitlePipe, GraniteToggleSwitchComponent, GraniteToggleSwitchModule, PurePipesModule, deviceDesktop, deviceTouch, disabledMixin, graniteMenuDesktopAnimations, graniteMenuTouchAnimations };
3066
4121
  //# sourceMappingURL=ifsworld-granite-components.mjs.map