@fundamental-ngx/cdk 0.57.4-rc.9 → 0.57.4

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.
@@ -8,7 +8,7 @@ import { coerceElement, coerceBooleanProperty, coerceNumberProperty, coerceArray
8
8
  import { get, findLastIndex, escape } from 'lodash-es';
9
9
  import { createFocusTrap } from 'focus-trap';
10
10
  import * as i1$1 from '@angular/cdk/a11y';
11
- import { FocusKeyManager, LiveAnnouncer } from '@angular/cdk/a11y';
11
+ import { FocusKeyManager, LiveAnnouncer, InteractivityChecker } from '@angular/cdk/a11y';
12
12
  import * as i1 from '@angular/cdk/observers';
13
13
  import * as i1$5 from '@angular/cdk/overlay';
14
14
  import { ViewportRuler, OverlayConfig, OverlayContainer } from '@angular/cdk/overlay';
@@ -355,7 +355,7 @@ class AutoCompleteDirective {
355
355
  * By ensuring that we set all properties we can proceed with stable data.
356
356
  */
357
357
  this._zone.runOutsideAngular(() => {
358
- const keyupEvent = fromEvent(this._elementRef.nativeElement, 'keyup');
358
+ const keyupEvent = fromEvent(this._elementRef.nativeElement, 'keydown');
359
359
  const compositionStartEvent = fromEvent(this._elementRef.nativeElement, 'compositionstart');
360
360
  const compositionEndEvent = fromEvent(this._elementRef.nativeElement, 'compositionend');
361
361
  keyupEvent
@@ -2093,6 +2093,10 @@ class FocusableItemDirective {
2093
2093
  this.cellFocusedEventAnnouncer = this._defaultItemFocusedEventAnnouncer;
2094
2094
  /** Event emitted when the cell receives focus, not being emitted when focus moves between item's children. */
2095
2095
  this.cellFocused = new EventEmitter();
2096
+ /** Event emitted when a focusable child element is focused. */
2097
+ this.focusableChildElementFocused = new EventEmitter();
2098
+ /** @hidden */
2099
+ this._parentFocusableItemFocused = new EventEmitter();
2096
2100
  /** Element reference. */
2097
2101
  this.elementRef = inject(ElementRef);
2098
2102
  /** @hidden */
@@ -2118,6 +2122,8 @@ class FocusableItemDirective {
2118
2122
  /** @hidden */
2119
2123
  this._document = inject(DOCUMENT);
2120
2124
  /** @hidden */
2125
+ this._checker = inject(InteractivityChecker);
2126
+ /** @hidden */
2121
2127
  this.element = () => this.elementRef.nativeElement;
2122
2128
  this._focusableObserver
2123
2129
  .observe(this.elementRef, false)
@@ -2133,11 +2139,6 @@ class FocusableItemDirective {
2133
2139
  .subscribe(async () => {
2134
2140
  await this._onFocusin();
2135
2141
  });
2136
- fromEvent(this.elementRef.nativeElement, 'focusout')
2137
- .pipe(takeUntilDestroyed())
2138
- .subscribe(() => {
2139
- this._onFocusout();
2140
- });
2141
2142
  fromEvent(this.elementRef.nativeElement, 'keydown')
2142
2143
  .pipe(takeUntilDestroyed())
2143
2144
  .subscribe((event) => {
@@ -2155,25 +2156,35 @@ class FocusableItemDirective {
2155
2156
  }
2156
2157
  /** Set tabbable state */
2157
2158
  setTabbable(state) {
2158
- this._tabbable = state;
2159
- this._renderer2.setAttribute(this.elementRef.nativeElement, 'tabindex', this._tabbable ? '0' : '-1');
2160
- if (state) {
2161
- this._enableTabbableElements();
2162
- }
2163
- else {
2164
- this._disableTabbableElements();
2159
+ this._zone.runOutsideAngular(() => {
2160
+ this._tabbable = state;
2161
+ this._renderer2.setAttribute(this.elementRef.nativeElement, 'tabindex', this._tabbable ? '0' : '-1');
2162
+ });
2163
+ }
2164
+ /** @hidden */
2165
+ enableTabbableElements() {
2166
+ if (this._tabbableElements.size === 0) {
2167
+ return;
2165
2168
  }
2169
+ this._tabbableElements.forEach((tabIndex, element) => (element.tabIndex = tabIndex));
2170
+ this._tabbable = false;
2171
+ }
2172
+ /** @hidden */
2173
+ disableTabbableElements() {
2174
+ // Since we cannot select by tabindex attribute (links, inputs, buttons might not have one but still can be focusable),
2175
+ // Select all elements from the cell and filter by tabIndex property.
2176
+ Array.from(this.elementRef.nativeElement.querySelectorAll('*'))
2177
+ .filter((elm) => elm.tabIndex >= 0)
2178
+ .forEach((elm) => {
2179
+ this._tabbableElements.set(elm, elm.tabIndex);
2180
+ elm.tabIndex = -1;
2181
+ });
2166
2182
  }
2167
2183
  /** @hidden */
2168
2184
  async _onFocusin() {
2169
2185
  if (!this.fdkFocusableItem) {
2170
2186
  return;
2171
2187
  }
2172
- if (this._timerId != null) {
2173
- clearTimeout(this._timerId);
2174
- this._timerId = null;
2175
- return;
2176
- }
2177
2188
  if (this._position) {
2178
2189
  this.cellFocused.next(this._position);
2179
2190
  if (this.cellFocusedEventAnnouncer) {
@@ -2181,27 +2192,28 @@ class FocusableItemDirective {
2181
2192
  await this._liveAnnouncer.announce(this.cellFocusedEventAnnouncer(this._position));
2182
2193
  }
2183
2194
  }
2184
- }
2185
- /** @hidden */
2186
- _onFocusout() {
2187
- if (!this.fdkFocusableItem) {
2188
- return;
2195
+ const activeEl = this._document.activeElement;
2196
+ if (activeEl === this.elementRef.nativeElement) {
2197
+ this._parentFocusableItemFocused.emit();
2198
+ }
2199
+ else if (activeEl && activeEl !== this.elementRef.nativeElement && this._checker.isFocusable(activeEl)) {
2200
+ this.focusableChildElementFocused.emit();
2189
2201
  }
2190
- // Timeout is needed to prevent focusout event from being emitted when focus moves between item's children.
2191
- this._timerId = setTimeout(() => (this._timerId = null));
2192
2202
  }
2193
2203
  /** @hidden */
2194
2204
  _onKeydown(event) {
2195
2205
  if (!this.fdkFocusableItem) {
2196
2206
  return;
2197
2207
  }
2198
- const isFocused = this._document.activeElement === this.elementRef.nativeElement;
2208
+ const activeEl = this._document.activeElement;
2209
+ const isFocused = activeEl === this.elementRef.nativeElement;
2199
2210
  const shouldFocusChild = KeyUtil.isKeyCode(event, [ENTER, MAC_ENTER, F2]) && !event.shiftKey && isFocused;
2200
2211
  const shouldFocusCell = ((KeyUtil.isKeyCode(event, F2) && event.shiftKey) || KeyUtil.isKeyCode(event, ESCAPE)) && !isFocused;
2201
2212
  if (shouldFocusChild) {
2202
2213
  event.stopPropagation();
2203
2214
  const tabbableElement = this._tabbableElementService.getTabbableElement(this.elementRef.nativeElement, false, true);
2204
2215
  tabbableElement?.focus();
2216
+ this.focusableChildElementFocused.emit();
2205
2217
  return;
2206
2218
  }
2207
2219
  else if (shouldFocusCell) {
@@ -2214,30 +2226,11 @@ class FocusableItemDirective {
2214
2226
  }
2215
2227
  }
2216
2228
  /** @hidden */
2217
- _enableTabbableElements() {
2218
- if (this._tabbableElements.size === 0) {
2219
- return;
2220
- }
2221
- this._tabbableElements.forEach((tabIndex, element) => (element.tabIndex = tabIndex));
2222
- this._tabbable = false;
2223
- }
2224
- /** @hidden */
2225
- _disableTabbableElements() {
2226
- // Since we cannot select by tabindex attribute (links, inputs, buttons might not have one but still can be focusable),
2227
- // Select all elements from the cell and filter by tabIndex property.
2228
- Array.from(this.elementRef.nativeElement.querySelectorAll('*'))
2229
- .filter((elm) => elm.tabIndex >= 0)
2230
- .forEach((elm) => {
2231
- this._tabbableElements.set(elm, elm.tabIndex);
2232
- elm.tabIndex = -1;
2233
- });
2234
- }
2235
- /** @hidden */
2236
2229
  _defaultItemFocusedEventAnnouncer(position) {
2237
2230
  return `Column ${position.colIndex + 1} of ${position.totalCols}, row: ${position.rowIndex + 1} of ${position.totalRows}`;
2238
2231
  }
2239
2232
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FocusableItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2240
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.1.4", type: FocusableItemDirective, isStandalone: true, selector: "[fdkFocusableItem]", inputs: { fdkFocusableItem: ["fdkFocusableItem", "fdkFocusableItem", booleanAttribute], cellFocusedEventAnnouncer: "cellFocusedEventAnnouncer" }, outputs: { cellFocused: "cellFocused" }, providers: [
2233
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.1.4", type: FocusableItemDirective, isStandalone: true, selector: "[fdkFocusableItem]", inputs: { fdkFocusableItem: ["fdkFocusableItem", "fdkFocusableItem", booleanAttribute], cellFocusedEventAnnouncer: "cellFocusedEventAnnouncer" }, outputs: { cellFocused: "cellFocused", focusableChildElementFocused: "focusableChildElementFocused", _parentFocusableItemFocused: "_parentFocusableItemFocused" }, providers: [
2241
2234
  {
2242
2235
  provide: FDK_FOCUSABLE_ITEM_DIRECTIVE,
2243
2236
  useExisting: FocusableItemDirective
@@ -2263,6 +2256,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
2263
2256
  type: Input
2264
2257
  }], cellFocused: [{
2265
2258
  type: Output
2259
+ }], focusableChildElementFocused: [{
2260
+ type: Output
2261
+ }], _parentFocusableItemFocused: [{
2262
+ type: Output
2266
2263
  }] } });
2267
2264
 
2268
2265
  class FocusableItemModule {
@@ -2643,7 +2640,8 @@ class FocusableListDirective {
2643
2640
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2644
2641
  this._gridItemFocused$.next(directiveItem._position);
2645
2642
  }
2646
- this.itemFocused.next({ index, total: items.length });
2643
+ const id = getItemElement(item)?.id ?? null;
2644
+ this.itemFocused.next({ index, total: items.length, id });
2647
2645
  this._focusableItems.forEach((i) => i.setTabbable(i === directiveItem));
2648
2646
  this._keyManager?.setActiveItem(index);
2649
2647
  }));
@@ -2761,7 +2759,21 @@ class FocusableGridDirective {
2761
2759
  ngAfterViewInit() {
2762
2760
  this._focusableLists.changes
2763
2761
  .pipe(startWith$1(this._focusableLists), takeUntilDestroyed(this._destroyRef))
2764
- .subscribe((lists) => lists.forEach((list, index) => list._setGridPosition({ rowIndex: index, totalRows: this._focusableLists.length })));
2762
+ .subscribe((lists) => {
2763
+ lists.forEach((list, index) => {
2764
+ list._setGridPosition({ rowIndex: index, totalRows: this._focusableLists.length });
2765
+ list._focusableItems.changes
2766
+ .pipe(startWith$1(list._focusableItems), takeUntilDestroyed(this._destroyRef))
2767
+ .subscribe((items) => {
2768
+ this._handleItemSubscriptions(items);
2769
+ });
2770
+ });
2771
+ });
2772
+ this._focusableItems.changes
2773
+ .pipe(startWith$1(this._focusableItems), takeUntilDestroyed(this._destroyRef))
2774
+ .subscribe((items) => {
2775
+ this._handleItemSubscriptions(items);
2776
+ });
2765
2777
  this._focusableLists.changes
2766
2778
  .pipe(startWith$1(this._focusableLists), switchMap((queryList) => merge(...queryList.toArray().map((list) => list._gridListFocused$))), takeUntilDestroyed(this._destroyRef))
2767
2779
  .subscribe((focusedEvent) => {
@@ -2861,13 +2873,38 @@ class FocusableGridDirective {
2861
2873
  }
2862
2874
  return this.shortRowFocus === 'first' ? 0 : list._focusableItems.length - 1;
2863
2875
  }
2876
+ /** @hidden */
2877
+ _handleItemSubscriptions(items) {
2878
+ items.forEach((item) => {
2879
+ item.focusableChildElementFocused.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
2880
+ this._focusableLists.forEach((focusableList) => {
2881
+ focusableList._focusableItems.forEach((focusableItem) => {
2882
+ focusableItem.setTabbable(false);
2883
+ focusableItem.enableTabbableElements();
2884
+ });
2885
+ });
2886
+ });
2887
+ item._parentFocusableItemFocused.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
2888
+ this._focusableLists.forEach((focusableList) => {
2889
+ focusableList._focusableItems.forEach((focusableItem) => {
2890
+ if (item !== focusableItem) {
2891
+ focusableItem.disableTabbableElements();
2892
+ }
2893
+ else {
2894
+ focusableItem.enableTabbableElements();
2895
+ }
2896
+ });
2897
+ });
2898
+ });
2899
+ });
2900
+ }
2864
2901
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FocusableGridDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2865
2902
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.1.4", type: FocusableGridDirective, isStandalone: true, selector: "[fdkFocusableGrid]", inputs: { contentDirection: "contentDirection", wrapHorizontally: ["wrapHorizontally", "wrapHorizontally", booleanAttribute], shortRowFocus: "shortRowFocus" }, outputs: { itemFocused: "itemFocused", rowFocused: "rowFocused" }, providers: [
2866
2903
  {
2867
2904
  provide: FDK_FOCUSABLE_GRID_DIRECTIVE,
2868
2905
  useExisting: FocusableGridDirective
2869
2906
  }
2870
- ], queries: [{ propertyName: "_focusableLists", predicate: FDK_FOCUSABLE_LIST_DIRECTIVE, descendants: true }], exportAs: ["fdkFocusableGrid"], ngImport: i0 }); }
2907
+ ], queries: [{ propertyName: "_focusableLists", predicate: FDK_FOCUSABLE_LIST_DIRECTIVE, descendants: true }, { propertyName: "_focusableItems", predicate: FDK_FOCUSABLE_ITEM_DIRECTIVE, descendants: true }], exportAs: ["fdkFocusableGrid"], ngImport: i0 }); }
2871
2908
  }
2872
2909
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FocusableGridDirective, decorators: [{
2873
2910
  type: Directive,
@@ -2896,6 +2933,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
2896
2933
  }], _focusableLists: [{
2897
2934
  type: ContentChildren,
2898
2935
  args: [FDK_FOCUSABLE_LIST_DIRECTIVE, { descendants: true }]
2936
+ }], _focusableItems: [{
2937
+ type: ContentChildren,
2938
+ args: [FDK_FOCUSABLE_ITEM_DIRECTIVE, { descendants: true }]
2899
2939
  }] } });
2900
2940
 
2901
2941
  class FocusableGridModule {