New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-roving-tabindex

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-roving-tabindex - npm Package Compare versions

Comparing version 2.0.0-alpha.1 to 2.0.0-alpha.2

233

dist/index.es.js

@@ -1,2 +0,2 @@

import React, { useRef, useContext, useEffect, useCallback, useLayoutEffect } from 'react';
import React, { createContext, useReducer, useEffect, useMemo, useRef, useContext, useCallback, useLayoutEffect } from 'react';
import warning from 'warning';

@@ -30,10 +30,2 @@

function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
var EventKey;

@@ -99,24 +91,28 @@ (function (EventKey) {

// the desired behaviour for the page.
//
// Note: The rowStartMap is only created if row-related
// navigation occurs (e.g., move to row start or end), so
// non-grid usage of this library does not pay the price
// (minimal as it is) of constructing this map. The map
// gets cleared if registering, unregistering, or updating.
function reducer(state, action) {
switch (action.type) {
case ActionType.REGISTER_TAB_STOP: {
var newTabStop_1 = action.payload;
if (!newTabStop_1.domElementRef.current) {
var newTabStop = action.payload;
if (!newTabStop.domElementRef.current) {
return state;
}
var index = state.tabStops.findIndex(function (tabStop) { return tabStop.id === newTabStop_1.id; });
if (index !== -1) {
warning(false, "'" + newTabStop_1.id + "' tab stop already registered");
return state;
var indexToInsertAt = -1;
for (var i = 0; i < state.tabStops.length; ++i) {
var loopTabStop = state.tabStops[i];
if (loopTabStop.id === newTabStop.id) {
warning(false, "'" + newTabStop.id + "' tab stop already registered");
return state;
}
if (indexToInsertAt === -1 &&
loopTabStop.domElementRef.current &&
!!(loopTabStop.domElementRef.current.compareDocumentPosition(newTabStop.domElementRef.current) & DOCUMENT_POSITION_PRECEDING)) {
indexToInsertAt = i;
}
}
var indexToInsertAt = state.tabStops.findIndex(function (tabStop) {
// This mess is for TypeScript:
if (!tabStop.domElementRef.current ||
!newTabStop_1.domElementRef.current) {
return -1;
}
// Returns true if newTabStop's element is located earlier
// in the DOM than tabStop's element, else returns false:
return !!(tabStop.domElementRef.current.compareDocumentPosition(newTabStop_1.domElementRef.current) & DOCUMENT_POSITION_PRECEDING);
});
// Array.findIndex returns -1 when newTabStop should be inserted

@@ -128,6 +124,5 @@ // at the end of tabStops (the compareDocumentPosition test

}
var newTabStops = __spreadArrays(state.tabStops.slice(0, indexToInsertAt), [
newTabStop_1
], state.tabStops.slice(indexToInsertAt));
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
var newTabStops = state.tabStops.slice();
newTabStops.splice(indexToInsertAt, 0, newTabStop);
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -141,3 +136,3 @@ case ActionType.UNREGISTER_TAB_STOP: {

}
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -156,6 +151,6 @@ case ActionType.TAB_STOP_UPDATED: {

}
var newTabStop = __assign(__assign({}, tabStop), { rowIndex: rowIndex, disabled: disabled });
var newTabStops = state.tabStops.slice();
var newTabStop = __assign(__assign({}, tabStop), { rowIndex: rowIndex, disabled: disabled });
newTabStops.splice(index, 1, newTabStop);
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -187,3 +182,3 @@ case ActionType.KEY_DOWN: {

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -201,3 +196,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -212,3 +207,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -223,3 +218,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -235,44 +230,46 @@ }

}
var rowStartIndexes_1 = {};
state.tabStops.forEach(function (_a, index) {
var rowIndex = _a.rowIndex;
if (rowIndex !== null &&
rowStartIndexes_1[rowIndex] === undefined) {
rowStartIndexes_1[rowIndex] = index;
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
var columnOffset = index - rowStartIndex;
for (var i = currentTabStop.rowIndex - 1; i >= 0; --i) {
var rowStartIndex_1 = rowStartMap.get(i);
if (rowStartIndex_1 === undefined) {
return state;
}
});
var columnOffset = index - rowStartIndexes_1[currentTabStop.rowIndex];
for (var i = currentTabStop.rowIndex - 1; i >= 0; --i) {
var rowTabStop = state.tabStops[rowStartIndexes_1[i] + columnOffset];
var rowTabStop = state.tabStops[rowStartIndex_1 + columnOffset];
if (!rowTabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: rowTabStop.id });
return selectTabStop(state, rowTabStop, rowStartMap);
}
}
return __assign(__assign({}, state), { allowFocusing: true, rowStartMap: rowStartMap });
}
break;
case Navigation.NEXT_ROW:
{
var maxRowIndex = state.tabStops[state.tabStops.length - 1].rowIndex;
if (currentTabStop.rowIndex === null ||
currentTabStop.rowIndex ===
state.tabStops[state.tabStops.length - 1].rowIndex) {
maxRowIndex === null ||
currentTabStop.rowIndex === maxRowIndex) {
return state;
}
var rowStartIndexes_2 = {};
state.tabStops.forEach(function (_a, index) {
var rowIndex = _a.rowIndex;
if (rowIndex !== null &&
rowStartIndexes_2[rowIndex] === undefined) {
rowStartIndexes_2[rowIndex] = index;
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
var columnOffset = index - rowStartIndex;
for (var i = currentTabStop.rowIndex + 1; i <= maxRowIndex; ++i) {
var rowStartIndex_2 = rowStartMap.get(i);
if (rowStartIndex_2 === undefined) {
return state;
}
});
var columnOffset = index - rowStartIndexes_2[currentTabStop.rowIndex];
var maxRowIndex = state.tabStops[state.tabStops.length - 1].rowIndex || 0;
for (var i = currentTabStop.rowIndex + 1; i <= maxRowIndex; ++i) {
var rowTabStop = state.tabStops[rowStartIndexes_2[i] + columnOffset];
var rowTabStop = state.tabStops[rowStartIndex_2 + columnOffset];
if (!rowTabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: rowTabStop.id });
return selectTabStop(state, rowTabStop, rowStartMap);
}
}
return __assign(__assign({}, state), { allowFocusing: true, rowStartMap: rowStartMap });
}
break;
case Navigation.FIRST_IN_ROW:

@@ -283,4 +280,8 @@ {

}
var newIndex = null;
for (var i = index - 1; i >= 0; --i) {
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
for (var i = rowStartIndex; i < state.tabStops.length; ++i) {
var tabStop = state.tabStops[i];

@@ -291,8 +292,5 @@ if (tabStop.rowIndex !== currentTabStop.rowIndex) {

else if (!tabStop.disabled) {
newIndex = i;
return selectTabStop(state, state.tabStops[i], rowStartMap);
}
}
if (newIndex !== null) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: state.tabStops[newIndex].id });
}
}

@@ -305,4 +303,7 @@ break;

}
var newIndex = null;
for (var i = index + 1; i < state.tabStops.length; ++i) {
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowEndIndex = rowStartMap.has(currentTabStop.rowIndex + 1)
? (rowStartMap.get(currentTabStop.rowIndex + 1) || 0) - 1
: state.tabStops.length - 1;
for (var i = rowEndIndex; i >= 0; --i) {
var tabStop = state.tabStops[i];

@@ -313,8 +314,5 @@ if (tabStop.rowIndex !== currentTabStop.rowIndex) {

else if (!tabStop.disabled) {
newIndex = i;
return selectTabStop(state, state.tabStops[i], rowStartMap);
}
}
if (newIndex !== null) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: state.tabStops[newIndex].id });
}
}

