@bbc/tv-lrud-spatial
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -245,2 +245,10 @@ /** | ||
/** | ||
* Get the closest spatial candidate | ||
* | ||
* @param {HTMLElement} elem The search origin | ||
* @param {HTMLElement[]} candidates An set of candidate elements to assess | ||
* @param {string} exitDir The direction in which we exited the elem (left, right, up, down) | ||
* @return {HTMLElement|null} The element that was spatially closest elem in candidates | ||
*/ | ||
const getBestCandidate = (elem, candidates, exitDir) => { | ||
@@ -276,9 +284,10 @@ let bestCandidate = null; | ||
* @param {HTMLElement} elem The search origin | ||
* @param {string} exitDir The direction in which we exited the elem (left, right, up, down) | ||
* @param {string|number} keyOrKeyCode The key or keyCode value (from KeyboardEvent) of the pressed key | ||
* @param {HTMLElement} scope The element LRUD spatial is scoped to operate within | ||
* @return {HTMLElement} The element that should receive focus next | ||
*/ | ||
export const getNextFocus = (elem, keyCode, scope) => { | ||
export const getNextFocus = (elem, keyOrKeyCode, scope) => { | ||
if (!scope || !scope.querySelector) scope = document.body; | ||
if (!elem) return getFocusables(scope)?.[0]; | ||
const exitDir = _keyMap[keyCode]; | ||
const exitDir = _keyMap[keyOrKeyCode]; | ||
@@ -358,2 +367,6 @@ // Get parent focus container | ||
216: _down, | ||
'ArrowLeft': _left, | ||
'ArrowRight': _right, | ||
'ArrowUp': _up, | ||
'ArrowDown': _down | ||
}; |
@@ -1,1 +0,1 @@ | ||
"use strict";exports.__esModule=true;exports.getNextFocus=void 0;var focusableSelector="[tabindex], a, input, button";var containerSelector="nav, section, .lrud-container";var focusableContainerSelector="[data-lrud-consider-container-distance]";var ignoredClass="lrud-ignore";var matches=function matches(element,selectors){var fn=Element.prototype.matches||Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(s){var matches=(this.document||this.ownerDocument).querySelectorAll(s),i=matches.length;while(--i>=0&&matches.item(i)!==this){}return i>-1};return fn.call(element,selectors)};var toArray=function toArray(nodeList){return Array.prototype.slice.call(nodeList)};var getParentContainer=function getParentContainer(elem){if(!elem.parentElement||elem.parentElement.tagName==="BODY"){return null}else if(matches(elem.parentElement,containerSelector)){return elem.parentElement}return getParentContainer(elem.parentElement)};var getFocusables=function getFocusables(scope){if(!scope)return[];var ignoredElements=toArray(scope.querySelectorAll("."+ignoredClass));if(scope.className.indexOf(ignoredClass)>-1)ignoredElements.push(scope);return toArray(scope.querySelectorAll(focusableSelector)).filter(function(node){return!ignoredElements.some(function(ignored){return ignored==node||ignored.contains(node)})})};var collectContainers=function collectContainers(initialContainer){if(!initialContainer)return[];var acc=[initialContainer];var cur=initialContainer;while(cur){cur=getParentContainer(cur);if(cur)acc.push(cur)}return acc};var getMidpointForEdge=function getMidpointForEdge(rect,dir){switch(dir){case"left":return{x:rect.left,y:(rect.top+rect.bottom)/2};case"right":return{x:rect.right,y:(rect.top+rect.bottom)/2};case"up":return{x:(rect.left+rect.right)/2,y:rect.top};case"down":return{x:(rect.left+rect.right)/2,y:rect.bottom};}};var getNearestPoint=function getNearestPoint(point,dir,rect){if(dir==="left"||dir==="right"){var x=dir==="left"?rect.right:rect.left;if(point.y<rect.top)return{x:x,y:rect.top};if(point.y>rect.bottom)return{x:x,y:rect.bottom};return{x:x,y:point.y}}else if(dir==="up"||dir==="down"){var y=dir==="up"?rect.bottom:rect.top;if(point.x<rect.left)return{x:rect.left,y:y};if(point.x>rect.right)return{x:rect.right,y:y};return{x:point.x,y:y}}};var getDistanceBetweenPoints=function getDistanceBetweenPoints(a,b){return Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y,2))};var isBelow=function isBelow(a,b){return a.y>b.y};var isRight=function isRight(a,b){return a.x>b.x};var getBlockedExitDirs=function getBlockedExitDirs(container,candidateContainer){var currentAncestorContainers=collectContainers(container);var candidateAncestorContainers=collectContainers(candidateContainer);for(var i=0;i<candidateAncestorContainers.length;i++){var commonCandidate=candidateAncestorContainers[i];var spliceIndex=currentAncestorContainers.indexOf(commonCandidate);if(spliceIndex>-1){currentAncestorContainers.splice(spliceIndex);break}}return currentAncestorContainers.reduce(function(acc,cur){var dirs=((cur===null||cur===void 0?void 0:cur.getAttribute("data-block-exit"))||"").split(" ");return acc.concat(dirs)},[])};var isValidCandidate=function isValidCandidate(entryRect,exitDir,exitPoint,entryWeighting){if(entryRect.width===0&&entryRect.height===0)return false;if(!entryWeighting&&entryWeighting!=0)entryWeighting=0.3;var weightedEntryPoint={x:entryRect.left+entryRect.width*(exitDir==="left"?1-entryWeighting:exitDir==="right"?entryWeighting:0.5),y:entryRect.top+entryRect.height*(exitDir==="up"?1-entryWeighting:exitDir==="down"?entryWeighting:0.5)};if(exitDir==="left"&&isRight(exitPoint,weightedEntryPoint)||exitDir==="right"&&isRight(weightedEntryPoint,exitPoint)||exitDir==="up"&&isBelow(exitPoint,weightedEntryPoint)||exitDir==="down"&&isBelow(weightedEntryPoint,exitPoint))return true;return false};var getBestCandidate=function getBestCandidate(elem,candidates,exitDir){var bestCandidate=null;var bestDistance=Infinity;var exitRect=elem.getBoundingClientRect();var exitPoint=getMidpointForEdge(exitRect,exitDir);for(var i=0;i<candidates.length;++i){var candidate=candidates[i];var entryRect=candidate.getBoundingClientRect();var allowedOverlap=parseFloat(candidate.getAttribute("data-lrud-overlap-threshold"));if(!isValidCandidate(entryRect,exitDir,exitPoint,allowedOverlap))continue;var nearestPoint=getNearestPoint(exitPoint,exitDir,entryRect);var distance=getDistanceBetweenPoints(exitPoint,nearestPoint);if(bestDistance>distance){bestDistance=distance;bestCandidate=candidate}}return bestCandidate};var getNextFocus=function getNextFocus(elem,keyCode,scope){var _getFocusables;if(!scope||!scope.querySelector)scope=document.body;if(!elem)return(_getFocusables=getFocusables(scope))===null||_getFocusables===void 0?void 0:_getFocusables[0];var exitDir=_keyMap[keyCode];var parentContainer=getParentContainer(elem);var bestCandidate;if((parentContainer===null||parentContainer===void 0?void 0:parentContainer.getAttribute("data-lrud-prioritise-children"))!=="false"&&scope.contains(parentContainer)){var focusableSiblings=getFocusables(parentContainer);bestCandidate=getBestCandidate(elem,focusableSiblings,exitDir)}if(!bestCandidate){var focusableCandidates=[].concat(getFocusables(scope),toArray(scope.querySelectorAll(focusableContainerSelector)).filter(function(container){var _getFocusables2;return((_getFocusables2=getFocusables(container))===null||_getFocusables2===void 0?void 0:_getFocusables2.length)>0&&container!==parentContainer}));bestCandidate=getBestCandidate(elem,focusableCandidates,exitDir)}if(bestCandidate){var isBestCandidateAContainer=matches(bestCandidate,containerSelector);var candidateContainer=isBestCandidateAContainer?bestCandidate:getParentContainer(bestCandidate);var isCurrentContainer=candidateContainer===parentContainer;var isNestedContainer=parentContainer===null||parentContainer===void 0?void 0:parentContainer.contains(candidateContainer);var isAnscestorContainer=candidateContainer===null||candidateContainer===void 0?void 0:candidateContainer.contains(parentContainer);if(!isCurrentContainer&&(!isNestedContainer||isBestCandidateAContainer)){var blockedExitDirs=getBlockedExitDirs(parentContainer,candidateContainer);if(blockedExitDirs.indexOf(exitDir)>-1)return;if(candidateContainer&&!isAnscestorContainer){var _getFocusables3;if(elem.id)parentContainer===null||parentContainer===void 0?void 0:parentContainer.setAttribute("data-focus",elem.id);var lastActiveChild=document.getElementById(candidateContainer.getAttribute("data-focus"));return lastActiveChild||((_getFocusables3=getFocusables(candidateContainer))===null||_getFocusables3===void 0?void 0:_getFocusables3[0])}}}return bestCandidate};exports.getNextFocus=getNextFocus;var _left="left",_right="right",_up="up",_down="down";var _keyMap={4:_left,21:_left,37:_left,214:_left,205:_left,218:_left,5:_right,22:_right,39:_right,213:_right,206:_right,217:_right,29460:_up,19:_up,38:_up,211:_up,203:_up,215:_up,29461:_down,20:_down,40:_down,212:_down,204:_down,216:_down}; | ||
"use strict";exports.__esModule=true;exports.getNextFocus=void 0;var focusableSelector="[tabindex], a, input, button";var containerSelector="nav, section, .lrud-container";var focusableContainerSelector="[data-lrud-consider-container-distance]";var ignoredClass="lrud-ignore";var matches=function matches(element,selectors){var fn=Element.prototype.matches||Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(s){var matches=(this.document||this.ownerDocument).querySelectorAll(s),i=matches.length;while(--i>=0&&matches.item(i)!==this){}return i>-1};return fn.call(element,selectors)};var toArray=function toArray(nodeList){return Array.prototype.slice.call(nodeList)};var getParentContainer=function getParentContainer(elem){if(!elem.parentElement||elem.parentElement.tagName==="BODY"){return null}else if(matches(elem.parentElement,containerSelector)){return elem.parentElement}return getParentContainer(elem.parentElement)};var getFocusables=function getFocusables(scope){if(!scope)return[];var ignoredElements=toArray(scope.querySelectorAll("."+ignoredClass));if(scope.className.indexOf(ignoredClass)>-1)ignoredElements.push(scope);return toArray(scope.querySelectorAll(focusableSelector)).filter(function(node){return!ignoredElements.some(function(ignored){return ignored==node||ignored.contains(node)})})};var collectContainers=function collectContainers(initialContainer){if(!initialContainer)return[];var acc=[initialContainer];var cur=initialContainer;while(cur){cur=getParentContainer(cur);if(cur)acc.push(cur)}return acc};var getMidpointForEdge=function getMidpointForEdge(rect,dir){switch(dir){case"left":return{x:rect.left,y:(rect.top+rect.bottom)/2};case"right":return{x:rect.right,y:(rect.top+rect.bottom)/2};case"up":return{x:(rect.left+rect.right)/2,y:rect.top};case"down":return{x:(rect.left+rect.right)/2,y:rect.bottom};}};var getNearestPoint=function getNearestPoint(point,dir,rect){if(dir==="left"||dir==="right"){var x=dir==="left"?rect.right:rect.left;if(point.y<rect.top)return{x:x,y:rect.top};if(point.y>rect.bottom)return{x:x,y:rect.bottom};return{x:x,y:point.y}}else if(dir==="up"||dir==="down"){var y=dir==="up"?rect.bottom:rect.top;if(point.x<rect.left)return{x:rect.left,y:y};if(point.x>rect.right)return{x:rect.right,y:y};return{x:point.x,y:y}}};var getDistanceBetweenPoints=function getDistanceBetweenPoints(a,b){return Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y,2))};var isBelow=function isBelow(a,b){return a.y>b.y};var isRight=function isRight(a,b){return a.x>b.x};var getBlockedExitDirs=function getBlockedExitDirs(container,candidateContainer){var currentAncestorContainers=collectContainers(container);var candidateAncestorContainers=collectContainers(candidateContainer);for(var i=0;i<candidateAncestorContainers.length;i++){var commonCandidate=candidateAncestorContainers[i];var spliceIndex=currentAncestorContainers.indexOf(commonCandidate);if(spliceIndex>-1){currentAncestorContainers.splice(spliceIndex);break}}return currentAncestorContainers.reduce(function(acc,cur){var dirs=((cur===null||cur===void 0?void 0:cur.getAttribute("data-block-exit"))||"").split(" ");return acc.concat(dirs)},[])};var isValidCandidate=function isValidCandidate(entryRect,exitDir,exitPoint,entryWeighting){if(entryRect.width===0&&entryRect.height===0)return false;if(!entryWeighting&&entryWeighting!=0)entryWeighting=0.3;var weightedEntryPoint={x:entryRect.left+entryRect.width*(exitDir==="left"?1-entryWeighting:exitDir==="right"?entryWeighting:0.5),y:entryRect.top+entryRect.height*(exitDir==="up"?1-entryWeighting:exitDir==="down"?entryWeighting:0.5)};if(exitDir==="left"&&isRight(exitPoint,weightedEntryPoint)||exitDir==="right"&&isRight(weightedEntryPoint,exitPoint)||exitDir==="up"&&isBelow(exitPoint,weightedEntryPoint)||exitDir==="down"&&isBelow(weightedEntryPoint,exitPoint))return true;return false};var getBestCandidate=function getBestCandidate(elem,candidates,exitDir){var bestCandidate=null;var bestDistance=Infinity;var exitRect=elem.getBoundingClientRect();var exitPoint=getMidpointForEdge(exitRect,exitDir);for(var i=0;i<candidates.length;++i){var candidate=candidates[i];var entryRect=candidate.getBoundingClientRect();var allowedOverlap=parseFloat(candidate.getAttribute("data-lrud-overlap-threshold"));if(!isValidCandidate(entryRect,exitDir,exitPoint,allowedOverlap))continue;var nearestPoint=getNearestPoint(exitPoint,exitDir,entryRect);var distance=getDistanceBetweenPoints(exitPoint,nearestPoint);if(bestDistance>distance){bestDistance=distance;bestCandidate=candidate}}return bestCandidate};var getNextFocus=function getNextFocus(elem,keyOrKeyCode,scope){var _getFocusables;if(!scope||!scope.querySelector)scope=document.body;if(!elem)return(_getFocusables=getFocusables(scope))===null||_getFocusables===void 0?void 0:_getFocusables[0];var exitDir=_keyMap[keyOrKeyCode];var parentContainer=getParentContainer(elem);var bestCandidate;if((parentContainer===null||parentContainer===void 0?void 0:parentContainer.getAttribute("data-lrud-prioritise-children"))!=="false"&&scope.contains(parentContainer)){var focusableSiblings=getFocusables(parentContainer);bestCandidate=getBestCandidate(elem,focusableSiblings,exitDir)}if(!bestCandidate){var focusableCandidates=[].concat(getFocusables(scope),toArray(scope.querySelectorAll(focusableContainerSelector)).filter(function(container){var _getFocusables2;return((_getFocusables2=getFocusables(container))===null||_getFocusables2===void 0?void 0:_getFocusables2.length)>0&&container!==parentContainer}));bestCandidate=getBestCandidate(elem,focusableCandidates,exitDir)}if(bestCandidate){var isBestCandidateAContainer=matches(bestCandidate,containerSelector);var candidateContainer=isBestCandidateAContainer?bestCandidate:getParentContainer(bestCandidate);var isCurrentContainer=candidateContainer===parentContainer;var isNestedContainer=parentContainer===null||parentContainer===void 0?void 0:parentContainer.contains(candidateContainer);var isAnscestorContainer=candidateContainer===null||candidateContainer===void 0?void 0:candidateContainer.contains(parentContainer);if(!isCurrentContainer&&(!isNestedContainer||isBestCandidateAContainer)){var blockedExitDirs=getBlockedExitDirs(parentContainer,candidateContainer);if(blockedExitDirs.indexOf(exitDir)>-1)return;if(candidateContainer&&!isAnscestorContainer){var _getFocusables3;if(elem.id)parentContainer===null||parentContainer===void 0?void 0:parentContainer.setAttribute("data-focus",elem.id);var lastActiveChild=document.getElementById(candidateContainer.getAttribute("data-focus"));return lastActiveChild||((_getFocusables3=getFocusables(candidateContainer))===null||_getFocusables3===void 0?void 0:_getFocusables3[0])}}}return bestCandidate};exports.getNextFocus=getNextFocus;var _left="left",_right="right",_up="up",_down="down";var _keyMap={4:_left,21:_left,37:_left,214:_left,205:_left,218:_left,5:_right,22:_right,39:_right,213:_right,206:_right,217:_right,29460:_up,19:_up,38:_up,211:_up,203:_up,215:_up,29461:_down,20:_down,40:_down,212:_down,204:_down,216:_down,"ArrowLeft":_left,"ArrowRight":_right,"ArrowUp":_up,"ArrowDown":_down}; |
{ | ||
"name": "@bbc/tv-lrud-spatial", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "Spatial navigation library", | ||
@@ -5,0 +5,0 @@ "main": "lib/lrud.min.js", |
@@ -10,3 +10,3 @@ <p align="center"> | ||
<pre> | ||
getNextFocus(<i>currentFocus</i>, <i>keyCode</i>, <i>[scope]</i>) | ||
getNextFocus(<i>currentFocus</i>, <i>keyOrKeyCode</i>, <i>[scope]</i>) | ||
</pre> | ||
@@ -20,4 +20,5 @@ | ||
In simple applications, this can just be a reference to `document.activeElement`. | ||
- `keyCode` should be a | ||
[`keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) | ||
- `keyOrKeyCode` should be a | ||
[`key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) string or | ||
a [`keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) | ||
decimal representing the directional key pressed. | ||
@@ -128,2 +129,2 @@ - `scope` is an optional `HTMLElement` that you only want to look for focusable candidates inside of. Defaults to the whole page if not provided. | ||
[TVOpenSource@bbc.co.uk](mailto:TVOpenSource@bbc.co.uk) | ||
[TVOpenSource@bbc.co.uk](mailto:TVOpenSource@bbc.co.uk) - we aim to respond to emails within a week. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92977
1078
128