UNPKG

8.45 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5Object.defineProperty(exports, "__esModule", {
6 value: true
7});
8exports.ariaHidden = ariaHidden;
9exports.default = void 0;
10
11var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
12
13var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
14
15var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
16
17var _getScrollbarSize = _interopRequireDefault(require("../utils/getScrollbarSize"));
18
19var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument"));
20
21var _ownerWindow = _interopRequireDefault(require("../utils/ownerWindow"));
22
23// Is a vertical scrollbar displayed?
24function isOverflowing(container) {
25 var doc = (0, _ownerDocument.default)(container);
26
27 if (doc.body === container) {
28 return (0, _ownerWindow.default)(doc).innerWidth > doc.documentElement.clientWidth;
29 }
30
31 return container.scrollHeight > container.clientHeight;
32}
33
34function ariaHidden(node, show) {
35 if (show) {
36 node.setAttribute('aria-hidden', 'true');
37 } else {
38 node.removeAttribute('aria-hidden');
39 }
40}
41
42function getPaddingRight(node) {
43 return parseInt(window.getComputedStyle(node)['padding-right'], 10) || 0;
44}
45
46function ariaHiddenSiblings(container, mountNode, currentNode) {
47 var nodesToExclude = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
48 var show = arguments.length > 4 ? arguments[4] : undefined;
49 var blacklist = [mountNode, currentNode].concat((0, _toConsumableArray2.default)(nodesToExclude));
50 var blacklistTagNames = ['TEMPLATE', 'SCRIPT', 'STYLE'];
51 [].forEach.call(container.children, function (node) {
52 if (node.nodeType === 1 && blacklist.indexOf(node) === -1 && blacklistTagNames.indexOf(node.tagName) === -1) {
53 ariaHidden(node, show);
54 }
55 });
56}
57
58function findIndexOf(containerInfo, callback) {
59 var idx = -1;
60 containerInfo.some(function (item, index) {
61 if (callback(item)) {
62 idx = index;
63 return true;
64 }
65
66 return false;
67 });
68 return idx;
69}
70
71function handleContainer(containerInfo, props) {
72 var restoreStyle = [];
73 var restorePaddings = [];
74 var container = containerInfo.container;
75 var fixedNodes;
76
77 if (!props.disableScrollLock) {
78 if (isOverflowing(container)) {
79 // Compute the size before applying overflow hidden to avoid any scroll jumps.
80 var scrollbarSize = (0, _getScrollbarSize.default)();
81 restoreStyle.push({
82 value: container.style.paddingRight,
83 key: 'padding-right',
84 el: container
85 }); // Use computed style, here to get the real padding to add our scrollbar width.
86
87 container.style['padding-right'] = "".concat(getPaddingRight(container) + scrollbarSize, "px"); // .mui-fixed is a global helper.
88
89 fixedNodes = (0, _ownerDocument.default)(container).querySelectorAll('.mui-fixed');
90 [].forEach.call(fixedNodes, function (node) {
91 restorePaddings.push(node.style.paddingRight);
92 node.style.paddingRight = "".concat(getPaddingRight(node) + scrollbarSize, "px");
93 });
94 } // Improve Gatsby support
95 // https://css-tricks.com/snippets/css/force-vertical-scrollbar/
96
97
98 var parent = container.parentElement;
99 var scrollContainer = parent.nodeName === 'HTML' && window.getComputedStyle(parent)['overflow-y'] === 'scroll' ? parent : container; // Block the scroll even if no scrollbar is visible to account for mobile keyboard
100 // screensize shrink.
101
102 restoreStyle.push({
103 value: scrollContainer.style.overflow,
104 key: 'overflow',
105 el: scrollContainer
106 });
107 scrollContainer.style.overflow = 'hidden';
108 }
109
110 var restore = function restore() {
111 if (fixedNodes) {
112 [].forEach.call(fixedNodes, function (node, i) {
113 if (restorePaddings[i]) {
114 node.style.paddingRight = restorePaddings[i];
115 } else {
116 node.style.removeProperty('padding-right');
117 }
118 });
119 }
120
121 restoreStyle.forEach(function (_ref) {
122 var value = _ref.value,
123 el = _ref.el,
124 key = _ref.key;
125
126 if (value) {
127 el.style.setProperty(key, value);
128 } else {
129 el.style.removeProperty(key);
130 }
131 });
132 };
133
134 return restore;
135}
136
137function getHiddenSiblings(container) {
138 var hiddenSiblings = [];
139 [].forEach.call(container.children, function (node) {
140 if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {
141 hiddenSiblings.push(node);
142 }
143 });
144 return hiddenSiblings;
145}
146/**
147 * @ignore - do not document.
148 *
149 * Proper state management for containers and the modals in those containers.
150 * Simplified, but inspired by react-overlay's ModalManager class.
151 * Used by the Modal to ensure proper styling of containers.
152 */
153
154
155var ModalManager = /*#__PURE__*/function () {
156 function ModalManager() {
157 (0, _classCallCheck2.default)(this, ModalManager);
158 // this.modals[modalIndex] = modal
159 this.modals = []; // this.containers[containerIndex] = {
160 // modals: [],
161 // container,
162 // restore: null,
163 // }
164
165 this.containers = [];
166 }
167
168 (0, _createClass2.default)(ModalManager, [{
169 key: "add",
170 value: function add(modal, container) {
171 var modalIndex = this.modals.indexOf(modal);
172
173 if (modalIndex !== -1) {
174 return modalIndex;
175 }
176
177 modalIndex = this.modals.length;
178 this.modals.push(modal); // If the modal we are adding is already in the DOM.
179
180 if (modal.modalRef) {
181 ariaHidden(modal.modalRef, false);
182 }
183
184 var hiddenSiblingNodes = getHiddenSiblings(container);
185 ariaHiddenSiblings(container, modal.mountNode, modal.modalRef, hiddenSiblingNodes, true);
186 var containerIndex = findIndexOf(this.containers, function (item) {
187 return item.container === container;
188 });
189
190 if (containerIndex !== -1) {
191 this.containers[containerIndex].modals.push(modal);
192 return modalIndex;
193 }
194
195 this.containers.push({
196 modals: [modal],
197 container: container,
198 restore: null,
199 hiddenSiblingNodes: hiddenSiblingNodes
200 });
201 return modalIndex;
202 }
203 }, {
204 key: "mount",
205 value: function mount(modal, props) {
206 var containerIndex = findIndexOf(this.containers, function (item) {
207 return item.modals.indexOf(modal) !== -1;
208 });
209 var containerInfo = this.containers[containerIndex];
210
211 if (!containerInfo.restore) {
212 containerInfo.restore = handleContainer(containerInfo, props);
213 }
214 }
215 }, {
216 key: "remove",
217 value: function remove(modal) {
218 var modalIndex = this.modals.indexOf(modal);
219
220 if (modalIndex === -1) {
221 return modalIndex;
222 }
223
224 var containerIndex = findIndexOf(this.containers, function (item) {
225 return item.modals.indexOf(modal) !== -1;
226 });
227 var containerInfo = this.containers[containerIndex];
228 containerInfo.modals.splice(containerInfo.modals.indexOf(modal), 1);
229 this.modals.splice(modalIndex, 1); // If that was the last modal in a container, clean up the container.
230
231 if (containerInfo.modals.length === 0) {
232 // The modal might be closed before it had the chance to be mounted in the DOM.
233 if (containerInfo.restore) {
234 containerInfo.restore();
235 }
236
237 if (modal.modalRef) {
238 // In case the modal wasn't in the DOM yet.
239 ariaHidden(modal.modalRef, true);
240 }
241
242 ariaHiddenSiblings(containerInfo.container, modal.mountNode, modal.modalRef, containerInfo.hiddenSiblingNodes, false);
243 this.containers.splice(containerIndex, 1);
244 } else {
245 // Otherwise make sure the next top modal is visible to a screen reader.
246 var nextTop = containerInfo.modals[containerInfo.modals.length - 1]; // as soon as a modal is adding its modalRef is undefined. it can't set
247 // aria-hidden because the dom element doesn't exist either
248 // when modal was unmounted before modalRef gets null
249
250 if (nextTop.modalRef) {
251 ariaHidden(nextTop.modalRef, false);
252 }
253 }
254
255 return modalIndex;
256 }
257 }, {
258 key: "isTopModal",
259 value: function isTopModal(modal) {
260 return this.modals.length > 0 && this.modals[this.modals.length - 1] === modal;
261 }
262 }]);
263 return ModalManager;
264}();
265
266exports.default = ModalManager;
\No newline at end of file