@@ -335,3 +333,3 @@ break;

? state
: __assign(__assign({}, state), { allowFocusing: true, selectedId: id_4 });
: selectTabStop(state, currentTabStop);
}

@@ -360,3 +358,3 @@ case ActionType.KEY_CONFIG_UPDATED: {

}
// Find the first tab stop that is not disabled and return
// Finds the first tab stop that is not disabled and return
// its id, otherwise return null.

@@ -366,3 +364,3 @@ index = tabStops.findIndex(function (tabStop) { return !tabStop.disabled; });

}
// Translate the user key down event info into a navigation instruction.
// Translates the user key down event info into a navigation instruction.
function getNavigationValue(key, ctrlKey, keyConfig) {

@@ -386,9 +384,27 @@ var translatedKey = null;

}
var RovingTabIndexContext = React.createContext({
state: {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: DEFAULT_KEY_CONFIG
},
// Creates the new state for a tab stop when it becomes the selected one.
function selectTabStop(state, tabStop, rowStartMap) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id, rowStartMap: rowStartMap || state.rowStartMap });
}
// Creates the row start index lookup map
// for the currently registered tab stops.
function createRowStartMap(state) {
var map = new Map();
for (var i = 0; i < state.tabStops.length; ++i) {
var rowIndex = state.tabStops[i].rowIndex;
if (rowIndex !== null && !map.has(rowIndex)) {
map.set(rowIndex, i);
}
}
return map;
}
var INITIAL_STATE = {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: DEFAULT_KEY_CONFIG,
rowStartMap: null
};
var RovingTabIndexContext = createContext({
state: INITIAL_STATE,
// eslint-disable-next-line @typescript-eslint/no-empty-function

@@ -399,3 +415,3 @@ dispatch: function () { }

* Creates a roving tabindex context.
* @param {React.ReactNode} children The child content, which will
* @param {ReactNode} children The child content, which will
* include the DOM elements to rove between using the tab key.

@@ -412,14 +428,9 @@ * @param {keyConfig} keyConfig An optional key navigation configuration

var children = _a.children, _b = _a.keyConfig, keyConfig = _b === void 0 ? DEFAULT_KEY_CONFIG : _b;
var _c = React.useReducer(reducer, {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: keyConfig
}), state = _c[0], dispatch = _c[1];
// Update the keyConfig whenever it is changed:
React.useEffect(function () {
var _c = useReducer(reducer, __assign(__assign({}, INITIAL_STATE), { keyConfig: keyConfig })), state = _c[0], dispatch = _c[1];
// Update the keyConfig whenever it changes:
useEffect(function () {
dispatch({ type: ActionType.KEY_CONFIG_UPDATED, payload: { keyConfig: keyConfig } });
}, [keyConfig]);
// Create a cached object to use as the context value:
var context = React.useMemo(function () { return ({ state: state, dispatch: dispatch }); }, [state]);
var context = useMemo(function () { return ({ state: state, dispatch: dispatch }); }, [state]);
return (React.createElement(RovingTabIndexContext.Provider, { value: context }, children));

@@ -466,2 +477,3 @@ };

}
var isMounted = useRef(false);
var context = useContext(RovingTabIndexContext);

@@ -487,17 +499,20 @@ // Register the tab stop on mount and unregister it on unmount:

}, []);
// Update the tab stop data if rowIndex or disabled change:
// Note: A TAB_STOP_UPDATED event is dispatched directly
// after the REGISTER_TAB_STOP event on mount. This is okay
// because the values of rowIndex and disabled will not
// have changed, and in that case the reducer treats
// the TAB_STOP_UPDATED event as a no-op.
// Update the tab stop data if rowIndex or disabled change.
// The isMounted flag is used to prevent this effect running
// on mount, which would be benign but is redundant as the
// REGISTER_TAB_STOP action would have just been dispatched.
useEffect(function () {
context.dispatch({
type: ActionType.TAB_STOP_UPDATED,
payload: {
id: getId(),
rowIndex: getRowIndexFromOptions(options),
disabled: disabled
}
});
if (isMounted.current) {
context.dispatch({
type: ActionType.TAB_STOP_UPDATED,
payload: {
id: getId(),
rowIndex: getRowIndexFromOptions(options),
disabled: disabled
}
});
}
else {
isMounted.current = true;
}
}, [options === null || options === void 0 ? void 0 : options.rowIndex, disabled]);

