Skip to content

Commit e8d0368

Browse files
modal detecting utils
1 parent 1c15e66 commit e8d0368

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { getViewportSize } from '../../commons/dom';
2+
export default function detectModalStack(options) {
3+
options = options || {};
4+
const modalPercent = options.modalPercent || 0.75;
5+
6+
// there is no "definitive" way to code a modal so detecting when one is open
7+
// is a bit of a guess. a modal won't always be accessible, so we can't rely
8+
// on the `role` attribute, and relying on a class name as a convention is
9+
// unreliable. we also cannot rely on the body/html not scrolling.
10+
//
11+
// because of this, we will look for two different types of modals:
12+
// "definitely a modal" and "could be a modal."
13+
//
14+
// "definitely a modal" is any visible element that is coded to be a modal
15+
// by using one of the following criteria:
16+
//
17+
// - has the attribute `role=dialog`
18+
// - has the attribute `aria-modal=true`
19+
// - is the dialog element
20+
//
21+
// "could be a modal" is a visible element that takes up more than 75% of
22+
// the screen (though typically full width/height) and is the top-most element
23+
// in the viewport. since we aren't sure if it is or is not a modal this is
24+
// just our best guess of being one based on convention.
25+
26+
// if (cache.get('isModalOpen')) {
27+
// return cache.get('isModalOpen');
28+
// }
29+
30+
const definiteModals = Array.from(
31+
document.querySelectorAll(
32+
'dialog[open], [role="dialog"], [role="alertdialog"], [aria-modal="true"]'
33+
)
34+
);
35+
36+
// to find a "could be a modal" we will take the element stack from each of
37+
// four corners and one from the middle of the viewport (total of 5). if each
38+
// stack contains an element whose width/height is >= 75% of the screen, we
39+
// found a "could be a modal"
40+
const viewport = getViewportSize(window);
41+
const percentWidth = viewport.width * modalPercent;
42+
const percentHeight = viewport.height * modalPercent;
43+
const x = (viewport.width - percentWidth) / 2;
44+
const y = (viewport.height - percentHeight) / 2;
45+
46+
const points = [
47+
// top-left corner
48+
{ x, y },
49+
// top-right corner
50+
{ x: viewport.width - x, y },
51+
// center
52+
{ x: viewport.width / 2, y: viewport.height / 2 },
53+
// bottom-left corner
54+
{ x, y: viewport.height - y },
55+
// bottom-right corner
56+
{ x: viewport.width - x, y: viewport.height - y }
57+
];
58+
59+
const stacks = points.map(point => {
60+
return Array.from(document.elementsFromPoint(point.x, point.y));
61+
});
62+
63+
return { definiteModals, stacks };
64+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { getViewportSize } from '../../commons/dom';
2+
3+
export default function getOverlayFromStack(elm, options) {
4+
options = options || {};
5+
const modalPercent = options.modalPercent || 0.75;
6+
7+
const viewport = getViewportSize(window);
8+
const percentWidth = viewport.width * modalPercent;
9+
const percentHeight = viewport.height * modalPercent;
10+
11+
if (elm instanceof window.Element) {
12+
const style = window.getComputedStyle(elm);
13+
if (
14+
parseInt(style?.width, 10) >= percentWidth &&
15+
parseInt(style?.height, 10) >= percentHeight &&
16+
style?.getPropertyValue('pointer-events') !== 'none' &&
17+
(style?.position === 'absolute' || style?.position === 'fixed')
18+
) {
19+
return true;
20+
}
21+
}
22+
return false;
23+
}

lib/core/utils/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,5 @@ export { default as uniqueArray } from './unique-array';
8686
export { default as uuid } from './uuid';
8787
export { default as validInputTypes } from './valid-input-type';
8888
export { default as isValidLang, validLangs } from './valid-langs';
89+
export { default as detectModalStack } from './detect-modal-stack';
90+
export { default as getOverlayFromStack } from './get-overlay-from-stack';

0 commit comments

Comments
 (0)