@workday/canvas-kit-react
Version:
The parent module that contains all Workday Canvas Kit React components
70 lines (69 loc) • 3.4 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useListItemRovingFocus = void 0;
const react_1 = __importDefault(require("react"));
const common_1 = require("@workday/canvas-kit-react/common");
const useCursorListModel_1 = require("./useCursorListModel");
const keyUtils_1 = require("./keyUtils");
const focusOnCurrentCursor_1 = require("./focusOnCurrentCursor");
/**
* This elemProps hook is used for cursor navigation by using [Roving
* Tabindex](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex). Only a single item in the
* collection has a tab stop. Pressing an arrow key moves the tab stop to a different item in the
* corresponding direction. See the [Roving Tabindex](#roving-tabindex) example. This elemProps hook
* should be applied to an `*.Item` component.
*
* ```ts
* const useMyItem = composeHooks(
* useListItemRovingFocus, // adds the roving tabindex support
* useListItemRegister
* );
```
*/
exports.useListItemRovingFocus = (0, common_1.createElemPropsHook)(useCursorListModel_1.useCursorListModel)((model, _ref, elemProps = {}) => {
// Create a ref out of state. We don't want to watch state on unmount, so we use a ref to get the
// current value at the time of unmounting. Otherwise, `state.items` would be a cached value of an
// empty array
const stateRef = react_1.default.useRef(model.state);
stateRef.current = model.state;
const keyElementRef = react_1.default.useRef(null);
const isRTL = (0, common_1.useIsRTL)();
react_1.default.useEffect(() => {
// If the cursor change was triggered by this hook, we should change focus
if (keyElementRef.current) {
(0, focusOnCurrentCursor_1.focusOnCurrentCursor)(model, model.state.cursorId, keyElementRef.current).then(() => {
// Reset key element since focus was successful
keyElementRef.current = null;
});
}
// we only want to run this effect if the cursor changes and not any other time
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [model.state.cursorId]);
// Roving focus must always have a focus stop to function correctly
react_1.default.useEffect(() => {
if (!model.state.cursorId && model.state.items.length) {
model.events.goTo({ id: model.state.items[0].id });
}
}, [model.state.cursorId, model.state.items, model.events]);
return {
onKeyDown(event) {
const handled = (0, keyUtils_1.keyboardEventToCursorEvents)(event, model, isRTL);
if (handled) {
event.preventDefault();
keyElementRef.current = event.currentTarget;
}
},
onClick() {
model.events.goTo({ id: elemProps['data-id'] });
},
'data-focus-id': `${model.state.id}-${elemProps['data-id']}`,
tabIndex: !model.state.cursorId
? 0 // cursor isn't known yet, be safe and mark this as focusable
: !!elemProps['data-id'] && model.state.cursorId === elemProps['data-id']
? 0 // A name is known and cursor is here
: -1, // A name is known an cursor is somewhere else
};
});
;