@@ -504,0 +519,0 @@ // Create a stable callback function for handling key down events:

@@ -39,10 +39,2 @@ 'use strict';

function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
(function (EventKey) {

@@ -104,24 +96,28 @@ EventKey["ArrowLeft"] = "ArrowLeft";

// the desired behaviour for the page.
//
// Note: The rowStartMap is only created if row-related
// navigation occurs (e.g., move to row start or end), so
// non-grid usage of this library does not pay the price
// (minimal as it is) of constructing this map. The map
// gets cleared if registering, unregistering, or updating.
function reducer(state, action) {
switch (action.type) {
case exports.ActionType.REGISTER_TAB_STOP: {
var newTabStop_1 = action.payload;
if (!newTabStop_1.domElementRef.current) {
var newTabStop = action.payload;
if (!newTabStop.domElementRef.current) {
return state;
}
var index = state.tabStops.findIndex(function (tabStop) { return tabStop.id === newTabStop_1.id; });
if (index !== -1) {
warning__default['default'](false, "'" + newTabStop_1.id + "' tab stop already registered");
return state;
var indexToInsertAt = -1;
for (var i = 0; i < state.tabStops.length; ++i) {
var loopTabStop = state.tabStops[i];
if (loopTabStop.id === newTabStop.id) {
warning__default['default'](false, "'" + newTabStop.id + "' tab stop already registered");
return state;
}
if (indexToInsertAt === -1 &&
loopTabStop.domElementRef.current &&
!!(loopTabStop.domElementRef.current.compareDocumentPosition(newTabStop.domElementRef.current) & DOCUMENT_POSITION_PRECEDING)) {
indexToInsertAt = i;
}
}
var indexToInsertAt = state.tabStops.findIndex(function (tabStop) {
// This mess is for TypeScript:
if (!tabStop.domElementRef.current ||
!newTabStop_1.domElementRef.current) {
return -1;
}
// Returns true if newTabStop's element is located earlier
// in the DOM than tabStop's element, else returns false:
return !!(tabStop.domElementRef.current.compareDocumentPosition(newTabStop_1.domElementRef.current) & DOCUMENT_POSITION_PRECEDING);
});
// Array.findIndex returns -1 when newTabStop should be inserted

@@ -133,6 +129,5 @@ // at the end of tabStops (the compareDocumentPosition test

}
var newTabStops = __spreadArrays(state.tabStops.slice(0, indexToInsertAt), [
newTabStop_1
], state.tabStops.slice(indexToInsertAt));
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
var newTabStops = state.tabStops.slice();
newTabStops.splice(indexToInsertAt, 0, newTabStop);
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -146,3 +141,3 @@ case exports.ActionType.UNREGISTER_TAB_STOP: {

}
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -161,6 +156,6 @@ case exports.ActionType.TAB_STOP_UPDATED: {

}
var newTabStop = __assign(__assign({}, tabStop), { rowIndex: rowIndex, disabled: disabled });
var newTabStops = state.tabStops.slice();
var newTabStop = __assign(__assign({}, tabStop), { rowIndex: rowIndex, disabled: disabled });
newTabStops.splice(index, 1, newTabStop);
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops });
return __assign(__assign({}, state), { selectedId: getUpdatedSelectedId(newTabStops, state.selectedId), tabStops: newTabStops, rowStartMap: null });
}

@@ -192,3 +187,3 @@ case exports.ActionType.KEY_DOWN: {

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -206,3 +201,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -217,3 +212,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -228,3 +223,3 @@ }

if (!tabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id });
return selectTabStop(state, tabStop);
}

@@ -240,44 +235,46 @@ }

}
var rowStartIndexes_1 = {};
state.tabStops.forEach(function (_a, index) {
var rowIndex = _a.rowIndex;
if (rowIndex !== null &&
rowStartIndexes_1[rowIndex] === undefined) {
rowStartIndexes_1[rowIndex] = index;
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
var columnOffset = index - rowStartIndex;
for (var i = currentTabStop.rowIndex - 1; i >= 0; --i) {
var rowStartIndex_1 = rowStartMap.get(i);
if (rowStartIndex_1 === undefined) {
return state;
}
});
var columnOffset = index - rowStartIndexes_1[currentTabStop.rowIndex];
for (var i = currentTabStop.rowIndex - 1; i >= 0; --i) {
var rowTabStop = state.tabStops[rowStartIndexes_1[i] + columnOffset];
var rowTabStop = state.tabStops[rowStartIndex_1 + columnOffset];
if (!rowTabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: rowTabStop.id });
return selectTabStop(state, rowTabStop, rowStartMap);
}
}
return __assign(__assign({}, state), { allowFocusing: true, rowStartMap: rowStartMap });
}
break;
case exports.Navigation.NEXT_ROW:
{
var maxRowIndex = state.tabStops[state.tabStops.length - 1].rowIndex;
if (currentTabStop.rowIndex === null ||
currentTabStop.rowIndex ===
state.tabStops[state.tabStops.length - 1].rowIndex) {
maxRowIndex === null ||
currentTabStop.rowIndex === maxRowIndex) {
return state;
}
var rowStartIndexes_2 = {};
state.tabStops.forEach(function (_a, index) {
var rowIndex = _a.rowIndex;
if (rowIndex !== null &&
rowStartIndexes_2[rowIndex] === undefined) {
rowStartIndexes_2[rowIndex] = index;
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
var columnOffset = index - rowStartIndex;
for (var i = currentTabStop.rowIndex + 1; i <= maxRowIndex; ++i) {
var rowStartIndex_2 = rowStartMap.get(i);
if (rowStartIndex_2 === undefined) {
return state;
}
});
var columnOffset = index - rowStartIndexes_2[currentTabStop.rowIndex];
var maxRowIndex = state.tabStops[state.tabStops.length - 1].rowIndex || 0;
for (var i = currentTabStop.rowIndex + 1; i <= maxRowIndex; ++i) {
var rowTabStop = state.tabStops[rowStartIndexes_2[i] + columnOffset];
var rowTabStop = state.tabStops[rowStartIndex_2 + columnOffset];
if (!rowTabStop.disabled) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: rowTabStop.id });
return selectTabStop(state, rowTabStop, rowStartMap);
}
}
return __assign(__assign({}, state), { allowFocusing: true, rowStartMap: rowStartMap });
}
break;
case exports.Navigation.FIRST_IN_ROW:

