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

solid-dismiss

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

solid-dismiss - npm Package Compare versions

Comparing version 1.0.2 to 1.0.3

dist/source/globalEvents.js

682

dist/esm/index.js

@@ -1,2 +0,2 @@

import { template, setAttribute, effect, delegateEvents, createComponent, insert, Portal, style, classList } from 'solid-js/web';
import { template, setAttribute, effect, delegateEvents, createComponent, insert, Portal, style as style$1, classList } from 'solid-js/web';
import { createUniqueId, onMount, createEffect, on, onCleanup, Show } from 'solid-js';

@@ -27,7 +27,8 @@

};
const focusableSelectors = 'button, [href], input, select, textarea, details, [contentEditable=true], [tabindex]:not([tabindex="-1"])';
const getNextFocusableElement = ({
const _tabbableSelectors = ["a[href]", "area[href]", "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", "button:not([disabled])", "iframe", "[tabindex]", "[contentEditable=true]"].reduce((a, c, idx) => `${a}${idx ? "," : ""}${c}:not([tabindex="-1"])`, "");
const getNextTabbableElement = ({
from = document.activeElement,
stopAtElement,
ignoreElement = [],
allowSelectors,
direction = "forwards"

@@ -37,4 +38,24 @@ }) => {

const visitedElement = from;
const tabbableSelectors = _tabbableSelectors + (allowSelectors ? "," + allowSelectors.join(",") : "");
if (!visitedElement) return null;
const getIframeDocument = iframe => {
try {
return iframe.contentDocument;
} catch (e) {
return null;
}
};
const queryIframe = (el, inverseQuery) => {
if (!el) return null;
if (el.tagName !== "IFRAME") return el;
const iframeDocument = getIframeDocument(el);
if (!iframeDocument) return el;
const tabindex = el.getAttribute("tabindex");
if (tabindex) return el;
const result = inverseQuery ? inverseQuerySelector(iframeDocument, tabbableSelectors) : iframeDocument.querySelector(tabbableSelectors);
return queryIframe(result);
};
const traverseNextSiblingsThenUp = (parent, visitedElement) => {

@@ -51,5 +72,16 @@ let hasPassedVisitedElement = false;

if (ignoreElement.some(el => el === child)) continue;
if (child.matches(focusableSelectors)) return child;
const el = child.querySelector(focusableSelectors);
if (el) return el;
if (child.matches(tabbableSelectors)) {
const el = queryIframe(child);
if (el) return el;
return child;
}
let el = child.querySelector(tabbableSelectors);
el = queryIframe(el);
if (el) {
return el;
}
continue;

@@ -73,4 +105,11 @@ }

if (ignoreElement.some(el => el === child)) continue;
if (child.matches(focusableSelectors)) return child;
const el = inverseQuerySelector(child, focusableSelectors);
if (child.matches(tabbableSelectors)) {
const el = queryIframe(child);
if (el) return el;
return child;
}
let el = inverseQuerySelector(child, tabbableSelectors);
el = queryIframe(el, true);
if (el) return el;

@@ -128,3 +167,54 @@ continue;

};
const matchByFirstChild = ({
parent,
matchEl
}) => {
if (parent === matchEl) return true;
const query = el => {
if (!el) return false;
const child = el.children[0];
if (child === matchEl) {
return true;
}
return query(child);
};
return query(parent);
};
let style;
const initStyleElement = id => {
if (style) {
updateIframeStyle({
id
});
return;
}
style = document.createElement("style");
style.type = "text/css";
updateIframeStyle({
id
});
document.head.appendChild(style);
};
const updateIframeStyle = ({
id,
clear
}) => {
// iframe {
// pointer-events: none !important;
// }
//
// [data-solid-dismiss-dropdown-container="${id}"] iframe {
// pointer-events: unset !important;
// }
const stylesheet = !clear ? `
` : "";
style.textContent = stylesheet;
};
const dismissStack = [];

@@ -159,2 +249,12 @@ const addDismissStack = props => {

if (prevStack) {
updateIframeStyle({
id: prevStack.uniqueId
});
} else {
updateIframeStyle({
clear: true
});
}
const foundStack = dismissStack[foundIdx];

@@ -453,2 +553,3 @@ dismissStack.splice(foundIdx, 1);

let init = true;
console.log("createResizeObserver!!");
resizeObserver = new ResizeObserver(() => {

@@ -479,2 +580,3 @@ if (init) {

if (resizeObserver) {
console.log("remove resize observer!");
resizeObserver.disconnect();

@@ -613,3 +715,3 @@ resizeObserver = null;

setAttribute(_el$12, "solid-dismiss-overlay-mask", id);
setAttribute(_el$12, "data-solid-dismiss-overlay-mask", id);

@@ -649,5 +751,302 @@ effect(() => setAttribute(_el$, "viewBox", `0 0 ${overlaySize.width} ${overlaySize.height}`));

const _tmpl$ = template(`<div></div>`, 2),
_tmpl$2 = template(`<div role="presentation"></div>`, 2),
_tmpl$3 = template(`<div tabindex="0" style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true"></div>`, 2);
let cachedScrollTarget;
let cachedPolledElement = null;
let pollTimeoutId = null;
const onWindowBlur = () => {
const item = dismissStack[dismissStack.length - 1];
const onBlurWindow = item => {
if (!item.closeWhenDocumentBlurs) return;
item.menuBtnEl.focus();
item.setOpen(false);
};
if (item.overlay) return;
setTimeout(() => {
const activeElement = document.activeElement;
if (!activeElement || activeElement.tagName !== "IFRAME") {
checkThenClose(dismissStack, item => item, item => onBlurWindow(item));
return;
}
checkThenClose(dismissStack, item => {
const {
menuPopupEl
} = item;
if (menuPopupEl.contains(activeElement)) {
cachedPolledElement = activeElement;
pollingIframe();
document.addEventListener("visibilitychange", onVisibilityChange);
return;
}
return item;
}, item => item.setOpen(false)); // if (menuPopupEl.contains(activeElement)) {
// cachedPolledElement = activeElement;
//
// pollingIframe();
//
// document.addEventListener("visibilitychange", onVisibilityChange);
//
// return;
// }
//
// item.setOpen(false);
// exit();
});
};
const onKeyDown = e => {
const {
setOpen,
menuBtnEl,
cursorKeys,
closeWhenEscapeKeyIsPressed,
focusElementOnClose
} = dismissStack[dismissStack.length - 1];
if (cursorKeys) {
onCursorKeys(e);
}
if (e.key !== "Escape" || !closeWhenEscapeKeyIsPressed) return;
const el = queryElement(focusElementOnClose, "focusElementOnClose", "escapeKey") || menuBtnEl;
if (el) {
el.focus();
}
setOpen(false);
};
const onScrollClose = e => {
const target = e.target;
if (cachedScrollTarget === target) return; // const exit = (item: TDismissStack) => {
// item.setOpen(false);
// const el =
// queryElement(
// item.focusElementOnClose,
// "focusElementOnClose",
// "scrolling"
// ) || item.menuBtnEl;
//
// if (el) {
// el.focus();
// }
// };
console.log("run expensive");
checkThenClose(dismissStack, item => {
const {
menuPopupEl
} = item;
if (menuPopupEl.contains(target)) {
cachedScrollTarget = target;
return null;
}
return item;
}, item => {
item.setOpen(false);
const el = queryElement(item.focusElementOnClose, "focusElementOnClose", "scrolling") || item.menuBtnEl;
if (el) {
el.focus();
}
}); // for (let i = dismissStack.length - 1; i >= 0; i--) {
// const item = dismissStack[i];
// const { menuPopupEl } = item;
//
// if (menuPopupEl!.contains(target)) {
// cachedScrollTarget = target;
// return;
// }
//
// exit(item);
// }
};
/**
* Iterate stack backwards, checks item, pass it close callback. First falsy value breaks iteration.
*/
const checkThenClose = (arr, checkCb, destroyCb) => {
for (let i = arr.length - 1; i >= 0; i--) {
const item = checkCb(arr[i]);
if (item) {
destroyCb(item);
continue;
}
return;
}
};
const addGlobalEvents = () => {
cachedScrollTarget = null;
if (dismissStack.length) return;
console.log("addGlobalEvents");
document.addEventListener("keydown", onKeyDown);
window.addEventListener("blur", onWindowBlur);
window.addEventListener("scroll", onScrollClose, {
capture: true,
passive: true
});
};
const removeGlobalEvents = () => {
if (dismissStack.length) return;
console.log("removeGlobalEvents");
document.removeEventListener("keydown", onKeyDown);
window.removeEventListener("blur", onWindowBlur);
window.removeEventListener("scroll", onScrollClose, {
capture: true
});
};
const onCursorKeys = e => {
const keys = ["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"];
const horizontalKeys = ["ArrowLeft", "ArrowRight"];
if (!keys.includes(e.key)) return;
e.preventDefault();
if (horizontalKeys.includes(e.key)) return;
const {
menuBtnEl,
menuPopupEl
} = dismissStack[dismissStack.length - 1];
const activeElement = document.activeElement;
if (activeElement === menuBtnEl || activeElement === menuPopupEl) {
const el = e.key === "ArrowDown" ? menuPopupEl?.querySelector(_tabbableSelectors) : inverseQuerySelector(menuPopupEl, _tabbableSelectors);
if (el) {
el.focus();
}
return;
}
const direction = e.key === "ArrowDown" ? "forwards" : "backwards";
const el = getNextTabbableElement({
from: activeElement,
direction,
stopAtElement: menuPopupEl
});
if (el) {
el.focus();
}
};
const onVisibilityChange = () => {
if (document.visibilityState === "visible" && pollTimeoutId != null) {
pollingIframe();
return;
}
clearInterval(pollTimeoutId);
}; // polls iframe to deal with edge case if menuPopup item selected is an iframe and then select another iframe that is "outside" of menuPopup
const pollingIframe = () => {
// worst case scenerio is user has to wait for up to 300ms for menuPop to close, while average case is 150ms
const duration = 300;
const poll = () => {
const activeElement = document.activeElement;
console.log("polling");
if (!activeElement) {
return;
}
if (cachedPolledElement === activeElement) {
pollTimeoutId = window.setTimeout(poll, duration);
return;
}
checkThenClose(dismissStack, item => {
const {
menuPopupEl
} = item;
if (menuPopupEl && menuPopupEl.contains(activeElement)) {
cachedPolledElement = activeElement;
pollTimeoutId = window.setTimeout(poll, duration);
return;
}
return item;
}, item => {
item.setOpen(false);
cachedPolledElement = null;
pollTimeoutId = null;
document.removeEventListener("visibilitychange", onVisibilityChange);
}); // const { menuPopupEl, setOpen } = dismissStack[dismissStack.length - 1];
//
// if (menuPopupEl && menuPopupEl.contains(activeElement)) {
// cachedPolledElement = activeElement;
// pollTimeoutId = window.setTimeout(poll, duration);
// return;
// }
// setOpen(false);
// cachedPolledElement = null;
// pollTimeoutId = null;
// document.removeEventListener("visibilitychange", onVisibilityChange);
};
pollTimeoutId = window.setTimeout(poll, duration);
};
const queryElement = (inputElement, type, subType) => {
if (typeof inputElement === "string") {
return document.querySelector(inputElement);
}
if (inputElement instanceof Element) {
return inputElement;
}
if (typeof inputElement === "function") {
const result = inputElement();
if (result instanceof Element) {
return result;
}
}
if (type === "focusElementOnClose") {
if (!inputElement) return null;
switch (subType) {
case "tabForwards":
return queryElement(inputElement.tabForwards);
case "tabBackwards":
return queryElement(inputElement.tabBackwards);
case "click":
return queryElement(inputElement.click);
case "escapeKey":
return queryElement(inputElement.escapeKey);
case "scrolling":
return queryElement(inputElement.scrolling);
}
}
if (inputElement == null) return null;
for (const key in inputElement) {
const item = inputElement[key];
return queryElement(item);
}
return null;
};
const _tmpl$ = template(`<div><div tabindex="0" style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true"></div><div style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true"></div></div>`, 6),
_tmpl$2 = template(`<div></div>`, 2),
_tmpl$3 = template(`<div role="presentation"></div>`, 2);
// buttons can't receive focus on tap, only through invoking `focus()` method

@@ -669,4 +1068,4 @@ // blur (tested so far on only buttons) will fire even on tapping same focused button (which would be invoked `focus()` )

menuPopup,
focusElWhenClosed,
focusElWhenOpened,
focusElementOnClose,
focusElementOnOpen,
closeButton,

@@ -678,11 +1077,13 @@ children,

closeWhenScrolling = false,
closeWhenWindowBlurs = false,
closeWhenDocumentBlurs = false,
closeWhenClickedOutside = true,
closeWhenEscapeKeyIsPressed = true,
overlay = false,
trapFocus = false,
removeScrollbar = false,
useAriaExpanded = false
useAriaExpanded = false,
mountedElseWhere = false
} = props;
const uniqueId = createUniqueId();
const hasFocusSentinels = focusElWhenClosed || overlay === "backdrop" || trapFocus;
const uniqueId = createUniqueId().replace(/\:/g, "-");
const hasFocusSentinels = focusElementOnClose || overlay === "backdrop" || trapFocus || mountedElseWhere;
let closeBtn = [];

@@ -702,2 +1103,6 @@ let menuPopupEl = null;

let prevFocusedEl = null;
let pollTimeoutId = null;
let containerFocusTimeoutId = null;
let menuButtonBlurTimeoutId = null;
const initDefer = !props.open(); // issue where it doesn't close following these steps: clicking menuPopup -> outside iframe -> open -> menuPopup -> devtools -> window.

@@ -713,9 +1118,15 @@ const refContainerCb = el => {

let containerFocusTimeoutId = null;
let menuButtonBlurTimeoutId = null;
const initDefer = !props.open();
const activateLastFocusSentinel = () => {
if (mountedElseWhere) return;
const menuBtnSibling = menuBtnEl.nextElementSibling;
if (matchByFirstChild({
parent: menuBtnSibling,
matchEl: containerEl
})) return;
focusSentinelLastEl.setAttribute("tabindex", "0");
};
const runFocusOnActive = () => {
if (focusElWhenOpened == null) return;
const el = queryElement(focusElWhenOpened);
if (focusElementOnOpen == null) return;
const el = queryElement(focusElementOnOpen);

@@ -732,72 +1143,2 @@ if (el) {

const onCursorKeys = e => {
const keys = ["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"];
const horizontalKeys = ["ArrowLeft", "ArrowRight"];
if (!keys.includes(e.key)) return;
e.preventDefault();
if (horizontalKeys.includes(e.key)) return;
const {
menuBtnEl,
menuPopupEl
} = dismissStack[dismissStack.length - 1];
const activeElement = document.activeElement;
if (activeElement === menuBtnEl || activeElement === menuPopupEl) {
const el = e.key === "ArrowDown" ? menuPopupEl?.querySelector(focusableSelectors) : inverseQuerySelector(menuPopupEl, focusableSelectors);
if (el) {
el.focus();
}
return;
}
const direction = e.key === "ArrowDown" ? "forwards" : "backwards";
const el = getNextFocusableElement({
from: activeElement,
direction,
stopAtElement: menuPopupEl
});
if (el) {
el.focus();
}
};
const onKeyDown = e => {
if (cursorKeys) {
onCursorKeys(e);
}
if (e.key !== "Escape") return;
const item = dismissStack[dismissStack.length - 1];
if (!item) return;
const el = queryElement(focusElWhenClosed, "focusOnLeave", "escapeKey") || item.menuBtnEl;
if (el) {
el.focus();
}
item.setOpen(false);
};
const onScrollClose = e => {
const target = e.target;
if (target.contains(menuBtnEl)) {
props.setOpen(false);
}
const el = queryElement(focusElWhenClosed, "focusOnLeave", "scrolling") || menuBtnEl;
if (el) {
el.focus();
}
};
const onWindowBlur = () => {
menuBtnEl.focus();
props.setOpen(false);
};
const onClickOverlay = () => {

@@ -813,3 +1154,3 @@ console.log({

const el = queryElement(focusElWhenClosed, "focusOnLeave", "click") || menuBtnEl;
const el = queryElement(focusElementOnClose, "focusElementOnClose", "click") || menuBtnEl;

@@ -883,3 +1224,3 @@ if (el) {

e.preventDefault();
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelFirstEl

@@ -920,2 +1261,3 @@ });

if (!prevFocusedEl) return;
console.log("removeOutsideFocusEvents");
prevFocusedEl.removeEventListener("focus", onFocusFromOutsideAppOrTab);

@@ -927,5 +1269,5 @@ document.removeEventListener("click", onClickDocument);

const onFocusOutContainer = e => {
console.log("runfocusout!!!");
const relatedTarget = e.relatedTarget;
if (focusElWhenClosed || overlay === "backdrop") {
if (focusElementOnClose || overlay === "backdrop") {
e.stopImmediatePropagation();

@@ -936,3 +1278,3 @@ }

if (!e.relatedTarget) {
if (!relatedTarget) {
if (addedFocusOutAppEvents) return;

@@ -977,3 +1319,3 @@ addedFocusOutAppEvents = true;

if (relatedTarget === containerEl || relatedTarget === menuBtnEl) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelFirstEl

@@ -987,3 +1329,3 @@ });

if (trapFocus) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelLastEl,

@@ -1002,3 +1344,3 @@ direction: "backwards"

const el = queryElement(focusElWhenClosed, "focusOnLeave", "tabBackwards") || menuBtnEl;
const el = queryElement(focusElementOnClose, "focusElementOnClose", "tabBackwards") || menuBtnEl;

@@ -1017,3 +1359,3 @@ if (el) {

if (trapFocus) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelFirstEl

@@ -1025,3 +1367,3 @@ });

const el = queryElement(focusElWhenClosed, "focusOnLeave", "tabForwards") || getNextFocusableElement({
const el = queryElement(focusElementOnClose, "focusElementOnClose", "tabForwards") || getNextTabbableElement({
from: menuBtnEl,

@@ -1050,4 +1392,3 @@ ignoreElement: [containerEl]

if (menuPopupEl) return menuPopupEl;
if (hasFocusSentinels) return containerEl.children[1];
return containerEl.children[0];
return containerEl.children[1];
}

@@ -1085,3 +1426,3 @@

if (type === "focusOnLeave") {
if (type === "focusElementOnClose") {
if (!inputElement) return null;

@@ -1182,2 +1523,9 @@

const removeMenuPopupEl = () => {
if (!menuPopupEl) return;
if (!menuPopupAdded) return;
menuPopupEl = null;
menuPopupAdded = false;
};
const runRemoveScrollbar = open => {

@@ -1202,9 +1550,2 @@ if (!removeScrollbar) return;

const removeMenuPopupEl = () => {
if (!menuPopupEl) return;
if (!menuPopupAdded) return;
menuPopupEl = null;
menuPopupAdded = false;
};
const onFocusMenuButton = () => {

@@ -1235,16 +1576,2 @@ if (!closeWhenMenuButtonIsTabbed) {

if (open === prevOpen) return;
if (closeWhenScrolling) {
window.addEventListener("scroll", onScrollClose, {
once: true,
capture: true
});
}
if (closeWhenWindowBlurs) {
window.addEventListener("blur", onWindowBlur, {
once: true
});
}
runAriaExpanded(open);

@@ -1256,8 +1583,3 @@

runFocusOnActive();
if (!addedKeydownListener) {
addedKeydownListener = true;
document.addEventListener("keydown", onKeyDown);
}
addGlobalEvents();
addDismissStack({

@@ -1274,2 +1596,6 @@ id,

overlay: typeof overlay === "object" ? "clipped" : overlay,
closeWhenDocumentBlurs,
closeWhenEscapeKeyIsPressed,
cursorKeys,
focusElementOnClose,
detectIfMenuButtonObscured: typeof overlay === "object" ? overlay.clipped.detectIfMenuButtonObscured == null ? true : overlay.clipped.detectIfMenuButtonObscured : true

@@ -1282,3 +1608,7 @@ });

}
activateLastFocusSentinel();
initStyleElement(uniqueId);
} else {
clearTimeout(pollTimeoutId);
removeOutsideFocusEvents();

@@ -1289,3 +1619,2 @@ removeMenuPopupEl();

const stack = removeDismissStack(uniqueId);
console.log("on false");

@@ -1296,8 +1625,4 @@ if (isOverlayClipped) {

removeGlobalEvents();
runRemoveScrollbar(open);
if (dismissStack.length < 1) {
addedKeydownListener = false;
document.removeEventListener("keydown", onKeyDown);
}
}

@@ -1320,4 +1645,4 @@ }, {

onCleanup(() => {
document.removeEventListener("keydown", onKeyDown);
menuBtnEl.removeEventListener("click", onClickMenuButton);
document.removeEventListener("click", onClickDocument);
removeCloseButtons();

@@ -1332,2 +1657,3 @@ removeMenuPopupEl();

removeGlobalEvents();
console.log("onCleanup");

@@ -1341,3 +1667,5 @@ });

get children() {
const _el$ = _tmpl$.cloneNode(true);
const _el$ = _tmpl$.cloneNode(true),
_el$2 = _el$.firstChild,
_el$3 = _el$2.nextSibling;

@@ -1351,13 +1679,13 @@ const _ref$ = refContainerCb;

setAttribute(_el$, "data-solid-dismiss-dropdown-container", id);
setAttribute(_el$, "data-solid-dismiss-dropdown-container", uniqueId);
insert(_el$, isOverlayClipped && createComponent(Portal, {
get children() {
const _el$2 = _tmpl$.cloneNode(true);
const _el$4 = _tmpl$2.cloneNode(true);
const _ref$2 = overlayEl;
typeof _ref$2 === "function" ? _ref$2(_el$2) : overlayEl = _el$2;
_el$2.$$click = onClickOverlay;
const _ref$4 = overlayEl;
typeof _ref$4 === "function" ? _ref$4(_el$4) : overlayEl = _el$4;
_el$4.$$click = onClickOverlay;
setAttribute(_el$2, "solid-dismiss-overlay-clipped", id);
setAttribute(_el$4, "data-solid-dismiss-overlay-clipped", id);

@@ -1367,4 +1695,4 @@ effect(_p$ => {

_v$5 = dismissStack.length;
_p$._v$4 = style(_el$2, _v$4, _p$._v$4);
_v$5 !== _p$._v$5 && setAttribute(_el$2, "solid-dismiss-overlay-clipped-level", _p$._v$5 = _v$5);
_p$._v$4 = style$1(_el$4, _v$4, _p$._v$4);
_v$5 !== _p$._v$5 && setAttribute(_el$4, "data-solid-dismiss-overlay-clipped-level", _p$._v$5 = _v$5);
return _p$;

@@ -1376,16 +1704,16 @@ }, {

return _el$2;
return _el$4;
}
}), null);
}), _el$2);
insert(_el$, overlay === "backdrop" && createComponent(Portal, {
get children() {
const _el$3 = _tmpl$2.cloneNode(true);
const _el$5 = _tmpl$3.cloneNode(true);
const _ref$3 = overlayEl;
typeof _ref$3 === "function" ? _ref$3(_el$3) : overlayEl = _el$3;
_el$3.$$click = onClickOverlay;
const _ref$5 = overlayEl;
typeof _ref$5 === "function" ? _ref$5(_el$5) : overlayEl = _el$5;
_el$5.$$click = onClickOverlay;
setAttribute(_el$3, "solid-dismiss-overlay-backdrop", id);
setAttribute(_el$5, "data-solid-dismiss-overlay-backdrop", id);

@@ -1395,4 +1723,4 @@ effect(_p$ => {

_v$7 = `position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: ${999 + dismissStack.length};`;
_v$6 !== _p$._v$6 && setAttribute(_el$3, "solid-dismiss-overlay-backdrop-level", _p$._v$6 = _v$6);
_p$._v$7 = style(_el$3, _v$7, _p$._v$7);
_v$6 !== _p$._v$6 && setAttribute(_el$5, "data-solid-dismiss-overlay-backdrop-level", _p$._v$6 = _v$6);
_p$._v$7 = style$1(_el$5, _v$7, _p$._v$7);
return _p$;

@@ -1404,33 +1732,25 @@ }, {

return _el$3;
return _el$5;
}
}), null);
}), _el$2);
insert(_el$, hasFocusSentinels && (() => {
const _el$4 = _tmpl$3.cloneNode(true);
const _ref$2 = focusSentinelFirstEl;
typeof _ref$2 === "function" ? _ref$2(_el$2) : focusSentinelFirstEl = _el$2;
const _ref$4 = focusSentinelFirstEl;
typeof _ref$4 === "function" ? _ref$4(_el$4) : focusSentinelFirstEl = _el$4;
_el$2.addEventListener("focus", e => {
onFocusSentinel("first", e.relatedTarget);
});
_el$4.addEventListener("focus", e => {
onFocusSentinel("first", e.relatedTarget);
});
insert(_el$, children, _el$3);
return _el$4;
})(), null);
const _ref$3 = focusSentinelLastEl;
typeof _ref$3 === "function" ? _ref$3(_el$3) : focusSentinelLastEl = _el$3;
insert(_el$, children, null);
_el$3.addEventListener("focus", () => onFocusSentinel("last"));
insert(_el$, hasFocusSentinels && (() => {
const _el$5 = _tmpl$3.cloneNode(true);
setAttribute(_el$3, "tabindex", hasFocusSentinels ? "0" : "-1");
const _ref$5 = focusSentinelLastEl;
typeof _ref$5 === "function" ? _ref$5(_el$5) : focusSentinelLastEl = _el$5;
setAttribute(_el$3, "data-solid-dismiss-focus-sentinel-last", uniqueId);
_el$5.addEventListener("focus", () => onFocusSentinel("last"));
return _el$5;
})(), null);
effect(_p$ => {

@@ -1443,3 +1763,3 @@ const _v$ = props.class,

_p$._v$2 = classList(_el$, _v$2, _p$._v$2);
_p$._v$3 = style(_el$, _v$3, _p$._v$3);
_p$._v$3 = style$1(_el$, _v$3, _p$._v$3);
return _p$;

@@ -1458,4 +1778,2 @@ }, {

let addedKeydownListener = false;
delegateEvents(["focusin", "focusout", "click"]);

@@ -1462,0 +1780,0 @@

@@ -255,2 +255,3 @@ import { dismissStack } from "./dismissStack";

let init = true;
console.log("createResizeObserver!!");
resizeObserver = new ResizeObserver(() => {

@@ -278,2 +279,3 @@ if (init) {

if (resizeObserver) {
console.log("remove resize observer!");
resizeObserver.disconnect();

@@ -356,3 +358,3 @@ resizeObserver = null;

<path clip-path={`url(#${clipPathMenuPopupId})`} d={navBarPath || ""} style="pointer-events: all" fill="none"/>
<path mask={`url(#${maskId})`} d={bgCoverPath} solid-dismiss-overlay-mask={id} fill="none" style="pointer-events: none"/>
<path mask={`url(#${maskId})`} d={bgCoverPath} data-solid-dismiss-overlay-mask={id} fill="none" style="pointer-events: none"/>
</svg>);

@@ -359,0 +361,0 @@ overlayEl.style.cssText = style;

@@ -0,1 +1,2 @@

import { updateIframeStyle } from "./stylesheet";
export const dismissStack = [];

@@ -30,2 +31,8 @@ export const addDismissStack = (props) => {

}
if (prevStack) {
updateIframeStyle({ id: prevStack.uniqueId });
}
else {
updateIframeStyle({ clear: true });
}
const foundStack = dismissStack[foundIdx];

@@ -32,0 +39,0 @@ dismissStack.splice(foundIdx, 1);

import "./browserInfo";
import { Show, onMount, createEffect, onCleanup, on, createUniqueId, } from "solid-js";
import { Portal } from "solid-js/web";
import { focusableSelectors, getNextFocusableElement, inverseQuerySelector, } from "./utils";
import { getNextTabbableElement, matchByFirstChild } from "./utils";
import { dismissStack, addDismissStack, removeDismissStack, } from "./dismissStack";
import { mountOverlayClipped, removeOverlayEvents, updateSVG, } from "./clippedOverlay";
import { initStyleElement } from "./stylesheet";
import { addGlobalEvents, removeGlobalEvents } from "./globalEvents";
// Safari iOS notes

@@ -18,5 +20,8 @@ // buttons can't receive focus on tap, only through invoking `focus()` method

const Dismiss = (props) => {
const { id = "", menuButton, menuPopup, focusElWhenClosed, focusElWhenOpened, closeButton, children, cursorKeys = false, closeWhenMenuButtonIsTabbed = false, closeWhenMenuButtonIsClicked = true, closeWhenScrolling = false, closeWhenWindowBlurs = false, closeWhenClickedOutside = true, overlay = false, trapFocus = false, removeScrollbar = false, useAriaExpanded = false, } = props;
const uniqueId = createUniqueId();
const hasFocusSentinels = focusElWhenClosed || overlay === "backdrop" || trapFocus;
const { id = "", menuButton, menuPopup, focusElementOnClose, focusElementOnOpen, closeButton, children, cursorKeys = false, closeWhenMenuButtonIsTabbed = false, closeWhenMenuButtonIsClicked = true, closeWhenScrolling = false, closeWhenDocumentBlurs = false, closeWhenClickedOutside = true, closeWhenEscapeKeyIsPressed = true, overlay = false, trapFocus = false, removeScrollbar = false, useAriaExpanded = false, mountedElseWhere = false, } = props;
const uniqueId = createUniqueId().replace(/\:/g, "-");
const hasFocusSentinels = focusElementOnClose ||
overlay === "backdrop" ||
trapFocus ||
mountedElseWhere;
let closeBtn = [];

@@ -36,2 +41,8 @@ let menuPopupEl = null;

let prevFocusedEl = null;
let cachedPolledElement = null;
let pollTimeoutId = null;
let containerFocusTimeoutId = null;
let menuButtonBlurTimeoutId = null;
const initDefer = !props.open();
// issue where it doesn't close following these steps: clicking menuPopup -> outside iframe -> open -> menuPopup -> devtools -> window.
const refContainerCb = (el) => {

@@ -44,16 +55,17 @@ if (props.ref) {

};
const refOverlayCb = (el) => {
if (props.ref) {
// @ts-ignore
props.ref(el);
}
containerEl = el;
const activateLastFocusSentinel = () => {
if (mountedElseWhere)
return;
const menuBtnSibling = menuBtnEl.nextElementSibling;
if (matchByFirstChild({
parent: menuBtnSibling,
matchEl: containerEl,
}))
return;
focusSentinelLastEl.setAttribute("tabindex", "0");
};
let containerFocusTimeoutId = null;
let menuButtonBlurTimeoutId = null;
const initDefer = !props.open();
const runFocusOnActive = () => {
if (focusElWhenOpened == null)
if (focusElementOnOpen == null)
return;
const el = queryElement(focusElWhenOpened);
const el = queryElement(focusElementOnOpen);
if (el) {

@@ -68,61 +80,2 @@ el.focus();

};
const onCursorKeys = (e) => {
const keys = ["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"];
const horizontalKeys = ["ArrowLeft", "ArrowRight"];
if (!keys.includes(e.key))
return;
e.preventDefault();
if (horizontalKeys.includes(e.key))
return;
const { menuBtnEl, menuPopupEl } = dismissStack[dismissStack.length - 1];
const activeElement = document.activeElement;
if (activeElement === menuBtnEl || activeElement === menuPopupEl) {
const el = e.key === "ArrowDown"
? menuPopupEl?.querySelector(focusableSelectors)
: inverseQuerySelector(menuPopupEl, focusableSelectors);
if (el) {
el.focus();
}
return;
}
const direction = e.key === "ArrowDown" ? "forwards" : "backwards";
const el = getNextFocusableElement({
from: activeElement,
direction,
stopAtElement: menuPopupEl,
});
if (el) {
el.focus();
}
};
const onKeyDown = (e) => {
if (cursorKeys) {
onCursorKeys(e);
}
if (e.key !== "Escape")
return;
const item = dismissStack[dismissStack.length - 1];
if (!item)
return;
const el = queryElement(focusElWhenClosed, "focusOnLeave", "escapeKey") ||
item.menuBtnEl;
if (el) {
el.focus();
}
item.setOpen(false);
};
const onScrollClose = (e) => {
const target = e.target;
if (target.contains(menuBtnEl)) {
props.setOpen(false);
}
const el = queryElement(focusElWhenClosed, "focusOnLeave", "scrolling") || menuBtnEl;
if (el) {
el.focus();
}
};
const onWindowBlur = () => {
menuBtnEl.focus();
props.setOpen(false);
};
const onClickOverlay = () => {

@@ -134,3 +87,4 @@ console.log({ closeWhenClickedOutside });

}
const el = queryElement(focusElWhenClosed, "focusOnLeave", "click") || menuBtnEl;
const el = queryElement(focusElementOnClose, "focusElementOnClose", "click") ||
menuBtnEl;
if (el) {

@@ -190,3 +144,3 @@ el.focus();

e.preventDefault();
const el = getNextFocusableElement({ from: focusSentinelFirstEl });
const el = getNextTabbableElement({ from: focusSentinelFirstEl });
if (el) {

@@ -222,2 +176,3 @@ el.focus();

return;
console.log("removeOutsideFocusEvents");
prevFocusedEl.removeEventListener("focus", onFocusFromOutsideAppOrTab);

@@ -228,4 +183,4 @@ document.removeEventListener("click", onClickDocument);

const onFocusOutContainer = (e) => {
console.log("runfocusout!!!");
if (focusElWhenClosed || overlay === "backdrop") {
const relatedTarget = e.relatedTarget;
if (focusElementOnClose || overlay === "backdrop") {
e.stopImmediatePropagation();

@@ -235,3 +190,3 @@ }

return;
if (!e.relatedTarget) {
if (!relatedTarget) {
if (addedFocusOutAppEvents)

@@ -269,3 +224,3 @@ return;

if (relatedTarget === containerEl || relatedTarget === menuBtnEl) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelFirstEl,

@@ -278,3 +233,3 @@ });

if (trapFocus) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelLastEl,

@@ -291,4 +246,3 @@ direction: "backwards",

}
const el = queryElement(focusElWhenClosed, "focusOnLeave", "tabBackwards") ||
menuBtnEl;
const el = queryElement(focusElementOnClose, "focusElementOnClose", "tabBackwards") || menuBtnEl;
if (el) {

@@ -303,3 +257,3 @@ el.focus();

if (trapFocus) {
const el = getNextFocusableElement({
const el = getNextTabbableElement({
from: focusSentinelFirstEl,

@@ -310,4 +264,4 @@ });

}
const el = queryElement(focusElWhenClosed, "focusOnLeave", "tabForwards") ||
getNextFocusableElement({
const el = queryElement(focusElementOnClose, "focusElementOnClose", "tabForwards") ||
getNextTabbableElement({
from: menuBtnEl,

@@ -333,5 +287,3 @@ ignoreElement: [containerEl],

return menuPopupEl;
if (hasFocusSentinels)
return containerEl.children[1];
return containerEl.children[0];
return containerEl.children[1];
}

@@ -363,3 +315,3 @@ if (typeof inputElement === "string" && type === "menuButton") {

}
if (type === "focusOnLeave") {
if (type === "focusElementOnClose") {
if (!inputElement)

@@ -448,2 +400,10 @@ return null;

};
const removeMenuPopupEl = () => {
if (!menuPopupEl)
return;
if (!menuPopupAdded)
return;
menuPopupEl = null;
menuPopupAdded = false;
};
const runRemoveScrollbar = (open) => {

@@ -467,10 +427,2 @@ if (!removeScrollbar)

};
const removeMenuPopupEl = () => {
if (!menuPopupEl)
return;
if (!menuPopupAdded)
return;
menuPopupEl = null;
menuPopupAdded = false;
};
const onFocusMenuButton = () => {

@@ -499,11 +451,2 @@ if (!closeWhenMenuButtonIsTabbed) {

return;
if (closeWhenScrolling) {
window.addEventListener("scroll", onScrollClose, {
once: true,
capture: true,
});
}
if (closeWhenWindowBlurs) {
window.addEventListener("blur", onWindowBlur, { once: true });
}
runAriaExpanded(open);

@@ -514,6 +457,3 @@ if (open) {

runFocusOnActive();
if (!addedKeydownListener) {
addedKeydownListener = true;
document.addEventListener("keydown", onKeyDown);
}
addGlobalEvents();
addDismissStack({

@@ -530,2 +470,6 @@ id,

overlay: typeof overlay === "object" ? "clipped" : overlay,
closeWhenDocumentBlurs,
closeWhenEscapeKeyIsPressed,
cursorKeys,
focusElementOnClose,
detectIfMenuButtonObscured: typeof overlay === "object"

@@ -541,4 +485,7 @@ ? overlay.clipped.detectIfMenuButtonObscured == null

}
activateLastFocusSentinel();
initStyleElement(uniqueId);
}
else {
clearTimeout(pollTimeoutId);
removeOutsideFocusEvents();

@@ -549,11 +496,7 @@ removeMenuPopupEl();

const stack = removeDismissStack(uniqueId);
console.log("on false");
if (isOverlayClipped) {
removeOverlayEvents(stack);
}
removeGlobalEvents();
runRemoveScrollbar(open);
if (dismissStack.length < 1) {
addedKeydownListener = false;
document.removeEventListener("keydown", onKeyDown);
}
}

@@ -572,4 +515,4 @@ }, { defer: initDefer }));

onCleanup(() => {
document.removeEventListener("keydown", onKeyDown);
menuBtnEl.removeEventListener("click", onClickMenuButton);
document.removeEventListener("click", onClickDocument);
removeCloseButtons();

@@ -582,21 +525,21 @@ removeMenuPopupEl();

}
removeGlobalEvents();
console.log("onCleanup");
});
return (<Show when={props.open()}>
<div id={id} class={props.class} data-solid-dismiss-dropdown-container={id} classList={props.classList || {}} onFocusIn={onFocusInContainer} onFocusOut={onFocusOutContainer} style={overlay === "backdrop" ? `z-index: ${1000 + dismissStack.length}` : ""} ref={refContainerCb}>
<div id={id} class={props.class} data-solid-dismiss-dropdown-container={uniqueId} classList={props.classList || {}} onFocusIn={onFocusInContainer} onFocusOut={onFocusOutContainer} style={overlay === "backdrop" ? `z-index: ${1000 + dismissStack.length}` : ""} ref={refContainerCb}>
{isOverlayClipped && (<Portal>
<div style={`position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: ${999 + dismissStack.length};`} solid-dismiss-overlay-clipped={id} solid-dismiss-overlay-clipped-level={dismissStack.length} onClick={onClickOverlay} ref={overlayEl}></div>
<div style={`position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: ${999 + dismissStack.length};`} data-solid-dismiss-overlay-clipped={id} data-solid-dismiss-overlay-clipped-level={dismissStack.length} onClick={onClickOverlay} ref={overlayEl}></div>
</Portal>)}
{overlay === "backdrop" && (<Portal>
<div role="presentation" solid-dismiss-overlay-backdrop={id} solid-dismiss-overlay-backdrop-level={dismissStack.length} onClick={onClickOverlay} style={`position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: ${999 + dismissStack.length};`} ref={overlayEl}></div>
<div role="presentation" data-solid-dismiss-overlay-backdrop={id} data-solid-dismiss-overlay-backdrop-level={dismissStack.length} onClick={onClickOverlay} style={`position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: ${999 + dismissStack.length};`} ref={overlayEl}></div>
</Portal>)}
{hasFocusSentinels && (<div tabindex="0" onFocus={(e) => {
onFocusSentinel("first", e.relatedTarget);
}} style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true" ref={focusSentinelFirstEl}></div>)}
<div tabindex="0" onFocus={(e) => {
onFocusSentinel("first", e.relatedTarget);
}} style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true" ref={focusSentinelFirstEl}></div>
{children}
{hasFocusSentinels && (<div tabindex="0" onFocus={() => onFocusSentinel("last")} style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true" ref={focusSentinelLastEl}></div>)}
<div tabindex={hasFocusSentinels ? "0" : "-1"} onFocus={() => onFocusSentinel("last")} style="position: absolute; top: 0; left: 0; outline: none; pointer-events: none; width: 0; height: 0;" aria-hidden="true" data-solid-dismiss-focus-sentinel-last={uniqueId} ref={focusSentinelLastEl}></div>
</div>
</Show>);
};
let addedKeydownListener = false;
export default Dismiss;

@@ -7,8 +7,43 @@ export const parseValToNum = (value) => {

};
export const focusableSelectors = 'button, [href], input, select, textarea, details, [contentEditable=true], [tabindex]:not([tabindex="-1"])';
export const getNextFocusableElement = ({ from = document.activeElement, stopAtElement, ignoreElement = [], direction = "forwards", }) => {
export const _tabbableSelectors = [
"a[href]",
"area[href]",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
"button:not([disabled])",
"iframe",
"[tabindex]",
"[contentEditable=true]",
].reduce((a, c, idx) => `${a}${idx ? "," : ""}${c}:not([tabindex="-1"])`, "");
export const getNextTabbableElement = ({ from = document.activeElement, stopAtElement, ignoreElement = [], allowSelectors, direction = "forwards", }) => {
const parent = from.parentElement;
const visitedElement = from;
const tabbableSelectors = _tabbableSelectors + (allowSelectors ? "," + allowSelectors.join(",") : "");
if (!visitedElement)
return null;
const getIframeDocument = (iframe) => {
try {
return iframe.contentDocument;
}
catch (e) {
return null;
}
};
const queryIframe = (el, inverseQuery) => {
if (!el)
return null;
if (el.tagName !== "IFRAME")
return el;
const iframeDocument = getIframeDocument(el);
if (!iframeDocument)
return el;
const tabindex = el.getAttribute("tabindex");
if (tabindex)
return el;
const result = inverseQuery
? inverseQuerySelector(iframeDocument, tabbableSelectors)
: iframeDocument.querySelector(tabbableSelectors);
return queryIframe(result);
};
const traverseNextSiblingsThenUp = (parent, visitedElement) => {

@@ -24,7 +59,13 @@ let hasPassedVisitedElement = false;

continue;
if (child.matches(focusableSelectors))
if (child.matches(tabbableSelectors)) {
const el = queryIframe(child);
if (el)
return el;
return child;
const el = child.querySelector(focusableSelectors);
if (el)
}
let el = child.querySelector(tabbableSelectors);
el = queryIframe(el);
if (el) {
return el;
}
continue;

@@ -47,5 +88,10 @@ }

continue;
if (child.matches(focusableSelectors))
if (child.matches(tabbableSelectors)) {
const el = queryIframe(child);
if (el)
return el;
return child;
const el = inverseQuerySelector(child, focusableSelectors);
}
let el = inverseQuerySelector(child, tabbableSelectors);
el = queryIframe(el, true);
if (el)

@@ -95,1 +141,15 @@ return el;

};
export const matchByFirstChild = ({ parent, matchEl, }) => {
if (parent === matchEl)
return true;
const query = (el) => {
if (!el)
return false;
const child = el.children[0];
if (child === matchEl) {
return true;
}
return query(child);
};
return query(parent);
};

@@ -1,2 +0,39 @@

import { Accessor } from "solid-js";
import { Accessor, JSX } from "solid-js";
export declare type TFocusElementOnClose = "menuButton" | string | JSX.Element | {
/**
* Default: menuButton
*
* focus on element when exiting menuPopup via tabbing backwards ie "Shift + Tab".
*
*/
tabBackwards?: "menuButton" | string | JSX.Element;
/**
* Default: next tabbable element after menuButton;
*
* focus on element when exiting menuPopup via tabbing forwards ie "Tab".
*
* Note: If popup is mounted elsewhere in the DOM, when tabbing outside, this library is able to grab the correct next tabbable element after menuButton, except for tabbable elements inside iframe with cross domain.
*/
tabForwards?: "menuButton" | string | JSX.Element;
/**
* focus on element when exiting menuPopup via click outside popup.
*
* If overlay present, and popup closes via click, then menuButton will be focused.
*
* Note: When clicking, user-agent determines which element recieves focus, to prevent this, use `overlay` prop.
*/
click?: "menuButton" | string | JSX.Element;
/**
* Default: menuButton
*
* focus on element when exiting menuPopup via "Escape" key
*/
escapeKey?: "menuButton" | string | JSX.Element;
/**
* Default: menuButton
*
* focus on element when exiting menuPopup via scrolling, from scrollable container that contains menuButton
*/
scrolling?: "menuButton" | string | JSX.Element;
};
export declare type TDismissStack = {

@@ -14,2 +51,6 @@ id: string;

detectIfMenuButtonObscured: boolean;
closeWhenDocumentBlurs: boolean;
cursorKeys: boolean;
closeWhenEscapeKeyIsPressed: boolean;
focusElementOnClose: TFocusElementOnClose;
};

@@ -16,0 +57,0 @@ export declare const dismissStack: TDismissStack[];

import "./browserInfo";
import { Accessor, Component, JSX } from "solid-js";
import { TDismissStack } from "./dismissStack";
import { TDismissStack, TFocusElementOnClose } from "./dismissStack";
/**

@@ -51,43 +51,20 @@ *

*
* *selector: css string queried from document, or if string value is `"menuPopup"` uses menuPopup element.
* *css string queried from document, or if string value is `"menuPopup"` uses menuPopup element.
*/
focusElWhenOpened?: "menuPopup" | string | JSX.Element | (() => JSX.Element);
focusElementOnOpen?: "menuPopup" | string | JSX.Element | (() => JSX.Element);
/**
* Default: When Tabbing forwards, focuses on focusable element after menuButton. When Tabbing backwards, focuses on menuButton. When pressing Escape key, menuButton will be focused. When "click", user-agent determines which element recieves focus, if overlay present, then menuButton will be focused instead.
* Default: When Tabbing forwards, focuses on tabbable element*¹ after menuButton. When Tabbing backwards, focuses on menuButton. When pressing Escape key, menuButton will be focused. When "click"*³, user-agent determines which element recieves focus, if overlay present, then menuButton will be focused instead.
*
* Which element, via selector*, to recieve focus after popup closes.
* Which element, via selector*², to recieve focus after popup closes.
*
* *selector: css string queried from document, or if string value is `"menuButton"` uses menuButton element
*
* An example would be to emulate native <select> element behavior, set which sets focus to menuButton after dismiss.
*
* Note: When clicking, user-agent determines which element recieves focus, to prevent this, use `overlay` prop.
* *¹ If menuPopup is mounted elsewhere in the DOM or doesn't share the same parent as menuButton, when tabbing outside menuPopup, this library programmatically grabs the correct next tabbable element after menuButton. However if that next tabbable element is inside an iframe that has different origin, then this library won't be able to grab tabbable elements inside it, instead the iframe will be focused.
*
* *² selector: css string queried from document, or if string value is `"menuButton"` uses menuButton element
*
* *³ When clicking, user-agent determines which element recieves focus, to prevent this, use `overlay` prop.
*
*/
focusElWhenClosed?: "menuButton" | string | JSX.Element | {
/**
* focus on element when exiting menuPopup via tabbing backwards ie "Shift + Tab".
*/
tabBackwards?: "menuButton" | string | JSX.Element;
/**
* focus on element when exiting menuPopup via tabbing forwards ie "Tab".
*/
tabForwards?: "menuButton" | string | JSX.Element;
/**
* focus on element when exiting menuPopup via click outside popup.
*
* If overlay present, and popup closes via click, then menuButton will be focused.
*
* Note: When clicking, user-agent determines which element recieves focus, to prevent this, use `overlay` prop.
*/
click?: "menuButton" | string | JSX.Element;
/**
* focus on element when exiting menuPopup via "Escape" key
*/
escapeKey?: "menuButton" | string | JSX.Element;
/**
* focus on element when exiting menuPopup via scrolling, from scrollable container that contains menuButton
*/
scrolling?: "menuButton" | string | JSX.Element;
};
focusElementOnClose?: TFocusElementOnClose;
/**

@@ -109,3 +86,5 @@ * Default: `false`

*
* Closes menuPopup when a scrollable container that contains menuButton is scrolled
* Closes menuPopup when any scrollable container (except inside menuPopup) is scrolled
*
* If `true` and `overlay` is not set, scrolling "outside" iframe won't be able to close menuPopup.
*/

@@ -120,7 +99,13 @@ closeWhenScrolling?: boolean;

/**
* Default: `true`
*
* Closes menuPopup when escape key is pressed
*/
closeWhenEscapeKeyIsPressed?: boolean;
/**
* Default: `false`
*
* Closes when viewport window "blurs". This would happen when interacting outside of the page such as Devtools, changing browser tabs, or switch different applications.
* Closes when the document "blurs". This would happen when interacting outside of the page such as Devtools, changing browser tabs, or switch different applications.
*/
closeWhenWindowBlurs?: boolean;
closeWhenDocumentBlurs?: boolean;
/**

@@ -179,2 +164,10 @@ * Default: `false`

useAriaExpanded?: boolean;
/**
* Default: `false`
*
* If `true` activates sentinel element as last tabbable item in menuPopup, that way when Tabbing "forwards" out of menuPopup, the next logical tabblable element after menuButton will be focused.
*
* Is set to `true`: `overlay` prop has `"backdrop"` property. This component's root container is not an adjacent sibling of menuButton. `focusElWhenClosed` prop has a value.
*/
mountedElseWhere?: boolean;
open: Accessor<boolean>;

@@ -181,0 +174,0 @@ setOpen: (v: boolean) => void;

export declare const parseValToNum: (value?: string | number) => number;
export declare const focusableSelectors = "button, [href], input, select, textarea, details, [contentEditable=true], [tabindex]:not([tabindex=\"-1\"])";
export declare const getNextFocusableElement: ({ from, stopAtElement, ignoreElement, direction, }: {
export declare const _tabbableSelectors: string;
export declare const getNextTabbableElement: ({ from, stopAtElement, ignoreElement, allowSelectors, direction, }: {
from: Element;
stopAtElement?: HTMLElement;
ignoreElement?: HTMLElement[];
allowSelectors?: string[];
direction?: "forwards" | "backwards";

@@ -14,1 +15,5 @@ }) => HTMLElement;

export declare const inverseQuerySelector: (el: Element, selector: string) => HTMLElement | null;
export declare const matchByFirstChild: ({ parent, matchEl, }: {
parent: HTMLElement | Element;
matchEl: HTMLElement;
}) => boolean;
{
"name": "solid-dismiss",
"version": "1.0.2",
"version": "1.0.3",
"homepage": "https://aquaductape.github.io/solid-dismiss/",

@@ -38,4 +38,5 @@ "description": "Handles \"click outside\" behavior for popup menu. Closing is triggered by click/focus outside of popup element or pressing \"Escape\" key.",

"release": "release-it",
"start": "cd demo && pnpm start",
"demo-deploy": "cd demo && ./deploy.sh"
"dev": "cd demo && pnpm start",
"demo-deploy": "cd demo && ./deploy.sh",
"demo-deploy-quick": "git add . && git commit -m 'update' && cd demo && ./deploy.sh"
},

@@ -42,0 +43,0 @@ "repository": {

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