Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

arrow-key-navigation

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arrow-key-navigation - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

136

dist-node/index.js

@@ -11,33 +11,28 @@ 'use strict';

/* global document, addEventListener, removeEventListener, getSelection */
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' + 'button, iframe, object, embed, [contenteditable], [tabindex], ' + 'video[controls], audio[controls], summary'; // TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null
// TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null
// As far as I can tell, there is no way to actually get the caret position from these inputs. So we
// don't do the proper caret handling for those inputs, unfortunately.
// https://html.spec.whatwg.org/multipage/input.html#do-not-apply
var textInputTypes = ['text', 'search', 'url', 'password', 'tel'];
var checkboxRadioInputTypes = ['checkbox', 'radio'];
var focusTrapTest = undefined;
var focusTrapTest = undefined; // This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
function getFocusableElements(activeElement) {
// Respect focus trap inside of dialogs
var dialogParent = getFocusTrapParent(activeElement);
var root = dialogParent || document;
var res = [];
var elements = root.querySelectorAll(focusablesQuery);
var len = elements.length;
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' + 'button, iframe, object, embed, [contenteditable], [tabindex], ' + 'video[controls], audio[controls], summary';
for (var i = 0; i < len; i++) {
var element = elements[i];
function getActiveElement() {
var activeElement = document.activeElement;
if (element === activeElement || !element.disabled && !/^-/.test(element.getAttribute('tabindex') || '') && !element.hasAttribute('inert') && ( // see https://github.com/GoogleChrome/inert-polyfill
element.offsetWidth > 0 || element.offsetHeight > 0)) {
res.push(element);
}
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
return res;
return activeElement;
}
function isFocusable(element) {
return element.matches(focusablesQuery) && !element.disabled && !/^-/.test(element.getAttribute('tabindex') || '') && !element.hasAttribute('inert') && ( // see https://github.com/GoogleChrome/inert-polyfill
element.offsetWidth > 0 || element.offsetHeight > 0);
}
function getFocusTrapParent(element) {

@@ -59,3 +54,3 @@ if (!focusTrapTest) {

function shouldIgnoreEvent(activeElement, key) {
function shouldIgnoreEvent(activeElement, forwardDirection) {
var tagName = activeElement.tagName;

@@ -87,5 +82,5 @@ var isTextarea = tagName === 'TEXTAREA';

if (key === 'ArrowLeft' && selectionStart === selectionEnd && selectionStart === 0) {
if (!forwardDirection && selectionStart === selectionEnd && selectionStart === 0) {
return false;
} else if (key === 'ArrowRight' && selectionStart === selectionEnd && selectionStart === len) {
} else if (forwardDirection && selectionStart === selectionEnd && selectionStart === len) {
return false;

@@ -97,31 +92,94 @@ }

function focusNextOrPrevious(event, key) {
var activeElement = document.activeElement;
function getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) {
// When the shadydom polyfill is running, we can't use TreeWalker on ShadowRoots because
// they aren't real Nodes. So we do this workaround where we run TreeWalker on the
// children instead.
var nodes = Array.prototype.slice.call(root.querySelectorAll('*'));
var idx = nodes.indexOf(targetElement);
if (shouldIgnoreEvent(activeElement, key)) {
return;
if (forwardDirection) {
nodes = nodes.slice(idx + 1);
} else {
if (idx === -1) {
idx = nodes.length;
}
nodes = nodes.slice(0, idx);
nodes.reverse();
}
var focusableElements = getFocusableElements(activeElement);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!focusableElements.length) {
return;
if (node instanceof HTMLElement && filter.acceptNode(node) === NodeFilter.FILTER_ACCEPT) {
return node;
}
}
var index = focusableElements.indexOf(activeElement);
var element;
return undefined;
}
if (key === 'ArrowLeft') {
element = focusableElements[index - 1] || focusableElements[0];
} else {
// ArrowRight
element = focusableElements[index + 1] || focusableElements[focusableElements.length - 1];
function getNextCandidateNode(root, targetElement, forwardDirection, filter) {
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter);
if (targetElement) {
walker.currentNode = targetElement;
}
element.focus();
event.preventDefault();
if (forwardDirection) {
return walker.nextNode();
} else if (targetElement) {
return walker.previousNode();
} // iterating backwards through shadow root, use last child
return walker.lastChild();
}
function isShadowDomPolyfill() {
return typeof ShadowRoot !== 'undefined' && ( // ShadowRoot.polyfill is just a hack for our unit tests
'polyfill' in ShadowRoot || !ShadowRoot.toString().includes('[native code]'));
}
function getNextNode(root, targetElement, forwardDirection) {
var filter = {
acceptNode: function (node) {
return node === targetElement || node.shadowRoot || isFocusable(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
}; // TODO: remove this when we don't need to support the Shadow DOM polyfill
var nextNode = isShadowDomPolyfill() && root instanceof ShadowRoot ? getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) : getNextCandidateNode(root, targetElement, forwardDirection, filter);
if (nextNode && nextNode.shadowRoot) {
// push into the shadow DOM
return getNextNode(nextNode.shadowRoot, null, forwardDirection);
}
if (!nextNode && root.host) {
// pop out of the shadow DOM
return getNextNode(root.host.getRootNode(), root.host, forwardDirection);
}
return nextNode;
}
function focusNextOrPrevious(event, key) {
var activeElement = getActiveElement();
var forwardDirection = key === 'ArrowRight';
if (shouldIgnoreEvent(activeElement, forwardDirection)) {
return;
}
var root = getFocusTrapParent(activeElement) || activeElement.getRootNode();
var nextNode = getNextNode(root, activeElement, forwardDirection);
if (nextNode && nextNode !== activeElement) {
nextNode.focus();
event.preventDefault();
}
}
function handleEnter(event) {
var activeElement = document.activeElement;
var activeElement = getActiveElement();

@@ -128,0 +186,0 @@ if (activeElement.tagName === 'INPUT' && checkboxRadioInputTypes.indexOf(activeElement.getAttribute('type').toLowerCase()) !== -1) {

@@ -6,7 +6,2 @@ /**

/* global document, addEventListener, removeEventListener, getSelection */
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' +
'button, iframe, object, embed, [contenteditable], [tabindex], ' +
'video[controls], audio[controls], summary';
// TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null

@@ -19,20 +14,21 @@ // As far as I can tell, there is no way to actually get the caret position from these inputs. So we

var focusTrapTest = undefined;
function getFocusableElements(activeElement) {
// Respect focus trap inside of dialogs
var dialogParent = getFocusTrapParent(activeElement);
var root = dialogParent || document;
var res = [];
var elements = root.querySelectorAll(focusablesQuery);
var len = elements.length;
for (var i = 0; i < len; i++) {
var element = elements[i];
if (element === activeElement || (!element.disabled &&
!/^-/.test(element.getAttribute('tabindex') || '') &&
!element.hasAttribute('inert') && // see https://github.com/GoogleChrome/inert-polyfill
(element.offsetWidth > 0 || element.offsetHeight > 0))) {
res.push(element);
}
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' +
'button, iframe, object, embed, [contenteditable], [tabindex], ' +
'video[controls], audio[controls], summary';
function getActiveElement() {
var activeElement = document.activeElement;
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
return res;
return activeElement;
}
function isFocusable(element) {
return element.matches(focusablesQuery) &&
!element.disabled &&
!/^-/.test(element.getAttribute('tabindex') || '') &&
!element.hasAttribute('inert') && // see https://github.com/GoogleChrome/inert-polyfill
(element.offsetWidth > 0 || element.offsetHeight > 0);
}
function getFocusTrapParent(element) {

@@ -50,3 +46,3 @@ if (!focusTrapTest) {

}
function shouldIgnoreEvent(activeElement, key) {
function shouldIgnoreEvent(activeElement, forwardDirection) {
var tagName = activeElement.tagName;

@@ -76,6 +72,6 @@ var isTextarea = tagName === 'TEXTAREA';

// unless the cursor is at the beginning or the end
if (key === 'ArrowLeft' && selectionStart === selectionEnd && selectionStart === 0) {
if (!forwardDirection && selectionStart === selectionEnd && selectionStart === 0) {
return false;
}
else if (key === 'ArrowRight' && selectionStart === selectionEnd && selectionStart === len) {
else if (forwardDirection && selectionStart === selectionEnd && selectionStart === len) {
return false;

@@ -85,24 +81,80 @@ }

}
function focusNextOrPrevious(event, key) {
var activeElement = document.activeElement;
if (shouldIgnoreEvent(activeElement, key)) {
return;
function getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) {
// When the shadydom polyfill is running, we can't use TreeWalker on ShadowRoots because
// they aren't real Nodes. So we do this workaround where we run TreeWalker on the
// children instead.
var nodes = Array.prototype.slice.call(root.querySelectorAll('*'));
var idx = nodes.indexOf(targetElement);
if (forwardDirection) {
nodes = nodes.slice(idx + 1);
}
var focusableElements = getFocusableElements(activeElement);
if (!focusableElements.length) {
return;
else {
if (idx === -1) {
idx = nodes.length;
}
nodes = nodes.slice(0, idx);
nodes.reverse();
}
var index = focusableElements.indexOf(activeElement);
var element;
if (key === 'ArrowLeft') {
element = focusableElements[index - 1] || focusableElements[0];
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node instanceof HTMLElement && filter.acceptNode(node) === NodeFilter.FILTER_ACCEPT) {
return node;
}
}
else { // ArrowRight
element = focusableElements[index + 1] || focusableElements[focusableElements.length - 1];
return undefined;
}
function getNextCandidateNode(root, targetElement, forwardDirection, filter) {
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter);
if (targetElement) {
walker.currentNode = targetElement;
}
element.focus();
event.preventDefault();
if (forwardDirection) {
return walker.nextNode();
}
else if (targetElement) {
return walker.previousNode();
}
// iterating backwards through shadow root, use last child
return walker.lastChild();
}
function isShadowDomPolyfill() {
return typeof ShadowRoot !== 'undefined' &&
// ShadowRoot.polyfill is just a hack for our unit tests
('polyfill' in ShadowRoot || !ShadowRoot.toString().includes('[native code]'));
}
function getNextNode(root, targetElement, forwardDirection) {
var filter = {
acceptNode: function (node) {
return (node === targetElement || node.shadowRoot || isFocusable(node))
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
};
// TODO: remove this when we don't need to support the Shadow DOM polyfill
var nextNode = isShadowDomPolyfill() && root instanceof ShadowRoot
? getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter)
: getNextCandidateNode(root, targetElement, forwardDirection, filter);
if (nextNode && nextNode.shadowRoot) { // push into the shadow DOM
return getNextNode(nextNode.shadowRoot, null, forwardDirection);
}
if (!nextNode && root.host) { // pop out of the shadow DOM
return getNextNode(root.host.getRootNode(), root.host, forwardDirection);
}
return nextNode;
}
function focusNextOrPrevious(event, key) {
var activeElement = getActiveElement();
var forwardDirection = key === 'ArrowRight';
if (shouldIgnoreEvent(activeElement, forwardDirection)) {
return;
}
var root = getFocusTrapParent(activeElement) || activeElement.getRootNode();
var nextNode = getNextNode(root, activeElement, forwardDirection);
if (nextNode && nextNode !== activeElement) {
nextNode.focus();
event.preventDefault();
}
}
function handleEnter(event) {
var activeElement = document.activeElement;
var activeElement = getActiveElement();
if (activeElement.tagName === 'INPUT' &&

@@ -109,0 +161,0 @@ checkboxRadioInputTypes.indexOf(activeElement.getAttribute('type').toLowerCase()) !== -1) {

@@ -13,33 +13,28 @@ (function (global, factory) {

/* global document, addEventListener, removeEventListener, getSelection */
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' + 'button, iframe, object, embed, [contenteditable], [tabindex], ' + 'video[controls], audio[controls], summary'; // TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null
// TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null
// As far as I can tell, there is no way to actually get the caret position from these inputs. So we
// don't do the proper caret handling for those inputs, unfortunately.
// https://html.spec.whatwg.org/multipage/input.html#do-not-apply
var textInputTypes = ['text', 'search', 'url', 'password', 'tel'];
var checkboxRadioInputTypes = ['checkbox', 'radio'];
var focusTrapTest = undefined;
var focusTrapTest = undefined; // This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
function getFocusableElements(activeElement) {
// Respect focus trap inside of dialogs
var dialogParent = getFocusTrapParent(activeElement);
var root = dialogParent || document;
var res = [];
var elements = root.querySelectorAll(focusablesQuery);
var len = elements.length;
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' + 'button, iframe, object, embed, [contenteditable], [tabindex], ' + 'video[controls], audio[controls], summary';
for (var i = 0; i < len; i++) {
var element = elements[i];
function getActiveElement() {
var activeElement = document.activeElement;
if (element === activeElement || !element.disabled && !/^-/.test(element.getAttribute('tabindex') || '') && !element.hasAttribute('inert') && ( // see https://github.com/GoogleChrome/inert-polyfill
element.offsetWidth > 0 || element.offsetHeight > 0)) {
res.push(element);
}
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
return res;
return activeElement;
}
function isFocusable(element) {
return element.matches(focusablesQuery) && !element.disabled && !/^-/.test(element.getAttribute('tabindex') || '') && !element.hasAttribute('inert') && ( // see https://github.com/GoogleChrome/inert-polyfill
element.offsetWidth > 0 || element.offsetHeight > 0);
}
function getFocusTrapParent(element) {

@@ -61,3 +56,3 @@ if (!focusTrapTest) {

function shouldIgnoreEvent(activeElement, key) {
function shouldIgnoreEvent(activeElement, forwardDirection) {
var tagName = activeElement.tagName;

@@ -89,5 +84,5 @@ var isTextarea = tagName === 'TEXTAREA';

if (key === 'ArrowLeft' && selectionStart === selectionEnd && selectionStart === 0) {
if (!forwardDirection && selectionStart === selectionEnd && selectionStart === 0) {
return false;
} else if (key === 'ArrowRight' && selectionStart === selectionEnd && selectionStart === len) {
} else if (forwardDirection && selectionStart === selectionEnd && selectionStart === len) {
return false;

@@ -99,31 +94,94 @@ }

function focusNextOrPrevious(event, key) {
var activeElement = document.activeElement;
function getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) {
// When the shadydom polyfill is running, we can't use TreeWalker on ShadowRoots because
// they aren't real Nodes. So we do this workaround where we run TreeWalker on the
// children instead.
var nodes = Array.prototype.slice.call(root.querySelectorAll('*'));
var idx = nodes.indexOf(targetElement);
if (shouldIgnoreEvent(activeElement, key)) {
return;
if (forwardDirection) {
nodes = nodes.slice(idx + 1);
} else {
if (idx === -1) {
idx = nodes.length;
}
nodes = nodes.slice(0, idx);
nodes.reverse();
}
var focusableElements = getFocusableElements(activeElement);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!focusableElements.length) {
return;
if (node instanceof HTMLElement && filter.acceptNode(node) === NodeFilter.FILTER_ACCEPT) {
return node;
}
}
var index = focusableElements.indexOf(activeElement);
var element;
return undefined;
}
if (key === 'ArrowLeft') {
element = focusableElements[index - 1] || focusableElements[0];
} else {
// ArrowRight
element = focusableElements[index + 1] || focusableElements[focusableElements.length - 1];
function getNextCandidateNode(root, targetElement, forwardDirection, filter) {
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter);
if (targetElement) {
walker.currentNode = targetElement;
}
element.focus();
event.preventDefault();
if (forwardDirection) {
return walker.nextNode();
} else if (targetElement) {
return walker.previousNode();
} // iterating backwards through shadow root, use last child
return walker.lastChild();
}
function isShadowDomPolyfill() {
return typeof ShadowRoot !== 'undefined' && ( // ShadowRoot.polyfill is just a hack for our unit tests
'polyfill' in ShadowRoot || !ShadowRoot.toString().includes('[native code]'));
}
function getNextNode(root, targetElement, forwardDirection) {
var filter = {
acceptNode: function acceptNode(node) {
return node === targetElement || node.shadowRoot || isFocusable(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
}; // TODO: remove this when we don't need to support the Shadow DOM polyfill
var nextNode = isShadowDomPolyfill() && root instanceof ShadowRoot ? getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) : getNextCandidateNode(root, targetElement, forwardDirection, filter);
if (nextNode && nextNode.shadowRoot) {
// push into the shadow DOM
return getNextNode(nextNode.shadowRoot, null, forwardDirection);
}
if (!nextNode && root.host) {
// pop out of the shadow DOM
return getNextNode(root.host.getRootNode(), root.host, forwardDirection);
}
return nextNode;
}
function focusNextOrPrevious(event, key) {
var activeElement = getActiveElement();
var forwardDirection = key === 'ArrowRight';
if (shouldIgnoreEvent(activeElement, forwardDirection)) {
return;
}
var root = getFocusTrapParent(activeElement) || activeElement.getRootNode();
var nextNode = getNextNode(root, activeElement, forwardDirection);
if (nextNode && nextNode !== activeElement) {
nextNode.focus();
event.preventDefault();
}
}
function handleEnter(event) {
var activeElement = document.activeElement;
var activeElement = getActiveElement();

@@ -130,0 +188,0 @@ if (activeElement.tagName === 'INPUT' && checkboxRadioInputTypes.indexOf(activeElement.getAttribute('type').toLowerCase()) !== -1) {

@@ -6,7 +6,2 @@ /**

/* global document, addEventListener, removeEventListener, getSelection */
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' +
'button, iframe, object, embed, [contenteditable], [tabindex], ' +
'video[controls], audio[controls], summary';
// TODO: email/number types are a special type, in that they return selectionStart/selectionEnd as null

@@ -19,20 +14,21 @@ // As far as I can tell, there is no way to actually get the caret position from these inputs. So we

var focusTrapTest = undefined;
function getFocusableElements(activeElement) {
// Respect focus trap inside of dialogs
var dialogParent = getFocusTrapParent(activeElement);
var root = dialogParent || document;
var res = [];
var elements = root.querySelectorAll(focusablesQuery);
var len = elements.length;
for (var i = 0; i < len; i++) {
var element = elements[i];
if (element === activeElement || (!element.disabled &&
!/^-/.test(element.getAttribute('tabindex') || '') &&
!element.hasAttribute('inert') && // see https://github.com/GoogleChrome/inert-polyfill
(element.offsetWidth > 0 || element.offsetHeight > 0))) {
res.push(element);
}
// This query is adapted from a11y-dialog
// https://github.com/edenspiekermann/a11y-dialog/blob/cf4ed81/a11y-dialog.js#L6-L18
var focusablesQuery = 'a[href], area[href], input, select, textarea, ' +
'button, iframe, object, embed, [contenteditable], [tabindex], ' +
'video[controls], audio[controls], summary';
function getActiveElement() {
var activeElement = document.activeElement;
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
return res;
return activeElement;
}
function isFocusable(element) {
return element.matches(focusablesQuery) &&
!element.disabled &&
!/^-/.test(element.getAttribute('tabindex') || '') &&
!element.hasAttribute('inert') && // see https://github.com/GoogleChrome/inert-polyfill
(element.offsetWidth > 0 || element.offsetHeight > 0);
}
function getFocusTrapParent(element) {

@@ -50,3 +46,3 @@ if (!focusTrapTest) {

}
function shouldIgnoreEvent(activeElement, key) {
function shouldIgnoreEvent(activeElement, forwardDirection) {
var tagName = activeElement.tagName;

@@ -76,6 +72,6 @@ var isTextarea = tagName === 'TEXTAREA';

// unless the cursor is at the beginning or the end
if (key === 'ArrowLeft' && selectionStart === selectionEnd && selectionStart === 0) {
if (!forwardDirection && selectionStart === selectionEnd && selectionStart === 0) {
return false;
}
else if (key === 'ArrowRight' && selectionStart === selectionEnd && selectionStart === len) {
else if (forwardDirection && selectionStart === selectionEnd && selectionStart === len) {
return false;

@@ -85,24 +81,80 @@ }

}
function focusNextOrPrevious(event, key) {
var activeElement = document.activeElement;
if (shouldIgnoreEvent(activeElement, key)) {
return;
function getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter) {
// When the shadydom polyfill is running, we can't use TreeWalker on ShadowRoots because
// they aren't real Nodes. So we do this workaround where we run TreeWalker on the
// children instead.
var nodes = Array.prototype.slice.call(root.querySelectorAll('*'));
var idx = nodes.indexOf(targetElement);
if (forwardDirection) {
nodes = nodes.slice(idx + 1);
}
var focusableElements = getFocusableElements(activeElement);
if (!focusableElements.length) {
return;
else {
if (idx === -1) {
idx = nodes.length;
}
nodes = nodes.slice(0, idx);
nodes.reverse();
}
var index = focusableElements.indexOf(activeElement);
var element;
if (key === 'ArrowLeft') {
element = focusableElements[index - 1] || focusableElements[0];
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node instanceof HTMLElement && filter.acceptNode(node) === NodeFilter.FILTER_ACCEPT) {
return node;
}
}
else { // ArrowRight
element = focusableElements[index + 1] || focusableElements[focusableElements.length - 1];
return undefined;
}
function getNextCandidateNode(root, targetElement, forwardDirection, filter) {
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter);
if (targetElement) {
walker.currentNode = targetElement;
}
element.focus();
event.preventDefault();
if (forwardDirection) {
return walker.nextNode();
}
else if (targetElement) {
return walker.previousNode();
}
// iterating backwards through shadow root, use last child
return walker.lastChild();
}
function isShadowDomPolyfill() {
return typeof ShadowRoot !== 'undefined' &&
// ShadowRoot.polyfill is just a hack for our unit tests
('polyfill' in ShadowRoot || !ShadowRoot.toString().includes('[native code]'));
}
function getNextNode(root, targetElement, forwardDirection) {
var filter = {
acceptNode: function (node) {
return (node === targetElement || node.shadowRoot || isFocusable(node))
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
};
// TODO: remove this when we don't need to support the Shadow DOM polyfill
var nextNode = isShadowDomPolyfill() && root instanceof ShadowRoot
? getNextCandidateNodeForShadowDomPolyfill(root, targetElement, forwardDirection, filter)
: getNextCandidateNode(root, targetElement, forwardDirection, filter);
if (nextNode && nextNode.shadowRoot) { // push into the shadow DOM
return getNextNode(nextNode.shadowRoot, null, forwardDirection);
}
if (!nextNode && root.host) { // pop out of the shadow DOM
return getNextNode(root.host.getRootNode(), root.host, forwardDirection);
}
return nextNode;
}
function focusNextOrPrevious(event, key) {
var activeElement = getActiveElement();
var forwardDirection = key === 'ArrowRight';
if (shouldIgnoreEvent(activeElement, forwardDirection)) {
return;
}
var root = getFocusTrapParent(activeElement) || activeElement.getRootNode();
var nextNode = getNextNode(root, activeElement, forwardDirection);
if (nextNode && nextNode !== activeElement) {
nextNode.focus();
event.preventDefault();
}
}
function handleEnter(event) {
var activeElement = document.activeElement;
var activeElement = getActiveElement();
if (activeElement.tagName === 'INPUT' &&

@@ -109,0 +161,0 @@ checkboxRadioInputTypes.indexOf(activeElement.getAttribute('type').toLowerCase()) !== -1) {

{
"name": "arrow-key-navigation",
"description": "Add left/right key navigation to a KaiOS app or web app",
"version": "1.1.0",
"version": "1.2.0",
"license": "Apache-2.0",

@@ -34,14 +34,26 @@ "files": [

"@pika/pack": "^0.5.0",
"@pika/plugin-build-node": "^0.7.1",
"@pika/plugin-build-umd": "^0.7.1",
"@pika/plugin-build-web": "^0.7.1",
"@pika/plugin-ts-standard-pkg": "^0.7.1",
"@pika/plugin-build-node": "^0.9.2",
"@pika/plugin-build-umd": "^0.9.2",
"@pika/plugin-build-web": "^0.9.2",
"@pika/plugin-ts-standard-pkg": "^0.9.2",
"@rollup/plugin-commonjs": "^13.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^8.0.1",
"assert": "^2.0.0",
"jsdom": "^15.2.0",
"jsdom": "^16.2.2",
"jsdom-global": "^3.0.2",
"mocha": "^6.2.2",
"standard": "^14.3.1",
"tslint": "^5.20.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.6.4"
"karma": "^5.1.0",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.2",
"karma-mocha": "^2.0.1",
"karma-rollup-preprocessor": "^7.0.5",
"mocha": "^8.0.1",
"nyc": "^15.1.0",
"rollup": "^2.17.1",
"rollup-plugin-istanbul": "^2.0.1",
"rollup-plugin-node-polyfills": "^0.2.1",
"standard": "^14.3.4",
"tslint": "^6.1.2",
"tslint-config-standard": "^9.0.0",
"typescript": "^3.9.5"
},

@@ -48,0 +60,0 @@ "source": "dist-src/index.js",

@@ -14,3 +14,3 @@ arrow-key-navigation [![Build Status](https://travis-ci.org/nolanlawson/arrow-key-navigation.svg)](https://travis-ci.org/nolanlawson/arrow-key-navigation)

It will also listen for the <kbd>Enter</kbd> key for certain special cases like checkbox/radio buttons.
It will also listen for the <kbd>Enter</kbd> key for certain special cases like checkbox/radio buttons. `contenteditable` and Shadow DOM are also supported.

@@ -78,2 +78,6 @@ ## Install

### Code coverage
npm run cover
### Manual KaiOS app test

@@ -80,0 +84,0 @@

Sorry, the diff of this file is not supported yet

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