UNPKG

5.09 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 var style = containerState.style;
83 Object.keys(style).forEach(function (key) {
84 container.style[key] = style[key];
85 });
86 };
87
88 _proto.add = function add(modal, container, className) {
89 var modalIdx = this.modals.indexOf(modal);
90 var containerIdx = this.containers.indexOf(container);
91
92 if (modalIdx !== -1) {
93 return modalIdx;
94 }
95
96 modalIdx = this.modals.length;
97 this.modals.push(modal);
98
99 if (this.hideSiblingNodes) {
100 hideSiblings(container, modal);
101 }
102
103 if (containerIdx !== -1) {
104 this.data[containerIdx].modals.push(modal);
105 return modalIdx;
106 }
107
108 var data = {
109 modals: [modal],
110 // right now only the first modal of a container will have its classes applied
111 classes: className ? className.split(/\s+/) : [],
112 overflowing: isOverflowing(container)
113 };
114
115 if (this.handleContainerOverflow) {
116 this.setContainerStyle(data, container);
117 }
118
119 data.classes.forEach(addClass.bind(null, container));
120 this.containers.push(container);
121 this.data.push(data);
122 return modalIdx;
123 };
124
125 _proto.remove = function remove(modal) {
126 var modalIdx = this.modals.indexOf(modal);
127
128 if (modalIdx === -1) {
129 return;
130 }
131
132 var containerIdx = this.containerIndexFromModal(modal);
133 var data = this.data[containerIdx];
134 var container = this.containers[containerIdx];
135 data.modals.splice(data.modals.indexOf(modal), 1);
136 this.modals.splice(modalIdx, 1); // if that was the last modal in a container,
137 // clean up the container
138
139 if (data.modals.length === 0) {
140 data.classes.forEach(removeClass.bind(null, container));
141
142 if (this.handleContainerOverflow) {
143 this.removeContainerStyle(data, container);
144 }
145
146 if (this.hideSiblingNodes) {
147 showSiblings(container, modal);
148 }
149
150 this.containers.splice(containerIdx, 1);
151 this.data.splice(containerIdx, 1);
152 } else if (this.hideSiblingNodes) {
153 // otherwise make sure the next top modal is visible to a SR
154 var _data$modals = data.modals[data.modals.length - 1],
155 backdrop = _data$modals.backdrop,
156 dialog = _data$modals.dialog;
157 ariaHidden(false, dialog);
158 ariaHidden(false, backdrop);
159 }
160 };
161
162 _proto.isTopModal = function isTopModal(modal) {
163 return !!this.modals.length && this.modals[this.modals.length - 1] === modal;
164 };
165
166 return ModalManager;
167}();
168
169export default ModalManager;
\No newline at end of file