Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
export const KEYBOARD_NAV_ATTRIBUTE = 'data-keyboard-nav';
export const KEYBOARD_NAV_SELECTOR = `:global([${KEYBOARD_NAV_ATTRIBUTE}])`;
/**
* @internal
*/ export const FOCUS_VISIBLE_ATTR = 'data-fui-focus-visible';
/**
* @internal
*/ export const FOCUS_WITHIN_ATTR = 'data-fui-focus-within';
export const defaultOptions = {
style: {},
selector: 'focus',
customizeSelector: (selector)=>selector
};
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/constants.ts"],"sourcesContent":["export const KEYBOARD_NAV_ATTRIBUTE = 'data-keyboard-nav' as const;\nexport const KEYBOARD_NAV_SELECTOR = `:global([${KEYBOARD_NAV_ATTRIBUTE}])` as const;\n\n/**\n * @internal\n */\nexport const FOCUS_VISIBLE_ATTR = 'data-fui-focus-visible';\n\n/**\n * @internal\n */\nexport const FOCUS_WITHIN_ATTR = 'data-fui-focus-within';\nexport const defaultOptions = {\n style: {},\n selector: 'focus',\n customizeSelector: (selector: string) => selector,\n} as const;\n"],"names":["KEYBOARD_NAV_ATTRIBUTE","KEYBOARD_NAV_SELECTOR","FOCUS_VISIBLE_ATTR","FOCUS_WITHIN_ATTR","defaultOptions","style","selector","customizeSelector"],"rangeMappings":";;;;;;;;;;;;","mappings":"AAAA,OAAO,MAAMA,yBAAyB,oBAA6B;AACnE,OAAO,MAAMC,wBAAwB,CAAC,SAAS,EAAED,uBAAuB,EAAE,CAAC,CAAU;AAErF;;CAEC,GACD,OAAO,MAAME,qBAAqB,yBAAyB;AAE3D;;CAEC,GACD,OAAO,MAAMC,oBAAoB,wBAAwB;AACzD,OAAO,MAAMC,iBAAiB;IAC5BC,OAAO,CAAC;IACRC,UAAU;IACVC,mBAAmB,CAACD,WAAqBA;AAC3C,EAAW"}
@@ -0,0 +1,43 @@
import { defaultOptions, FOCUS_VISIBLE_ATTR, FOCUS_WITHIN_ATTR } from './constants';
/**
* Creates a style for @see makeStyles that includes the necessary selectors for focus.
* Should be used only when @see createFocusOutlineStyle does not fit requirements
*
* If you're using `createCustomFocusIndicatorStyle` instead of `createFocusOutlineStyle`
* keep in mind that the default outline style is not going to be removed
* (as it is in `createFocusOutlineStyle`),
* and is your responsibility to manually remove it from your styles.
*
* @example
* ```ts
* // Link styles
* const useStyles = makeStyles({
focusIndicator: createCustomFocusIndicatorStyle({
textDecorationColor: tokens.colorStrokeFocus2,
textDecorationLine: 'underline',
textDecorationStyle: 'double',
outlineStyle: 'none',
}),
// Common styles.
root: {
// ❗️ DO NOT FORGET TO REMOVE THE DEFAULT OUTLINE STYLE
':focus-visible': {
outlineStyle: 'none',
},
* ```
*
* @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyles
* @param options - Configure the style of the focus outline
*/ export function createCustomFocusIndicatorStyle(style, { selector: selectorType = defaultOptions.selector, customizeSelector = defaultOptions.customizeSelector } = defaultOptions) {
return {
[customizeSelector(createBaseSelector(selectorType))]: style
};
}
function createBaseSelector(selectorType) {
switch(selectorType){
case 'focus':
return `&[${FOCUS_VISIBLE_ATTR}]`;
case 'focus-within':
return `&[${FOCUS_WITHIN_ATTR}]:focus-within`;
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/createCustomFocusIndicatorStyle.ts"],"sourcesContent":["import { defaultOptions, FOCUS_VISIBLE_ATTR, FOCUS_WITHIN_ATTR } from './constants';\nimport { makeResetStyles } from '@griffel/react';\nimport type { GriffelStyle } from '@griffel/react';\n\n// TODO: Use the type directly from @griffel/react\n// https://github.com/microsoft/griffel/pull/278\ntype GriffelResetStyle = Parameters<typeof makeResetStyles>[0];\n\nexport interface CreateCustomFocusIndicatorStyleOptions {\n /**\n * Control if the indicator appears when the corresponding element is focused,\n * or any child is focused within the corresponding element.\n * @default 'focus'\n * @alias selectorType\n */\n selector?: 'focus' | 'focus-within';\n /**\n * Customizes the selector provided based on the selector type.\n */\n customizeSelector?: (selector: string) => string;\n /**\n * Enables the browser default outline style\n * @deprecated The custom focus indicator no longer affects outline styles. Outline is overridden\n * in the default focus indicator function, `createFocusOutlineStyle`.\n */\n enableOutline?: boolean;\n}\n\n/**\n * Creates a style for @see makeStyles that includes the necessary selectors for focus.\n * Should be used only when @see createFocusOutlineStyle does not fit requirements\n *\n * If you're using `createCustomFocusIndicatorStyle` instead of `createFocusOutlineStyle`\n * keep in mind that the default outline style is not going to be removed\n * (as it is in `createFocusOutlineStyle`),\n * and is your responsibility to manually remove it from your styles.\n *\n * @example\n * ```ts\n * // Link styles\n * const useStyles = makeStyles({\n focusIndicator: createCustomFocusIndicatorStyle({\n textDecorationColor: tokens.colorStrokeFocus2,\n textDecorationLine: 'underline',\n textDecorationStyle: 'double',\n outlineStyle: 'none',\n }),\n // Common styles.\n root: {\n // ❗️ DO NOT FORGET TO REMOVE THE DEFAULT OUTLINE STYLE\n ':focus-visible': {\n outlineStyle: 'none',\n },\n * ```\n *\n * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyles\n * @param options - Configure the style of the focus outline\n */\nexport function createCustomFocusIndicatorStyle<TStyle extends GriffelStyle | GriffelResetStyle>(\n style: TStyle,\n {\n selector: selectorType = defaultOptions.selector,\n customizeSelector = defaultOptions.customizeSelector,\n }: CreateCustomFocusIndicatorStyleOptions = defaultOptions,\n): TStyle extends GriffelStyle ? GriffelStyle : GriffelResetStyle {\n return { [customizeSelector(createBaseSelector(selectorType))]: style };\n}\n\nfunction createBaseSelector(selectorType: 'focus' | 'focus-within'): string {\n switch (selectorType) {\n case 'focus':\n return `&[${FOCUS_VISIBLE_ATTR}]`;\n case 'focus-within':\n return `&[${FOCUS_WITHIN_ATTR}]:focus-within`;\n }\n}\n"],"names":["defaultOptions","FOCUS_VISIBLE_ATTR","FOCUS_WITHIN_ATTR","createCustomFocusIndicatorStyle","style","selector","selectorType","customizeSelector","createBaseSelector"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,cAAc,EAAEC,kBAAkB,EAAEC,iBAAiB,QAAQ,cAAc;AA4BpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BC,GACD,OAAO,SAASC,gCACdC,KAAa,EACb,EACEC,UAAUC,eAAeN,eAAeK,QAAQ,EAChDE,oBAAoBP,eAAeO,iBAAiB,EACb,GAAGP,cAAc;IAE1D,OAAO;QAAE,CAACO,kBAAkBC,mBAAmBF,eAAe,EAAEF;IAAM;AACxE;AAEA,SAASI,mBAAmBF,YAAsC;IAChE,OAAQA;QACN,KAAK;YACH,OAAO,CAAC,EAAE,EAAEL,mBAAmB,CAAC,CAAC;QACnC,KAAK;YACH,OAAO,CAAC,EAAE,EAAEC,kBAAkB,cAAc,CAAC;IACjD;AACF"}
@@ -0,0 +1,70 @@
import { tokens } from '@fluentui/react-theme';
import { shorthands } from '@griffel/react';
import { createCustomFocusIndicatorStyle } from './createCustomFocusIndicatorStyle';
import { defaultOptions } from './constants';
/**
* Get the position of the focus outline
*
* @param options - Configures the style of the focus outline
* @param position - The position of the focus outline
* @returns CSS value for the position of the focus outline
*/ function getOutlinePosition({ outlineWidth, outlineOffset }, position) {
const offsetValue = (outlineOffset === null || outlineOffset === void 0 ? void 0 : outlineOffset[position]) || outlineOffset;
if (!outlineOffset) {
return `calc(${outlineWidth} * -1)`;
}
return `calc(0px - ${outlineWidth} - ${offsetValue})`;
}
/**
* NOTE: the element with the focus outline needs to have `position: relative` so that the
* pseudo element can be properly positioned.
*
* @param options - Configures the style of the focus outline
* @returns focus outline styles object
*/ const getFocusOutlineStyles = (options)=>{
const { outlineRadius, outlineColor, outlineWidth } = options;
return {
...shorthands.borderColor('transparent'),
'@media (forced-colors: active)': {
'::after': {
...shorthands.borderColor('Highlight')
}
},
'::after': {
content: '""',
position: 'absolute',
pointerEvents: 'none',
zIndex: 1,
border: `${outlineWidth} solid ${outlineColor}`,
borderRadius: outlineRadius,
top: getOutlinePosition(options, 'top'),
right: getOutlinePosition(options, 'right'),
bottom: getOutlinePosition(options, 'bottom'),
left: getOutlinePosition(options, 'left')
}
};
};
/**
* NOTE: The element with the focus outline needs to have `position: relative` so that the
* pseudo element can be properly positioned.
*
* @param options - Configure the style of the focus outline
* @returns focus outline styles object for @see makeStyles
*/ export const createFocusOutlineStyle = ({ enableOutline = false, selector = defaultOptions.selector, customizeSelector, style = defaultOptions.style } = defaultOptions)=>({
':focus': {
outlineStyle: enableOutline ? undefined : 'none'
},
':focus-visible': {
outlineStyle: enableOutline ? undefined : 'none'
},
...createCustomFocusIndicatorStyle(getFocusOutlineStyles({
outlineColor: tokens.colorStrokeFocus2,
outlineRadius: tokens.borderRadiusMedium,
// FIXME: tokens.strokeWidthThick causes some weird bugs
outlineWidth: '2px',
...style
}), {
selector,
customizeSelector
})
});
File diff suppressed because one or more lines are too long
+71
View File
@@ -0,0 +1,71 @@
import { isHTMLElement } from '@fluentui/react-utilities';
import { KEYBORG_FOCUSIN, createKeyborg, disposeKeyborg } from 'keyborg';
import { FOCUS_VISIBLE_ATTR } from './constants';
/**
* @internal
* @param scope - Applies the ponyfill to all DOM children
* @param targetWindow - window
*/ export function applyFocusVisiblePolyfill(scope, targetWindow) {
if (alreadyInScope(scope)) {
// Focus visible polyfill already applied at this scope
return ()=>undefined;
}
const state = {
current: undefined
};
const keyborg = createKeyborg(targetWindow);
function registerElementIfNavigating(el) {
if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(el)) {
state.current = el;
el.setAttribute(FOCUS_VISIBLE_ATTR, '');
}
}
function disposeCurrentElement() {
if (state.current) {
state.current.removeAttribute(FOCUS_VISIBLE_ATTR);
state.current = undefined;
}
}
// When navigation mode changes remove the focus-visible selector
keyborg.subscribe((isNavigatingWithKeyboard)=>{
if (!isNavigatingWithKeyboard) {
disposeCurrentElement();
}
});
// Keyborg's focusin event is delegated so it's only registered once on the window
// and contains metadata about the focus event
const keyborgListener = (e)=>{
disposeCurrentElement();
const target = e.composedPath()[0];
registerElementIfNavigating(target);
};
// Make sure that when focus leaves the scope, the focus visible class is removed
const blurListener = (e)=>{
if (!e.relatedTarget || isHTMLElement(e.relatedTarget) && !scope.contains(e.relatedTarget)) {
disposeCurrentElement();
}
};
scope.addEventListener(KEYBORG_FOCUSIN, keyborgListener);
scope.addEventListener('focusout', blurListener);
scope.focusVisible = true;
if (scope.contains(targetWindow.document.activeElement)) {
registerElementIfNavigating(targetWindow.document.activeElement);
}
// Return disposer
return ()=>{
disposeCurrentElement();
scope.removeEventListener(KEYBORG_FOCUSIN, keyborgListener);
scope.removeEventListener('focusout', blurListener);
delete scope.focusVisible;
disposeKeyborg(keyborg);
};
}
function alreadyInScope(el) {
if (!el) {
return false;
}
if (el.focusVisible) {
return true;
}
return alreadyInScope(el === null || el === void 0 ? void 0 : el.parentElement);
}
File diff suppressed because one or more lines are too long
+49
View File
@@ -0,0 +1,49 @@
import { KEYBORG_FOCUSIN, createKeyborg, disposeKeyborg } from 'keyborg';
import { FOCUS_WITHIN_ATTR } from './constants';
/**
* A ponyfill that allows `:focus-within` to support visibility based on keyboard/mouse navigation
* like `:focus-visible` https://github.com/WICG/focus-visible/issues/151
* @returns ref to the element that uses `:focus-within` styles
*/ export function applyFocusWithinPolyfill(element, win) {
const keyborg = createKeyborg(win);
// When navigation mode changes to mouse, remove the focus-within selector
keyborg.subscribe((isNavigatingWithKeyboard)=>{
if (!isNavigatingWithKeyboard) {
removeFocusWithinClass(element);
}
});
// Keyborg's focusin event is delegated so it's only registered once on the window
// and contains metadata about the focus event
const keyborgListener = (e)=>{
if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(e.target)) {
// Griffel can't create chained global styles so use the parent element for now
applyFocusWithinClass(element);
}
};
// Make sure that when focus leaves the scope, the focus within class is removed
const blurListener = (e)=>{
if (!e.relatedTarget || isHTMLElement(e.relatedTarget) && !element.contains(e.relatedTarget)) {
removeFocusWithinClass(element);
}
};
element.addEventListener(KEYBORG_FOCUSIN, keyborgListener);
element.addEventListener('focusout', blurListener);
// Return disposer
return ()=>{
element.removeEventListener(KEYBORG_FOCUSIN, keyborgListener);
element.removeEventListener('focusout', blurListener);
disposeKeyborg(keyborg);
};
}
function applyFocusWithinClass(el) {
el.setAttribute(FOCUS_WITHIN_ATTR, '');
}
function removeFocusWithinClass(el) {
el.removeAttribute(FOCUS_WITHIN_ATTR);
}
function isHTMLElement(target) {
if (!target) {
return false;
}
return Boolean(target && typeof target === 'object' && 'classList' in target && 'contains' in target);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/focusWithinPolyfill.ts"],"sourcesContent":["import { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\nimport { FOCUS_WITHIN_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\n/**\n * A ponyfill that allows `:focus-within` to support visibility based on keyboard/mouse navigation\n * like `:focus-visible` https://github.com/WICG/focus-visible/issues/151\n * @returns ref to the element that uses `:focus-within` styles\n */\nexport function applyFocusWithinPolyfill(element: HTMLElement, win: Window): () => void {\n const keyborg = createKeyborg(win);\n\n // When navigation mode changes to mouse, remove the focus-within selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n removeFocusWithinClass(element);\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 if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(e.target)) {\n // Griffel can't create chained global styles so use the parent element for now\n applyFocusWithinClass(element);\n }\n };\n\n // Make sure that when focus leaves the scope, the focus within class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !element.contains(e.relatedTarget))) {\n removeFocusWithinClass(element);\n }\n };\n\n element.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n element.addEventListener('focusout', blurListener);\n\n // Return disposer\n return () => {\n element.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n element.removeEventListener('focusout', blurListener);\n disposeKeyborg(keyborg);\n };\n}\n\nfunction applyFocusWithinClass(el: HTMLElement) {\n el.setAttribute(FOCUS_WITHIN_ATTR, '');\n}\n\nfunction removeFocusWithinClass(el: HTMLElement) {\n el.removeAttribute(FOCUS_WITHIN_ATTR);\n}\n\nfunction isHTMLElement(target: EventTarget | null): target is HTMLElement {\n if (!target) {\n return false;\n }\n return Boolean(target && typeof target === 'object' && 'classList' in target && 'contains' in target);\n}\n"],"names":["KEYBORG_FOCUSIN","createKeyborg","disposeKeyborg","FOCUS_WITHIN_ATTR","applyFocusWithinPolyfill","element","win","keyborg","subscribe","isNavigatingWithKeyboard","removeFocusWithinClass","keyborgListener","e","isHTMLElement","target","applyFocusWithinClass","blurListener","relatedTarget","contains","addEventListener","removeEventListener","el","setAttribute","removeAttribute","Boolean"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,eAAe,EAAuBC,aAAa,EAAEC,cAAc,QAAQ,UAAU;AAC9F,SAASC,iBAAiB,QAAQ,cAAc;AAShD;;;;CAIC,GACD,OAAO,SAASC,yBAAyBC,OAAoB,EAAEC,GAAW;IACxE,MAAMC,UAAUN,cAAcK;IAE9B,0EAA0E;IAC1EC,QAAQC,SAAS,CAACC,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BC,uBAAuBL;QACzB;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMM,kBAAkB,CAACC;QACvB,IAAIL,QAAQE,wBAAwB,MAAMI,cAAcD,EAAEE,MAAM,GAAG;YACjE,+EAA+E;YAC/EC,sBAAsBV;QACxB;IACF;IAEA,gFAAgF;IAChF,MAAMW,eAAe,CAACJ;QACpB,IAAI,CAACA,EAAEK,aAAa,IAAKJ,cAAcD,EAAEK,aAAa,KAAK,CAACZ,QAAQa,QAAQ,CAACN,EAAEK,aAAa,GAAI;YAC9FP,uBAAuBL;QACzB;IACF;IAEAA,QAAQc,gBAAgB,CAACnB,iBAAiBW;IAC1CN,QAAQc,gBAAgB,CAAC,YAAYH;IAErC,kBAAkB;IAClB,OAAO;QACLX,QAAQe,mBAAmB,CAACpB,iBAAiBW;QAC7CN,QAAQe,mBAAmB,CAAC,YAAYJ;QACxCd,eAAeK;IACjB;AACF;AAEA,SAASQ,sBAAsBM,EAAe;IAC5CA,GAAGC,YAAY,CAACnB,mBAAmB;AACrC;AAEA,SAASO,uBAAuBW,EAAe;IAC7CA,GAAGE,eAAe,CAACpB;AACrB;AAEA,SAASU,cAAcC,MAA0B;IAC/C,IAAI,CAACA,QAAQ;QACX,OAAO;IACT;IACA,OAAOU,QAAQV,UAAU,OAAOA,WAAW,YAAY,eAAeA,UAAU,cAAcA;AAChG"}
+4
View File
@@ -0,0 +1,4 @@
export { createCustomFocusIndicatorStyle } from './createCustomFocusIndicatorStyle';
export { createFocusOutlineStyle } from './createFocusOutlineStyle';
export { applyFocusVisiblePolyfill } from './focusVisiblePolyfill';
export { applyFocusWithinPolyfill } from './focusWithinPolyfill';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/index.ts"],"sourcesContent":["export type { CreateCustomFocusIndicatorStyleOptions } from './createCustomFocusIndicatorStyle';\nexport { createCustomFocusIndicatorStyle } from './createCustomFocusIndicatorStyle';\nexport type {\n CreateFocusOutlineStyleOptions,\n FocusOutlineOffset,\n FocusOutlineStyleOptions,\n} from './createFocusOutlineStyle';\nexport { createFocusOutlineStyle } from './createFocusOutlineStyle';\nexport { applyFocusVisiblePolyfill } from './focusVisiblePolyfill';\nexport { applyFocusWithinPolyfill } from './focusWithinPolyfill';\n"],"names":["createCustomFocusIndicatorStyle","createFocusOutlineStyle","applyFocusVisiblePolyfill","applyFocusWithinPolyfill"],"rangeMappings":";;;","mappings":"AACA,SAASA,+BAA+B,QAAQ,oCAAoC;AAMpF,SAASC,uBAAuB,QAAQ,4BAA4B;AACpE,SAASC,yBAAyB,QAAQ,yBAAyB;AACnE,SAASC,wBAAwB,QAAQ,wBAAwB"}
+18
View File
@@ -0,0 +1,18 @@
export { useArrowNavigationGroup } from './useArrowNavigationGroup';
export { useFocusableGroup } from './useFocusableGroup';
export { useFocusFinders } from './useFocusFinders';
export { useFocusVisible } from './useFocusVisible';
export { useFocusWithin } from './useFocusWithin';
export { useKeyboardNavAttribute } from './useKeyboardNavAttribute';
export { useOnKeyboardNavigationChange } from './useOnKeyboardNavigationChange';
export { useDangerousNeverHidden_unstable, useModalAttributes } from './useModalAttributes';
export { useTabsterAttributes } from './useTabsterAttributes';
export { useObservedElement } from './useObservedElement';
export { useMergedTabsterAttributes_unstable } from './useMergeTabsterAttributes';
export { useFocusObserved } from './useFocusObserved';
export { useRestoreFocusSource, useRestoreFocusTarget } from './useRestoreFocus';
export { useUncontrolledFocus } from './useUncontrolledFocus';
export { useIsNavigatingWithKeyboard } from './useIsNavigatingWithKeyboard';
export { useSetKeyboardNavigation } from './useSetKeyboardNavigation';
export { useFocusedElementChange } from './useFocusedElementChange';
export { useActivateModal } from './useActivateModal';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/index.ts"],"sourcesContent":["export type { UseArrowNavigationGroupOptions } from './useArrowNavigationGroup';\nexport { useArrowNavigationGroup } from './useArrowNavigationGroup';\nexport type { UseFocusableGroupOptions } from './useFocusableGroup';\nexport { useFocusableGroup } from './useFocusableGroup';\nexport { useFocusFinders } from './useFocusFinders';\nexport { useFocusVisible } from './useFocusVisible';\nexport { useFocusWithin } from './useFocusWithin';\nexport { useKeyboardNavAttribute } from './useKeyboardNavAttribute';\nexport { useOnKeyboardNavigationChange } from './useOnKeyboardNavigationChange';\nexport type { UseModalAttributesOptions } from './useModalAttributes';\nexport { useDangerousNeverHidden_unstable, useModalAttributes } from './useModalAttributes';\nexport { useTabsterAttributes } from './useTabsterAttributes';\nexport { useObservedElement } from './useObservedElement';\nexport { useMergedTabsterAttributes_unstable } from './useMergeTabsterAttributes';\nexport { useFocusObserved } from './useFocusObserved';\nexport { useRestoreFocusSource, useRestoreFocusTarget } from './useRestoreFocus';\nexport { useUncontrolledFocus } from './useUncontrolledFocus';\nexport { useIsNavigatingWithKeyboard } from './useIsNavigatingWithKeyboard';\nexport { useSetKeyboardNavigation } from './useSetKeyboardNavigation';\nexport { useFocusedElementChange } from './useFocusedElementChange';\nexport { useActivateModal } from './useActivateModal';\n"],"names":["useArrowNavigationGroup","useFocusableGroup","useFocusFinders","useFocusVisible","useFocusWithin","useKeyboardNavAttribute","useOnKeyboardNavigationChange","useDangerousNeverHidden_unstable","useModalAttributes","useTabsterAttributes","useObservedElement","useMergedTabsterAttributes_unstable","useFocusObserved","useRestoreFocusSource","useRestoreFocusTarget","useUncontrolledFocus","useIsNavigatingWithKeyboard","useSetKeyboardNavigation","useFocusedElementChange","useActivateModal"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,uBAAuB,QAAQ,4BAA4B;AAEpE,SAASC,iBAAiB,QAAQ,sBAAsB;AACxD,SAASC,eAAe,QAAQ,oBAAoB;AACpD,SAASC,eAAe,QAAQ,oBAAoB;AACpD,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,uBAAuB,QAAQ,4BAA4B;AACpE,SAASC,6BAA6B,QAAQ,kCAAkC;AAEhF,SAASC,gCAAgC,EAAEC,kBAAkB,QAAQ,uBAAuB;AAC5F,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,kBAAkB,QAAQ,uBAAuB;AAC1D,SAASC,mCAAmC,QAAQ,8BAA8B;AAClF,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,qBAAqB,EAAEC,qBAAqB,QAAQ,oBAAoB;AACjF,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,2BAA2B,QAAQ,gCAAgC;AAC5E,SAASC,wBAAwB,QAAQ,6BAA6B;AACtE,SAASC,uBAAuB,QAAQ,4BAA4B;AACpE,SAASC,gBAAgB,QAAQ,qBAAqB"}
+24
View File
@@ -0,0 +1,24 @@
import * as React from 'react';
import { getModalizer } from 'tabster';
import { useTimeout } from '@fluentui/react-utilities';
import { useTabster } from './useTabster';
/**
* Returns a function that activates a modal by element from the modal or modal container.
*/ export function useActivateModal() {
const tabster = useTabster();
const modalizerAPI = tabster ? getModalizer(tabster) : undefined;
const [setActivateModalTimeout] = useTimeout();
const activateModal = React.useCallback((elementFromModal)=>{
// We call the actual activation function on the next tick, because with the typical use case,
// the hook will be called on the same tick when other Tabster attributes are being applied,
// and on the current tick the element has just received the attributes, but Tabster has not
// instantiated the Modalizer yet.
setActivateModalTimeout(()=>{
modalizerAPI === null || modalizerAPI === void 0 ? void 0 : modalizerAPI.activate(elementFromModal);
}, 0);
}, [
modalizerAPI,
setActivateModalTimeout
]);
return activateModal;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useActivateModal.ts"],"sourcesContent":["import * as React from 'react';\nimport { getModalizer } from 'tabster';\nimport { useTimeout } from '@fluentui/react-utilities';\nimport { useTabster } from './useTabster';\n\n/**\n * Returns a function that activates a modal by element from the modal or modal container.\n */\nexport function useActivateModal(): (elementFromModal: HTMLElement | undefined) => void {\n const tabster = useTabster();\n const modalizerAPI = tabster ? getModalizer(tabster) : undefined;\n const [setActivateModalTimeout] = useTimeout();\n\n const activateModal = React.useCallback(\n (elementFromModal: HTMLElement | undefined) => {\n // We call the actual activation function on the next tick, because with the typical use case,\n // the hook will be called on the same tick when other Tabster attributes are being applied,\n // and on the current tick the element has just received the attributes, but Tabster has not\n // instantiated the Modalizer yet.\n setActivateModalTimeout(() => {\n modalizerAPI?.activate(elementFromModal);\n }, 0);\n },\n [modalizerAPI, setActivateModalTimeout],\n );\n\n return activateModal;\n}\n"],"names":["React","getModalizer","useTimeout","useTabster","useActivateModal","tabster","modalizerAPI","undefined","setActivateModalTimeout","activateModal","useCallback","elementFromModal","activate"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,YAAY,QAAQ,UAAU;AACvC,SAASC,UAAU,QAAQ,4BAA4B;AACvD,SAASC,UAAU,QAAQ,eAAe;AAE1C;;CAEC,GACD,OAAO,SAASC;IACd,MAAMC,UAAUF;IAChB,MAAMG,eAAeD,UAAUJ,aAAaI,WAAWE;IACvD,MAAM,CAACC,wBAAwB,GAAGN;IAElC,MAAMO,gBAAgBT,MAAMU,WAAW,CACrC,CAACC;QACC,8FAA8F;QAC9F,4FAA4F;QAC5F,4FAA4F;QAC5F,kCAAkC;QAClCH,wBAAwB;YACtBF,yBAAAA,mCAAAA,aAAcM,QAAQ,CAACD;QACzB,GAAG;IACL,GACA;QAACL;QAAcE;KAAwB;IAGzC,OAAOC;AACT"}
@@ -0,0 +1,43 @@
import { getMover, MoverDirections } from 'tabster';
import { useTabsterAttributes } from './useTabsterAttributes';
import { useTabster } from './useTabster';
/**
* A hook that returns the necessary tabster attributes to support arrow key navigation
* @param options - Options to configure keyboard navigation
*/ export const useArrowNavigationGroup = (options = {})=>{
const { circular, axis, memorizeCurrent = true, tabbable, ignoreDefaultKeydown, // eslint-disable-next-line @typescript-eslint/naming-convention
unstable_hasDefault } = options;
const tabster = useTabster();
if (tabster) {
getMover(tabster);
}
return useTabsterAttributes({
mover: {
cyclic: !!circular,
direction: axisToMoverDirection(axis !== null && axis !== void 0 ? axis : 'vertical'),
memorizeCurrent,
tabbable,
hasDefault: unstable_hasDefault
},
...ignoreDefaultKeydown && {
focusable: {
ignoreKeydown: ignoreDefaultKeydown
}
}
});
};
function axisToMoverDirection(axis) {
switch(axis){
case 'horizontal':
return MoverDirections.Horizontal;
case 'grid':
return MoverDirections.Grid;
case 'grid-linear':
return MoverDirections.GridLinear;
case 'both':
return MoverDirections.Both;
case 'vertical':
default:
return MoverDirections.Vertical;
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useArrowNavigationGroup.ts"],"sourcesContent":["import { Types, getMover, MoverDirections } from 'tabster';\nimport { useTabsterAttributes } from './useTabsterAttributes';\nimport { useTabster } from './useTabster';\n\nexport interface UseArrowNavigationGroupOptions {\n /**\n * Focus will navigate vertically, horizontally or in both directions (grid), defaults to horizontally\n * @defaultValue vertical\n */\n axis?: 'vertical' | 'horizontal' | 'grid' | 'grid-linear' | 'both';\n /**\n * Focus will cycle to the first/last elements of the group without stopping\n */\n circular?: boolean;\n /**\n * Last focused element in the group will be remembered and focused (if still\n * available) when tabbing from outside of the group\n * @default true\n */\n memorizeCurrent?: boolean;\n /**\n * Allow tabbing within the arrow navigation group items.\n */\n tabbable?: boolean;\n /**\n * Tabster should ignore default handling of keydown events\n */\n ignoreDefaultKeydown?: Types.FocusableProps['ignoreKeydown'];\n /**\n * The default focusable item in the group will be an element with Focusable.isDefault property.\n * Note that there is no way in \\@fluentui/react-tabster to set default focusable element,\n * and this option is currently for internal testing purposes only.\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n unstable_hasDefault?: boolean;\n}\n\n/**\n * A hook that returns the necessary tabster attributes to support arrow key navigation\n * @param options - Options to configure keyboard navigation\n */\nexport const useArrowNavigationGroup = (options: UseArrowNavigationGroupOptions = {}): Types.TabsterDOMAttribute => {\n const {\n circular,\n axis,\n memorizeCurrent = true,\n tabbable,\n ignoreDefaultKeydown,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n unstable_hasDefault,\n } = options;\n const tabster = useTabster();\n\n if (tabster) {\n getMover(tabster);\n }\n\n return useTabsterAttributes({\n mover: {\n cyclic: !!circular,\n direction: axisToMoverDirection(axis ?? 'vertical'),\n memorizeCurrent,\n tabbable,\n hasDefault: unstable_hasDefault,\n },\n ...(ignoreDefaultKeydown && {\n focusable: {\n ignoreKeydown: ignoreDefaultKeydown,\n },\n }),\n });\n};\n\nfunction axisToMoverDirection(axis: UseArrowNavigationGroupOptions['axis']): Types.MoverDirection {\n switch (axis) {\n case 'horizontal':\n return MoverDirections.Horizontal;\n case 'grid':\n return MoverDirections.Grid;\n case 'grid-linear':\n return MoverDirections.GridLinear;\n case 'both':\n return MoverDirections.Both;\n\n case 'vertical':\n default:\n return MoverDirections.Vertical;\n }\n}\n"],"names":["getMover","MoverDirections","useTabsterAttributes","useTabster","useArrowNavigationGroup","options","circular","axis","memorizeCurrent","tabbable","ignoreDefaultKeydown","unstable_hasDefault","tabster","mover","cyclic","direction","axisToMoverDirection","hasDefault","focusable","ignoreKeydown","Horizontal","Grid","GridLinear","Both","Vertical"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAAgBA,QAAQ,EAAEC,eAAe,QAAQ,UAAU;AAC3D,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,UAAU,QAAQ,eAAe;AAmC1C;;;CAGC,GACD,OAAO,MAAMC,0BAA0B,CAACC,UAA0C,CAAC,CAAC;IAClF,MAAM,EACJC,QAAQ,EACRC,IAAI,EACJC,kBAAkB,IAAI,EACtBC,QAAQ,EACRC,oBAAoB,EACpB,gEAAgE;IAChEC,mBAAmB,EACpB,GAAGN;IACJ,MAAMO,UAAUT;IAEhB,IAAIS,SAAS;QACXZ,SAASY;IACX;IAEA,OAAOV,qBAAqB;QAC1BW,OAAO;YACLC,QAAQ,CAAC,CAACR;YACVS,WAAWC,qBAAqBT,iBAAAA,kBAAAA,OAAQ;YACxCC;YACAC;YACAQ,YAAYN;QACd;QACA,GAAID,wBAAwB;YAC1BQ,WAAW;gBACTC,eAAeT;YACjB;QACF,CAAC;IACH;AACF,EAAE;AAEF,SAASM,qBAAqBT,IAA4C;IACxE,OAAQA;QACN,KAAK;YACH,OAAON,gBAAgBmB,UAAU;QACnC,KAAK;YACH,OAAOnB,gBAAgBoB,IAAI;QAC7B,KAAK;YACH,OAAOpB,gBAAgBqB,UAAU;QACnC,KAAK;YACH,OAAOrB,gBAAgBsB,IAAI;QAE7B,KAAK;QACL;YACE,OAAOtB,gBAAgBuB,QAAQ;IACnC;AACF"}
+59
View File
@@ -0,0 +1,59 @@
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { useTabster } from './useTabster';
/**
* Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element
*/ export const useFocusFinders = ()=>{
const tabster = useTabster();
const { targetDocument } = useFluent();
// Narrow props for now and let need dictate additional props in the future
const findAllFocusable = React.useCallback((container, acceptCondition)=>(tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findAll({
container,
acceptCondition
})) || [], [
tabster
]);
const findFirstFocusable = React.useCallback((container)=>tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findFirst({
container
}), [
tabster
]);
const findLastFocusable = React.useCallback((container)=>tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findLast({
container
}), [
tabster
]);
const findNextFocusable = React.useCallback((currentElement, options = {})=>{
if (!tabster || !targetDocument) {
return null;
}
const { container = targetDocument.body } = options;
return tabster.focusable.findNext({
currentElement,
container
});
}, [
tabster,
targetDocument
]);
const findPrevFocusable = React.useCallback((currentElement, options = {})=>{
if (!tabster || !targetDocument) {
return null;
}
const { container = targetDocument.body } = options;
return tabster.focusable.findPrev({
currentElement,
container
});
}, [
tabster,
targetDocument
]);
return {
findAllFocusable,
findFirstFocusable,
findLastFocusable,
findNextFocusable,
findPrevFocusable
};
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusFinders.ts"],"sourcesContent":["import * as React from 'react';\nimport { Types as TabsterTypes } from 'tabster';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useTabster } from './useTabster';\n\n/**\n * Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element\n */\nexport const useFocusFinders = () => {\n const tabster = useTabster();\n const { targetDocument } = useFluent();\n\n // Narrow props for now and let need dictate additional props in the future\n const findAllFocusable = React.useCallback(\n (container: HTMLElement, acceptCondition?: (el: HTMLElement) => boolean) =>\n tabster?.focusable.findAll({ container, acceptCondition }) || [],\n [tabster],\n );\n\n const findFirstFocusable = React.useCallback(\n (container: HTMLElement) => tabster?.focusable.findFirst({ container }),\n [tabster],\n );\n\n const findLastFocusable = React.useCallback(\n (container: HTMLElement) => tabster?.focusable.findLast({ container }),\n [tabster],\n );\n\n const findNextFocusable = React.useCallback(\n (currentElement: HTMLElement, options: Pick<Partial<TabsterTypes.FindNextProps>, 'container'> = {}) => {\n if (!tabster || !targetDocument) {\n return null;\n }\n\n const { container = targetDocument.body } = options;\n\n return tabster.focusable.findNext({ currentElement, container });\n },\n [tabster, targetDocument],\n );\n\n const findPrevFocusable = React.useCallback(\n (currentElement: HTMLElement, options: Pick<Partial<TabsterTypes.FindNextProps>, 'container'> = {}) => {\n if (!tabster || !targetDocument) {\n return null;\n }\n\n const { container = targetDocument.body } = options;\n\n return tabster.focusable.findPrev({ currentElement, container });\n },\n [tabster, targetDocument],\n );\n\n return {\n findAllFocusable,\n findFirstFocusable,\n findLastFocusable,\n findNextFocusable,\n findPrevFocusable,\n };\n};\n"],"names":["React","useFluent_unstable","useFluent","useTabster","useFocusFinders","tabster","targetDocument","findAllFocusable","useCallback","container","acceptCondition","focusable","findAll","findFirstFocusable","findFirst","findLastFocusable","findLast","findNextFocusable","currentElement","options","body","findNext","findPrevFocusable","findPrev"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,UAAU,QAAQ,eAAe;AAE1C;;CAEC,GACD,OAAO,MAAMC,kBAAkB;IAC7B,MAAMC,UAAUF;IAChB,MAAM,EAAEG,cAAc,EAAE,GAAGJ;IAE3B,2EAA2E;IAC3E,MAAMK,mBAAmBP,MAAMQ,WAAW,CACxC,CAACC,WAAwBC,kBACvBL,CAAAA,oBAAAA,8BAAAA,QAASM,SAAS,CAACC,OAAO,CAAC;YAAEH;YAAWC;QAAgB,OAAM,EAAE,EAClE;QAACL;KAAQ;IAGX,MAAMQ,qBAAqBb,MAAMQ,WAAW,CAC1C,CAACC,YAA2BJ,oBAAAA,8BAAAA,QAASM,SAAS,CAACG,SAAS,CAAC;YAAEL;QAAU,IACrE;QAACJ;KAAQ;IAGX,MAAMU,oBAAoBf,MAAMQ,WAAW,CACzC,CAACC,YAA2BJ,oBAAAA,8BAAAA,QAASM,SAAS,CAACK,QAAQ,CAAC;YAAEP;QAAU,IACpE;QAACJ;KAAQ;IAGX,MAAMY,oBAAoBjB,MAAMQ,WAAW,CACzC,CAACU,gBAA6BC,UAAkE,CAAC,CAAC;QAChG,IAAI,CAACd,WAAW,CAACC,gBAAgB;YAC/B,OAAO;QACT;QAEA,MAAM,EAAEG,YAAYH,eAAec,IAAI,EAAE,GAAGD;QAE5C,OAAOd,QAAQM,SAAS,CAACU,QAAQ,CAAC;YAAEH;YAAgBT;QAAU;IAChE,GACA;QAACJ;QAASC;KAAe;IAG3B,MAAMgB,oBAAoBtB,MAAMQ,WAAW,CACzC,CAACU,gBAA6BC,UAAkE,CAAC,CAAC;QAChG,IAAI,CAACd,WAAW,CAACC,gBAAgB;YAC/B,OAAO;QACT;QAEA,MAAM,EAAEG,YAAYH,eAAec,IAAI,EAAE,GAAGD;QAE5C,OAAOd,QAAQM,SAAS,CAACY,QAAQ,CAAC;YAAEL;YAAgBT;QAAU;IAChE,GACA;QAACJ;QAASC;KAAe;IAG3B,OAAO;QACLC;QACAM;QACAE;QACAE;QACAK;IACF;AACF,EAAE"}
+25
View File
@@ -0,0 +1,25 @@
import * as React from 'react';
import { getObservedElement } from 'tabster';
import { useTabster } from './useTabster';
/**
*
* @param name - The observed element to focus
* @returns Function that will focus the
*/ export function useFocusObserved(name, options = {}) {
const { timeout = 1000 } = options;
const tabster = useTabster();
const observedAPI = tabster ? getObservedElement(tabster) : null;
return React.useCallback(()=>{
if (observedAPI) {
return observedAPI.requestFocus(name, timeout);
}
return {
result: Promise.resolve(false),
cancel: ()=>null
};
}, [
observedAPI,
name,
timeout
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusObserved.ts"],"sourcesContent":["import * as React from 'react';\nimport { getObservedElement, Types as TabsterTypes } from 'tabster';\nimport { useTabster } from './useTabster';\n\ninterface UseFocusObservedOptions {\n /**\n * After timeout the focus attempt fails\n */\n timeout?: number;\n}\n\n/**\n *\n * @param name - The observed element to focus\n * @returns Function that will focus the\n */\nexport function useFocusObserved(\n name: string,\n options: UseFocusObservedOptions = {},\n): () => TabsterTypes.ObservedElementAsyncRequest<boolean> {\n const { timeout = 1000 } = options;\n const tabster = useTabster();\n\n const observedAPI = tabster ? getObservedElement(tabster) : null;\n\n return React.useCallback(() => {\n if (observedAPI) {\n return observedAPI.requestFocus(name, timeout);\n }\n\n return { result: Promise.resolve(false), cancel: () => null };\n }, [observedAPI, name, timeout]);\n}\n"],"names":["React","getObservedElement","useTabster","useFocusObserved","name","options","timeout","tabster","observedAPI","useCallback","requestFocus","result","Promise","resolve","cancel"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,kBAAkB,QAA+B,UAAU;AACpE,SAASC,UAAU,QAAQ,eAAe;AAS1C;;;;CAIC,GACD,OAAO,SAASC,iBACdC,IAAY,EACZC,UAAmC,CAAC,CAAC;IAErC,MAAM,EAAEC,UAAU,IAAI,EAAE,GAAGD;IAC3B,MAAME,UAAUL;IAEhB,MAAMM,cAAcD,UAAUN,mBAAmBM,WAAW;IAE5D,OAAOP,MAAMS,WAAW,CAAC;QACvB,IAAID,aAAa;YACf,OAAOA,YAAYE,YAAY,CAACN,MAAME;QACxC;QAEA,OAAO;YAAEK,QAAQC,QAAQC,OAAO,CAAC;YAAQC,QAAQ,IAAM;QAAK;IAC9D,GAAG;QAACN;QAAaJ;QAAME;KAAQ;AACjC"}
+18
View File
@@ -0,0 +1,18 @@
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { applyFocusVisiblePolyfill } from '../focus/focusVisiblePolyfill';
export function useFocusVisible(options = {}) {
const contextValue = useFluent();
const scopeRef = React.useRef(null);
var _options_targetDocument;
const targetDocument = (_options_targetDocument = options.targetDocument) !== null && _options_targetDocument !== void 0 ? _options_targetDocument : contextValue.targetDocument;
React.useEffect(()=>{
if ((targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) && scopeRef.current) {
return applyFocusVisiblePolyfill(scopeRef.current, targetDocument.defaultView);
}
}, [
scopeRef,
targetDocument
]);
return scopeRef;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusVisible.ts"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\nimport { applyFocusVisiblePolyfill } from '../focus/focusVisiblePolyfill';\n\ntype UseFocusVisibleOptions = {\n targetDocument?: Document;\n};\n\nexport function useFocusVisible<TElement extends HTMLElement = HTMLElement>(options: UseFocusVisibleOptions = {}) {\n const contextValue = useFluent();\n const scopeRef = React.useRef<TElement>(null);\n\n const targetDocument = options.targetDocument ?? contextValue.targetDocument;\n\n React.useEffect(() => {\n if (targetDocument?.defaultView && scopeRef.current) {\n return applyFocusVisiblePolyfill(scopeRef.current, targetDocument.defaultView);\n }\n }, [scopeRef, targetDocument]);\n\n return scopeRef;\n}\n"],"names":["React","useFluent_unstable","useFluent","applyFocusVisiblePolyfill","useFocusVisible","options","contextValue","scopeRef","useRef","targetDocument","useEffect","defaultView","current"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF,SAASC,yBAAyB,QAAQ,gCAAgC;AAM1E,OAAO,SAASC,gBAA4DC,UAAkC,CAAC,CAAC;IAC9G,MAAMC,eAAeJ;IACrB,MAAMK,WAAWP,MAAMQ,MAAM,CAAW;QAEjBH;IAAvB,MAAMI,iBAAiBJ,CAAAA,0BAAAA,QAAQI,cAAc,cAAtBJ,qCAAAA,0BAA0BC,aAAaG,cAAc;IAE5ET,MAAMU,SAAS,CAAC;QACd,IAAID,CAAAA,2BAAAA,qCAAAA,eAAgBE,WAAW,KAAIJ,SAASK,OAAO,EAAE;YACnD,OAAOT,0BAA0BI,SAASK,OAAO,EAAEH,eAAeE,WAAW;QAC/E;IACF,GAAG;QAACJ;QAAUE;KAAe;IAE7B,OAAOF;AACT"}
+20
View File
@@ -0,0 +1,20 @@
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { applyFocusWithinPolyfill } from '../focus/focusWithinPolyfill';
/**
* A ponyfill that allows `:focus-within` to support visibility based on keyboard/mouse navigation
* like `:focus-visible` https://github.com/WICG/focus-visible/issues/151
* @returns ref to the element that uses `:focus-within` styles
*/ export function useFocusWithin() {
const { targetDocument } = useFluent();
const elementRef = React.useRef(null);
React.useEffect(()=>{
if ((targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) && elementRef.current) {
return applyFocusWithinPolyfill(elementRef.current, targetDocument.defaultView);
}
}, [
elementRef,
targetDocument
]);
return elementRef;
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusWithin.ts"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { applyFocusWithinPolyfill } from '../focus/focusWithinPolyfill';\n\n/**\n * A ponyfill that allows `:focus-within` to support visibility based on keyboard/mouse navigation\n * like `:focus-visible` https://github.com/WICG/focus-visible/issues/151\n * @returns ref to the element that uses `:focus-within` styles\n */\nexport function useFocusWithin<TElement extends HTMLElement = HTMLElement>() {\n const { targetDocument } = useFluent();\n const elementRef = React.useRef<TElement>(null);\n\n React.useEffect(() => {\n if (targetDocument?.defaultView && elementRef.current) {\n return applyFocusWithinPolyfill(elementRef.current, targetDocument.defaultView);\n }\n }, [elementRef, targetDocument]);\n\n return elementRef;\n}\n"],"names":["React","useFluent_unstable","useFluent","applyFocusWithinPolyfill","useFocusWithin","targetDocument","elementRef","useRef","useEffect","defaultView","current"],"rangeMappings":";;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,wBAAwB,QAAQ,+BAA+B;AAExE;;;;CAIC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGH;IAC3B,MAAMI,aAAaN,MAAMO,MAAM,CAAW;IAE1CP,MAAMQ,SAAS,CAAC;QACd,IAAIH,CAAAA,2BAAAA,qCAAAA,eAAgBI,WAAW,KAAIH,WAAWI,OAAO,EAAE;YACrD,OAAOP,yBAAyBG,WAAWI,OAAO,EAAEL,eAAeI,WAAW;QAChF;IACF,GAAG;QAACH;QAAYD;KAAe;IAE/B,OAAOC;AACT"}
+32
View File
@@ -0,0 +1,32 @@
import { getGroupper, GroupperTabbabilities } from 'tabster';
import { useTabsterAttributes } from './useTabsterAttributes';
import { useTabster } from './useTabster';
/**
* A hook that returns the necessary tabster attributes to support groupping.
* @param options - Options to configure keyboard navigation
*/ export const useFocusableGroup = (options)=>{
const tabster = useTabster();
if (tabster) {
getGroupper(tabster);
}
return useTabsterAttributes({
groupper: {
tabbability: getTabbability(options === null || options === void 0 ? void 0 : options.tabBehavior)
},
focusable: {
ignoreKeydown: options === null || options === void 0 ? void 0 : options.ignoreDefaultKeydown
}
});
};
const getTabbability = (tabBehavior)=>{
switch(tabBehavior){
case 'unlimited':
return GroupperTabbabilities.Unlimited;
case 'limited':
return GroupperTabbabilities.Limited;
case 'limited-trap-focus':
return GroupperTabbabilities.LimitedTrapFocus;
default:
return undefined;
}
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusableGroup.ts"],"sourcesContent":["import { Types, getGroupper, GroupperTabbabilities } from 'tabster';\nimport { useTabsterAttributes } from './useTabsterAttributes';\nimport { useTabster } from './useTabster';\n\nexport interface UseFocusableGroupOptions {\n /**\n * Behavior for the Tab key.\n */\n tabBehavior?: 'unlimited' | 'limited' | 'limited-trap-focus';\n\n /**\n * Tabster can ignore default handling of keydown events\n */\n ignoreDefaultKeydown?: Types.FocusableProps['ignoreKeydown'];\n}\n\n/**\n * A hook that returns the necessary tabster attributes to support groupping.\n * @param options - Options to configure keyboard navigation\n */\nexport const useFocusableGroup = (options?: UseFocusableGroupOptions): Types.TabsterDOMAttribute => {\n const tabster = useTabster();\n\n if (tabster) {\n getGroupper(tabster);\n }\n\n return useTabsterAttributes({\n groupper: {\n tabbability: getTabbability(options?.tabBehavior),\n },\n focusable: {\n ignoreKeydown: options?.ignoreDefaultKeydown,\n },\n });\n};\n\nconst getTabbability = (\n tabBehavior?: UseFocusableGroupOptions['tabBehavior'],\n): Types.GroupperTabbability | undefined => {\n switch (tabBehavior) {\n case 'unlimited':\n return GroupperTabbabilities.Unlimited;\n case 'limited':\n return GroupperTabbabilities.Limited;\n case 'limited-trap-focus':\n return GroupperTabbabilities.LimitedTrapFocus;\n default:\n return undefined;\n }\n};\n"],"names":["getGroupper","GroupperTabbabilities","useTabsterAttributes","useTabster","useFocusableGroup","options","tabster","groupper","tabbability","getTabbability","tabBehavior","focusable","ignoreKeydown","ignoreDefaultKeydown","Unlimited","Limited","LimitedTrapFocus","undefined"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAAgBA,WAAW,EAAEC,qBAAqB,QAAQ,UAAU;AACpE,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,UAAU,QAAQ,eAAe;AAc1C;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,CAACC;IAChC,MAAMC,UAAUH;IAEhB,IAAIG,SAAS;QACXN,YAAYM;IACd;IAEA,OAAOJ,qBAAqB;QAC1BK,UAAU;YACRC,aAAaC,eAAeJ,oBAAAA,8BAAAA,QAASK,WAAW;QAClD;QACAC,WAAW;YACTC,aAAa,EAAEP,oBAAAA,8BAAAA,QAASQ,oBAAoB;QAC9C;IACF;AACF,EAAE;AAEF,MAAMJ,iBAAiB,CACrBC;IAEA,OAAQA;QACN,KAAK;YACH,OAAOT,sBAAsBa,SAAS;QACxC,KAAK;YACH,OAAOb,sBAAsBc,OAAO;QACtC,KAAK;YACH,OAAOd,sBAAsBe,gBAAgB;QAC/C;YACE,OAAOC;IACX;AACF"}
@@ -0,0 +1,17 @@
import { useTabster } from './useTabster';
import * as React from 'react';
/**
* Subscribes to the tabster focused element. Calls the callback when the focused element changes.
* @param callback - Callback to subscribe to the focused element.
*/ export function useFocusedElementChange(callback) {
const tabster = useTabster();
React.useEffect(()=>{
if (tabster) {
tabster.focusedElement.subscribe(callback);
return ()=>tabster.focusedElement.unsubscribe(callback);
}
}, [
tabster,
callback
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFocusedElementChange.ts"],"sourcesContent":["import type { Types as TabsterTypes } from 'tabster';\n\nimport { useTabster } from './useTabster';\nimport * as React from 'react';\n\n/**\n * Subscribes to the tabster focused element. Calls the callback when the focused element changes.\n * @param callback - Callback to subscribe to the focused element.\n */\nexport function useFocusedElementChange(\n callback: TabsterTypes.SubscribableCallback<HTMLElement | undefined, TabsterTypes.FocusedElementDetail>,\n) {\n const tabster = useTabster();\n React.useEffect(() => {\n if (tabster) {\n tabster.focusedElement.subscribe(callback);\n return () => tabster.focusedElement.unsubscribe(callback);\n }\n }, [tabster, callback]);\n}\n"],"names":["useTabster","React","useFocusedElementChange","callback","tabster","useEffect","focusedElement","subscribe","unsubscribe"],"rangeMappings":";;;;;;;;;;;;;;;;","mappings":"AAEA,SAASA,UAAU,QAAQ,eAAe;AAC1C,YAAYC,WAAW,QAAQ;AAE/B;;;CAGC,GACD,OAAO,SAASC,wBACdC,QAAuG;IAEvG,MAAMC,UAAUJ;IAChBC,MAAMI,SAAS,CAAC;QACd,IAAID,SAAS;YACXA,QAAQE,cAAc,CAACC,SAAS,CAACJ;YACjC,OAAO,IAAMC,QAAQE,cAAc,CAACE,WAAW,CAACL;QAClD;IACF,GAAG;QAACC;QAASD;KAAS;AACxB"}
@@ -0,0 +1,15 @@
import * as React from 'react';
import { useKeyborgRef } from './useKeyborgRef';
/**
* Instantiates [keyborg](https://github.com/microsoft/keyborg) and checks if the user is navigating with the keyboard.
* @returns
*/ export function useIsNavigatingWithKeyboard() {
const keyborgRef = useKeyborgRef();
return React.useCallback(()=>{
var _keyborgRef_current;
var _keyborgRef_current_isNavigatingWithKeyboard;
return (_keyborgRef_current_isNavigatingWithKeyboard = (_keyborgRef_current = keyborgRef.current) === null || _keyborgRef_current === void 0 ? void 0 : _keyborgRef_current.isNavigatingWithKeyboard()) !== null && _keyborgRef_current_isNavigatingWithKeyboard !== void 0 ? _keyborgRef_current_isNavigatingWithKeyboard : false;
}, [
keyborgRef
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useIsNavigatingWithKeyboard.ts"],"sourcesContent":["import * as React from 'react';\nimport { useKeyborgRef } from './useKeyborgRef';\n\n/**\n * Instantiates [keyborg](https://github.com/microsoft/keyborg) and checks if the user is navigating with the keyboard.\n * @returns\n */\nexport function useIsNavigatingWithKeyboard(): () => boolean {\n const keyborgRef = useKeyborgRef();\n\n return React.useCallback(() => {\n return keyborgRef.current?.isNavigatingWithKeyboard() ?? false;\n }, [keyborgRef]);\n}\n"],"names":["React","useKeyborgRef","useIsNavigatingWithKeyboard","keyborgRef","useCallback","current","isNavigatingWithKeyboard"],"rangeMappings":";;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,aAAa,QAAQ,kBAAkB;AAEhD;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,aAAaF;IAEnB,OAAOD,MAAMI,WAAW,CAAC;YAChBD;YAAAA;QAAP,OAAOA,CAAAA,gDAAAA,sBAAAA,WAAWE,OAAO,cAAlBF,0CAAAA,oBAAoBG,wBAAwB,gBAA5CH,0DAAAA,+CAAkD;IAC3D,GAAG;QAACA;KAAW;AACjB"}
@@ -0,0 +1,38 @@
import * as React from 'react';
import { createKeyborg } from 'keyborg';
import { KEYBOARD_NAV_ATTRIBUTE } from '../focus/constants';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
/**
* Instantiates [keyborg](https://github.com/microsoft/keyborg) and adds `data-keyboard-nav`
* attribute to a referenced element to ensure keyboard navigation awareness
* synced to keyborg logic without having to cause a re-render on react tree.
*/ export function useKeyboardNavAttribute() {
const { targetDocument } = useFluent();
const keyborg = React.useMemo(()=>targetDocument && createKeyborg(targetDocument.defaultView), [
targetDocument
]);
const ref = React.useRef(null);
React.useEffect(()=>{
if (keyborg) {
setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, keyborg.isNavigatingWithKeyboard());
const cb = (next)=>{
setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, next);
};
keyborg.subscribe(cb);
return ()=>keyborg.unsubscribe(cb);
}
}, [
keyborg
]);
return ref;
}
function setBooleanAttribute(elementRef, attribute, value) {
if (!elementRef.current) {
return;
}
if (value) {
elementRef.current.setAttribute(attribute, '');
} else {
elementRef.current.removeAttribute(attribute);
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useKeyboardNavAttribute.ts"],"sourcesContent":["import * as React from 'react';\nimport { createKeyborg } from 'keyborg';\nimport { KEYBOARD_NAV_ATTRIBUTE } from '../focus/constants';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { KeyborgCallback } from 'keyborg';\n\n/**\n * Instantiates [keyborg](https://github.com/microsoft/keyborg) and adds `data-keyboard-nav`\n * attribute to a referenced element to ensure keyboard navigation awareness\n * synced to keyborg logic without having to cause a re-render on react tree.\n */\nexport function useKeyboardNavAttribute<E extends HTMLElement>() {\n const { targetDocument } = useFluent();\n const keyborg = React.useMemo(() => targetDocument && createKeyborg(targetDocument.defaultView!), [targetDocument]);\n const ref = React.useRef<E>(null);\n React.useEffect(() => {\n if (keyborg) {\n setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, keyborg.isNavigatingWithKeyboard());\n const cb: KeyborgCallback = next => {\n setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, next);\n };\n keyborg.subscribe(cb);\n return () => keyborg.unsubscribe(cb);\n }\n }, [keyborg]);\n return ref;\n}\n\nfunction setBooleanAttribute(elementRef: React.RefObject<HTMLElement>, attribute: string, value: boolean) {\n if (!elementRef.current) {\n return;\n }\n if (value) {\n elementRef.current.setAttribute(attribute, '');\n } else {\n elementRef.current.removeAttribute(attribute);\n }\n}\n"],"names":["React","createKeyborg","KEYBOARD_NAV_ATTRIBUTE","useFluent_unstable","useFluent","useKeyboardNavAttribute","targetDocument","keyborg","useMemo","defaultView","ref","useRef","useEffect","setBooleanAttribute","isNavigatingWithKeyboard","cb","next","subscribe","unsubscribe","elementRef","attribute","value","current","setAttribute","removeAttribute"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,aAAa,QAAQ,UAAU;AACxC,SAASC,sBAAsB,QAAQ,qBAAqB;AAC5D,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAGlF;;;;CAIC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGF;IAC3B,MAAMG,UAAUP,MAAMQ,OAAO,CAAC,IAAMF,kBAAkBL,cAAcK,eAAeG,WAAW,GAAI;QAACH;KAAe;IAClH,MAAMI,MAAMV,MAAMW,MAAM,CAAI;IAC5BX,MAAMY,SAAS,CAAC;QACd,IAAIL,SAAS;YACXM,oBAAoBH,KAAKR,wBAAwBK,QAAQO,wBAAwB;YACjF,MAAMC,KAAsBC,CAAAA;gBAC1BH,oBAAoBH,KAAKR,wBAAwBc;YACnD;YACAT,QAAQU,SAAS,CAACF;YAClB,OAAO,IAAMR,QAAQW,WAAW,CAACH;QACnC;IACF,GAAG;QAACR;KAAQ;IACZ,OAAOG;AACT;AAEA,SAASG,oBAAoBM,UAAwC,EAAEC,SAAiB,EAAEC,KAAc;IACtG,IAAI,CAACF,WAAWG,OAAO,EAAE;QACvB;IACF;IACA,IAAID,OAAO;QACTF,WAAWG,OAAO,CAACC,YAAY,CAACH,WAAW;IAC7C,OAAO;QACLD,WAAWG,OAAO,CAACE,eAAe,CAACJ;IACrC;AACF"}
+24
View File
@@ -0,0 +1,24 @@
import * as React from 'react';
import { createKeyborg, disposeKeyborg } from 'keyborg';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
/**
* @internal
* Instantiates [keyborg](https://github.com/microsoft/keyborg)
* @returns - keyborg instance
*/ export function useKeyborgRef() {
const { targetDocument } = useFluent();
const keyborgRef = React.useRef(null);
React.useEffect(()=>{
if (targetDocument) {
const keyborg = createKeyborg(targetDocument.defaultView);
keyborgRef.current = keyborg;
return ()=>{
disposeKeyborg(keyborg);
keyborgRef.current = null;
};
}
}, [
targetDocument
]);
return keyborgRef;
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useKeyborgRef.ts"],"sourcesContent":["import * as React from 'react';\nimport { createKeyborg, disposeKeyborg, type Keyborg } from 'keyborg';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\n/**\n * @internal\n * Instantiates [keyborg](https://github.com/microsoft/keyborg)\n * @returns - keyborg instance\n */\nexport function useKeyborgRef() {\n const { targetDocument } = useFluent();\n const keyborgRef = React.useRef<Keyborg | null>(null);\n\n React.useEffect(() => {\n if (targetDocument) {\n const keyborg = createKeyborg(targetDocument.defaultView!);\n keyborgRef.current = keyborg;\n\n return () => {\n disposeKeyborg(keyborg);\n keyborgRef.current = null;\n };\n }\n }, [targetDocument]);\n\n return keyborgRef;\n}\n"],"names":["React","createKeyborg","disposeKeyborg","useFluent_unstable","useFluent","useKeyborgRef","targetDocument","keyborgRef","useRef","useEffect","keyborg","defaultView","current"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,aAAa,EAAEC,cAAc,QAAsB,UAAU;AACtE,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF;;;;CAIC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGF;IAC3B,MAAMG,aAAaP,MAAMQ,MAAM,CAAiB;IAEhDR,MAAMS,SAAS,CAAC;QACd,IAAIH,gBAAgB;YAClB,MAAMI,UAAUT,cAAcK,eAAeK,WAAW;YACxDJ,WAAWK,OAAO,GAAGF;YAErB,OAAO;gBACLR,eAAeQ;gBACfH,WAAWK,OAAO,GAAG;YACvB;QACF;IACF,GAAG;QAACN;KAAe;IAEnB,OAAOC;AACT"}
@@ -0,0 +1,75 @@
import * as React from 'react';
import { TABSTER_ATTRIBUTE_NAME } from 'tabster';
/**
* Merges a collection of tabster attributes.
*
* ⚠️The attributes passed as arguments to this hook cannot change at runtime.
* @internal
* @param attributes - collection of tabster attributes from other react-tabster hooks
* @returns single merged tabster attribute
*/ export const useMergedTabsterAttributes_unstable = (...attributes)=>{
'use no memo';
const stringAttributes = attributes.reduce((acc, curr)=>{
if (curr === null || curr === void 0 ? void 0 : curr[TABSTER_ATTRIBUTE_NAME]) {
acc.push(curr[TABSTER_ATTRIBUTE_NAME]);
}
return acc;
}, []);
if (process.env.NODE_ENV !== 'production') {
// ignoring rules of hooks because this is a condition based on the environment
// it's safe to ignore the rule
// eslint-disable-next-line react-hooks/rules-of-hooks
useWarnIfUnstableAttributes(stringAttributes);
}
return React.useMemo(()=>({
[TABSTER_ATTRIBUTE_NAME]: stringAttributes.length > 0 ? stringAttributes.reduce(mergeJSONStrings) : undefined
}), // disable exhaustive-deps because we want to memoize the result of the reduction
// this is safe because the collection of attributes is not expected to change at runtime
// eslint-disable-next-line react-hooks/exhaustive-deps
stringAttributes);
};
/**
* Merges two JSON strings into one.
*/ const mergeJSONStrings = (a, b)=>JSON.stringify(Object.assign(safelyParseJSON(a), safelyParseJSON(b)));
/**
* Tries to parse a JSON string and returns an object.
* If the JSON string is invalid, an empty object is returned.
*/ const safelyParseJSON = (json)=>{
try {
return JSON.parse(json);
} catch {
return {};
}
};
/**
* Helper hook that ensures that the attributes passed to the hook are stable.
* This is necessary because the attributes are expected to not change at runtime.
*
* This hook will console.warn if the attributes change at runtime.
*/ const useWarnIfUnstableAttributes = (attributes)=>{
'use no memo';
const initialAttributesRef = React.useRef(attributes);
let isStable = initialAttributesRef.current.length === attributes.length;
if (initialAttributesRef.current !== attributes && isStable) {
for(let i = 0; i < attributes.length; i++){
if (initialAttributesRef.current[i] !== attributes[i]) {
isStable = false;
break;
}
}
}
React.useEffect(()=>{
if (!isStable) {
const error = new Error();
// eslint-disable-next-line no-console
console.warn(/** #__DE-INDENT__ */ `
@fluentui/react-tabster [useMergedTabsterAttributes]:
The attributes passed to the hook changed at runtime.
This might lead to unexpected behavior, please ensure that the attributes are stable.
${error.stack}
`);
}
}, [
isStable
]);
};
File diff suppressed because one or more lines are too long
+56
View File
@@ -0,0 +1,56 @@
import { useId } from '@fluentui/react-utilities';
import { useTabsterAttributes } from './useTabsterAttributes';
import { getModalizer, getRestorer, RestorerTypes } from 'tabster';
import { useTabster } from './useTabster';
const DangerousNeverHiddenAttribute = 'data-tabster-never-hide';
const DangerousNeverHiddenPropObject = {
[DangerousNeverHiddenAttribute]: ''
};
/**
* !!DANGEROUS!! Designates an element that will not be hidden even when outside an open modal.
* Only works for top-level elements; should be used with extreme care.
* @returns Attribute to apply to the target element that should never receive aria-hidden
*/ export function useDangerousNeverHidden_unstable() {
return DangerousNeverHiddenPropObject;
}
const tabsterAccessibleCheck = (element)=>{
return element.hasAttribute(DangerousNeverHiddenAttribute);
};
/**
* Applies modal dialog behaviour through DOM attributes
* Modal element will focus trap and hide other content on the page
* The trigger element will be focused if focus is lost after the modal element is removed
*
* @returns DOM attributes to apply to the modal element and its trigger
*/ export const useModalAttributes = (options = {})=>{
const { trapFocus, alwaysFocusable, legacyTrapFocus } = options;
const tabster = useTabster();
// Initializes the modalizer and restorer APIs
if (tabster) {
getModalizer(tabster, undefined, tabsterAccessibleCheck);
getRestorer(tabster);
}
const id = useId('modal-', options.id);
const modalAttributes = useTabsterAttributes({
restorer: {
type: RestorerTypes.Source
},
...trapFocus && {
modalizer: {
id,
isOthersAccessible: !trapFocus,
isAlwaysAccessible: alwaysFocusable,
isTrapped: legacyTrapFocus && trapFocus
}
}
});
const triggerAttributes = useTabsterAttributes({
restorer: {
type: RestorerTypes.Target
}
});
return {
modalAttributes,
triggerAttributes
};
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useModalAttributes.ts"],"sourcesContent":["import { useId } from '@fluentui/react-utilities';\nimport { useTabsterAttributes } from './useTabsterAttributes';\nimport { getModalizer, getRestorer, Types as TabsterTypes, RestorerTypes } from 'tabster';\nimport { useTabster } from './useTabster';\n\nconst DangerousNeverHiddenAttribute = 'data-tabster-never-hide';\nconst DangerousNeverHiddenPropObject = { [DangerousNeverHiddenAttribute]: '' };\n\nexport interface UseModalAttributesOptions {\n /**\n * Traps focus inside the elements the attributes are applied.\n * it forbids users to tab out of the focus trap into the actual browser.\n */\n trapFocus?: boolean;\n\n /**\n * Traps focus inside the elements the attributes are applied.\n * This prop enables traditional force-focus behavior to match previous versions of Fluent.\n * Without this, users can tab out of the focus trap and into the browser chrome.\n * This matches the behavior of the native <dialog> element and inert.\n * We recommend setting this to true based on user feedback and consistency.\n */\n legacyTrapFocus?: boolean;\n\n /**\n * Always reachabled in Tab order\n */\n alwaysFocusable?: boolean;\n\n /**\n * Id to use for the modalizer. An id will be generated if not provided.\n */\n id?: string;\n}\n\n/**\n * !!DANGEROUS!! Designates an element that will not be hidden even when outside an open modal.\n * Only works for top-level elements; should be used with extreme care.\n * @returns Attribute to apply to the target element that should never receive aria-hidden\n */\nexport function useDangerousNeverHidden_unstable(): { [key: string]: string } {\n return DangerousNeverHiddenPropObject;\n}\n\nconst tabsterAccessibleCheck: TabsterTypes.ModalizerElementAccessibleCheck = element => {\n return element.hasAttribute(DangerousNeverHiddenAttribute);\n};\n\n/**\n * Applies modal dialog behaviour through DOM attributes\n * Modal element will focus trap and hide other content on the page\n * The trigger element will be focused if focus is lost after the modal element is removed\n *\n * @returns DOM attributes to apply to the modal element and its trigger\n */\nexport const useModalAttributes = (\n options: UseModalAttributesOptions = {},\n): { modalAttributes: TabsterTypes.TabsterDOMAttribute; triggerAttributes: TabsterTypes.TabsterDOMAttribute } => {\n const { trapFocus, alwaysFocusable, legacyTrapFocus } = options;\n const tabster = useTabster();\n // Initializes the modalizer and restorer APIs\n if (tabster) {\n getModalizer(tabster, undefined, tabsterAccessibleCheck);\n getRestorer(tabster);\n }\n\n const id = useId('modal-', options.id);\n const modalAttributes = useTabsterAttributes({\n restorer: { type: RestorerTypes.Source },\n ...(trapFocus && {\n modalizer: {\n id,\n isOthersAccessible: !trapFocus,\n isAlwaysAccessible: alwaysFocusable,\n isTrapped: legacyTrapFocus && trapFocus,\n },\n }),\n });\n\n const triggerAttributes = useTabsterAttributes({\n restorer: { type: RestorerTypes.Target },\n });\n\n return { modalAttributes, triggerAttributes };\n};\n"],"names":["useId","useTabsterAttributes","getModalizer","getRestorer","RestorerTypes","useTabster","DangerousNeverHiddenAttribute","DangerousNeverHiddenPropObject","useDangerousNeverHidden_unstable","tabsterAccessibleCheck","element","hasAttribute","useModalAttributes","options","trapFocus","alwaysFocusable","legacyTrapFocus","tabster","undefined","id","modalAttributes","restorer","type","Source","modalizer","isOthersAccessible","isAlwaysAccessible","isTrapped","triggerAttributes","Target"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,KAAK,QAAQ,4BAA4B;AAClD,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,YAAY,EAAEC,WAAW,EAAyBC,aAAa,QAAQ,UAAU;AAC1F,SAASC,UAAU,QAAQ,eAAe;AAE1C,MAAMC,gCAAgC;AACtC,MAAMC,iCAAiC;IAAE,CAACD,8BAA8B,EAAE;AAAG;AA6B7E;;;;CAIC,GACD,OAAO,SAASE;IACd,OAAOD;AACT;AAEA,MAAME,yBAAuEC,CAAAA;IAC3E,OAAOA,QAAQC,YAAY,CAACL;AAC9B;AAEA;;;;;;CAMC,GACD,OAAO,MAAMM,qBAAqB,CAChCC,UAAqC,CAAC,CAAC;IAEvC,MAAM,EAAEC,SAAS,EAAEC,eAAe,EAAEC,eAAe,EAAE,GAAGH;IACxD,MAAMI,UAAUZ;IAChB,8CAA8C;IAC9C,IAAIY,SAAS;QACXf,aAAae,SAASC,WAAWT;QACjCN,YAAYc;IACd;IAEA,MAAME,KAAKnB,MAAM,UAAUa,QAAQM,EAAE;IACrC,MAAMC,kBAAkBnB,qBAAqB;QAC3CoB,UAAU;YAAEC,MAAMlB,cAAcmB,MAAM;QAAC;QACvC,GAAIT,aAAa;YACfU,WAAW;gBACTL;gBACAM,oBAAoB,CAACX;gBACrBY,oBAAoBX;gBACpBY,WAAWX,mBAAmBF;YAChC;QACF,CAAC;IACH;IAEA,MAAMc,oBAAoB3B,qBAAqB;QAC7CoB,UAAU;YAAEC,MAAMlB,cAAcyB,MAAM;QAAC;IACzC;IAEA,OAAO;QAAET;QAAiBQ;IAAkB;AAC9C,EAAE"}
+16
View File
@@ -0,0 +1,16 @@
import { useTabster } from './useTabster';
import { getObservedElement } from 'tabster';
import { useTabsterAttributes } from './useTabsterAttributes';
export function useObservedElement(name) {
const tabster = useTabster();
if (tabster) {
getObservedElement(tabster);
}
return useTabsterAttributes({
observed: {
names: Array.isArray(name) ? name : [
name
]
}
});
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useObservedElement.ts"],"sourcesContent":["import { useTabster } from './useTabster';\nimport { getObservedElement, Types as TabsterTypes } from 'tabster';\nimport { useTabsterAttributes } from './useTabsterAttributes';\n\nexport function useObservedElement(name: string | string[]): TabsterTypes.TabsterDOMAttribute {\n const tabster = useTabster();\n if (tabster) {\n getObservedElement(tabster);\n }\n\n return useTabsterAttributes({ observed: { names: Array.isArray(name) ? name : [name] } });\n}\n"],"names":["useTabster","getObservedElement","useTabsterAttributes","useObservedElement","name","tabster","observed","names","Array","isArray"],"rangeMappings":";;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,UAAU,QAAQ,eAAe;AAC1C,SAASC,kBAAkB,QAA+B,UAAU;AACpE,SAASC,oBAAoB,QAAQ,yBAAyB;AAE9D,OAAO,SAASC,mBAAmBC,IAAuB;IACxD,MAAMC,UAAUL;IAChB,IAAIK,SAAS;QACXJ,mBAAmBI;IACrB;IAEA,OAAOH,qBAAqB;QAAEI,UAAU;YAAEC,OAAOC,MAAMC,OAAO,CAACL,QAAQA,OAAO;gBAACA;aAAK;QAAC;IAAE;AACzF"}
@@ -0,0 +1,28 @@
import * as React from 'react';
import { useEventCallback } from '@fluentui/react-utilities';
import { useKeyborgRef } from './useKeyborgRef';
/**
* Instantiates [keyborg](https://github.com/microsoft/keyborg) and subscribes to changes
* in the keyboard navigation mode.
*
* @param callback - called every time the keyboard navigation state changes
*/ export function useOnKeyboardNavigationChange(callback) {
const keyborgRef = useKeyborgRef();
const eventCallback = useEventCallback(callback);
React.useEffect(()=>{
const keyborg = keyborgRef.current;
if (keyborg) {
const cb = (next)=>{
eventCallback(next);
};
keyborg.subscribe(cb);
cb(keyborg.isNavigatingWithKeyboard());
return ()=>{
keyborg.unsubscribe(cb);
};
}
}, [
keyborgRef,
eventCallback
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useOnKeyboardNavigationChange.ts"],"sourcesContent":["import type { KeyborgCallback } from 'keyborg';\nimport * as React from 'react';\nimport { useEventCallback } from '@fluentui/react-utilities';\n\nimport { useKeyborgRef } from './useKeyborgRef';\n\n/**\n * Instantiates [keyborg](https://github.com/microsoft/keyborg) and subscribes to changes\n * in the keyboard navigation mode.\n *\n * @param callback - called every time the keyboard navigation state changes\n */\nexport function useOnKeyboardNavigationChange(callback: (isNavigatingWithKeyboard: boolean) => void) {\n const keyborgRef = useKeyborgRef();\n const eventCallback = useEventCallback(callback);\n\n React.useEffect(() => {\n const keyborg = keyborgRef.current;\n\n if (keyborg) {\n const cb: KeyborgCallback = next => {\n eventCallback(next);\n };\n\n keyborg.subscribe(cb);\n cb(keyborg.isNavigatingWithKeyboard());\n\n return () => {\n keyborg.unsubscribe(cb);\n };\n }\n }, [keyborgRef, eventCallback]);\n}\n"],"names":["React","useEventCallback","useKeyborgRef","useOnKeyboardNavigationChange","callback","keyborgRef","eventCallback","useEffect","keyborg","current","cb","next","subscribe","isNavigatingWithKeyboard","unsubscribe"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,gBAAgB,QAAQ,4BAA4B;AAE7D,SAASC,aAAa,QAAQ,kBAAkB;AAEhD;;;;;CAKC,GACD,OAAO,SAASC,8BAA8BC,QAAqD;IACjG,MAAMC,aAAaH;IACnB,MAAMI,gBAAgBL,iBAAiBG;IAEvCJ,MAAMO,SAAS,CAAC;QACd,MAAMC,UAAUH,WAAWI,OAAO;QAElC,IAAID,SAAS;YACX,MAAME,KAAsBC,CAAAA;gBAC1BL,cAAcK;YAChB;YAEAH,QAAQI,SAAS,CAACF;YAClBA,GAAGF,QAAQK,wBAAwB;YAEnC,OAAO;gBACLL,QAAQM,WAAW,CAACJ;YACtB;QACF;IACF,GAAG;QAACL;QAAYC;KAAc;AAChC"}
+32
View File
@@ -0,0 +1,32 @@
import { getRestorer, getTabsterAttribute, RestorerTypes } from 'tabster';
import { useTabster } from './useTabster';
/**
* Focus will be restored to the most recent target element when it is lost from a source
* @returns Attribute to apply to the target element where focus is restored
*/ export function useRestoreFocusTarget() {
const tabster = useTabster();
// Initializes the restorer API
if (tabster) {
getRestorer(tabster);
}
return getTabsterAttribute({
restorer: {
type: RestorerTypes.Target
}
});
}
/**
* Focus will be restored to the most recent target element when it is lost from a source
* @returns Attribute to apply to the element that might lose focus
*/ export function useRestoreFocusSource() {
const tabster = useTabster();
// Initializes the restorer API
if (tabster) {
getRestorer(tabster);
}
return getTabsterAttribute({
restorer: {
type: RestorerTypes.Source
}
});
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useRestoreFocus.ts"],"sourcesContent":["import { getRestorer, getTabsterAttribute, Types as TabsterTypes, RestorerTypes } from 'tabster';\nimport { useTabster } from './useTabster';\n\n/**\n * Focus will be restored to the most recent target element when it is lost from a source\n * @returns Attribute to apply to the target element where focus is restored\n */\nexport function useRestoreFocusTarget(): TabsterTypes.TabsterDOMAttribute {\n const tabster = useTabster();\n // Initializes the restorer API\n if (tabster) {\n getRestorer(tabster);\n }\n\n return getTabsterAttribute({ restorer: { type: RestorerTypes.Target } });\n}\n\n/**\n * Focus will be restored to the most recent target element when it is lost from a source\n * @returns Attribute to apply to the element that might lose focus\n */\nexport function useRestoreFocusSource(): TabsterTypes.TabsterDOMAttribute {\n const tabster = useTabster();\n // Initializes the restorer API\n if (tabster) {\n getRestorer(tabster);\n }\n\n return getTabsterAttribute({ restorer: { type: RestorerTypes.Source } });\n}\n"],"names":["getRestorer","getTabsterAttribute","RestorerTypes","useTabster","useRestoreFocusTarget","tabster","restorer","type","Target","useRestoreFocusSource","Source"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,WAAW,EAAEC,mBAAmB,EAAyBC,aAAa,QAAQ,UAAU;AACjG,SAASC,UAAU,QAAQ,eAAe;AAE1C;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,UAAUF;IAChB,+BAA+B;IAC/B,IAAIE,SAAS;QACXL,YAAYK;IACd;IAEA,OAAOJ,oBAAoB;QAAEK,UAAU;YAAEC,MAAML,cAAcM,MAAM;QAAC;IAAE;AACxE;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMJ,UAAUF;IAChB,+BAA+B;IAC/B,IAAIE,SAAS;QACXL,YAAYK;IACd;IAEA,OAAOJ,oBAAoB;QAAEK,UAAU;YAAEC,MAAML,cAAcQ,MAAM;QAAC;IAAE;AACxE"}
@@ -0,0 +1,12 @@
import * as React from 'react';
import { useKeyborgRef } from './useKeyborgRef';
/**
*/ export function useSetKeyboardNavigation() {
const keyborgRef = useKeyborgRef();
return React.useCallback((isNavigatingWithKeyboard)=>{
var _keyborgRef_current;
(_keyborgRef_current = keyborgRef.current) === null || _keyborgRef_current === void 0 ? void 0 : _keyborgRef_current.setVal(isNavigatingWithKeyboard);
}, [
keyborgRef
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useSetKeyboardNavigation.ts"],"sourcesContent":["import * as React from 'react';\nimport { useKeyborgRef } from './useKeyborgRef';\n\n/**\n */\nexport function useSetKeyboardNavigation() {\n const keyborgRef = useKeyborgRef();\n\n return React.useCallback(\n (isNavigatingWithKeyboard: boolean) => {\n keyborgRef.current?.setVal(isNavigatingWithKeyboard);\n },\n [keyborgRef],\n );\n}\n"],"names":["React","useKeyborgRef","useSetKeyboardNavigation","keyborgRef","useCallback","isNavigatingWithKeyboard","current","setVal"],"rangeMappings":";;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,aAAa,QAAQ,kBAAkB;AAEhD;CACC,GACD,OAAO,SAASC;IACd,MAAMC,aAAaF;IAEnB,OAAOD,MAAMI,WAAW,CACtB,CAACC;YACCF;SAAAA,sBAAAA,WAAWG,OAAO,cAAlBH,0CAAAA,oBAAoBI,MAAM,CAACF;IAC7B,GACA;QAACF;KAAW;AAEhB"}
+43
View File
@@ -0,0 +1,43 @@
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { createTabster, disposeTabster } from 'tabster';
import { useIsomorphicLayoutEffect, getParent } from '@fluentui/react-utilities';
/**
* Tries to get a tabster instance on the current window or creates a new one
* Since Tabster is single instance only, feel free to call this hook to ensure Tabster exists if necessary
*
* @internal
* @returns Tabster core instance
*/ export const useTabster = ()=>{
const { targetDocument } = useFluent();
const defaultView = (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) || undefined;
const shadowDOMAPI = defaultView === null || defaultView === void 0 ? void 0 : defaultView.__tabsterShadowDOMAPI;
const tabster = React.useMemo(()=>{
if (!defaultView) {
return null;
}
return createTabster(defaultView, {
autoRoot: {},
controlTab: false,
getParent,
checkUncontrolledTrappingFocus: (element)=>{
var _element_firstElementChild;
return !!((_element_firstElementChild = element.firstElementChild) === null || _element_firstElementChild === void 0 ? void 0 : _element_firstElementChild.hasAttribute('data-is-focus-trap-zone-bumper'));
},
DOMAPI: shadowDOMAPI
});
}, [
defaultView,
shadowDOMAPI
]);
useIsomorphicLayoutEffect(()=>{
return ()=>{
if (tabster) {
disposeTabster(tabster);
}
};
}, [
tabster
]);
return tabster;
};
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useTabster.ts"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { createTabster, disposeTabster, Types as TabsterTypes } from 'tabster';\nimport { useIsomorphicLayoutEffect, getParent } from '@fluentui/react-utilities';\n\ninterface WindowWithTabsterShadowDOMAPI extends Window {\n __tabsterShadowDOMAPI?: TabsterTypes.DOMAPI;\n}\n\n/**\n * Tries to get a tabster instance on the current window or creates a new one\n * Since Tabster is single instance only, feel free to call this hook to ensure Tabster exists if necessary\n *\n * @internal\n * @returns Tabster core instance\n */\nexport const useTabster = (): TabsterTypes.TabsterCore | null => {\n const { targetDocument } = useFluent();\n\n const defaultView = targetDocument?.defaultView || undefined;\n\n const shadowDOMAPI = (defaultView as WindowWithTabsterShadowDOMAPI | undefined)?.__tabsterShadowDOMAPI;\n\n const tabster = React.useMemo(() => {\n if (!defaultView) {\n return null;\n }\n\n return createTabster(defaultView, {\n autoRoot: {},\n controlTab: false,\n getParent,\n checkUncontrolledTrappingFocus: element =>\n !!element.firstElementChild?.hasAttribute('data-is-focus-trap-zone-bumper'),\n DOMAPI: shadowDOMAPI,\n });\n }, [defaultView, shadowDOMAPI]);\n\n useIsomorphicLayoutEffect(() => {\n return () => {\n if (tabster) {\n disposeTabster(tabster);\n }\n };\n }, [tabster]);\n\n return tabster;\n};\n"],"names":["React","useFluent_unstable","useFluent","createTabster","disposeTabster","useIsomorphicLayoutEffect","getParent","useTabster","targetDocument","defaultView","undefined","shadowDOMAPI","__tabsterShadowDOMAPI","tabster","useMemo","autoRoot","controlTab","checkUncontrolledTrappingFocus","element","firstElementChild","hasAttribute","DOMAPI"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,aAAa,EAAEC,cAAc,QAA+B,UAAU;AAC/E,SAASC,yBAAyB,EAAEC,SAAS,QAAQ,4BAA4B;AAMjF;;;;;;CAMC,GACD,OAAO,MAAMC,aAAa;IACxB,MAAM,EAAEC,cAAc,EAAE,GAAGN;IAE3B,MAAMO,cAAcD,CAAAA,2BAAAA,qCAAAA,eAAgBC,WAAW,KAAIC;IAEnD,MAAMC,eAAgBF,wBAAAA,kCAAD,AAACA,YAA2DG,qBAAqB;IAEtG,MAAMC,UAAUb,MAAMc,OAAO,CAAC;QAC5B,IAAI,CAACL,aAAa;YAChB,OAAO;QACT;QAEA,OAAON,cAAcM,aAAa;YAChCM,UAAU,CAAC;YACXC,YAAY;YACZV;YACAW,gCAAgCC,CAAAA;oBAC5BA;uBAAF,CAAC,GAACA,6BAAAA,QAAQC,iBAAiB,cAAzBD,iDAAAA,2BAA2BE,YAAY,CAAC;;YAC5CC,QAAQV;QACV;IACF,GAAG;QAACF;QAAaE;KAAa;IAE9BN,0BAA0B;QACxB,OAAO;YACL,IAAIQ,SAAS;gBACXT,eAAeS;YACjB;QACF;IACF,GAAG;QAACA;KAAQ;IAEZ,OAAOA;AACT,EAAE"}
+17
View File
@@ -0,0 +1,17 @@
import { getTabsterAttribute, TABSTER_ATTRIBUTE_NAME } from 'tabster';
import { useTabster } from './useTabster';
import * as React from 'react';
/**
* @internal
* Hook that returns tabster attributes while ensuring tabster exists
*/ export const useTabsterAttributes = (props)=>{
// A tabster instance is not necessary to generate tabster attributes
// but calling the hook will ensure that a tabster instance exists internally and avoids consumers doing the same
useTabster();
const strAttr = getTabsterAttribute(props, true);
return React.useMemo(()=>({
[TABSTER_ATTRIBUTE_NAME]: strAttr
}), [
strAttr
]);
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useTabsterAttributes.ts"],"sourcesContent":["import { getTabsterAttribute, Types as TabsterTypes, TABSTER_ATTRIBUTE_NAME } from 'tabster';\nimport { useTabster } from './useTabster';\nimport * as React from 'react';\n\n/**\n * @internal\n * Hook that returns tabster attributes while ensuring tabster exists\n */\nexport const useTabsterAttributes = (props: TabsterTypes.TabsterAttributeProps): TabsterTypes.TabsterDOMAttribute => {\n // A tabster instance is not necessary to generate tabster attributes\n // but calling the hook will ensure that a tabster instance exists internally and avoids consumers doing the same\n useTabster();\n\n const strAttr = getTabsterAttribute(props, true);\n\n return React.useMemo(\n () => ({\n [TABSTER_ATTRIBUTE_NAME]: strAttr,\n }),\n [strAttr],\n );\n};\n"],"names":["getTabsterAttribute","TABSTER_ATTRIBUTE_NAME","useTabster","React","useTabsterAttributes","props","strAttr","useMemo"],"rangeMappings":";;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,mBAAmB,EAAyBC,sBAAsB,QAAQ,UAAU;AAC7F,SAASC,UAAU,QAAQ,eAAe;AAC1C,YAAYC,WAAW,QAAQ;AAE/B;;;CAGC,GACD,OAAO,MAAMC,uBAAuB,CAACC;IACnC,qEAAqE;IACrE,iHAAiH;IACjHH;IAEA,MAAMI,UAAUN,oBAAoBK,OAAO;IAE3C,OAAOF,MAAMI,OAAO,CAClB,IAAO,CAAA;YACL,CAACN,uBAAuB,EAAEK;QAC5B,CAAA,GACA;QAACA;KAAQ;AAEb,EAAE"}
+11
View File
@@ -0,0 +1,11 @@
import { getTabsterAttribute } from 'tabster';
import { useTabster } from './useTabster';
/**
* Designates an area where tabster does not control focus
* @returns Attribute to apply to the target element that should be uncontrolled by tabster
*/ export function useUncontrolledFocus() {
useTabster();
return getTabsterAttribute({
uncontrolled: {}
});
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useUncontrolledFocus.ts"],"sourcesContent":["import { getTabsterAttribute, Types as TabsterTypes } from 'tabster';\nimport { useTabster } from './useTabster';\n\n/**\n * Designates an area where tabster does not control focus\n * @returns Attribute to apply to the target element that should be uncontrolled by tabster\n */\nexport function useUncontrolledFocus(): TabsterTypes.TabsterDOMAttribute {\n useTabster();\n\n return getTabsterAttribute({ uncontrolled: {} });\n}\n"],"names":["getTabsterAttribute","useTabster","useUncontrolledFocus","uncontrolled"],"rangeMappings":";;;;;;;;;;","mappings":"AAAA,SAASA,mBAAmB,QAA+B,UAAU;AACrE,SAASC,UAAU,QAAQ,eAAe;AAE1C;;;CAGC,GACD,OAAO,SAASC;IACdD;IAEA,OAAOD,oBAAoB;QAAEG,cAAc,CAAC;IAAE;AAChD"}
+19
View File
@@ -0,0 +1,19 @@
export { useArrowNavigationGroup, useFocusableGroup, useFocusFinders, useFocusVisible, useFocusWithin, useKeyboardNavAttribute, useDangerousNeverHidden_unstable, useModalAttributes, useTabsterAttributes, useObservedElement, useFocusObserved, useMergedTabsterAttributes_unstable, useRestoreFocusSource, useRestoreFocusTarget, useUncontrolledFocus, useOnKeyboardNavigationChange, useIsNavigatingWithKeyboard, useSetKeyboardNavigation, useFocusedElementChange, useActivateModal } from './hooks/index';
export { createCustomFocusIndicatorStyle, createFocusOutlineStyle } from './focus/index';
export { applyFocusVisiblePolyfill } from './focus/index';
import { dispatchGroupperMoveFocusEvent, dispatchMoverMoveFocusEvent, MoverMoveFocusEventName, MoverMoveFocusEvent, MoverKeys, GroupperMoveFocusEventName, GroupperMoveFocusEvent, GroupperMoveFocusActions, MoverMemorizedElementEventName, MoverMemorizedElementEvent, TabsterMoveFocusEventName, TabsterMoveFocusEvent } from 'tabster';
export { KEYBORG_FOCUSIN } from 'keyborg';
// WARNING! ATTENTION! Tabster.Types was exported from here by mistake. To avoid breaking changes,
// we are putting a snapshot of Tabster.Types@6.0.1 and marking the entire export as deprecated.
// eslint-disable-next-line @typescript-eslint/naming-convention
import * as TabsterTypes6_0_1_DoNotUse from './tabster-types-6.0.1-do-not-use';
export { /** @deprecated (Do not use! Exposed by mistake and will be removed in the next major version.) */ TabsterTypes6_0_1_DoNotUse as TabsterTypes, /** @deprecated Use element.dispatchEvent(new GroupperMoveFocusEvent({ action: GroupperMoveFocusActions.Escape })) */ // eslint-disable-next-line @typescript-eslint/no-deprecated
dispatchGroupperMoveFocusEvent, /** @deprecated Use element.dispatchEvent(new MoverMoveFocusEvent({ key: MoverKeys.ArrowDown })) */ // eslint-disable-next-line @typescript-eslint/no-deprecated
dispatchMoverMoveFocusEvent };
/**
* For all exports below, we don't do wildcard exports to keep Tabster API flexible. We export only required
* parts when they are needed.
*/ export { MoverMoveFocusEventName, MoverMoveFocusEvent, MoverKeys };
export { GroupperMoveFocusEventName, GroupperMoveFocusEvent, GroupperMoveFocusActions };
export { MoverMemorizedElementEventName, MoverMemorizedElementEvent };
export { TabsterMoveFocusEventName, TabsterMoveFocusEvent };
File diff suppressed because one or more lines are too long
@@ -0,0 +1,96 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/ /**
* WARNING! ATTENTION! WARNING! ATTENTION! WARNING! ATTENTION!
* WARNING! ATTENTION! WARNING! ATTENTION! WARNING! ATTENTION!
*
* Do not use anything from this file. It is a snapshot of the older Tabster typings exposed by a mistake.
* The exposed typings should have been removed, but we don't do it in minor versions to avoid breaking changes.
* Everything reexported from this file as react-tabster/TabsterTypes is marked as deprecated and shouldn't
* be used anywhre.
*
* WARNING! ATTENTION! WARNING! ATTENTION! WARNING! ATTENTION!
* WARNING! ATTENTION! WARNING! ATTENTION! WARNING! ATTENTION!
*/ export const TabsterAttributeName = 'data-tabster';
export const TabsterDummyInputAttributeName = 'data-tabster-dummy';
export const DeloserEventName = 'tabster:deloser';
export const ModalizerActiveEventName = 'tabster:modalizer:active';
export const ModalizerInactiveEventName = 'tabster:modalizer:inactive';
export const ModalizerFocusInEventName = 'tabster:modalizer:focusin';
export const ModalizerFocusOutEventName = 'tabster:modalizer:focusout';
export const ModalizerBeforeFocusOutEventName = 'tabster:modalizer:beforefocusout';
export const MoverEventName = 'tabster:mover';
export const FocusInEventName = 'tabster:focusin';
export const FocusOutEventName = 'tabster:focusout';
// Event to be triggered when Tabster wants to move focus as the result of
// keyboard event. This allows to preventDefault() if you want to have
// some custom logic.
export const MoveFocusEventName = 'tabster:movefocus';
// Event that can be triggered by the application to programmatically move
// focus inside Mover.
export const MoverMoveFocusEventName = 'tabster:mover:movefocus';
// Event that can be triggered by the application to programmatically enter
// or escape Groupper.
export const GroupperMoveFocusEventName = 'tabster:groupper:movefocus';
export const FocusableSelector = [
'a[href]',
'button:not([disabled])',
'input:not([disabled])',
'select:not([disabled])',
'textarea:not([disabled])',
'*[tabindex]',
'*[contenteditable]'
].join(', ');
export const GroupperMoveFocusActions = {
Enter: 1,
Escape: 2
};
export const ObservedElementAccesibilities = {
Any: 0,
Accessible: 1,
Focusable: 2
};
export const RestoreFocusOrders = {
History: 0,
DeloserDefault: 1,
RootDefault: 2,
DeloserFirst: 3,
RootFirst: 4
};
export const Visibilities = {
Invisible: 0,
PartiallyVisible: 1,
Visible: 2
};
export const RestorerTypes = {
Source: 0,
Target: 1
};
export const MoverDirections = {
Both: 0,
Vertical: 1,
Horizontal: 2,
Grid: 3,
GridLinear: 4
};
export const MoverKeys = {
ArrowUp: 1,
ArrowDown: 2,
ArrowLeft: 3,
ArrowRight: 4,
PageUp: 5,
PageDown: 6,
Home: 7,
End: 8
};
export const GroupperTabbabilities = {
Unlimited: 0,
Limited: 1,
LimitedTrapFocus: 2
};
export const SysDummyInputsPositions = {
Auto: 0,
Inside: 1,
Outside: 2
};
File diff suppressed because one or more lines are too long