@@ -288,4 +285,8 @@ {

}
var newIndex = null;
for (var i = index - 1; i >= 0; --i) {
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowStartIndex = rowStartMap.get(currentTabStop.rowIndex);
if (rowStartIndex === undefined) {
return state;
}
for (var i = rowStartIndex; i < state.tabStops.length; ++i) {
var tabStop = state.tabStops[i];

@@ -296,8 +297,5 @@ if (tabStop.rowIndex !== currentTabStop.rowIndex) {

else if (!tabStop.disabled) {
newIndex = i;
return selectTabStop(state, state.tabStops[i], rowStartMap);
}
}
if (newIndex !== null) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: state.tabStops[newIndex].id });
}
}

@@ -310,4 +308,7 @@ break;

}
var newIndex = null;
for (var i = index + 1; i < state.tabStops.length; ++i) {
var rowStartMap = state.rowStartMap || createRowStartMap(state);
var rowEndIndex = rowStartMap.has(currentTabStop.rowIndex + 1)
? (rowStartMap.get(currentTabStop.rowIndex + 1) || 0) - 1
: state.tabStops.length - 1;
for (var i = rowEndIndex; i >= 0; --i) {
var tabStop = state.tabStops[i];

@@ -318,8 +319,5 @@ if (tabStop.rowIndex !== currentTabStop.rowIndex) {

else if (!tabStop.disabled) {
newIndex = i;
return selectTabStop(state, state.tabStops[i], rowStartMap);
}
}
if (newIndex !== null) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: state.tabStops[newIndex].id });
}
}

