@react-aria/overlays
Version:
Spectrum UI components in React
135 lines (130 loc) • 6.88 kB
JavaScript
function $parcel$export(e, n, v, s) {
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
}
$parcel$export(module.exports, "ariaHideOutside", () => $08ef1685902b6011$export$1c3ebcada18427bf);
$parcel$export(module.exports, "keepVisible", () => $08ef1685902b6011$export$1020fa7f77e17884);
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/ // Keeps a ref count of all hidden elements. Added to when hiding an element, and
// subtracted from when showing it again. When it reaches zero, aria-hidden is removed.
let $08ef1685902b6011$var$refCountMap = new WeakMap();
let $08ef1685902b6011$var$observerStack = [];
function $08ef1685902b6011$export$1c3ebcada18427bf(targets, root = document.body) {
let visibleNodes = new Set(targets);
let hiddenNodes = new Set();
let walk = (root)=>{
// Keep live announcer and top layer elements (e.g. toasts) visible.
for (let element of root.querySelectorAll('[data-live-announcer], [data-react-aria-top-layer]'))visibleNodes.add(element);
let acceptNode = (node)=>{
// Skip this node and its children if it is one of the target nodes, or a live announcer.
// Also skip children of already hidden nodes, as aria-hidden is recursive. An exception is
// made for elements with role="row" since VoiceOver on iOS has issues hiding elements with role="row".
// For that case we want to hide the cells inside as well (https://bugs.webkit.org/show_bug.cgi?id=222623).
if (visibleNodes.has(node) || node.parentElement && hiddenNodes.has(node.parentElement) && node.parentElement.getAttribute('role') !== 'row') return NodeFilter.FILTER_REJECT;
// Skip this node but continue to children if one of the targets is inside the node.
for (let target of visibleNodes){
if (node.contains(target)) return NodeFilter.FILTER_SKIP;
}
return NodeFilter.FILTER_ACCEPT;
};
let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
acceptNode: acceptNode
});
// TreeWalker does not include the root.
let acceptRoot = acceptNode(root);
if (acceptRoot === NodeFilter.FILTER_ACCEPT) hide(root);
if (acceptRoot !== NodeFilter.FILTER_REJECT) {
let node = walker.nextNode();
while(node != null){
hide(node);
node = walker.nextNode();
}
}
};
let hide = (node)=>{
var _refCountMap_get;
let refCount = (_refCountMap_get = $08ef1685902b6011$var$refCountMap.get(node)) !== null && _refCountMap_get !== void 0 ? _refCountMap_get : 0;
// If already aria-hidden, and the ref count is zero, then this element
// was already hidden and there's nothing for us to do.
if (node.getAttribute('aria-hidden') === 'true' && refCount === 0) return;
if (refCount === 0) node.setAttribute('aria-hidden', 'true');
hiddenNodes.add(node);
$08ef1685902b6011$var$refCountMap.set(node, refCount + 1);
};
// If there is already a MutationObserver listening from a previous call,
// disconnect it so the new on takes over.
if ($08ef1685902b6011$var$observerStack.length) $08ef1685902b6011$var$observerStack[$08ef1685902b6011$var$observerStack.length - 1].disconnect();
walk(root);
let observer = new MutationObserver((changes)=>{
for (let change of changes){
if (change.type !== 'childList' || change.addedNodes.length === 0) continue;
// If the parent element of the added nodes is not within one of the targets,
// and not already inside a hidden node, hide all of the new children.
if (![
...visibleNodes,
...hiddenNodes
].some((node)=>node.contains(change.target))) {
for (let node of change.removedNodes)if (node instanceof Element) {
visibleNodes.delete(node);
hiddenNodes.delete(node);
}
for (let node of change.addedNodes){
if ((node instanceof HTMLElement || node instanceof SVGElement) && (node.dataset.liveAnnouncer === 'true' || node.dataset.reactAriaTopLayer === 'true')) visibleNodes.add(node);
else if (node instanceof Element) walk(node);
}
}
}
});
observer.observe(root, {
childList: true,
subtree: true
});
let observerWrapper = {
visibleNodes: visibleNodes,
hiddenNodes: hiddenNodes,
observe () {
observer.observe(root, {
childList: true,
subtree: true
});
},
disconnect () {
observer.disconnect();
}
};
$08ef1685902b6011$var$observerStack.push(observerWrapper);
return ()=>{
observer.disconnect();
for (let node of hiddenNodes){
let count = $08ef1685902b6011$var$refCountMap.get(node);
if (count == null) continue;
if (count === 1) {
node.removeAttribute('aria-hidden');
$08ef1685902b6011$var$refCountMap.delete(node);
} else $08ef1685902b6011$var$refCountMap.set(node, count - 1);
}
// Remove this observer from the stack, and start the previous one.
if (observerWrapper === $08ef1685902b6011$var$observerStack[$08ef1685902b6011$var$observerStack.length - 1]) {
$08ef1685902b6011$var$observerStack.pop();
if ($08ef1685902b6011$var$observerStack.length) $08ef1685902b6011$var$observerStack[$08ef1685902b6011$var$observerStack.length - 1].observe();
} else $08ef1685902b6011$var$observerStack.splice($08ef1685902b6011$var$observerStack.indexOf(observerWrapper), 1);
};
}
function $08ef1685902b6011$export$1020fa7f77e17884(element) {
let observer = $08ef1685902b6011$var$observerStack[$08ef1685902b6011$var$observerStack.length - 1];
if (observer && !observer.visibleNodes.has(element)) {
observer.visibleNodes.add(element);
return ()=>{
observer.visibleNodes.delete(element);
};
}
}
//# sourceMappingURL=ariaHideOutside.main.js.map