Tidy up Roving Tab Index helpers and create one for RovingAccessibleTooltipButton

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-07-15 04:22:19 +01:00
parent 1b08c1e9df
commit 933945130e
5 changed files with 132 additions and 31 deletions

View file

@ -23,12 +23,11 @@ import React, {
useRef,
useReducer,
Reducer,
RefObject,
Dispatch,
} from "react";
import {Key} from "../Keyboard";
import AccessibleButton from "../components/views/elements/AccessibleButton";
import {FocusHandler, Ref} from "./roving/types";
/**
* Module to simplify implementing the Roving TabIndex accessibility technique
@ -45,8 +44,6 @@ import AccessibleButton from "../components/views/elements/AccessibleButton";
const DOCUMENT_POSITION_PRECEDING = 2;
type Ref = RefObject<HTMLElement>;
export interface IState {
activeRef: Ref;
refs: Ref[];
@ -202,8 +199,6 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({children, handleHomeEn
</RovingTabIndexContext.Provider>;
};
type FocusHandler = () => void;
// Hook to register a roving tab index
// inputRef parameter specifies the ref to use
// onFocus should be called when the index gained focus in any manner
@ -244,28 +239,7 @@ export const useRovingTabIndex = (inputRef: Ref): [FocusHandler, boolean, Ref] =
return [onFocus, isActive, ref];
};
interface IRovingTabIndexWrapperProps {
inputRef?: Ref;
children(renderProps: {
onFocus: FocusHandler;
isActive: boolean;
ref: Ref;
});
}
// Wrapper to allow use of useRovingTabIndex outside of React Functional Components.
export const RovingTabIndexWrapper: React.FC<IRovingTabIndexWrapperProps> = ({children, inputRef}) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
return children({onFocus, isActive, ref});
};
interface IRovingAccessibleButtonProps extends Omit<React.ComponentProps<typeof AccessibleButton>, "onFocus" | "inputRef" | "tabIndex"> {
inputRef?: Ref;
}
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
export const RovingAccessibleButton: React.FC<IRovingAccessibleButtonProps> = ({inputRef, ...props}) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
return <AccessibleButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
};
// re-export the semantic helper components for simplicity
export {RovingTabIndexWrapper} from "./roving/RovingTabIndexWrapper";
export {RovingAccessibleButton} from "./roving/RovingAccessibleButton";
export {RovingAccessibleTooltipButton} from "./roving/RovingAccessibleTooltipButton";

View file

@ -0,0 +1,34 @@
/*
*
* Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
import React from "react";
import AccessibleButton from "../../components/views/elements/AccessibleButton";
import {useRovingTabIndex} from "../RovingTabIndex";
import {Ref} from "./types";
interface IProps extends Omit<React.ComponentProps<typeof AccessibleButton>, "onFocus" | "inputRef" | "tabIndex"> {
inputRef?: Ref;
}
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
export const RovingAccessibleButton: React.FC<IProps> = ({inputRef, ...props}) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
return <AccessibleButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
};

View file

@ -0,0 +1,34 @@
/*
*
* Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
import React from "react";
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
import {useRovingTabIndex} from "../RovingTabIndex";
import {Ref} from "./types";
interface IProps extends Omit<React.ComponentProps<typeof AccessibleTooltipButton>, "onFocus" | "inputRef" | "tabIndex"> {
inputRef?: Ref;
}
// Wrapper to allow use of useRovingTabIndex for simple AccessibleTooltipButtons outside of React Functional Components.
export const RovingAccessibleTooltipButton: React.FC<IProps> = ({inputRef, ...props}) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
return <AccessibleTooltipButton {...props} onFocus={onFocus} inputRef={ref} tabIndex={isActive ? 0 : -1} />;
};

View file

@ -0,0 +1,38 @@
/*
*
* Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
import React from "react";
import AccessibleButton from "../../components/views/elements/AccessibleButton";
import {useRovingTabIndex} from "../RovingTabIndex";
import {FocusHandler, Ref} from "./types";
interface IProps {
inputRef?: Ref;
children(renderProps: {
onFocus: FocusHandler;
isActive: boolean;
ref: Ref;
});
}
// Wrapper to allow use of useRovingTabIndex outside of React Functional Components.
export const RovingTabIndexWrapper: React.FC<IProps> = ({children, inputRef}) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
return children({onFocus, isActive, ref});
};

View file

@ -0,0 +1,21 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {RefObject} from "react";
export type Ref = RefObject<HTMLElement>;
export type FocusHandler = () => void;