@@ -340,3 +338,3 @@ break;

? state
: __assign(__assign({}, state), { allowFocusing: true, selectedId: id_4 });
: selectTabStop(state, currentTabStop);
}

@@ -365,3 +363,3 @@ case exports.ActionType.KEY_CONFIG_UPDATED: {

}
// Find the first tab stop that is not disabled and return
// Finds the first tab stop that is not disabled and return
// its id, otherwise return null.

@@ -371,3 +369,3 @@ index = tabStops.findIndex(function (tabStop) { return !tabStop.disabled; });

}
// Translate the user key down event info into a navigation instruction.
// Translates the user key down event info into a navigation instruction.
function getNavigationValue(key, ctrlKey, keyConfig) {

@@ -391,9 +389,27 @@ var translatedKey = null;

}
var RovingTabIndexContext = React__default['default'].createContext({
state: {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: DEFAULT_KEY_CONFIG
},
// Creates the new state for a tab stop when it becomes the selected one.
function selectTabStop(state, tabStop, rowStartMap) {
return __assign(__assign({}, state), { allowFocusing: true, selectedId: tabStop.id, rowStartMap: rowStartMap || state.rowStartMap });
}
// Creates the row start index lookup map
// for the currently registered tab stops.
function createRowStartMap(state) {
var map = new Map();
for (var i = 0; i < state.tabStops.length; ++i) {
var rowIndex = state.tabStops[i].rowIndex;
if (rowIndex !== null && !map.has(rowIndex)) {
map.set(rowIndex, i);
}
}
return map;
}
var INITIAL_STATE = {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: DEFAULT_KEY_CONFIG,
rowStartMap: null
};
var RovingTabIndexContext = React.createContext({
state: INITIAL_STATE,
// eslint-disable-next-line @typescript-eslint/no-empty-function

@@ -404,3 +420,3 @@ dispatch: function () { }

* Creates a roving tabindex context.
* @param {React.ReactNode} children The child content, which will
* @param {ReactNode} children The child content, which will
* include the DOM elements to rove between using the tab key.

@@ -417,14 +433,9 @@ * @param {keyConfig} keyConfig An optional key navigation configuration

var children = _a.children, _b = _a.keyConfig, keyConfig = _b === void 0 ? DEFAULT_KEY_CONFIG : _b;
var _c = React__default['default'].useReducer(reducer, {
selectedId: null,
allowFocusing: false,
tabStops: [],
keyConfig: keyConfig
}), state = _c[0], dispatch = _c[1];
// Update the keyConfig whenever it is changed:
React__default['default'].useEffect(function () {
var _c = React.useReducer(reducer, __assign(__assign({}, INITIAL_STATE), { keyConfig: keyConfig })), state = _c[0], dispatch = _c[1];
// Update the keyConfig whenever it changes:
React.useEffect(function () {
dispatch({ type: exports.ActionType.KEY_CONFIG_UPDATED, payload: { keyConfig: keyConfig } });
}, [keyConfig]);
// Create a cached object to use as the context value:
var context = React__default['default'].useMemo(function () { return ({ state: state, dispatch: dispatch }); }, [state]);
var context = React.useMemo(function () { return ({ state: state, dispatch: dispatch }); }, [state]);
return (React__default['default'].createElement(RovingTabIndexContext.Provider, { value: context }, children));

@@ -471,2 +482,3 @@ };

}
var isMounted = React.useRef(false);
var context = React.useContext(RovingTabIndexContext);

@@ -492,17 +504,20 @@ // Register the tab stop on mount and unregister it on unmount:

}, []);
// Update the tab stop data if rowIndex or disabled change:
// Note: A TAB_STOP_UPDATED event is dispatched directly
// after the REGISTER_TAB_STOP event on mount. This is okay
// because the values of rowIndex and disabled will not
// have changed, and in that case the reducer treats
// the TAB_STOP_UPDATED event as a no-op.
// Update the tab stop data if rowIndex or disabled change.
// The isMounted flag is used to prevent this effect running
// on mount, which would be benign but is redundant as the
// REGISTER_TAB_STOP action would have just been dispatched.
React.useEffect(function () {
context.dispatch({
type: exports.ActionType.TAB_STOP_UPDATED,
payload: {
id: getId(),
rowIndex: getRowIndexFromOptions(options),
disabled: disabled
}
});
if (isMounted.current) {
context.dispatch({
type: exports.ActionType.TAB_STOP_UPDATED,
payload: {
id: getId(),
rowIndex: getRowIndexFromOptions(options),
disabled: disabled
}
});
}
else {
isMounted.current = true;
}
}, [options === null || options === void 0 ? void 0 : options.rowIndex, disabled]);

@@ -509,0 +524,0 @@ // Create a stable callback function for handling key down events:

@@ -1,3 +0,3 @@

import React from "react";
import { Action, KeyConfig, State } from "./types";
import React, { ReactElement, ReactNode } from "react";
import { Action, KeyConfig, RowStartMap, State } from "./types";
export declare const DEFAULT_KEY_CONFIG: KeyConfig;

@@ -16,2 +16,3 @@ export declare function reducer(state: State, action: Action): State;

keyConfig: KeyConfig;
rowStartMap: RowStartMap | null;
}>;

@@ -22,3 +23,3 @@ dispatch: React.Dispatch<Action>;

* Creates a roving tabindex context.
* @param {React.ReactNode} children The child content, which will
* @param {ReactNode} children The child content, which will
* include the DOM elements to rove between using the tab key.

@@ -34,4 +35,4 @@ * @param {keyConfig} keyConfig An optional key navigation configuration

export declare const Provider: ({ children, keyConfig }: {
children: React.ReactNode;
children: ReactNode;
keyConfig?: KeyConfig | undefined;
}) => React.ReactElement;
}) => ReactElement;

