mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[react-interaction] Refactor a11y components more (#16866)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./src/FocusControl');
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {ReactScopeMethods} from 'shared/ReactTypes';
|
||||
import type {KeyboardEvent} from 'react-interactions/events/keyboard';
|
||||
|
||||
function getTabbableNodes(scope: ReactScopeMethods) {
|
||||
const tabbableNodes = scope.getScopedNodes();
|
||||
if (tabbableNodes === null || tabbableNodes.length === 0) {
|
||||
return [null, null, null, 0, null];
|
||||
}
|
||||
const firstTabbableElem = tabbableNodes[0];
|
||||
const lastTabbableElem = tabbableNodes[tabbableNodes.length - 1];
|
||||
const currentIndex = tabbableNodes.indexOf(document.activeElement);
|
||||
let focusedElement = null;
|
||||
if (currentIndex !== -1) {
|
||||
focusedElement = tabbableNodes[currentIndex];
|
||||
}
|
||||
return [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
];
|
||||
}
|
||||
|
||||
export function focusFirst(scope: ReactScopeMethods): void {
|
||||
const [, firstTabbableElem] = getTabbableNodes(scope);
|
||||
focusElem(firstTabbableElem);
|
||||
}
|
||||
|
||||
function focusElem(elem: null | HTMLElement): void {
|
||||
if (elem !== null) {
|
||||
elem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export function focusNext(
|
||||
scope: ReactScopeMethods,
|
||||
event?: KeyboardEvent,
|
||||
contain?: boolean,
|
||||
): void {
|
||||
const [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
] = getTabbableNodes(scope);
|
||||
|
||||
if (focusedElement === null) {
|
||||
if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else if (focusedElement === lastTabbableElem) {
|
||||
if (contain) {
|
||||
focusElem(firstTabbableElem);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
} else if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else {
|
||||
focusElem((tabbableNodes: any)[currentIndex + 1]);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function focusPrevious(
|
||||
scope: ReactScopeMethods,
|
||||
event?: KeyboardEvent,
|
||||
contain?: boolean,
|
||||
): void {
|
||||
const [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
] = getTabbableNodes(scope);
|
||||
|
||||
if (focusedElement === null) {
|
||||
if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else if (focusedElement === firstTabbableElem) {
|
||||
if (contain) {
|
||||
focusElem(lastTabbableElem);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
} else if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else {
|
||||
focusElem((tabbableNodes: any)[currentIndex - 1]);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getNextController(
|
||||
scope: ReactScopeMethods,
|
||||
): null | ReactScopeMethods {
|
||||
const allScopes = scope.getChildrenFromRoot();
|
||||
if (allScopes === null) {
|
||||
return null;
|
||||
}
|
||||
const currentScopeIndex = allScopes.indexOf(scope);
|
||||
if (currentScopeIndex === -1 || currentScopeIndex === allScopes.length - 1) {
|
||||
return null;
|
||||
}
|
||||
return allScopes[currentScopeIndex + 1];
|
||||
}
|
||||
|
||||
export function getPreviousController(
|
||||
scope: ReactScopeMethods,
|
||||
): null | ReactScopeMethods {
|
||||
const allScopes = scope.getChildrenFromRoot();
|
||||
if (allScopes === null) {
|
||||
return null;
|
||||
}
|
||||
const currentScopeIndex = allScopes.indexOf(scope);
|
||||
if (currentScopeIndex <= 0) {
|
||||
return null;
|
||||
}
|
||||
return allScopes[currentScopeIndex - 1];
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import type {ReactScopeMethods} from 'shared/ReactTypes';
|
||||
import type {KeyboardEvent} from 'react-interactions/events/keyboard';
|
||||
|
||||
import React from 'react';
|
||||
import {tabFocusableImpl} from 'react-interactions/accessibility/tabbable-scope';
|
||||
import {useKeyboard} from 'react-interactions/events/keyboard';
|
||||
|
||||
type FocusCellProps = {
|
||||
@@ -128,8 +127,10 @@ function triggerNavigateOut(
|
||||
}
|
||||
}
|
||||
|
||||
export function createFocusTable(): Array<React.Component> {
|
||||
const TableScope = React.unstable_createScope(tabFocusableImpl);
|
||||
export function createFocusTable(
|
||||
scopeImpl: (type: string, props: Object) => boolean,
|
||||
): Array<React.Component> {
|
||||
const TableScope = React.unstable_createScope(scopeImpl);
|
||||
|
||||
function Table({children, onKeyboardOut, id}): FocusTableProps {
|
||||
return (
|
||||
|
||||
+15
-145
@@ -7,158 +7,26 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {ReactScopeMethods} from 'shared/ReactTypes';
|
||||
import type {ReactScope} from 'shared/ReactTypes';
|
||||
import type {KeyboardEvent} from 'react-interactions/events/keyboard';
|
||||
|
||||
import React from 'react';
|
||||
import {TabbableScope} from 'react-interactions/accessibility/tabbable-scope';
|
||||
import {useKeyboard} from 'react-interactions/events/keyboard';
|
||||
import {
|
||||
focusPrevious,
|
||||
focusNext,
|
||||
} from 'react-interactions/accessibility/focus-control';
|
||||
|
||||
type TabFocusControllerProps = {
|
||||
type TabFocusProps = {
|
||||
children: React.Node,
|
||||
contain?: boolean,
|
||||
scope: ReactScope,
|
||||
};
|
||||
|
||||
const {useRef} = React;
|
||||
|
||||
function getTabbableNodes(scope: ReactScopeMethods) {
|
||||
const tabbableNodes = scope.getScopedNodes();
|
||||
if (tabbableNodes === null || tabbableNodes.length === 0) {
|
||||
return [null, null, null, 0, null];
|
||||
}
|
||||
const firstTabbableElem = tabbableNodes[0];
|
||||
const lastTabbableElem = tabbableNodes[tabbableNodes.length - 1];
|
||||
const currentIndex = tabbableNodes.indexOf(document.activeElement);
|
||||
let focusedElement = null;
|
||||
if (currentIndex !== -1) {
|
||||
focusedElement = tabbableNodes[currentIndex];
|
||||
}
|
||||
return [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
];
|
||||
}
|
||||
|
||||
export function focusFirst(scope: ReactScopeMethods): void {
|
||||
const [, firstTabbableElem] = getTabbableNodes(scope);
|
||||
focusElem(firstTabbableElem);
|
||||
}
|
||||
|
||||
function focusElem(elem: null | HTMLElement): void {
|
||||
if (elem !== null) {
|
||||
elem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function internalFocusNext(
|
||||
scope: ReactScopeMethods,
|
||||
event?: KeyboardEvent,
|
||||
contain?: boolean,
|
||||
): void {
|
||||
const [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
] = getTabbableNodes(scope);
|
||||
|
||||
if (focusedElement === null) {
|
||||
if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else if (focusedElement === lastTabbableElem) {
|
||||
if (contain) {
|
||||
focusElem(firstTabbableElem);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
} else if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else {
|
||||
focusElem((tabbableNodes: any)[currentIndex + 1]);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function internalFocusPrevious(
|
||||
scope: ReactScopeMethods,
|
||||
event?: KeyboardEvent,
|
||||
contain?: boolean,
|
||||
): void {
|
||||
const [
|
||||
tabbableNodes,
|
||||
firstTabbableElem,
|
||||
lastTabbableElem,
|
||||
currentIndex,
|
||||
focusedElement,
|
||||
] = getTabbableNodes(scope);
|
||||
|
||||
if (focusedElement === null) {
|
||||
if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else if (focusedElement === firstTabbableElem) {
|
||||
if (contain) {
|
||||
focusElem(lastTabbableElem);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
} else if (event) {
|
||||
event.continuePropagation();
|
||||
}
|
||||
} else {
|
||||
focusElem((tabbableNodes: any)[currentIndex - 1]);
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function focusPrevious(scope: ReactScopeMethods): void {
|
||||
internalFocusPrevious(scope);
|
||||
}
|
||||
|
||||
export function focusNext(scope: ReactScopeMethods): void {
|
||||
internalFocusNext(scope);
|
||||
}
|
||||
|
||||
export function getNextController(
|
||||
scope: ReactScopeMethods,
|
||||
): null | ReactScopeMethods {
|
||||
const allScopes = scope.getChildrenFromRoot();
|
||||
if (allScopes === null) {
|
||||
return null;
|
||||
}
|
||||
const currentScopeIndex = allScopes.indexOf(scope);
|
||||
if (currentScopeIndex === -1 || currentScopeIndex === allScopes.length - 1) {
|
||||
return null;
|
||||
}
|
||||
return allScopes[currentScopeIndex + 1];
|
||||
}
|
||||
|
||||
export function getPreviousController(
|
||||
scope: ReactScopeMethods,
|
||||
): null | ReactScopeMethods {
|
||||
const allScopes = scope.getChildrenFromRoot();
|
||||
if (allScopes === null) {
|
||||
return null;
|
||||
}
|
||||
const currentScopeIndex = allScopes.indexOf(scope);
|
||||
if (currentScopeIndex <= 0) {
|
||||
return null;
|
||||
}
|
||||
return allScopes[currentScopeIndex - 1];
|
||||
}
|
||||
|
||||
export const TabFocusController = React.forwardRef(
|
||||
({children, contain}: TabFocusControllerProps, ref): React.Node => {
|
||||
const TabFocus = React.forwardRef(
|
||||
({children, contain, scope: Scope}: TabFocusProps, ref): React.Node => {
|
||||
const scopeRef = useRef(null);
|
||||
const keyboard = useKeyboard({
|
||||
onKeyDown(event: KeyboardEvent): void {
|
||||
@@ -169,16 +37,16 @@ export const TabFocusController = React.forwardRef(
|
||||
const scope = scopeRef.current;
|
||||
if (scope !== null) {
|
||||
if (event.shiftKey) {
|
||||
internalFocusPrevious(scope, event, contain);
|
||||
focusPrevious(scope, event, contain);
|
||||
} else {
|
||||
internalFocusNext(scope, event, contain);
|
||||
focusNext(scope, event, contain);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<TabbableScope
|
||||
<Scope
|
||||
ref={node => {
|
||||
if (ref) {
|
||||
if (typeof ref === 'function') {
|
||||
@@ -191,7 +59,9 @@ export const TabFocusController = React.forwardRef(
|
||||
}}
|
||||
listeners={keyboard}>
|
||||
{children}
|
||||
</TabbableScope>
|
||||
</Scope>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default TabFocus;
|
||||
|
||||
@@ -32,4 +32,6 @@ export const tabFocusableImpl = (type: string, props: Object): boolean => {
|
||||
);
|
||||
};
|
||||
|
||||
export const TabbableScope = React.unstable_createScope(tabFocusableImpl);
|
||||
const TabbableScope = React.unstable_createScope(tabFocusableImpl);
|
||||
|
||||
export default TabbableScope;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {createEventTarget} from 'react-interactions/events/src/dom/testing-libra
|
||||
let React;
|
||||
let ReactFeatureFlags;
|
||||
let createFocusTable;
|
||||
let tabFocusableImpl;
|
||||
|
||||
describe('ReactFocusTable', () => {
|
||||
beforeEach(() => {
|
||||
@@ -20,6 +21,7 @@ describe('ReactFocusTable', () => {
|
||||
ReactFeatureFlags.enableScopeAPI = true;
|
||||
ReactFeatureFlags.enableFlareAPI = true;
|
||||
createFocusTable = require('../FocusTable').createFocusTable;
|
||||
tabFocusableImpl = require('../TabbableScope').tabFocusableImpl;
|
||||
React = require('react');
|
||||
});
|
||||
|
||||
@@ -39,7 +41,9 @@ describe('ReactFocusTable', () => {
|
||||
});
|
||||
|
||||
function createFocusTableComponent() {
|
||||
const [FocusTable, FocusTableRow, FocusTableCell] = createFocusTable();
|
||||
const [FocusTable, FocusTableRow, FocusTableCell] = createFocusTable(
|
||||
tabFocusableImpl,
|
||||
);
|
||||
|
||||
return ({onKeyboardOut, id}) => (
|
||||
<FocusTable onKeyboardOut={onKeyboardOut} id={id}>
|
||||
|
||||
@@ -11,8 +11,9 @@ import {createEventTarget} from 'react-interactions/events/src/dom/testing-libra
|
||||
|
||||
let React;
|
||||
let ReactFeatureFlags;
|
||||
let TabFocusController;
|
||||
let ReactTabFocus;
|
||||
let TabFocus;
|
||||
let TabbableScope;
|
||||
let FocusControl;
|
||||
|
||||
describe('TabFocusController', () => {
|
||||
beforeEach(() => {
|
||||
@@ -20,8 +21,9 @@ describe('TabFocusController', () => {
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableScopeAPI = true;
|
||||
ReactFeatureFlags.enableFlareAPI = true;
|
||||
ReactTabFocus = require('../TabFocus');
|
||||
TabFocusController = ReactTabFocus.TabFocusController;
|
||||
TabFocus = require('../TabFocus').default;
|
||||
TabbableScope = require('../TabbableScope').default;
|
||||
FocusControl = require('../FocusControl');
|
||||
React = require('react');
|
||||
});
|
||||
|
||||
@@ -48,13 +50,13 @@ describe('TabFocusController', () => {
|
||||
const divRef = React.createRef();
|
||||
|
||||
const Test = () => (
|
||||
<TabFocusController>
|
||||
<TabFocus scope={TabbableScope}>
|
||||
<input ref={inputRef} />
|
||||
<button ref={buttonRef} />
|
||||
<div ref={divRef} tabIndex={0} />
|
||||
<input ref={input2Ref} tabIndex={-1} />
|
||||
<button ref={butto2nRef} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Test />, container);
|
||||
@@ -76,12 +78,12 @@ describe('TabFocusController', () => {
|
||||
const button2Ref = React.createRef();
|
||||
|
||||
const Test = () => (
|
||||
<TabFocusController contain={true}>
|
||||
<TabFocus scope={TabbableScope} contain={true}>
|
||||
<input ref={inputRef} tabIndex={-1} />
|
||||
<button ref={buttonRef} id={1} />
|
||||
<button ref={button2Ref} id={2} />
|
||||
<input ref={input2Ref} tabIndex={-1} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Test />, container);
|
||||
@@ -107,16 +109,16 @@ describe('TabFocusController', () => {
|
||||
const button4Ref = React.createRef();
|
||||
|
||||
const Test = () => (
|
||||
<TabFocusController>
|
||||
<TabFocus scope={TabbableScope}>
|
||||
<input ref={inputRef} tabIndex={-1} />
|
||||
<button ref={buttonRef} id={1} />
|
||||
<TabFocusController>
|
||||
<TabFocus scope={TabbableScope}>
|
||||
<button ref={button2Ref} id={2} />
|
||||
<button ref={button3Ref} id={3} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
<input ref={input2Ref} tabIndex={-1} />
|
||||
<button ref={button4Ref} id={4} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Test />, container);
|
||||
@@ -143,16 +145,16 @@ describe('TabFocusController', () => {
|
||||
const button4Ref = React.createRef();
|
||||
|
||||
const Test = () => (
|
||||
<TabFocusController>
|
||||
<TabFocus scope={TabbableScope}>
|
||||
<input ref={inputRef} tabIndex={-1} />
|
||||
<button ref={buttonRef} id={1} />
|
||||
<TabFocusController contain={true}>
|
||||
<TabFocus contain={true} scope={TabbableScope}>
|
||||
<button ref={button2Ref} id={2} />
|
||||
<button ref={button3Ref} id={3} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
<input ref={input2Ref} tabIndex={-1} />
|
||||
<button ref={button4Ref} id={4} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Test />, container);
|
||||
@@ -193,14 +195,14 @@ describe('TabFocusController', () => {
|
||||
}
|
||||
|
||||
const Test = () => (
|
||||
<TabFocusController>
|
||||
<TabFocus scope={TabbableScope}>
|
||||
<button ref={buttonRef} id={1} />
|
||||
<button ref={button2Ref} id={2} />
|
||||
<React.Suspense fallback={<button ref={button3Ref} id={3} />}>
|
||||
<Component />
|
||||
</React.Suspense>
|
||||
<button ref={button4Ref} id={4} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Test />, container);
|
||||
@@ -227,16 +229,16 @@ describe('TabFocusController', () => {
|
||||
|
||||
const Test = () => (
|
||||
<div>
|
||||
<TabFocusController ref={firstFocusControllerRef}>
|
||||
<TabFocus ref={firstFocusControllerRef} scope={TabbableScope}>
|
||||
<input tabIndex={-1} />
|
||||
<button ref={buttonRef} />
|
||||
<button ref={button2Ref} />
|
||||
<input tabIndex={-1} />
|
||||
</TabFocusController>
|
||||
<TabFocusController ref={secondFocusControllerRef}>
|
||||
</TabFocus>
|
||||
<TabFocus ref={secondFocusControllerRef} scope={TabbableScope}>
|
||||
<input tabIndex={-1} />
|
||||
<div ref={divRef} tabIndex={0} />
|
||||
</TabFocusController>
|
||||
</TabFocus>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -244,25 +246,25 @@ describe('TabFocusController', () => {
|
||||
const firstFocusController = firstFocusControllerRef.current;
|
||||
const secondFocusController = secondFocusControllerRef.current;
|
||||
|
||||
ReactTabFocus.focusFirst(firstFocusController);
|
||||
FocusControl.focusFirst(firstFocusController);
|
||||
expect(document.activeElement).toBe(buttonRef.current);
|
||||
ReactTabFocus.focusNext(firstFocusController);
|
||||
FocusControl.focusNext(firstFocusController);
|
||||
expect(document.activeElement).toBe(button2Ref.current);
|
||||
ReactTabFocus.focusPrevious(firstFocusController);
|
||||
FocusControl.focusPrevious(firstFocusController);
|
||||
expect(document.activeElement).toBe(buttonRef.current);
|
||||
|
||||
const nextController = ReactTabFocus.getNextController(
|
||||
const nextController = FocusControl.getNextController(
|
||||
firstFocusController,
|
||||
);
|
||||
expect(nextController).toBe(secondFocusController);
|
||||
ReactTabFocus.focusFirst(nextController);
|
||||
FocusControl.focusFirst(nextController);
|
||||
expect(document.activeElement).toBe(divRef.current);
|
||||
|
||||
const previousController = ReactTabFocus.getPreviousController(
|
||||
const previousController = FocusControl.getPreviousController(
|
||||
nextController,
|
||||
);
|
||||
expect(previousController).toBe(firstFocusController);
|
||||
ReactTabFocus.focusFirst(previousController);
|
||||
FocusControl.focusFirst(previousController);
|
||||
expect(document.activeElement).toBe(buttonRef.current);
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ describe('TabbableScope', () => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableScopeAPI = true;
|
||||
TabbableScope = require('../TabbableScope').TabbableScope;
|
||||
TabbableScope = require('../TabbableScope').default;
|
||||
React = require('react');
|
||||
});
|
||||
|
||||
|
||||
@@ -687,9 +687,18 @@ const bundles = [
|
||||
'react',
|
||||
'react-interactions/events/keyboard',
|
||||
'react-interactions/accessibility/tabbable-scope',
|
||||
'react-interactions/accessibility/focus-control',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
|
||||
moduleType: NON_FIBER_RENDERER,
|
||||
entry: 'react-interactions/accessibility/focus-control',
|
||||
global: 'ReactFocusControl',
|
||||
externals: ['react'],
|
||||
},
|
||||
|
||||
{
|
||||
bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
|
||||
moduleType: NON_FIBER_RENDERER,
|
||||
@@ -703,6 +712,7 @@ const fbBundleExternalsMap = {
|
||||
'react-interactions/events/keyboard': 'ReactEventsKeyboard',
|
||||
'react-interactions/events/tap': 'ReactEventsTap',
|
||||
'react-interactions/accessibility/tabbable-scope': 'ReactTabbableScope',
|
||||
'react-interactions/accessibility/focus-control': 'ReactFocusControl',
|
||||
};
|
||||
|
||||
// Based on deep-freeze by substack (public domain)
|
||||
|
||||
Reference in New Issue
Block a user