@angular/cdk 14.1.0-next.3 → 14.1.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/fesm2015/a11y.mjs CHANGED
@@ -1940,10 +1940,14 @@ class FocusMonitor {
1940
1940
  */
1941
1941
  this._rootNodeFocusAndBlurListener = (event) => {
1942
1942
  const target = _getEventTarget(event);
1943
- const handler = event.type === 'focus' ? this._onFocus : this._onBlur;
1944
1943
  // We need to walk up the ancestor chain in order to support `checkChildren`.
1945
1944
  for (let element = target; element; element = element.parentElement) {
1946
- handler.call(this, event, element);
1945
+ if (event.type === 'focus') {
1946
+ this._onFocus(event, element);
1947
+ }
1948
+ else {
1949
+ this._onBlur(event, element);
1950
+ }
1947
1951
  }
1948
1952
  };
1949
1953
  this._document = document;
@@ -2039,7 +2043,17 @@ class FocusMonitor {
2039
2043
  // events).
2040
2044
  //
2041
2045
  // Because we can't distinguish between these two cases, we default to setting `program`.
2042
- return this._windowFocused && this._lastFocusOrigin ? this._lastFocusOrigin : 'program';
2046
+ if (this._windowFocused && this._lastFocusOrigin) {
2047
+ return this._lastFocusOrigin;
2048
+ }
2049
+ // If the interaction is coming from an input label, we consider it a mouse interactions.
2050
+ // This is a special case where focus moves on `click`, rather than `mousedown` which breaks
2051
+ // our detection, because all our assumptions are for `mousedown`. We need to handle this
2052
+ // special case, because it's very common for checkboxes and radio buttons.
2053
+ if (focusEventTarget && this._isLastInteractionFromInputLabel(focusEventTarget)) {
2054
+ return 'mouse';
2055
+ }
2056
+ return 'program';
2043
2057
  }
2044
2058
  /**
2045
2059
  * Returns whether the focus event should be attributed to touch. Recall that in IMMEDIATE mode, a
@@ -2213,6 +2227,33 @@ class FocusMonitor {
2213
2227
  });
2214
2228
  return results;
2215
2229
  }
2230
+ /**
2231
+ * Returns whether an interaction is likely to have come from the user clicking the `label` of
2232
+ * an `input` or `textarea` in order to focus it.
2233
+ * @param focusEventTarget Target currently receiving focus.
2234
+ */
2235
+ _isLastInteractionFromInputLabel(focusEventTarget) {
2236
+ const { _mostRecentTarget: mostRecentTarget, mostRecentModality } = this._inputModalityDetector;
2237
+ // If the last interaction used the mouse on an element contained by one of the labels
2238
+ // of an `input`/`textarea` that is currently focused, it is very likely that the
2239
+ // user redirected focus using the label.
2240
+ if (mostRecentModality !== 'mouse' ||
2241
+ !mostRecentTarget ||
2242
+ mostRecentTarget === focusEventTarget ||
2243
+ (focusEventTarget.nodeName !== 'INPUT' && focusEventTarget.nodeName !== 'TEXTAREA') ||
2244
+ focusEventTarget.disabled) {
2245
+ return false;
2246
+ }
2247
+ const labels = focusEventTarget.labels;
2248
+ if (labels) {
2249
+ for (let i = 0; i < labels.length; i++) {
2250
+ if (labels[i].contains(mostRecentTarget)) {
2251
+ return true;
2252
+ }
2253
+ }
2254
+ }
2255
+ return false;
2256
+ }
2216
2257
  }
2217
2258
  FocusMonitor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: FocusMonitor, deps: [{ token: i0.NgZone }, { token: i1.Platform }, { token: InputModalityDetector }, { token: DOCUMENT, optional: true }, { token: FOCUS_MONITOR_DEFAULT_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
2218
2259
  FocusMonitor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: FocusMonitor, providedIn: 'root' });