@fluentui/react-tabster 9.24.6 → 9.24.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,21 @@
1
1
  # Change Log - @fluentui/react-tabster
2
2
 
3
- This log was last generated on Thu, 24 Apr 2025 09:56:28 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 14 May 2025 18:45:48 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.24.7](https://github.com/microsoft/fluentui/tree/@fluentui/react-tabster_v9.24.7)
8
+
9
+ Wed, 14 May 2025 18:45:48 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-tabster_v9.24.6..@fluentui/react-tabster_v9.24.7)
11
+
12
+ ### Patches
13
+
14
+ - Apply focus visible attribute on navigation state change ([PR #34426](https://github.com/microsoft/fluentui/pull/34426) by lingfangao@hotmail.com)
15
+
7
16
  ## [9.24.6](https://github.com/microsoft/fluentui/tree/@fluentui/react-tabster_v9.24.6)
8
17
 
9
- Thu, 24 Apr 2025 09:56:28 GMT
18
+ Thu, 24 Apr 2025 09:59:45 GMT
10
19
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-tabster_v9.24.5..@fluentui/react-tabster_v9.24.6)
11
20
 
12
21
  ### Patches
@@ -30,6 +30,8 @@ import { FOCUS_VISIBLE_ATTR } from './constants';
30
30
  keyborg.subscribe((isNavigatingWithKeyboard)=>{
31
31
  if (!isNavigatingWithKeyboard) {
32
32
  disposeCurrentElement();
33
+ } else {
34
+ registerElementIfNavigating(targetWindow.document.activeElement);
33
35
  }
34
36
  });
35
37
  // Keyborg's focusin event is delegated so it's only registered once on the window
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/focus/focusVisiblePolyfill.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\n\nimport { FOCUS_VISIBLE_ATTR } from './constants';\n\n/**\n * Because `addEventListener` type override falls back to 2nd definition (evt name is unknown string literal)\n * evt is being typed as a base class of MouseEvent -> `Event`.\n * This type is used to override `listener` calls to make TS happy\n */\ntype ListenerOverride = (evt: Event) => void;\n\ntype FocusVisibleState = {\n /**\n * Current element with focus visible in state\n */\n current: HTMLElement | undefined;\n};\n\ntype HTMLElementWithFocusVisibleScope = {\n focusVisible: boolean | undefined;\n} & HTMLElement;\n\n/**\n * @internal\n * @param scope - Applies the ponyfill to all DOM children\n * @param targetWindow - window\n */\nexport function applyFocusVisiblePolyfill(scope: HTMLElement, targetWindow: Window): () => void {\n if (alreadyInScope(scope)) {\n // Focus visible polyfill already applied at this scope\n return () => undefined;\n }\n\n const state: FocusVisibleState = {\n current: undefined,\n };\n\n const keyborg = createKeyborg(targetWindow);\n\n function registerElementIfNavigating(el: EventTarget | HTMLElement | null) {\n if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(el)) {\n state.current = el;\n el.setAttribute(FOCUS_VISIBLE_ATTR, '');\n }\n }\n\n function disposeCurrentElement() {\n if (state.current) {\n state.current.removeAttribute(FOCUS_VISIBLE_ATTR);\n state.current = undefined;\n }\n }\n\n // When navigation mode changes remove the focus-visible selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n disposeCurrentElement();\n }\n });\n\n // Keyborg's focusin event is delegated so it's only registered once on the window\n // and contains metadata about the focus event\n const keyborgListener = (e: KeyborgFocusInEvent) => {\n disposeCurrentElement();\n const target = e.composedPath()[0];\n registerElementIfNavigating(target);\n };\n\n // Make sure that when focus leaves the scope, the focus visible class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !scope.contains(e.relatedTarget))) {\n disposeCurrentElement();\n }\n };\n\n scope.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.addEventListener('focusout', blurListener);\n (scope as HTMLElementWithFocusVisibleScope).focusVisible = true;\n\n if (scope.contains(targetWindow.document.activeElement)) {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n\n // Return disposer\n return () => {\n disposeCurrentElement();\n\n scope.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.removeEventListener('focusout', blurListener);\n delete (scope as HTMLElementWithFocusVisibleScope).focusVisible;\n\n disposeKeyborg(keyborg);\n };\n}\n\nfunction alreadyInScope(el: HTMLElement | null | undefined): boolean {\n if (!el) {\n return false;\n }\n\n if ((el as HTMLElementWithFocusVisibleScope).focusVisible) {\n return true;\n }\n\n return alreadyInScope(el?.parentElement);\n}\n"],"names":["isHTMLElement","KEYBORG_FOCUSIN","createKeyborg","disposeKeyborg","FOCUS_VISIBLE_ATTR","applyFocusVisiblePolyfill","scope","targetWindow","alreadyInScope","undefined","state","current","keyborg","registerElementIfNavigating","el","isNavigatingWithKeyboard","setAttribute","disposeCurrentElement","removeAttribute","subscribe","keyborgListener","e","target","composedPath","blurListener","relatedTarget","contains","addEventListener","focusVisible","document","activeElement","removeEventListener","parentElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,eAAe,EAAuBC,aAAa,EAAEC,cAAc,QAAQ,UAAU;AAE9F,SAASC,kBAAkB,QAAQ,cAAc;AAoBjD;;;;CAIC,GACD,OAAO,SAASC,0BAA0BC,KAAkB,EAAEC,YAAoB;IAChF,IAAIC,eAAeF,QAAQ;QACzB,uDAAuD;QACvD,OAAO,IAAMG;IACf;IAEA,MAAMC,QAA2B;QAC/BC,SAASF;IACX;IAEA,MAAMG,UAAUV,cAAcK;IAE9B,SAASM,4BAA4BC,EAAoC;QACvE,IAAIF,QAAQG,wBAAwB,MAAMf,cAAcc,KAAK;YAC3DJ,MAAMC,OAAO,GAAGG;YAChBA,GAAGE,YAAY,CAACZ,oBAAoB;QACtC;IACF;IAEA,SAASa;QACP,IAAIP,MAAMC,OAAO,EAAE;YACjBD,MAAMC,OAAO,CAACO,eAAe,CAACd;YAC9BM,MAAMC,OAAO,GAAGF;QAClB;IACF;IAEA,iEAAiE;IACjEG,QAAQO,SAAS,CAACJ,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BE;QACF;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMG,kBAAkB,CAACC;QACvBJ;QACA,MAAMK,SAASD,EAAEE,YAAY,EAAE,CAAC,EAAE;QAClCV,4BAA4BS;IAC9B;IAEA,iFAAiF;IACjF,MAAME,eAAe,CAACH;QACpB,IAAI,CAACA,EAAEI,aAAa,IAAKzB,cAAcqB,EAAEI,aAAa,KAAK,CAACnB,MAAMoB,QAAQ,CAACL,EAAEI,aAAa,GAAI;YAC5FR;QACF;IACF;IAEAX,MAAMqB,gBAAgB,CAAC1B,iBAAiBmB;IACxCd,MAAMqB,gBAAgB,CAAC,YAAYH;IAClClB,MAA2CsB,YAAY,GAAG;IAE3D,IAAItB,MAAMoB,QAAQ,CAACnB,aAAasB,QAAQ,CAACC,aAAa,GAAG;QACvDjB,4BAA4BN,aAAasB,QAAQ,CAACC,aAAa;IACjE;IAEA,kBAAkB;IAClB,OAAO;QACLb;QAEAX,MAAMyB,mBAAmB,CAAC9B,iBAAiBmB;QAC3Cd,MAAMyB,mBAAmB,CAAC,YAAYP;QACtC,OAAO,AAAClB,MAA2CsB,YAAY;QAE/DzB,eAAeS;IACjB;AACF;AAEA,SAASJ,eAAeM,EAAkC;IACxD,IAAI,CAACA,IAAI;QACP,OAAO;IACT;IAEA,IAAI,AAACA,GAAwCc,YAAY,EAAE;QACzD,OAAO;IACT;IAEA,OAAOpB,eAAeM,eAAAA,yBAAAA,GAAIkB,aAAa;AACzC"}
1
+ {"version":3,"sources":["../src/focus/focusVisiblePolyfill.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\n\nimport { FOCUS_VISIBLE_ATTR } from './constants';\n\n/**\n * Because `addEventListener` type override falls back to 2nd definition (evt name is unknown string literal)\n * evt is being typed as a base class of MouseEvent -> `Event`.\n * This type is used to override `listener` calls to make TS happy\n */\ntype ListenerOverride = (evt: Event) => void;\n\ntype FocusVisibleState = {\n /**\n * Current element with focus visible in state\n */\n current: HTMLElement | undefined;\n};\n\ntype HTMLElementWithFocusVisibleScope = {\n focusVisible: boolean | undefined;\n} & HTMLElement;\n\n/**\n * @internal\n * @param scope - Applies the ponyfill to all DOM children\n * @param targetWindow - window\n */\nexport function applyFocusVisiblePolyfill(scope: HTMLElement, targetWindow: Window): () => void {\n if (alreadyInScope(scope)) {\n // Focus visible polyfill already applied at this scope\n return () => undefined;\n }\n\n const state: FocusVisibleState = {\n current: undefined,\n };\n\n const keyborg = createKeyborg(targetWindow);\n\n function registerElementIfNavigating(el: EventTarget | HTMLElement | null) {\n if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(el)) {\n state.current = el;\n el.setAttribute(FOCUS_VISIBLE_ATTR, '');\n }\n }\n\n function disposeCurrentElement() {\n if (state.current) {\n state.current.removeAttribute(FOCUS_VISIBLE_ATTR);\n state.current = undefined;\n }\n }\n\n // When navigation mode changes remove the focus-visible selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n disposeCurrentElement();\n } else {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n });\n\n // Keyborg's focusin event is delegated so it's only registered once on the window\n // and contains metadata about the focus event\n const keyborgListener = (e: KeyborgFocusInEvent) => {\n disposeCurrentElement();\n const target = e.composedPath()[0];\n registerElementIfNavigating(target);\n };\n\n // Make sure that when focus leaves the scope, the focus visible class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !scope.contains(e.relatedTarget))) {\n disposeCurrentElement();\n }\n };\n\n scope.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.addEventListener('focusout', blurListener);\n (scope as HTMLElementWithFocusVisibleScope).focusVisible = true;\n\n if (scope.contains(targetWindow.document.activeElement)) {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n\n // Return disposer\n return () => {\n disposeCurrentElement();\n\n scope.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.removeEventListener('focusout', blurListener);\n delete (scope as HTMLElementWithFocusVisibleScope).focusVisible;\n\n disposeKeyborg(keyborg);\n };\n}\n\nfunction alreadyInScope(el: HTMLElement | null | undefined): boolean {\n if (!el) {\n return false;\n }\n\n if ((el as HTMLElementWithFocusVisibleScope).focusVisible) {\n return true;\n }\n\n return alreadyInScope(el?.parentElement);\n}\n"],"names":["isHTMLElement","KEYBORG_FOCUSIN","createKeyborg","disposeKeyborg","FOCUS_VISIBLE_ATTR","applyFocusVisiblePolyfill","scope","targetWindow","alreadyInScope","undefined","state","current","keyborg","registerElementIfNavigating","el","isNavigatingWithKeyboard","setAttribute","disposeCurrentElement","removeAttribute","subscribe","document","activeElement","keyborgListener","e","target","composedPath","blurListener","relatedTarget","contains","addEventListener","focusVisible","removeEventListener","parentElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,eAAe,EAAuBC,aAAa,EAAEC,cAAc,QAAQ,UAAU;AAE9F,SAASC,kBAAkB,QAAQ,cAAc;AAoBjD;;;;CAIC,GACD,OAAO,SAASC,0BAA0BC,KAAkB,EAAEC,YAAoB;IAChF,IAAIC,eAAeF,QAAQ;QACzB,uDAAuD;QACvD,OAAO,IAAMG;IACf;IAEA,MAAMC,QAA2B;QAC/BC,SAASF;IACX;IAEA,MAAMG,UAAUV,cAAcK;IAE9B,SAASM,4BAA4BC,EAAoC;QACvE,IAAIF,QAAQG,wBAAwB,MAAMf,cAAcc,KAAK;YAC3DJ,MAAMC,OAAO,GAAGG;YAChBA,GAAGE,YAAY,CAACZ,oBAAoB;QACtC;IACF;IAEA,SAASa;QACP,IAAIP,MAAMC,OAAO,EAAE;YACjBD,MAAMC,OAAO,CAACO,eAAe,CAACd;YAC9BM,MAAMC,OAAO,GAAGF;QAClB;IACF;IAEA,iEAAiE;IACjEG,QAAQO,SAAS,CAACJ,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BE;QACF,OAAO;YACLJ,4BAA4BN,aAAaa,QAAQ,CAACC,aAAa;QACjE;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMC,kBAAkB,CAACC;QACvBN;QACA,MAAMO,SAASD,EAAEE,YAAY,EAAE,CAAC,EAAE;QAClCZ,4BAA4BW;IAC9B;IAEA,iFAAiF;IACjF,MAAME,eAAe,CAACH;QACpB,IAAI,CAACA,EAAEI,aAAa,IAAK3B,cAAcuB,EAAEI,aAAa,KAAK,CAACrB,MAAMsB,QAAQ,CAACL,EAAEI,aAAa,GAAI;YAC5FV;QACF;IACF;IAEAX,MAAMuB,gBAAgB,CAAC5B,iBAAiBqB;IACxChB,MAAMuB,gBAAgB,CAAC,YAAYH;IAClCpB,MAA2CwB,YAAY,GAAG;IAE3D,IAAIxB,MAAMsB,QAAQ,CAACrB,aAAaa,QAAQ,CAACC,aAAa,GAAG;QACvDR,4BAA4BN,aAAaa,QAAQ,CAACC,aAAa;IACjE;IAEA,kBAAkB;IAClB,OAAO;QACLJ;QAEAX,MAAMyB,mBAAmB,CAAC9B,iBAAiBqB;QAC3ChB,MAAMyB,mBAAmB,CAAC,YAAYL;QACtC,OAAO,AAACpB,MAA2CwB,YAAY;QAE/D3B,eAAeS;IACjB;AACF;AAEA,SAASJ,eAAeM,EAAkC;IACxD,IAAI,CAACA,IAAI;QACP,OAAO;IACT;IAEA,IAAI,AAACA,GAAwCgB,YAAY,EAAE;QACzD,OAAO;IACT;IAEA,OAAOtB,eAAeM,eAAAA,yBAAAA,GAAIkB,aAAa;AACzC"}
@@ -36,6 +36,8 @@ function applyFocusVisiblePolyfill(scope, targetWindow) {
36
36
  keyborg.subscribe((isNavigatingWithKeyboard)=>{
37
37
  if (!isNavigatingWithKeyboard) {
38
38
  disposeCurrentElement();
39
+ } else {
40
+ registerElementIfNavigating(targetWindow.document.activeElement);
39
41
  }
40
42
  });
41
43
  // Keyborg's focusin event is delegated so it's only registered once on the window
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/focus/focusVisiblePolyfill.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\n\nimport { FOCUS_VISIBLE_ATTR } from './constants';\n\n/**\n * Because `addEventListener` type override falls back to 2nd definition (evt name is unknown string literal)\n * evt is being typed as a base class of MouseEvent -> `Event`.\n * This type is used to override `listener` calls to make TS happy\n */\ntype ListenerOverride = (evt: Event) => void;\n\ntype FocusVisibleState = {\n /**\n * Current element with focus visible in state\n */\n current: HTMLElement | undefined;\n};\n\ntype HTMLElementWithFocusVisibleScope = {\n focusVisible: boolean | undefined;\n} & HTMLElement;\n\n/**\n * @internal\n * @param scope - Applies the ponyfill to all DOM children\n * @param targetWindow - window\n */\nexport function applyFocusVisiblePolyfill(scope: HTMLElement, targetWindow: Window): () => void {\n if (alreadyInScope(scope)) {\n // Focus visible polyfill already applied at this scope\n return () => undefined;\n }\n\n const state: FocusVisibleState = {\n current: undefined,\n };\n\n const keyborg = createKeyborg(targetWindow);\n\n function registerElementIfNavigating(el: EventTarget | HTMLElement | null) {\n if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(el)) {\n state.current = el;\n el.setAttribute(FOCUS_VISIBLE_ATTR, '');\n }\n }\n\n function disposeCurrentElement() {\n if (state.current) {\n state.current.removeAttribute(FOCUS_VISIBLE_ATTR);\n state.current = undefined;\n }\n }\n\n // When navigation mode changes remove the focus-visible selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n disposeCurrentElement();\n }\n });\n\n // Keyborg's focusin event is delegated so it's only registered once on the window\n // and contains metadata about the focus event\n const keyborgListener = (e: KeyborgFocusInEvent) => {\n disposeCurrentElement();\n const target = e.composedPath()[0];\n registerElementIfNavigating(target);\n };\n\n // Make sure that when focus leaves the scope, the focus visible class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !scope.contains(e.relatedTarget))) {\n disposeCurrentElement();\n }\n };\n\n scope.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.addEventListener('focusout', blurListener);\n (scope as HTMLElementWithFocusVisibleScope).focusVisible = true;\n\n if (scope.contains(targetWindow.document.activeElement)) {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n\n // Return disposer\n return () => {\n disposeCurrentElement();\n\n scope.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.removeEventListener('focusout', blurListener);\n delete (scope as HTMLElementWithFocusVisibleScope).focusVisible;\n\n disposeKeyborg(keyborg);\n };\n}\n\nfunction alreadyInScope(el: HTMLElement | null | undefined): boolean {\n if (!el) {\n return false;\n }\n\n if ((el as HTMLElementWithFocusVisibleScope).focusVisible) {\n return true;\n }\n\n return alreadyInScope(el?.parentElement);\n}\n"],"names":["applyFocusVisiblePolyfill","scope","targetWindow","alreadyInScope","undefined","state","current","keyborg","createKeyborg","registerElementIfNavigating","el","isNavigatingWithKeyboard","isHTMLElement","setAttribute","FOCUS_VISIBLE_ATTR","disposeCurrentElement","removeAttribute","subscribe","keyborgListener","e","target","composedPath","blurListener","relatedTarget","contains","addEventListener","KEYBORG_FOCUSIN","focusVisible","document","activeElement","removeEventListener","disposeKeyborg","parentElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA4BgBA;;;eAAAA;;;gCA5Bc;yBACsD;2BAEjD;AAyB5B,SAASA,0BAA0BC,KAAkB,EAAEC,YAAoB;IAChF,IAAIC,eAAeF,QAAQ;QACzB,uDAAuD;QACvD,OAAO,IAAMG;IACf;IAEA,MAAMC,QAA2B;QAC/BC,SAASF;IACX;IAEA,MAAMG,UAAUC,IAAAA,sBAAa,EAACN;IAE9B,SAASO,4BAA4BC,EAAoC;QACvE,IAAIH,QAAQI,wBAAwB,MAAMC,IAAAA,6BAAa,EAACF,KAAK;YAC3DL,MAAMC,OAAO,GAAGI;YAChBA,GAAGG,YAAY,CAACC,6BAAkB,EAAE;QACtC;IACF;IAEA,SAASC;QACP,IAAIV,MAAMC,OAAO,EAAE;YACjBD,MAAMC,OAAO,CAACU,eAAe,CAACF,6BAAkB;YAChDT,MAAMC,OAAO,GAAGF;QAClB;IACF;IAEA,iEAAiE;IACjEG,QAAQU,SAAS,CAACN,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BI;QACF;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMG,kBAAkB,CAACC;QACvBJ;QACA,MAAMK,SAASD,EAAEE,YAAY,EAAE,CAAC,EAAE;QAClCZ,4BAA4BW;IAC9B;IAEA,iFAAiF;IACjF,MAAME,eAAe,CAACH;QACpB,IAAI,CAACA,EAAEI,aAAa,IAAKX,IAAAA,6BAAa,EAACO,EAAEI,aAAa,KAAK,CAACtB,MAAMuB,QAAQ,CAACL,EAAEI,aAAa,GAAI;YAC5FR;QACF;IACF;IAEAd,MAAMwB,gBAAgB,CAACC,wBAAe,EAAER;IACxCjB,MAAMwB,gBAAgB,CAAC,YAAYH;IAClCrB,MAA2C0B,YAAY,GAAG;IAE3D,IAAI1B,MAAMuB,QAAQ,CAACtB,aAAa0B,QAAQ,CAACC,aAAa,GAAG;QACvDpB,4BAA4BP,aAAa0B,QAAQ,CAACC,aAAa;IACjE;IAEA,kBAAkB;IAClB,OAAO;QACLd;QAEAd,MAAM6B,mBAAmB,CAACJ,wBAAe,EAAER;QAC3CjB,MAAM6B,mBAAmB,CAAC,YAAYR;QACtC,OAAO,AAACrB,MAA2C0B,YAAY;QAE/DI,IAAAA,uBAAc,EAACxB;IACjB;AACF;AAEA,SAASJ,eAAeO,EAAkC;IACxD,IAAI,CAACA,IAAI;QACP,OAAO;IACT;IAEA,IAAI,AAACA,GAAwCiB,YAAY,EAAE;QACzD,OAAO;IACT;IAEA,OAAOxB,eAAeO,eAAAA,yBAAAA,GAAIsB,aAAa;AACzC"}
1
+ {"version":3,"sources":["../src/focus/focusVisiblePolyfill.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\n\nimport { FOCUS_VISIBLE_ATTR } from './constants';\n\n/**\n * Because `addEventListener` type override falls back to 2nd definition (evt name is unknown string literal)\n * evt is being typed as a base class of MouseEvent -> `Event`.\n * This type is used to override `listener` calls to make TS happy\n */\ntype ListenerOverride = (evt: Event) => void;\n\ntype FocusVisibleState = {\n /**\n * Current element with focus visible in state\n */\n current: HTMLElement | undefined;\n};\n\ntype HTMLElementWithFocusVisibleScope = {\n focusVisible: boolean | undefined;\n} & HTMLElement;\n\n/**\n * @internal\n * @param scope - Applies the ponyfill to all DOM children\n * @param targetWindow - window\n */\nexport function applyFocusVisiblePolyfill(scope: HTMLElement, targetWindow: Window): () => void {\n if (alreadyInScope(scope)) {\n // Focus visible polyfill already applied at this scope\n return () => undefined;\n }\n\n const state: FocusVisibleState = {\n current: undefined,\n };\n\n const keyborg = createKeyborg(targetWindow);\n\n function registerElementIfNavigating(el: EventTarget | HTMLElement | null) {\n if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(el)) {\n state.current = el;\n el.setAttribute(FOCUS_VISIBLE_ATTR, '');\n }\n }\n\n function disposeCurrentElement() {\n if (state.current) {\n state.current.removeAttribute(FOCUS_VISIBLE_ATTR);\n state.current = undefined;\n }\n }\n\n // When navigation mode changes remove the focus-visible selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n disposeCurrentElement();\n } else {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n });\n\n // Keyborg's focusin event is delegated so it's only registered once on the window\n // and contains metadata about the focus event\n const keyborgListener = (e: KeyborgFocusInEvent) => {\n disposeCurrentElement();\n const target = e.composedPath()[0];\n registerElementIfNavigating(target);\n };\n\n // Make sure that when focus leaves the scope, the focus visible class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !scope.contains(e.relatedTarget))) {\n disposeCurrentElement();\n }\n };\n\n scope.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.addEventListener('focusout', blurListener);\n (scope as HTMLElementWithFocusVisibleScope).focusVisible = true;\n\n if (scope.contains(targetWindow.document.activeElement)) {\n registerElementIfNavigating(targetWindow.document.activeElement);\n }\n\n // Return disposer\n return () => {\n disposeCurrentElement();\n\n scope.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n scope.removeEventListener('focusout', blurListener);\n delete (scope as HTMLElementWithFocusVisibleScope).focusVisible;\n\n disposeKeyborg(keyborg);\n };\n}\n\nfunction alreadyInScope(el: HTMLElement | null | undefined): boolean {\n if (!el) {\n return false;\n }\n\n if ((el as HTMLElementWithFocusVisibleScope).focusVisible) {\n return true;\n }\n\n return alreadyInScope(el?.parentElement);\n}\n"],"names":["applyFocusVisiblePolyfill","scope","targetWindow","alreadyInScope","undefined","state","current","keyborg","createKeyborg","registerElementIfNavigating","el","isNavigatingWithKeyboard","isHTMLElement","setAttribute","FOCUS_VISIBLE_ATTR","disposeCurrentElement","removeAttribute","subscribe","document","activeElement","keyborgListener","e","target","composedPath","blurListener","relatedTarget","contains","addEventListener","KEYBORG_FOCUSIN","focusVisible","removeEventListener","disposeKeyborg","parentElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA4BgBA;;;eAAAA;;;gCA5Bc;yBACsD;2BAEjD;AAyB5B,SAASA,0BAA0BC,KAAkB,EAAEC,YAAoB;IAChF,IAAIC,eAAeF,QAAQ;QACzB,uDAAuD;QACvD,OAAO,IAAMG;IACf;IAEA,MAAMC,QAA2B;QAC/BC,SAASF;IACX;IAEA,MAAMG,UAAUC,IAAAA,sBAAa,EAACN;IAE9B,SAASO,4BAA4BC,EAAoC;QACvE,IAAIH,QAAQI,wBAAwB,MAAMC,IAAAA,6BAAa,EAACF,KAAK;YAC3DL,MAAMC,OAAO,GAAGI;YAChBA,GAAGG,YAAY,CAACC,6BAAkB,EAAE;QACtC;IACF;IAEA,SAASC;QACP,IAAIV,MAAMC,OAAO,EAAE;YACjBD,MAAMC,OAAO,CAACU,eAAe,CAACF,6BAAkB;YAChDT,MAAMC,OAAO,GAAGF;QAClB;IACF;IAEA,iEAAiE;IACjEG,QAAQU,SAAS,CAACN,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BI;QACF,OAAO;YACLN,4BAA4BP,aAAagB,QAAQ,CAACC,aAAa;QACjE;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMC,kBAAkB,CAACC;QACvBN;QACA,MAAMO,SAASD,EAAEE,YAAY,EAAE,CAAC,EAAE;QAClCd,4BAA4Ba;IAC9B;IAEA,iFAAiF;IACjF,MAAME,eAAe,CAACH;QACpB,IAAI,CAACA,EAAEI,aAAa,IAAKb,IAAAA,6BAAa,EAACS,EAAEI,aAAa,KAAK,CAACxB,MAAMyB,QAAQ,CAACL,EAAEI,aAAa,GAAI;YAC5FV;QACF;IACF;IAEAd,MAAM0B,gBAAgB,CAACC,wBAAe,EAAER;IACxCnB,MAAM0B,gBAAgB,CAAC,YAAYH;IAClCvB,MAA2C4B,YAAY,GAAG;IAE3D,IAAI5B,MAAMyB,QAAQ,CAACxB,aAAagB,QAAQ,CAACC,aAAa,GAAG;QACvDV,4BAA4BP,aAAagB,QAAQ,CAACC,aAAa;IACjE;IAEA,kBAAkB;IAClB,OAAO;QACLJ;QAEAd,MAAM6B,mBAAmB,CAACF,wBAAe,EAAER;QAC3CnB,MAAM6B,mBAAmB,CAAC,YAAYN;QACtC,OAAO,AAACvB,MAA2C4B,YAAY;QAE/DE,IAAAA,uBAAc,EAACxB;IACjB;AACF;AAEA,SAASJ,eAAeO,EAAkC;IACxD,IAAI,CAACA,IAAI;QACP,OAAO;IACT;IAEA,IAAI,AAACA,GAAwCmB,YAAY,EAAE;QACzD,OAAO;IACT;IAEA,OAAO1B,eAAeO,eAAAA,yBAAAA,GAAIsB,aAAa;AACzC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-tabster",
3
- "version": "9.24.6",
3
+ "version": "9.24.7",
4
4
  "description": "Utilities for focus management and facade for tabster",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",