UNPKG

5.01 kBJavaScriptView Raw
1import addClass from 'dom-helpers/addClass';
2import removeClass from 'dom-helpers/removeClass';
3import css from 'dom-helpers/css';
4import getScrollbarSize from 'dom-helpers/scrollbarSize';
5import isOverflowing from './isOverflowing';
6import { ariaHidden, hideSiblings, showSiblings } from './manageAriaHidden';
7
8function findIndexOf(arr, cb) {
9 var idx = -1;
10 arr.some(function (d, i) {
11 if (cb(d, i)) {
12 idx = i;
13 return true;
14 }
15
16 return false;
17 });
18 return idx;
19}
20
21/**
22 * Proper state management for containers and the modals in those containers.
23 *
24 * @internal Used by the Modal to ensure proper styling of containers.
25 */
26var ModalManager = /*#__PURE__*/function () {
27 function ModalManager(_temp) {
28 var _ref = _temp === void 0 ? {} : _temp,
29 _ref$hideSiblingNodes = _ref.hideSiblingNodes,
30 hideSiblingNodes = _ref$hideSiblingNodes === void 0 ? true : _ref$hideSiblingNodes,
31 _ref$handleContainerO = _ref.handleContainerOverflow,
32 handleContainerOverflow = _ref$handleContainerO === void 0 ? true : _ref$handleContainerO;
33
34 this.hideSiblingNodes = void 0;
35 this.handleContainerOverflow = void 0;
36 this.modals = void 0;
37 this.containers = void 0;
38 this.data = void 0;
39 this.scrollbarSize = void 0;
40 this.hideSiblingNodes = hideSiblingNodes;
41 this.handleContainerOverflow = handleContainerOverflow;
42 this.modals = [];
43 this.containers = [];
44 this.data = [];
45 this.scrollbarSize = getScrollbarSize();
46 }
47
48 var _proto = ModalManager.prototype;
49
50 _proto.isContainerOverflowing = function isContainerOverflowing(modal) {
51 var data = this.data[this.containerIndexFromModal(modal)];
52 return data && data.overflowing;
53 };
54
55 _proto.containerIndexFromModal = function containerIndexFromModal(modal) {
56 return findIndexOf(this.data, function (d) {
57 return d.modals.indexOf(modal) !== -1;
58 });
59 };
60
61 _proto.setContainerStyle = function setContainerStyle(containerState, container) {
62 var style = {
63 overflow: 'hidden'
64 }; // we are only interested in the actual `style` here
65 // because we will override it
66
67 containerState.style = {
68 overflow: container.style.overflow,
69 paddingRight: container.style.paddingRight
70 };
71
72 if (containerState.overflowing) {
73 // use computed style, here to get the real padding
74 // to add our scrollbar width
75 style.paddingRight = parseInt(css(container, 'paddingRight') || '0', 10) + this.scrollbarSize + "px";
76 }
77
78 css(container, style);
79 };
80
81 _proto.removeContainerStyle = function removeContainerStyle(containerState, container) {
82 Object.assign(container.style, containerState.style);
83 };
84
85 _proto.add = function add(modal, container, className) {
86 var modalIdx = this.modals.indexOf(modal);
87 var containerIdx = this.containers.indexOf(container);
88
89 if (modalIdx !== -1) {
90 return modalIdx;
91 }
92
93 modalIdx = this.modals.length;
94 this.modals.push(modal);
95
96 if (this.hideSiblingNodes) {
97 hideSiblings(container, modal);
98 }
99
100 if (containerIdx !== -1) {
101 this.data[containerIdx].modals.push(modal);
102 return modalIdx;
103 }
104
105 var data = {
106 modals: [modal],
107 // right now only the first modal of a container will have its classes applied
108 classes: className ? className.split(/\s+/) : [],
109 overflowing: isOverflowing(container)
110 };
111
112 if (this.handleContainerOverflow) {
113 this.setContainerStyle(data, container);
114 }
115
116 data.classes.forEach(addClass.bind(null, container));
117 this.containers.push(container);
118 this.data.push(data);
119 return modalIdx;
120 };
121
122 _proto.remove = function remove(modal) {
123 var modalIdx = this.modals.indexOf(modal);
124
125 if (modalIdx === -1) {
126 return;
127 }
128
129 var containerIdx = this.containerIndexFromModal(modal);
130 var data = this.data[containerIdx];
131 var container = this.containers[containerIdx];
132 data.modals.splice(data.modals.indexOf(modal), 1);
133 this.modals.splice(modalIdx, 1); // if that was the last modal in a container,
134 // clean up the container
135
136 if (data.modals.length === 0) {
137 data.classes.forEach(removeClass.bind(null, container));
138
139 if (this.handleContainerOverflow) {
140 this.removeContainerStyle(data, container);
141 }
142
143 if (this.hideSiblingNodes) {
144 showSiblings(container, modal);
145 }
146
147 this.containers.splice(containerIdx, 1);
148 this.data.splice(containerIdx, 1);
149 } else if (this.hideSiblingNodes) {
150 // otherwise make sure the next top modal is visible to a SR
151 var _data$modals = data.modals[data.modals.length - 1],
152 backdrop = _data$modals.backdrop,
153 dialog = _data$modals.dialog;
154 ariaHidden(false, dialog);
155 ariaHidden(false, backdrop);
156 }
157 };
158
159 _proto.isTopModal = function isTopModal(modal) {
160 return !!this.modals.length && this.modals[this.modals.length - 1] === modal;
161 };
162
163 return ModalManager;
164}();
165
166export default ModalManager;
\No newline at end of file