@@ -31,10 +31,10 @@ /// <reference types="react" />

export declare type KeyConfig = {
[Key.ARROW_LEFT]?: Navigation.PREVIOUS;
[Key.ARROW_RIGHT]?: Navigation.NEXT;
[Key.ARROW_UP]?: Navigation.PREVIOUS | Navigation.PREVIOUS_ROW;
[Key.ARROW_DOWN]?: Navigation.NEXT | Navigation.NEXT_ROW;
[Key.HOME]?: Navigation.FIRST | Navigation.FIRST_IN_ROW;
[Key.END]?: Navigation.LAST | Navigation.LAST_IN_ROW;
[Key.HOME_WITH_CTRL]?: Navigation.FIRST;
[Key.END_WITH_CTRL]?: Navigation.LAST;
[Key.ARROW_LEFT]?: Navigation.PREVIOUS | null;
[Key.ARROW_RIGHT]?: Navigation.NEXT | null;
[Key.ARROW_UP]?: Navigation.PREVIOUS | Navigation.PREVIOUS_ROW | null;
[Key.ARROW_DOWN]?: Navigation.NEXT | Navigation.NEXT_ROW | null;
[Key.HOME]?: Navigation.FIRST | Navigation.FIRST_IN_ROW | null;
[Key.END]?: Navigation.LAST | Navigation.LAST_IN_ROW | null;
[Key.HOME_WITH_CTRL]?: Navigation.FIRST | null;
[Key.END_WITH_CTRL]?: Navigation.LAST | null;
};

