@spaced-out/ui-design-system 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/lib/components/Modal/Modal.js +45 -8
- package/lib/components/Modal/Modal.js.flow +53 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.1.8](https://github.com/spaced-out/ui-design-system/compare/v0.1.7...v0.1.8) (2023-04-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* modal scroll fix ([47a2349](https://github.com/spaced-out/ui-design-system/commit/47a23496c8b9328ab6cbe3f7736635776fb4f797))
|
|
11
|
+
* modal scroll fix ([c33b8bd](https://github.com/spaced-out/ui-design-system/commit/c33b8bd6b4a7cf4c4a51c2abe8a3211c829b054b))
|
|
12
|
+
|
|
13
|
+
### [0.1.7](https://github.com/spaced-out/ui-design-system/compare/v0.1.6...v0.1.7) (2023-04-05)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* added documentation for link ([b233ce2](https://github.com/spaced-out/ui-design-system/commit/b233ce236a2ef4d8297bf4a333cf280d24fb6c87))
|
|
19
|
+
* modal fix ([a8bcb31](https://github.com/spaced-out/ui-design-system/commit/a8bcb318f23006c502f74b569fa268c44856bb9c))
|
|
20
|
+
|
|
5
21
|
### [0.1.6](https://github.com/spaced-out/ui-design-system/compare/v0.1.5...v0.1.6) (2023-04-05)
|
|
6
22
|
|
|
7
23
|
|
|
@@ -10,6 +10,7 @@ var _reactDomInteractions = require("@floating-ui/react-dom-interactions");
|
|
|
10
10
|
var _useMountTransition = _interopRequireDefault(require("../../hooks/useMountTransition"));
|
|
11
11
|
var _motion = require("../../styles/variables/_motion");
|
|
12
12
|
var _classify = _interopRequireDefault(require("../../utils/classify"));
|
|
13
|
+
var _helpers = require("../../utils/helpers");
|
|
13
14
|
var _Button = require("../Button/Button");
|
|
14
15
|
var _Truncate = require("../Truncate/Truncate");
|
|
15
16
|
var _ModalModule = _interopRequireDefault(require("./Modal.module.css"));
|
|
@@ -60,11 +61,40 @@ const ModalFooter = _ref3 => {
|
|
|
60
61
|
}, children)));
|
|
61
62
|
};
|
|
62
63
|
exports.ModalFooter = ModalFooter;
|
|
63
|
-
const createPortalRoot =
|
|
64
|
+
const createPortalRoot = id => {
|
|
64
65
|
const modalRoot = document.createElement('div');
|
|
65
|
-
modalRoot.setAttribute('id',
|
|
66
|
+
modalRoot.setAttribute('id', `modal-root-${id}`);
|
|
66
67
|
return modalRoot;
|
|
67
68
|
};
|
|
69
|
+
const getModalRoot = id => document.getElementById(`modal-root-${id}`);
|
|
70
|
+
function hasChildNode(nodeList) {
|
|
71
|
+
for (let i = 0, len = nodeList.length; i < len; i++) {
|
|
72
|
+
if (nodeList[i].firstChild !== null) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const fixBody = bodyEl => {
|
|
79
|
+
document.getElementsByTagName('body')[0].classList.add('fixed');
|
|
80
|
+
bodyEl.style.overflow = 'hidden';
|
|
81
|
+
};
|
|
82
|
+
const unfixBody = bodyEl => {
|
|
83
|
+
document.getElementsByTagName('body')[0].classList.remove('fixed');
|
|
84
|
+
bodyEl.style.overflow = '';
|
|
85
|
+
};
|
|
86
|
+
const checkAndAddBodyOverflow = bodyEl => {
|
|
87
|
+
const nodes = document.querySelectorAll('[id^="modal-root"]');
|
|
88
|
+
let isParentModalPresent = false;
|
|
89
|
+
if (nodes.length) {
|
|
90
|
+
isParentModalPresent = hasChildNode(nodes);
|
|
91
|
+
}
|
|
92
|
+
if (isParentModalPresent) {
|
|
93
|
+
fixBody(bodyEl);
|
|
94
|
+
} else {
|
|
95
|
+
unfixBody(bodyEl);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
68
98
|
const Modal = _ref4 => {
|
|
69
99
|
let {
|
|
70
100
|
classNames,
|
|
@@ -72,7 +102,6 @@ const Modal = _ref4 => {
|
|
|
72
102
|
isOpen = false,
|
|
73
103
|
onClose,
|
|
74
104
|
hideBackdrop = false,
|
|
75
|
-
removeWhenClosed = true,
|
|
76
105
|
tapOutsideToClose = true,
|
|
77
106
|
initialFocus = -1
|
|
78
107
|
} = _ref4;
|
|
@@ -80,8 +109,9 @@ const Modal = _ref4 => {
|
|
|
80
109
|
floating,
|
|
81
110
|
context
|
|
82
111
|
} = (0, _reactDomInteractions.useFloating)();
|
|
112
|
+
const modalId = (0, _helpers.uuid)();
|
|
83
113
|
const bodyRef = React.useRef(document.querySelector('body'));
|
|
84
|
-
const portalRootRef = React.useRef(
|
|
114
|
+
const portalRootRef = React.useRef(getModalRoot(modalId) || createPortalRoot(modalId));
|
|
85
115
|
const isTransitioning = (0, _useMountTransition.default)(isOpen, parseInt(_motion.motionDurationNormal));
|
|
86
116
|
|
|
87
117
|
// Append portal root on mount
|
|
@@ -94,7 +124,7 @@ const Modal = _ref4 => {
|
|
|
94
124
|
portal.remove();
|
|
95
125
|
// Ensure scroll overflow is removed
|
|
96
126
|
if (bodyEl) {
|
|
97
|
-
bodyEl
|
|
127
|
+
unfixBody(bodyEl);
|
|
98
128
|
}
|
|
99
129
|
};
|
|
100
130
|
}, []);
|
|
@@ -104,11 +134,11 @@ const Modal = _ref4 => {
|
|
|
104
134
|
const updatePageScroll = () => {
|
|
105
135
|
if (isOpen) {
|
|
106
136
|
if (bodyRef.current) {
|
|
107
|
-
bodyRef.current
|
|
137
|
+
fixBody(bodyRef.current);
|
|
108
138
|
}
|
|
109
139
|
} else {
|
|
110
140
|
if (bodyRef.current) {
|
|
111
|
-
bodyRef.current
|
|
141
|
+
unfixBody(bodyRef.current);
|
|
112
142
|
}
|
|
113
143
|
}
|
|
114
144
|
};
|
|
@@ -129,7 +159,14 @@ const Modal = _ref4 => {
|
|
|
129
159
|
window.removeEventListener('keyup', onKeyPress);
|
|
130
160
|
};
|
|
131
161
|
}, [isOpen, onClose]);
|
|
132
|
-
if (!isTransitioning &&
|
|
162
|
+
if (!isTransitioning && !isOpen) {
|
|
163
|
+
// Check overflow after resetting the DOM for modal. This should always happen after DOM reset
|
|
164
|
+
// TODO(Nishant): Better way to do this?
|
|
165
|
+
setTimeout(() => {
|
|
166
|
+
if (bodyRef && !!bodyRef.current) {
|
|
167
|
+
checkAndAddBodyOverflow(bodyRef.current);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
133
170
|
return null;
|
|
134
171
|
}
|
|
135
172
|
const onBackdropClick = e => {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import useMountTransition from '../../hooks/useMountTransition';
|
|
14
14
|
import {motionDurationNormal} from '../../styles/variables/_motion';
|
|
15
15
|
import classify from '../../utils/classify';
|
|
16
|
+
import {uuid} from '../../utils/helpers';
|
|
16
17
|
import {Button} from '../Button/Button';
|
|
17
18
|
import {Truncate} from '../Truncate/Truncate';
|
|
18
19
|
|
|
@@ -36,6 +37,7 @@ export type ModalProps = {
|
|
|
36
37
|
isOpen?: boolean,
|
|
37
38
|
onClose?: ?(SyntheticEvent<HTMLElement>) => mixed,
|
|
38
39
|
hideBackdrop?: boolean,
|
|
40
|
+
// This prop is removed now
|
|
39
41
|
removeWhenClosed?: boolean,
|
|
40
42
|
tapOutsideToClose?: boolean,
|
|
41
43
|
initialFocus?: number,
|
|
@@ -105,28 +107,63 @@ export const ModalFooter = ({
|
|
|
105
107
|
</>
|
|
106
108
|
);
|
|
107
109
|
|
|
108
|
-
const createPortalRoot = () => {
|
|
110
|
+
const createPortalRoot = (id: string) => {
|
|
109
111
|
const modalRoot = document.createElement('div');
|
|
110
|
-
modalRoot.setAttribute('id',
|
|
112
|
+
modalRoot.setAttribute('id', `modal-root-${id}`);
|
|
111
113
|
|
|
112
114
|
return modalRoot;
|
|
113
115
|
};
|
|
114
116
|
|
|
117
|
+
const getModalRoot = (id: string) =>
|
|
118
|
+
document.getElementById(`modal-root-${id}`);
|
|
119
|
+
|
|
120
|
+
function hasChildNode(nodeList) {
|
|
121
|
+
for (let i = 0, len = nodeList.length; i < len; i++) {
|
|
122
|
+
if (nodeList[i].firstChild !== null) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const fixBody = (bodyEl: HTMLBodyElement) => {
|
|
130
|
+
document.getElementsByTagName('body')[0].classList.add('fixed');
|
|
131
|
+
bodyEl.style.overflow = 'hidden';
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const unfixBody = (bodyEl: HTMLBodyElement) => {
|
|
135
|
+
document.getElementsByTagName('body')[0].classList.remove('fixed');
|
|
136
|
+
bodyEl.style.overflow = '';
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const checkAndAddBodyOverflow = (bodyEl: HTMLBodyElement) => {
|
|
140
|
+
const nodes = document.querySelectorAll('[id^="modal-root"]');
|
|
141
|
+
let isParentModalPresent = false;
|
|
142
|
+
if (nodes.length) {
|
|
143
|
+
isParentModalPresent = hasChildNode(nodes);
|
|
144
|
+
}
|
|
145
|
+
if (isParentModalPresent) {
|
|
146
|
+
fixBody(bodyEl);
|
|
147
|
+
} else {
|
|
148
|
+
unfixBody(bodyEl);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
115
152
|
export const Modal = ({
|
|
116
153
|
classNames,
|
|
117
154
|
children,
|
|
118
155
|
isOpen = false,
|
|
119
156
|
onClose,
|
|
120
157
|
hideBackdrop = false,
|
|
121
|
-
removeWhenClosed = true,
|
|
122
158
|
tapOutsideToClose = true,
|
|
123
159
|
initialFocus = -1,
|
|
124
160
|
}: ModalProps): React.Node => {
|
|
125
161
|
const {floating, context} = useFloating();
|
|
162
|
+
const modalId = uuid();
|
|
126
163
|
|
|
127
164
|
const bodyRef = React.useRef(document.querySelector('body'));
|
|
128
165
|
const portalRootRef = React.useRef(
|
|
129
|
-
|
|
166
|
+
getModalRoot(modalId) || createPortalRoot(modalId),
|
|
130
167
|
);
|
|
131
168
|
|
|
132
169
|
const isTransitioning = useMountTransition(
|
|
@@ -145,7 +182,7 @@ export const Modal = ({
|
|
|
145
182
|
portal.remove();
|
|
146
183
|
// Ensure scroll overflow is removed
|
|
147
184
|
if (bodyEl) {
|
|
148
|
-
bodyEl
|
|
185
|
+
unfixBody(bodyEl);
|
|
149
186
|
}
|
|
150
187
|
};
|
|
151
188
|
}, []);
|
|
@@ -155,11 +192,11 @@ export const Modal = ({
|
|
|
155
192
|
const updatePageScroll = () => {
|
|
156
193
|
if (isOpen) {
|
|
157
194
|
if (bodyRef.current) {
|
|
158
|
-
bodyRef.current
|
|
195
|
+
fixBody(bodyRef.current);
|
|
159
196
|
}
|
|
160
197
|
} else {
|
|
161
198
|
if (bodyRef.current) {
|
|
162
|
-
bodyRef.current
|
|
199
|
+
unfixBody(bodyRef.current);
|
|
163
200
|
}
|
|
164
201
|
}
|
|
165
202
|
};
|
|
@@ -184,7 +221,15 @@ export const Modal = ({
|
|
|
184
221
|
};
|
|
185
222
|
}, [isOpen, onClose]);
|
|
186
223
|
|
|
187
|
-
if (!isTransitioning &&
|
|
224
|
+
if (!isTransitioning && !isOpen) {
|
|
225
|
+
// Check overflow after resetting the DOM for modal. This should always happen after DOM reset
|
|
226
|
+
// TODO(Nishant): Better way to do this?
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
if (bodyRef && !!bodyRef.current) {
|
|
229
|
+
checkAndAddBodyOverflow(bodyRef.current);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
188
233
|
return null;
|
|
189
234
|
}
|
|
190
235
|
|