@zohodesk/a11y
Advanced tools
Comparing version 2.2.0 to 2.2.1
export default function uniqueNumber() { | ||
let prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||
//let randomId = (Date.now() + Math.random()).toString(36); | ||
var date = Date.now(); | ||
var date = Date.now(); // If created at same millisecond as previous | ||
// If created at same millisecond as previous | ||
if (date <= uniqueNumber.previous) { | ||
@@ -12,4 +11,5 @@ date = ++uniqueNumber.previous; | ||
} | ||
return prefix ? `${prefix}-${date}` : date; | ||
} | ||
uniqueNumber.previous = 0; |
@@ -18,2 +18,3 @@ import { useEffect } from 'react'; | ||
let focusableEl = autoFocusEle || focusContainer || contentRef() && contentRef(); | ||
if (needAutoFocus && focusableEl) { | ||
@@ -20,0 +21,0 @@ setTimeout(() => { |
@@ -7,6 +7,6 @@ import { useRef, useLayoutEffect, useCallback } from 'react'; | ||
*/ | ||
export default function useEvent(handler) { | ||
const handlerRef = useRef(null); | ||
const handlerRef = useRef(null); // In a real implementation, this would run before layout effects | ||
// In a real implementation, this would run before layout effects | ||
useLayoutEffect(() => { | ||
@@ -13,0 +13,0 @@ handlerRef.current = handler; |
@@ -11,2 +11,3 @@ import { useEffect, useRef } from 'react'; | ||
} = customAttributes; | ||
const checkActiveElementInRightContentRef = (activeElement, contentRef) => { | ||
@@ -16,9 +17,13 @@ if (!contentRef().contains(activeElement)) { | ||
} | ||
let nestNodes = contentRef().querySelectorAll(`[${focusScope}]`); | ||
let isThisSomebodyIsActiveElement = Array.from(nestNodes).some(el => el.contains(activeElement)); | ||
if (isThisSomebodyIsActiveElement) { | ||
return false; | ||
} | ||
return true; | ||
}; | ||
export default (_ref => { | ||
@@ -56,7 +61,8 @@ let { | ||
threshold: 0.5 // Trigger the intersection callback when at least 50% of the target is visible | ||
}; | ||
// observing last list element to load next options while navigating down the list container | ||
}; // observing last list element to load next options while navigating down the list container | ||
const listObserver = new IntersectionObserver(entries => { | ||
const bottomList = entries[0]; | ||
if (bottomList.isIntersecting) { | ||
@@ -74,2 +80,3 @@ nextOptionsLoaded.current = true; | ||
} | ||
if (nextOptionsLoaded.current) { | ||
@@ -81,2 +88,3 @@ nextOptionsLoaded.current = false; | ||
}); | ||
if (initialListArr) { | ||
@@ -88,7 +96,10 @@ if (oldListArr.current.length !== initialListArr.length) { | ||
} | ||
let tabLooping = useEvent(event => { | ||
let activeElement = document.activeElement; | ||
if (!checkActiveElementInRightContentRef(activeElement, contentRef)) { | ||
return; | ||
} | ||
let { | ||
@@ -109,5 +120,5 @@ focusArr, | ||
let focusContainer = contentRef().closest(`[${focusContainerEle}=true]`) || contentRef(); //animation | ||
let focusedListEle = contentRef().querySelector(`[${listFocused} = true]`); | ||
// if list elements get modified, we should modify the selectedIndex. Ex: search case | ||
let focusedListEle = contentRef().querySelector(`[${listFocused} = true]`); // if list elements get modified, we should modify the selectedIndex. Ex: search case | ||
if (oldListArr.current.length !== listArr.length) { | ||
@@ -117,5 +128,5 @@ oldListArr.current = listArr; | ||
listChanged(arrowBottomListEle); | ||
} | ||
} // esc key | ||
// esc key | ||
if (event.keyCode == 27) { | ||
@@ -127,10 +138,11 @@ preventDOMAvailabllityAndFocus(newRestoreEle.el, onFocus); | ||
}); | ||
} | ||
} // enter key | ||
// enter key | ||
if (needEnterAction && event.keyCode == 13) { | ||
if (event.target && event.target.tagName.toUpperCase() !== 'TEXTAREA') { | ||
event.preventDefault(); | ||
} | ||
// event.stopPropagation(); | ||
} // event.stopPropagation(); | ||
if (focusedListEle) { | ||
@@ -143,6 +155,6 @@ selectedIndex.current > -1 && listArr[selectedIndex.current].click(); | ||
} | ||
} | ||
} //for Switch Tabs | ||
// if(isSwitchTab){ | ||
//for Switch Tabs | ||
// if(isSwitchTab){ | ||
if (event.key == 'ArrowLeft' || event.key == 'ArrowRight') { | ||
@@ -152,2 +164,3 @@ // event.preventDefault(); | ||
let currentIndex = tabArr.indexOf(activeElement); | ||
if (tabArr.includes(activeElement)) { | ||
@@ -162,6 +175,6 @@ if (event.key == 'ArrowRight') { | ||
} | ||
} | ||
// } | ||
} // } | ||
//for ArrowControls | ||
//for ArrowControls | ||
if (needListNavigation) { | ||
@@ -174,2 +187,3 @@ if (event.key === 'ArrowUp' || event.key === 'ArrowDown') { | ||
let currentIndex = listArr.includes(activeElement) ? listArr.indexOf(activeElement) : selectedIndex.current; // what if auto focus on the list element. | ||
if (isTabKeyEnabled() && focusContainer !== contentRef()) { | ||
@@ -180,2 +194,3 @@ removeFocusStyle({ | ||
} | ||
if (!isFetchingOptions) { | ||
@@ -209,2 +224,3 @@ if (event.key === 'ArrowDown') { | ||
} | ||
applyListStyle({ | ||
@@ -218,5 +234,5 @@ element: listArr[selectedIndex.current], | ||
} | ||
} | ||
} //For TabControls | ||
//For TabControls | ||
if (event.key === 'Tab' || event.keyCode === 9 && event.shiftKey) { | ||
@@ -228,2 +244,3 @@ let previousEle = focusedListEle ? focusArr[focusArr.indexOf(focusedListEle) - 1] : focusArr[focusArr.indexOf(activeElement) - 1]; | ||
}); | ||
if (isTabKeyEnabled() && focusContainer !== contentRef()) { | ||
@@ -234,2 +251,3 @@ removeFocusStyle({ | ||
} | ||
if (event.key === 'Tab' && !event.shiftKey) { | ||
@@ -257,2 +275,3 @@ if (activeElement == lastEle || focusedListEle == lastEle) { | ||
} | ||
isHiddenElement({ | ||
@@ -289,2 +308,3 @@ ele: nextEle, | ||
} | ||
isHiddenElement({ | ||
@@ -297,2 +317,3 @@ ele: previousEle, | ||
} | ||
focusedListEle && removeListStyle({ | ||
@@ -302,5 +323,4 @@ ele: focusedListEle | ||
} | ||
}); | ||
}); //To listen the focus, whenever happens within a scope | ||
//To listen the focus, whenever happens within a scope | ||
const onEleFocus = useEvent(event => { | ||
@@ -312,5 +332,4 @@ applyFocusStyle({ | ||
onFocus && onFocus(event); | ||
}); | ||
}); //To listen the blur, whenever happens within a scope | ||
//To listen the blur, whenever happens within a scope | ||
const onEleBlur = useEvent(event => { | ||
@@ -321,5 +340,4 @@ removeFocusStyle({ | ||
}); | ||
}); | ||
}); //To prevent focus style when focus happens using mouse action | ||
//To prevent focus style when focus happens using mouse action | ||
const onEleMouseDown = useEvent(event => { | ||
@@ -329,6 +347,3 @@ isArrowEvent.current = false; | ||
onEleBlur(event); | ||
}); | ||
// const isListenerAdded = contentRef() && contentRef().getAttribute('data-a11y-focus-listener') == 'true'; | ||
}); // const isListenerAdded = contentRef() && contentRef().getAttribute('data-a11y-focus-listener') == 'true'; | ||
// const onFocusOut = useEvent((event) => { | ||
@@ -340,4 +355,4 @@ // if(!contentRef().contains(event.relatedTarget)) { | ||
// }) | ||
//Adding Event Listeners to the FocusScope | ||
//Adding Event Listeners to the FocusScope | ||
let createTabLoop = useEvent(() => { | ||
@@ -350,7 +365,5 @@ listeners({ | ||
isBubbling: true | ||
}); | ||
// contentRef() && contentRef().addEventListener('focusout', onFocusOut); | ||
}); | ||
}); // contentRef() && contentRef().addEventListener('focusout', onFocusOut); | ||
}); //Removing Event Listeners to the FocusScope | ||
//Removing Event Listeners to the FocusScope | ||
let clearTabLoop = useEvent(() => { | ||
@@ -373,4 +386,5 @@ listeners({ | ||
} | ||
return clearTabLoop; | ||
}, [needListNavigation, needFocusLoop]); | ||
}); |
@@ -25,2 +25,3 @@ import React, { useEffect } from "react"; | ||
} | ||
return () => { | ||
@@ -27,0 +28,0 @@ if (contentRef && contentRef()) { |
@@ -6,3 +6,2 @@ // import { useMemo } from 'react'; | ||
// } | ||
import React, { useRef } from "react"; | ||
@@ -12,5 +11,7 @@ import uniqueNumber from './uniqueNumber'; | ||
const initialRender = useRef(''); | ||
if (initialRender.current) { | ||
return initialRender.current; | ||
} | ||
; | ||
@@ -17,0 +18,0 @@ let uid = uniqueNumber(prefix); |
@@ -26,2 +26,3 @@ import { useEffect, useRef } from 'react'; | ||
updateNodes([...restoreNodesRef.current, newRestoreEle]); | ||
if (onUpdateCallback) { | ||
@@ -44,2 +45,3 @@ updateNodes(onUpdateCallback(restoreNodesRef.current)); | ||
fireFocus(); | ||
if (restoreNodesRef.current) { | ||
@@ -50,2 +52,3 @@ updateNodes(restoreNodesRef.current.filter(item => { | ||
} | ||
if (onClearCallback) { | ||
@@ -61,4 +64,5 @@ updateNodes(onClearCallback(restoreNodesRef.current)); | ||
} | ||
return clearRestore; | ||
}, [isRestoreFocus]); | ||
}); |
@@ -6,5 +6,7 @@ import React from "react"; | ||
import defaultProps from "./props/defaultProps"; | ||
const onDocumentMouseDown = e => { | ||
clearFocusStorage(e); | ||
}; | ||
document.addEventListener('mousedown', onDocumentMouseDown); | ||
@@ -11,0 +13,0 @@ export default function FocusScope(props) { |
@@ -26,4 +26,4 @@ import { getA11yLibraryConfig, setA11yLibraryConfig } from '../../Provider/Config'; | ||
landmarkLabel: 'data-a11y-landmark-label' // value: string => To get the landmark label of an element which will be used to 'Skip navigation'. | ||
}; | ||
const { | ||
@@ -84,2 +84,3 @@ customFocusStyle, | ||
}; | ||
const findMainElement = elements => { | ||
@@ -96,6 +97,35 @@ for (let [i, element] of elements.entries()) { | ||
} | ||
return { | ||
elements | ||
}; | ||
}; | ||
}; // export const getLandmarkElements = ( element ) => { | ||
// if (element) { | ||
// let elements = []; | ||
// Object.keys(landmarkElements).forEach((ele) => { | ||
// let eleObj = landmarkElements[ele]; | ||
// if(eleObj.attributes) { | ||
// eleObj.attributes.forEach((attribute) => { | ||
// elements.push(`${ele}[${attribute}]`, `[role=${eleObj.role}][${attribute}]`) | ||
// }); | ||
// } else if(eleObj.ancestors) { | ||
// let eleSelector = `${ele}`; | ||
// let roleSelector = `[role=${eleObj.role}]`; | ||
// eleObj.ancestors.forEach((ancestor) => { | ||
// eleSelector = eleSelector + `:not(${ancestor} ${ele})`; | ||
// roleSelector = roleSelector + `:not(${ancestor} [role=${eleObj.role}])` | ||
// }); | ||
// elements.push(eleSelector, roleSelector); | ||
// } else { | ||
// elements.push(ele, `[role=${eleObj.role}]`) | ||
// } | ||
// }); | ||
// let filteredElements = elements.map(ele => ele + ':not([data-a11y-skip-landmark=true])'); | ||
// filteredElements = element && Object.values(element.querySelectorAll(filteredElements)); | ||
// const elementsObj = findMainElement(filteredElements); | ||
// return elementsObj || {}; | ||
// } | ||
// } | ||
export const getLandmarkElements = element => { | ||
@@ -106,17 +136,3 @@ if (element) { | ||
let eleObj = landmarkElements[ele]; | ||
if (eleObj.attributes) { | ||
eleObj.attributes.forEach(attribute => { | ||
elements.push(`${ele}[${attribute}]`, `[role=${eleObj.role}][${attribute}]`); | ||
}); | ||
} else if (eleObj.ancestors) { | ||
let eleSelector = `${ele}`; | ||
let roleSelector = `[role=${eleObj.role}]`; | ||
eleObj.ancestors.forEach(ancestor => { | ||
eleSelector = eleSelector + `:not(${ancestor} ${ele})`; | ||
roleSelector = roleSelector + `:not(${ancestor} [role=${eleObj.role}])`; | ||
}); | ||
elements.push(eleSelector, roleSelector); | ||
} else { | ||
elements.push(ele, `[role=${eleObj.role}]`); | ||
} | ||
elements.push(`${ele}[data-a11y-landmark-label]`, `[role=${eleObj.role}][data-a11y-landmark-label]`); | ||
}); | ||
@@ -131,2 +147,3 @@ let filteredElements = elements.map(ele => ele + ':not([data-a11y-skip-landmark=true])'); | ||
const name = ele.getAttribute('role') ? ele.getAttribute('role') : landmarkElementsObj[ele.tagName]; | ||
if (ele.getAttribute(landmarkLabel) !== null) { | ||
@@ -156,2 +173,3 @@ return ele.getAttribute(landmarkLabel); | ||
}; | ||
const getAutoFocusEle = elements => { | ||
@@ -161,2 +179,3 @@ const autoFocusEle = elements.find(ele => ele.getAttribute(autoFocus) === 'true'); | ||
}; | ||
export const getScrollContainer = container => { | ||
@@ -177,2 +196,3 @@ return container.querySelectorAll(`[${scrollContainer}=true]`)[0] || container; | ||
} = _ref; | ||
if (ele && getComputedStyle(ele).visibility == 'hidden') { | ||
@@ -185,2 +205,3 @@ ele.classList.add(style.focusVisible); | ||
} | ||
if (shiftFocus) { | ||
@@ -192,2 +213,3 @@ preventDOMAvailabllityAndFocus(ele, onFocus); | ||
let focusArr = contentRef && contentRef.querySelectorAll(TAB_ELEMENT); // All focusable Elements | ||
focusArr = focusArr && Object.values(focusArr); | ||
@@ -206,2 +228,3 @@ let firstEle = focusArr && focusArr[0]; | ||
let listArr = contentRef && contentRef.querySelectorAll(listElements); // list elements | ||
listArr = listArr && Object.values(listArr); | ||
@@ -253,4 +276,6 @@ var firstListEle = listArr && listArr[0]; | ||
} = _ref4; | ||
if (ele) { | ||
const listStyle = getA11yLibraryConfig('globalListFocusClass') || style.listFocusStyle; | ||
if (ele.getAttribute(customListStyle)) { | ||
@@ -261,2 +286,3 @@ ele.classList.remove(ele.getAttribute(customListStyle)); | ||
} | ||
ele.setAttribute(listFocused, 'false'); | ||
@@ -272,2 +298,3 @@ } | ||
} = _ref5; | ||
if (element) { | ||
@@ -278,2 +305,3 @@ if (shiftFocus) { | ||
const listStyle = getA11yLibraryConfig('globalListFocusClass') || style.listFocusStyle; | ||
if (element.getAttribute(customListStyle)) { | ||
@@ -284,2 +312,3 @@ element.classList.add(element.getAttribute(customListStyle)); | ||
} | ||
element.setAttribute(listFocused, 'true'); | ||
@@ -292,2 +321,3 @@ element.scrollIntoView({ | ||
} | ||
if (prevListEle && element !== prevListEle) { | ||
@@ -304,2 +334,3 @@ removeListStyle({ | ||
} = _ref6; | ||
if (ele) { | ||
@@ -309,2 +340,3 @@ const focusStyle = getA11yLibraryConfig('globalFocusClass') || style.focusStyle; | ||
const isApplyStyle = ele.getAttribute(needFocusStyle) === 'true' || ele.getAttribute(needFocusStyle) !== 'false' && isFocusRingEnabled && isTabKeyEnabled(); // what if we don't need focusStyle for some ares. Ex: Dialog container | ||
if (isApplyStyle) { | ||
@@ -315,2 +347,3 @@ if (ele.getAttribute(customFocusStyle)) { | ||
ele.classList.add(focusStyle); | ||
if (ele.getAttribute(insetFocus) == 'true') { | ||
@@ -321,2 +354,3 @@ ele.classList.add(style.insetFocus); | ||
} | ||
if (isArrowEventEnabled && isListEle(ele)) { | ||
@@ -340,2 +374,3 @@ applyListStyle({ | ||
}); | ||
if (isArrowEventEnabled && isListEle(ele)) { | ||
@@ -348,2 +383,3 @@ ele.setAttribute(listFocused, 'false'); | ||
let initialFocusedListEle = contentRef().querySelector(`[${listFocused} = true]`); | ||
if (initialFocusedListEle) { | ||
@@ -350,0 +386,0 @@ initialFocusedListEle && removeListStyle({ |
@@ -18,2 +18,3 @@ import { useEffect } from 'react'; | ||
} | ||
if (event.keyCode == 13) { | ||
@@ -24,2 +25,3 @@ if (isTabKeyEnabled() && document.querySelectorAll(`[data-a11y-list-active=true]`).length === 0 && event.target.click && !event.target.closest(`[${focusScope}=true]`)) { | ||
} | ||
event.target.click(); | ||
@@ -26,0 +28,0 @@ } |
@@ -12,5 +12,7 @@ import { useEffect, useState } from 'react'; | ||
const landmarkElements = getLandmarkElements(element()); | ||
const onOpenMenu = () => { | ||
!isActive && setActive(true); | ||
}; | ||
const onDocumentClick = event => { | ||
@@ -21,5 +23,7 @@ if (menuContainer.current && !menuContainer.current.contains(event.target)) { | ||
}; | ||
const onCloseMenu = () => { | ||
isActive && setActive(false); | ||
}; | ||
const onClickLandmark = ele => { | ||
@@ -33,2 +37,3 @@ setActive(false); | ||
}; | ||
useEffect(() => { | ||
@@ -35,0 +40,0 @@ element().addEventListener('click', onDocumentClick, true); |
{ | ||
"name": "@zohodesk/a11y", | ||
"version": "2.2.0", | ||
"version": "2.2.1", | ||
"main": "es/index.js", | ||
@@ -39,4 +39,4 @@ "module": "es/index.js", | ||
"devDependencies": { | ||
"@zohodesk/components": "../components" | ||
"@zohodesk/components": "1.2.29" | ||
} | ||
} |
@@ -5,2 +5,6 @@ # DOT Style Guide | ||
# 2.2.1 | ||
- **FocusScopeUtil** - `getLandmarkElements` method - Web app querySelectorAll compound selector issue fix. | ||
# 2.2.0 | ||
@@ -7,0 +11,0 @@ |
43180
110
1189