@@ -47,2 +47,3 @@ export declare type TabStop = Readonly<{

}>;
export declare type RowStartMap = Map<Exclude<TabStop["rowIndex"], null>, number>;
export declare type State = Readonly<{

@@ -53,2 +54,3 @@ selectedId: string | null;

keyConfig: KeyConfig;
rowStartMap: RowStartMap | null;
}>;

@@ -107,4 +109,4 @@ export declare enum ActionType {

boolean,
(event: React.KeyboardEvent<Element>) => void,
(event: React.KeyboardEvent) => void,
() => void
];
{
"name": "react-roving-tabindex",
"version": "2.0.0-alpha.1",
"description": "React implementation of a roving tabindex",
"version": "2.0.0-alpha.2",
"description": "React implementation of a roving tabindex, now with grid support",
"author": "stevejay",

@@ -68,4 +68,5 @@ "license": "MIT",

"@testing-library/react": "^11.1.0",
"@testing-library/react-hooks": "^3.4.2",
"@types/array-find-index": "^1.0.0",
"@types/jest": "^26.0.14",
"@types/jest": "^26.0.15",
"@types/jsdom": "^16.2.4",

@@ -81,2 +82,3 @@ "@types/lodash.uniqueid": "^4.0.6",

"babel-loader": "^8.1.0",
"coveralls": "^3.1.0",
"cross-env": "^7.0.2",

@@ -86,3 +88,3 @@ "eslint": "^7.11.0",

"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.21.4",
"eslint-plugin-react": "^7.21.5",
"fork-ts-checker-webpack-plugin": "^5.2.0",

@@ -100,3 +102,2 @@ "gh-pages": "^3.1.0",

"react-dom": "^16.14.0",
"react-hooks-testing-library": "^0.6.0",
"react-test-renderer": "^16.14.0",

@@ -107,3 +108,3 @@ "rollup": "^2.32.0",

"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.3",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^3.1.8",

@@ -113,3 +114,3 @@ "rollup-plugin-typescript2": "^0.28.0",

"styled-components": "^5.2.0",
"ts-loader": "^8.0.5",
"ts-loader": "^8.0.6",
"typescript": "^4.0.3"

@@ -116,0 +117,0 @@ },

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc