ivt
Version:
Ivt Components Library
1,211 lines (1,187 loc) • 44.3 kB
JavaScript
import * as React from 'react';
import { useState } from 'react';
import { u as useComposedRefs } from './index-1tQVI0Jh.mjs';
import { P as Primitive } from './index-DgKlJYZP.mjs';
import { u as useCallbackRef$1 } from './index-Cbm3--wc.mjs';
import { jsx } from 'react/jsx-runtime';
import { _ as __assign, a as __rest, b as __spreadArray } from './tslib.es6-DXUeYCTx.mjs';
var AUTOFOCUS_ON_MOUNT = "focusScope.autoFocusOnMount";
var AUTOFOCUS_ON_UNMOUNT = "focusScope.autoFocusOnUnmount";
var EVENT_OPTIONS = {
bubbles: false,
cancelable: true
};
var FOCUS_SCOPE_NAME = "FocusScope";
var FocusScope = React.forwardRef((props, forwardedRef)=>{
const { loop = false, trapped = false, onMountAutoFocus: onMountAutoFocusProp, onUnmountAutoFocus: onUnmountAutoFocusProp, ...scopeProps } = props;
const [container, setContainer] = React.useState(null);
const onMountAutoFocus = useCallbackRef$1(onMountAutoFocusProp);
const onUnmountAutoFocus = useCallbackRef$1(onUnmountAutoFocusProp);
const lastFocusedElementRef = React.useRef(null);
const composedRefs = useComposedRefs(forwardedRef, (node)=>setContainer(node));
const focusScope = React.useRef({
paused: false,
pause () {
this.paused = true;
},
resume () {
this.paused = false;
}
}).current;
React.useEffect(()=>{
if (trapped) {
let handleFocusIn2 = function(event) {
if (focusScope.paused || !container) return;
const target = event.target;
if (container.contains(target)) {
lastFocusedElementRef.current = target;
} else {
focus(lastFocusedElementRef.current, {
select: true
});
}
}, handleFocusOut2 = function(event) {
if (focusScope.paused || !container) return;
const relatedTarget = event.relatedTarget;
if (relatedTarget === null) return;
if (!container.contains(relatedTarget)) {
focus(lastFocusedElementRef.current, {
select: true
});
}
}, handleMutations2 = function(mutations) {
const focusedElement = document.activeElement;
if (focusedElement !== document.body) return;
for (const mutation of mutations){
if (mutation.removedNodes.length > 0) focus(container);
}
};
document.addEventListener("focusin", handleFocusIn2);
document.addEventListener("focusout", handleFocusOut2);
const mutationObserver = new MutationObserver(handleMutations2);
if (container) mutationObserver.observe(container, {
childList: true,
subtree: true
});
return ()=>{
document.removeEventListener("focusin", handleFocusIn2);
document.removeEventListener("focusout", handleFocusOut2);
mutationObserver.disconnect();
};
}
}, [
trapped,
container,
focusScope.paused
]);
React.useEffect(()=>{
if (container) {
focusScopesStack.add(focusScope);
const previouslyFocusedElement = document.activeElement;
const hasFocusedCandidate = container.contains(previouslyFocusedElement);
if (!hasFocusedCandidate) {
const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);
container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
container.dispatchEvent(mountEvent);
if (!mountEvent.defaultPrevented) {
focusFirst(removeLinks(getTabbableCandidates(container)), {
select: true
});
if (document.activeElement === previouslyFocusedElement) {
focus(container);
}
}
}
return ()=>{
container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
setTimeout(()=>{
const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
container.dispatchEvent(unmountEvent);
if (!unmountEvent.defaultPrevented) {
focus(previouslyFocusedElement ?? document.body, {
select: true
});
}
container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
focusScopesStack.remove(focusScope);
}, 0);
};
}
}, [
container,
onMountAutoFocus,
onUnmountAutoFocus,
focusScope
]);
const handleKeyDown = React.useCallback((event)=>{
if (!loop && !trapped) return;
if (focusScope.paused) return;
const isTabKey = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
const focusedElement = document.activeElement;
if (isTabKey && focusedElement) {
const container2 = event.currentTarget;
const [first, last] = getTabbableEdges(container2);
const hasTabbableElementsInside = first && last;
if (!hasTabbableElementsInside) {
if (focusedElement === container2) event.preventDefault();
} else {
if (!event.shiftKey && focusedElement === last) {
event.preventDefault();
if (loop) focus(first, {
select: true
});
} else if (event.shiftKey && focusedElement === first) {
event.preventDefault();
if (loop) focus(last, {
select: true
});
}
}
}
}, [
loop,
trapped,
focusScope.paused
]);
return /* @__PURE__ */ jsx(Primitive.div, {
tabIndex: -1,
...scopeProps,
ref: composedRefs,
onKeyDown: handleKeyDown
});
});
FocusScope.displayName = FOCUS_SCOPE_NAME;
function focusFirst(candidates, { select = false } = {}) {
const previouslyFocusedElement = document.activeElement;
for (const candidate of candidates){
focus(candidate, {
select
});
if (document.activeElement !== previouslyFocusedElement) return;
}
}
function getTabbableEdges(container) {
const candidates = getTabbableCandidates(container);
const first = findVisible(candidates, container);
const last = findVisible(candidates.reverse(), container);
return [
first,
last
];
}
function getTabbableCandidates(container) {
const nodes = [];
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
acceptNode: (node)=>{
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
});
while(walker.nextNode())nodes.push(walker.currentNode);
return nodes;
}
function findVisible(elements, container) {
for (const element of elements){
if (!isHidden(element, {
upTo: container
})) return element;
}
}
function isHidden(node, { upTo }) {
if (getComputedStyle(node).visibility === "hidden") return true;
while(node){
if (upTo !== void 0 && node === upTo) return false;
if (getComputedStyle(node).display === "none") return true;
node = node.parentElement;
}
return false;
}
function isSelectableInput(element) {
return element instanceof HTMLInputElement && "select" in element;
}
function focus(element, { select = false } = {}) {
if (element && element.focus) {
const previouslyFocusedElement = document.activeElement;
element.focus({
preventScroll: true
});
if (element !== previouslyFocusedElement && isSelectableInput(element) && select) element.select();
}
}
var focusScopesStack = createFocusScopesStack();
function createFocusScopesStack() {
let stack = [];
return {
add (focusScope) {
const activeFocusScope = stack[0];
if (focusScope !== activeFocusScope) {
activeFocusScope?.pause();
}
stack = arrayRemove(stack, focusScope);
stack.unshift(focusScope);
},
remove (focusScope) {
stack = arrayRemove(stack, focusScope);
stack[0]?.resume();
}
};
}
function arrayRemove(array, item) {
const updatedArray = [
...array
];
const index = updatedArray.indexOf(item);
if (index !== -1) {
updatedArray.splice(index, 1);
}
return updatedArray;
}
function removeLinks(items) {
return items.filter((item)=>item.tagName !== "A");
}
var count = 0;
function useFocusGuards() {
React.useEffect(()=>{
const edgeGuards = document.querySelectorAll("[data-radix-focus-guard]");
document.body.insertAdjacentElement("afterbegin", edgeGuards[0] ?? createFocusGuard());
document.body.insertAdjacentElement("beforeend", edgeGuards[1] ?? createFocusGuard());
count++;
return ()=>{
if (count === 1) {
document.querySelectorAll("[data-radix-focus-guard]").forEach((node)=>node.remove());
}
count--;
};
}, []);
}
function createFocusGuard() {
const element = document.createElement("span");
element.setAttribute("data-radix-focus-guard", "");
element.tabIndex = 0;
element.style.outline = "none";
element.style.opacity = "0";
element.style.position = "fixed";
element.style.pointerEvents = "none";
return element;
}
var zeroRightClassName = 'right-scroll-bar-position';
var fullWidthClassName = 'width-before-scroll-bar';
var noScrollbarsClassName = 'with-scroll-bars-hidden';
/**
* Name of a CSS variable containing the amount of "hidden" scrollbar
* ! might be undefined ! use will fallback!
*/ var removedBarSizeVariable = '--removed-body-scroll-bar-size';
/**
* Assigns a value for a given ref, no matter of the ref format
* @param {RefObject} ref - a callback function or ref object
* @param value - a new value
*
* @see https://github.com/theKashey/use-callback-ref#assignref
* @example
* const refObject = useRef();
* const refFn = (ref) => {....}
*
* assignRef(refObject, "refValue");
* assignRef(refFn, "refValue");
*/ function assignRef(ref, value) {
if (typeof ref === 'function') {
ref(value);
} else if (ref) {
ref.current = value;
}
return ref;
}
/**
* creates a MutableRef with ref change callback
* @param initialValue - initial ref value
* @param {Function} callback - a callback to run when value changes
*
* @example
* const ref = useCallbackRef(0, (newValue, oldValue) => console.log(oldValue, '->', newValue);
* ref.current = 1;
* // prints 0 -> 1
*
* @see https://reactjs.org/docs/hooks-reference.html#useref
* @see https://github.com/theKashey/use-callback-ref#usecallbackref---to-replace-reactuseref
* @returns {MutableRefObject}
*/ function useCallbackRef(initialValue, callback) {
var ref = useState(function() {
return {
// value
value: initialValue,
// last callback
callback: callback,
// "memoized" public interface
facade: {
get current () {
return ref.value;
},
set current (value){
var last = ref.value;
if (last !== value) {
ref.value = value;
ref.callback(value, last);
}
}
}
};
})[0];
// update callback
ref.callback = callback;
return ref.facade;
}
var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
var currentValues = new WeakMap();
/**
* Merges two or more refs together providing a single interface to set their value
* @param {RefObject|Ref} refs
* @returns {MutableRefObject} - a new ref, which translates all changes to {refs}
*
* @see {@link mergeRefs} a version without buit-in memoization
* @see https://github.com/theKashey/use-callback-ref#usemergerefs
* @example
* const Component = React.forwardRef((props, ref) => {
* const ownRef = useRef();
* const domRef = useMergeRefs([ref, ownRef]); // 👈 merge together
* return <div ref={domRef}>...</div>
* }
*/ function useMergeRefs(refs, defaultValue) {
var callbackRef = useCallbackRef(null, function(newValue) {
return refs.forEach(function(ref) {
return assignRef(ref, newValue);
});
});
// handle refs changes - added or removed
useIsomorphicLayoutEffect(function() {
var oldValue = currentValues.get(callbackRef);
if (oldValue) {
var prevRefs_1 = new Set(oldValue);
var nextRefs_1 = new Set(refs);
var current_1 = callbackRef.current;
prevRefs_1.forEach(function(ref) {
if (!nextRefs_1.has(ref)) {
assignRef(ref, null);
}
});
nextRefs_1.forEach(function(ref) {
if (!prevRefs_1.has(ref)) {
assignRef(ref, current_1);
}
});
}
currentValues.set(callbackRef, refs);
}, [
refs
]);
return callbackRef;
}
function ItoI(a) {
return a;
}
function innerCreateMedium(defaults, middleware) {
if (middleware === void 0) {
middleware = ItoI;
}
var buffer = [];
var assigned = false;
var medium = {
read: function() {
if (assigned) {
throw new Error('Sidecar: could not `read` from an `assigned` medium. `read` could be used only with `useMedium`.');
}
if (buffer.length) {
return buffer[buffer.length - 1];
}
return defaults;
},
useMedium: function(data) {
var item = middleware(data, assigned);
buffer.push(item);
return function() {
buffer = buffer.filter(function(x) {
return x !== item;
});
};
},
assignSyncMedium: function(cb) {
assigned = true;
while(buffer.length){
var cbs = buffer;
buffer = [];
cbs.forEach(cb);
}
buffer = {
push: function(x) {
return cb(x);
},
filter: function() {
return buffer;
}
};
},
assignMedium: function(cb) {
assigned = true;
var pendingQueue = [];
if (buffer.length) {
var cbs = buffer;
buffer = [];
cbs.forEach(cb);
pendingQueue = buffer;
}
var executeQueue = function() {
var cbs = pendingQueue;
pendingQueue = [];
cbs.forEach(cb);
};
var cycle = function() {
return Promise.resolve().then(executeQueue);
};
cycle();
buffer = {
push: function(x) {
pendingQueue.push(x);
cycle();
},
filter: function(filter) {
pendingQueue = pendingQueue.filter(filter);
return buffer;
}
};
}
};
return medium;
}
// eslint-disable-next-line @typescript-eslint/ban-types
function createSidecarMedium(options) {
if (options === void 0) {
options = {};
}
var medium = innerCreateMedium(null);
medium.options = __assign({
async: true,
ssr: false
}, options);
return medium;
}
var SideCar$1 = function(_a) {
var sideCar = _a.sideCar, rest = __rest(_a, [
"sideCar"
]);
if (!sideCar) {
throw new Error('Sidecar: please provide `sideCar` property to import the right car');
}
var Target = sideCar.read();
if (!Target) {
throw new Error('Sidecar medium not found');
}
return React.createElement(Target, __assign({}, rest));
};
SideCar$1.isSideCarExport = true;
function exportSidecar(medium, exported) {
medium.useMedium(exported);
return SideCar$1;
}
var effectCar = createSidecarMedium();
var nothing = function() {
return;
};
/**
* Removes scrollbar from the page and contain the scroll within the Lock
*/ var RemoveScroll = React.forwardRef(function(props, parentRef) {
var ref = React.useRef(null);
var _a = React.useState({
onScrollCapture: nothing,
onWheelCapture: nothing,
onTouchMoveCapture: nothing
}), callbacks = _a[0], setCallbacks = _a[1];
var forwardProps = props.forwardProps, children = props.children, className = props.className, removeScrollBar = props.removeScrollBar, enabled = props.enabled, shards = props.shards, sideCar = props.sideCar, noRelative = props.noRelative, noIsolation = props.noIsolation, inert = props.inert, allowPinchZoom = props.allowPinchZoom, _b = props.as, Container = _b === void 0 ? 'div' : _b, gapMode = props.gapMode, rest = __rest(props, [
"forwardProps",
"children",
"className",
"removeScrollBar",
"enabled",
"shards",
"sideCar",
"noRelative",
"noIsolation",
"inert",
"allowPinchZoom",
"as",
"gapMode"
]);
var SideCar = sideCar;
var containerRef = useMergeRefs([
ref,
parentRef
]);
var containerProps = __assign(__assign({}, rest), callbacks);
return React.createElement(React.Fragment, null, enabled && React.createElement(SideCar, {
sideCar: effectCar,
removeScrollBar: removeScrollBar,
shards: shards,
noRelative: noRelative,
noIsolation: noIsolation,
inert: inert,
setCallbacks: setCallbacks,
allowPinchZoom: !!allowPinchZoom,
lockRef: ref,
gapMode: gapMode
}), forwardProps ? React.cloneElement(React.Children.only(children), __assign(__assign({}, containerProps), {
ref: containerRef
})) : React.createElement(Container, __assign({}, containerProps, {
className: className,
ref: containerRef
}), children));
});
RemoveScroll.defaultProps = {
enabled: true,
removeScrollBar: true,
inert: false
};
RemoveScroll.classNames = {
fullWidth: fullWidthClassName,
zeroRight: zeroRightClassName
};
var getNonce = function() {
if (typeof __webpack_nonce__ !== 'undefined') {
return __webpack_nonce__;
}
return undefined;
};
function makeStyleTag() {
if (!document) return null;
var tag = document.createElement('style');
tag.type = 'text/css';
var nonce = getNonce();
if (nonce) {
tag.setAttribute('nonce', nonce);
}
return tag;
}
function injectStyles(tag, css) {
// @ts-ignore
if (tag.styleSheet) {
// @ts-ignore
tag.styleSheet.cssText = css;
} else {
tag.appendChild(document.createTextNode(css));
}
}
function insertStyleTag(tag) {
var head = document.head || document.getElementsByTagName('head')[0];
head.appendChild(tag);
}
var stylesheetSingleton = function() {
var counter = 0;
var stylesheet = null;
return {
add: function(style) {
if (counter == 0) {
if (stylesheet = makeStyleTag()) {
injectStyles(stylesheet, style);
insertStyleTag(stylesheet);
}
}
counter++;
},
remove: function() {
counter--;
if (!counter && stylesheet) {
stylesheet.parentNode && stylesheet.parentNode.removeChild(stylesheet);
stylesheet = null;
}
}
};
};
/**
* creates a hook to control style singleton
* @see {@link styleSingleton} for a safer component version
* @example
* ```tsx
* const useStyle = styleHookSingleton();
* ///
* useStyle('body { overflow: hidden}');
*/ var styleHookSingleton = function() {
var sheet = stylesheetSingleton();
return function(styles, isDynamic) {
React.useEffect(function() {
sheet.add(styles);
return function() {
sheet.remove();
};
}, [
styles && isDynamic
]);
};
};
/**
* create a Component to add styles on demand
* - styles are added when first instance is mounted
* - styles are removed when the last instance is unmounted
* - changing styles in runtime does nothing unless dynamic is set. But with multiple components that can lead to the undefined behavior
*/ var styleSingleton = function() {
var useStyle = styleHookSingleton();
var Sheet = function(_a) {
var styles = _a.styles, dynamic = _a.dynamic;
useStyle(styles, dynamic);
return null;
};
return Sheet;
};
var zeroGap = {
left: 0,
top: 0,
right: 0,
gap: 0
};
var parse = function(x) {
return parseInt(x || '', 10) || 0;
};
var getOffset = function(gapMode) {
var cs = window.getComputedStyle(document.body);
var left = cs[gapMode === 'padding' ? 'paddingLeft' : 'marginLeft'];
var top = cs[gapMode === 'padding' ? 'paddingTop' : 'marginTop'];
var right = cs[gapMode === 'padding' ? 'paddingRight' : 'marginRight'];
return [
parse(left),
parse(top),
parse(right)
];
};
var getGapWidth = function(gapMode) {
if (gapMode === void 0) {
gapMode = 'margin';
}
if (typeof window === 'undefined') {
return zeroGap;
}
var offsets = getOffset(gapMode);
var documentWidth = document.documentElement.clientWidth;
var windowWidth = window.innerWidth;
return {
left: offsets[0],
top: offsets[1],
right: offsets[2],
gap: Math.max(0, windowWidth - documentWidth + offsets[2] - offsets[0])
};
};
var Style = styleSingleton();
var lockAttribute = 'data-scroll-locked';
// important tip - once we measure scrollBar width and remove them
// we could not repeat this operation
// thus we are using style-singleton - only the first "yet correct" style will be applied.
var getStyles = function(_a, allowRelative, gapMode, important) {
var left = _a.left, top = _a.top, right = _a.right, gap = _a.gap;
if (gapMode === void 0) {
gapMode = 'margin';
}
return "\n .".concat(noScrollbarsClassName, " {\n overflow: hidden ").concat(important, ";\n padding-right: ").concat(gap, "px ").concat(important, ";\n }\n body[").concat(lockAttribute, "] {\n overflow: hidden ").concat(important, ";\n overscroll-behavior: contain;\n ").concat([
allowRelative && "position: relative ".concat(important, ";"),
gapMode === 'margin' && "\n padding-left: ".concat(left, "px;\n padding-top: ").concat(top, "px;\n padding-right: ").concat(right, "px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(gap, "px ").concat(important, ";\n "),
gapMode === 'padding' && "padding-right: ".concat(gap, "px ").concat(important, ";")
].filter(Boolean).join(''), "\n }\n \n .").concat(zeroRightClassName, " {\n right: ").concat(gap, "px ").concat(important, ";\n }\n \n .").concat(fullWidthClassName, " {\n margin-right: ").concat(gap, "px ").concat(important, ";\n }\n \n .").concat(zeroRightClassName, " .").concat(zeroRightClassName, " {\n right: 0 ").concat(important, ";\n }\n \n .").concat(fullWidthClassName, " .").concat(fullWidthClassName, " {\n margin-right: 0 ").concat(important, ";\n }\n \n body[").concat(lockAttribute, "] {\n ").concat(removedBarSizeVariable, ": ").concat(gap, "px;\n }\n");
};
var getCurrentUseCounter = function() {
var counter = parseInt(document.body.getAttribute(lockAttribute) || '0', 10);
return isFinite(counter) ? counter : 0;
};
var useLockAttribute = function() {
React.useEffect(function() {
document.body.setAttribute(lockAttribute, (getCurrentUseCounter() + 1).toString());
return function() {
var newCounter = getCurrentUseCounter() - 1;
if (newCounter <= 0) {
document.body.removeAttribute(lockAttribute);
} else {
document.body.setAttribute(lockAttribute, newCounter.toString());
}
};
}, []);
};
/**
* Removes page scrollbar and blocks page scroll when mounted
*/ var RemoveScrollBar = function(_a) {
var noRelative = _a.noRelative, noImportant = _a.noImportant, _b = _a.gapMode, gapMode = _b === void 0 ? 'margin' : _b;
useLockAttribute();
/*
gap will be measured on every component mount
however it will be used only by the "first" invocation
due to singleton nature of <Style
*/ var gap = React.useMemo(function() {
return getGapWidth(gapMode);
}, [
gapMode
]);
return React.createElement(Style, {
styles: getStyles(gap, !noRelative, gapMode, !noImportant ? '!important' : '')
});
};
var passiveSupported = false;
if (typeof window !== 'undefined') {
try {
var options = Object.defineProperty({}, 'passive', {
get: function() {
passiveSupported = true;
return true;
}
});
// @ts-ignore
window.addEventListener('test', options, options);
// @ts-ignore
window.removeEventListener('test', options, options);
} catch (err) {
passiveSupported = false;
}
}
var nonPassive = passiveSupported ? {
passive: false
} : false;
var alwaysContainsScroll = function(node) {
// textarea will always _contain_ scroll inside self. It only can be hidden
return node.tagName === 'TEXTAREA';
};
var elementCanBeScrolled = function(node, overflow) {
if (!(node instanceof Element)) {
return false;
}
var styles = window.getComputedStyle(node);
return(// not-not-scrollable
styles[overflow] !== 'hidden' && // contains scroll inside self
!(styles.overflowY === styles.overflowX && !alwaysContainsScroll(node) && styles[overflow] === 'visible'));
};
var elementCouldBeVScrolled = function(node) {
return elementCanBeScrolled(node, 'overflowY');
};
var elementCouldBeHScrolled = function(node) {
return elementCanBeScrolled(node, 'overflowX');
};
var locationCouldBeScrolled = function(axis, node) {
var ownerDocument = node.ownerDocument;
var current = node;
do {
// Skip over shadow root
if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
current = current.host;
}
var isScrollable = elementCouldBeScrolled(axis, current);
if (isScrollable) {
var _a = getScrollVariables(axis, current), scrollHeight = _a[1], clientHeight = _a[2];
if (scrollHeight > clientHeight) {
return true;
}
}
current = current.parentNode;
}while (current && current !== ownerDocument.body)
return false;
};
var getVScrollVariables = function(_a) {
var scrollTop = _a.scrollTop, scrollHeight = _a.scrollHeight, clientHeight = _a.clientHeight;
return [
scrollTop,
scrollHeight,
clientHeight
];
};
var getHScrollVariables = function(_a) {
var scrollLeft = _a.scrollLeft, scrollWidth = _a.scrollWidth, clientWidth = _a.clientWidth;
return [
scrollLeft,
scrollWidth,
clientWidth
];
};
var elementCouldBeScrolled = function(axis, node) {
return axis === 'v' ? elementCouldBeVScrolled(node) : elementCouldBeHScrolled(node);
};
var getScrollVariables = function(axis, node) {
return axis === 'v' ? getVScrollVariables(node) : getHScrollVariables(node);
};
var getDirectionFactor = function(axis, direction) {
/**
* If the element's direction is rtl (right-to-left), then scrollLeft is 0 when the scrollbar is at its rightmost position,
* and then increasingly negative as you scroll towards the end of the content.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
*/ return axis === 'h' && direction === 'rtl' ? -1 : 1;
};
var handleScroll = function(axis, endTarget, event, sourceDelta, noOverscroll) {
var directionFactor = getDirectionFactor(axis, window.getComputedStyle(endTarget).direction);
var delta = directionFactor * sourceDelta;
// find scrollable target
var target = event.target;
var targetInLock = endTarget.contains(target);
var shouldCancelScroll = false;
var isDeltaPositive = delta > 0;
var availableScroll = 0;
var availableScrollTop = 0;
do {
if (!target) {
break;
}
var _a = getScrollVariables(axis, target), position = _a[0], scroll_1 = _a[1], capacity = _a[2];
var elementScroll = scroll_1 - capacity - directionFactor * position;
if (position || elementScroll) {
if (elementCouldBeScrolled(axis, target)) {
availableScroll += elementScroll;
availableScrollTop += position;
}
}
var parent_1 = target.parentNode;
// we will "bubble" from ShadowDom in case we are, or just to the parent in normal case
// this is the same logic used in focus-lock
target = parent_1 && parent_1.nodeType === Node.DOCUMENT_FRAGMENT_NODE ? parent_1.host : parent_1;
}while (// portaled content
!targetInLock && target !== document.body || // self content
targetInLock && (endTarget.contains(target) || endTarget === target))
// handle epsilon around 0 (non standard zoom levels)
if (isDeltaPositive && (Math.abs(availableScroll) < 1 || false)) {
shouldCancelScroll = true;
} else if (!isDeltaPositive && (Math.abs(availableScrollTop) < 1 || false)) {
shouldCancelScroll = true;
}
return shouldCancelScroll;
};
var getTouchXY = function(event) {
return 'changedTouches' in event ? [
event.changedTouches[0].clientX,
event.changedTouches[0].clientY
] : [
0,
0
];
};
var getDeltaXY = function(event) {
return [
event.deltaX,
event.deltaY
];
};
var extractRef = function(ref) {
return ref && 'current' in ref ? ref.current : ref;
};
var deltaCompare = function(x, y) {
return x[0] === y[0] && x[1] === y[1];
};
var generateStyle = function(id) {
return "\n .block-interactivity-".concat(id, " {pointer-events: none;}\n .allow-interactivity-").concat(id, " {pointer-events: all;}\n");
};
var idCounter = 0;
var lockStack = [];
function RemoveScrollSideCar(props) {
var shouldPreventQueue = React.useRef([]);
var touchStartRef = React.useRef([
0,
0
]);
var activeAxis = React.useRef();
var id = React.useState(idCounter++)[0];
var Style = React.useState(styleSingleton)[0];
var lastProps = React.useRef(props);
React.useEffect(function() {
lastProps.current = props;
}, [
props
]);
React.useEffect(function() {
if (props.inert) {
document.body.classList.add("block-interactivity-".concat(id));
var allow_1 = __spreadArray([
props.lockRef.current
], (props.shards || []).map(extractRef), true).filter(Boolean);
allow_1.forEach(function(el) {
return el.classList.add("allow-interactivity-".concat(id));
});
return function() {
document.body.classList.remove("block-interactivity-".concat(id));
allow_1.forEach(function(el) {
return el.classList.remove("allow-interactivity-".concat(id));
});
};
}
return;
}, [
props.inert,
props.lockRef.current,
props.shards
]);
var shouldCancelEvent = React.useCallback(function(event, parent) {
if ('touches' in event && event.touches.length === 2 || event.type === 'wheel' && event.ctrlKey) {
return !lastProps.current.allowPinchZoom;
}
var touch = getTouchXY(event);
var touchStart = touchStartRef.current;
var deltaX = 'deltaX' in event ? event.deltaX : touchStart[0] - touch[0];
var deltaY = 'deltaY' in event ? event.deltaY : touchStart[1] - touch[1];
var currentAxis;
var target = event.target;
var moveDirection = Math.abs(deltaX) > Math.abs(deltaY) ? 'h' : 'v';
// allow horizontal touch move on Range inputs. They will not cause any scroll
if ('touches' in event && moveDirection === 'h' && target.type === 'range') {
return false;
}
var canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
if (!canBeScrolledInMainDirection) {
return true;
}
if (canBeScrolledInMainDirection) {
currentAxis = moveDirection;
} else {
currentAxis = moveDirection === 'v' ? 'h' : 'v';
canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
// other axis might be not scrollable
}
if (!canBeScrolledInMainDirection) {
return false;
}
if (!activeAxis.current && 'changedTouches' in event && (deltaX || deltaY)) {
activeAxis.current = currentAxis;
}
if (!currentAxis) {
return true;
}
var cancelingAxis = activeAxis.current || currentAxis;
return handleScroll(cancelingAxis, parent, event, cancelingAxis === 'h' ? deltaX : deltaY);
}, []);
var shouldPrevent = React.useCallback(function(_event) {
var event = _event;
if (!lockStack.length || lockStack[lockStack.length - 1] !== Style) {
// not the last active
return;
}
var delta = 'deltaY' in event ? getDeltaXY(event) : getTouchXY(event);
var sourceEvent = shouldPreventQueue.current.filter(function(e) {
return e.name === event.type && (e.target === event.target || event.target === e.shadowParent) && deltaCompare(e.delta, delta);
})[0];
// self event, and should be canceled
if (sourceEvent && sourceEvent.should) {
if (event.cancelable) {
event.preventDefault();
}
return;
}
// outside or shard event
if (!sourceEvent) {
var shardNodes = (lastProps.current.shards || []).map(extractRef).filter(Boolean).filter(function(node) {
return node.contains(event.target);
});
var shouldStop = shardNodes.length > 0 ? shouldCancelEvent(event, shardNodes[0]) : !lastProps.current.noIsolation;
if (shouldStop) {
if (event.cancelable) {
event.preventDefault();
}
}
}
}, []);
var shouldCancel = React.useCallback(function(name, delta, target, should) {
var event = {
name: name,
delta: delta,
target: target,
should: should,
shadowParent: getOutermostShadowParent(target)
};
shouldPreventQueue.current.push(event);
setTimeout(function() {
shouldPreventQueue.current = shouldPreventQueue.current.filter(function(e) {
return e !== event;
});
}, 1);
}, []);
var scrollTouchStart = React.useCallback(function(event) {
touchStartRef.current = getTouchXY(event);
activeAxis.current = undefined;
}, []);
var scrollWheel = React.useCallback(function(event) {
shouldCancel(event.type, getDeltaXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
}, []);
var scrollTouchMove = React.useCallback(function(event) {
shouldCancel(event.type, getTouchXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
}, []);
React.useEffect(function() {
lockStack.push(Style);
props.setCallbacks({
onScrollCapture: scrollWheel,
onWheelCapture: scrollWheel,
onTouchMoveCapture: scrollTouchMove
});
document.addEventListener('wheel', shouldPrevent, nonPassive);
document.addEventListener('touchmove', shouldPrevent, nonPassive);
document.addEventListener('touchstart', scrollTouchStart, nonPassive);
return function() {
lockStack = lockStack.filter(function(inst) {
return inst !== Style;
});
document.removeEventListener('wheel', shouldPrevent, nonPassive);
document.removeEventListener('touchmove', shouldPrevent, nonPassive);
document.removeEventListener('touchstart', scrollTouchStart, nonPassive);
};
}, []);
var removeScrollBar = props.removeScrollBar, inert = props.inert;
return React.createElement(React.Fragment, null, inert ? React.createElement(Style, {
styles: generateStyle(id)
}) : null, removeScrollBar ? React.createElement(RemoveScrollBar, {
noRelative: props.noRelative,
gapMode: props.gapMode
}) : null);
}
function getOutermostShadowParent(node) {
var shadowParent = null;
while(node !== null){
if (node instanceof ShadowRoot) {
shadowParent = node.host;
node = node.host;
}
node = node.parentNode;
}
return shadowParent;
}
var SideCar = exportSidecar(effectCar, RemoveScrollSideCar);
var ReactRemoveScroll = React.forwardRef(function(props, ref) {
return React.createElement(RemoveScroll, __assign({}, props, {
ref: ref,
sideCar: SideCar
}));
});
ReactRemoveScroll.classNames = RemoveScroll.classNames;
var getDefaultParent = function(originalTarget) {
if (typeof document === 'undefined') {
return null;
}
var sampleTarget = Array.isArray(originalTarget) ? originalTarget[0] : originalTarget;
return sampleTarget.ownerDocument.body;
};
var counterMap = new WeakMap();
var uncontrolledNodes = new WeakMap();
var markerMap = {};
var lockCount = 0;
var unwrapHost = function(node) {
return node && (node.host || unwrapHost(node.parentNode));
};
var correctTargets = function(parent, targets) {
return targets.map(function(target) {
if (parent.contains(target)) {
return target;
}
var correctedTarget = unwrapHost(target);
if (correctedTarget && parent.contains(correctedTarget)) {
return correctedTarget;
}
console.error('aria-hidden', target, 'in not contained inside', parent, '. Doing nothing');
return null;
}).filter(function(x) {
return Boolean(x);
});
};
/**
* Marks everything except given node(or nodes) as aria-hidden
* @param {Element | Element[]} originalTarget - elements to keep on the page
* @param [parentNode] - top element, defaults to document.body
* @param {String} [markerName] - a special attribute to mark every node
* @param {String} [controlAttribute] - html Attribute to control
* @return {Undo} undo command
*/ var applyAttributeToOthers = function(originalTarget, parentNode, markerName, controlAttribute) {
var targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [
originalTarget
]);
if (!markerMap[markerName]) {
markerMap[markerName] = new WeakMap();
}
var markerCounter = markerMap[markerName];
var hiddenNodes = [];
var elementsToKeep = new Set();
var elementsToStop = new Set(targets);
var keep = function(el) {
if (!el || elementsToKeep.has(el)) {
return;
}
elementsToKeep.add(el);
keep(el.parentNode);
};
targets.forEach(keep);
var deep = function(parent) {
if (!parent || elementsToStop.has(parent)) {
return;
}
Array.prototype.forEach.call(parent.children, function(node) {
if (elementsToKeep.has(node)) {
deep(node);
} else {
try {
var attr = node.getAttribute(controlAttribute);
var alreadyHidden = attr !== null && attr !== 'false';
var counterValue = (counterMap.get(node) || 0) + 1;
var markerValue = (markerCounter.get(node) || 0) + 1;
counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);
hiddenNodes.push(node);
if (counterValue === 1 && alreadyHidden) {
uncontrolledNodes.set(node, true);
}
if (markerValue === 1) {
node.setAttribute(markerName, 'true');
}
if (!alreadyHidden) {
node.setAttribute(controlAttribute, 'true');
}
} catch (e) {
console.error('aria-hidden: cannot operate on ', node, e);
}
}
});
};
deep(parentNode);
elementsToKeep.clear();
lockCount++;
return function() {
hiddenNodes.forEach(function(node) {
var counterValue = counterMap.get(node) - 1;
var markerValue = markerCounter.get(node) - 1;
counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);
if (!counterValue) {
if (!uncontrolledNodes.has(node)) {
node.removeAttribute(controlAttribute);
}
uncontrolledNodes.delete(node);
}
if (!markerValue) {
node.removeAttribute(markerName);
}
});
lockCount--;
if (!lockCount) {
// clear
counterMap = new WeakMap();
counterMap = new WeakMap();
uncontrolledNodes = new WeakMap();
markerMap = {};
}
};
};
/**
* Marks everything except given node(or nodes) as aria-hidden
* @param {Element | Element[]} originalTarget - elements to keep on the page
* @param [parentNode] - top element, defaults to document.body
* @param {String} [markerName] - a special attribute to mark every node
* @return {Undo} undo command
*/ var hideOthers = function(originalTarget, parentNode, markerName) {
if (markerName === void 0) {
markerName = 'data-aria-hidden';
}
var targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [
originalTarget
]);
var activeParentNode = getDefaultParent(originalTarget);
if (!activeParentNode) {
return function() {
return null;
};
}
// we should not hide aria-live elements - https://github.com/theKashey/aria-hidden/issues/10
// and script elements, as they have no impact on accessibility.
targets.push.apply(targets, Array.from(activeParentNode.querySelectorAll('[aria-live], script')));
return applyAttributeToOthers(targets, activeParentNode, markerName, 'aria-hidden');
};
export { FocusScope as F, ReactRemoveScroll as R, hideOthers as h, useFocusGuards as u };
//# sourceMappingURL=index-DvCZGX3H.mjs.map