@ifsworld/granite-components 6.1.0 → 6.1.2

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