react-pure-modal 2.2.8 → 3.0.0
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/README.md +94 -78
- package/package.json +38 -63
- package/.babelrc.js +0 -12
- package/.eslintrc +0 -22
- package/.github/release-drafter-config.yml +0 -20
- package/.github/workflows/build.yml +0 -24
- package/.github/workflows/npm-publish.yml +0 -22
- package/.github/workflows/release-drafter.yml +0 -16
- package/.prettierrc +0 -19
- package/.travis.yml +0 -16
- package/__tests__/__snapshots__/react-pure-modal-test.js.snap +0 -92
- package/__tests__/react-pure-modal-test.js +0 -44
- package/dist/pure-modal-content.d.ts +0 -25
- package/dist/react-pure-modal.d.ts +0 -20
- package/dist/react-pure-modal.min.css +0 -1
- package/dist/react-pure-modal.min.js +0 -1
- package/dist/types.d.ts +0 -1
- package/example/content.ts +0 -50
- package/example/example.min.js +0 -2
- package/example/example.min.js.LICENSE.txt +0 -167
- package/example/example.tsx +0 -109
- package/index.html +0 -22
- package/screencast/scrollable.gif +0 -0
- package/screencast/simple.gif +0 -0
- package/src/pure-modal-content.tsx +0 -74
- package/src/react-pure-modal.css +0 -123
- package/src/react-pure-modal.tsx +0 -254
- package/src/types.ts +0 -1
- package/tsconfig.json +0 -21
- package/webpack.config.dev.js +0 -65
- package/webpack.config.js +0 -62
package/src/react-pure-modal.tsx
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
|
-
import { createPortal } from 'react-dom';
|
|
3
|
-
|
|
4
|
-
// components
|
|
5
|
-
import PureModalContent from './pure-modal-content';
|
|
6
|
-
|
|
7
|
-
// types
|
|
8
|
-
import type { MouseOrTouch } from './types';
|
|
9
|
-
|
|
10
|
-
// styles
|
|
11
|
-
import './react-pure-modal.css';
|
|
12
|
-
|
|
13
|
-
type Props = {
|
|
14
|
-
children: JSX.Element;
|
|
15
|
-
replace?: boolean;
|
|
16
|
-
className?: string;
|
|
17
|
-
header?: JSX.Element | string;
|
|
18
|
-
footer?: JSX.Element | string;
|
|
19
|
-
scrollable?: boolean;
|
|
20
|
-
draggable?: boolean;
|
|
21
|
-
width?: string;
|
|
22
|
-
isOpen?: boolean;
|
|
23
|
-
onClose?: Function;
|
|
24
|
-
closeButton?: JSX.Element | string;
|
|
25
|
-
closeButtonPosition?: string;
|
|
26
|
-
portal?: boolean;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function PureModal(props: Props) {
|
|
30
|
-
let hash = Math.random().toString();
|
|
31
|
-
const [isDragged, setIsDragged] = useState(false);
|
|
32
|
-
const [x, setX] = useState<number | null>(null);
|
|
33
|
-
const [y, setY] = useState<number | null>(null);
|
|
34
|
-
const [deltaX, setDeltaX] = useState(0);
|
|
35
|
-
const [deltaY, setDeltaY] = useState(0);
|
|
36
|
-
const [mouseOffsetX, setMouseOffsetX] = useState(0);
|
|
37
|
-
const [mouseOffsetY, setMouseOffsetY] = useState(0);
|
|
38
|
-
|
|
39
|
-
const { isOpen, onClose } = props;
|
|
40
|
-
|
|
41
|
-
const removeClassBody = useCallback(() => {
|
|
42
|
-
document.body.classList.remove('body-modal-fix');
|
|
43
|
-
}, []);
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* useEffect to setup popup OR perform a cleanup after popup was closed
|
|
47
|
-
*/
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
/**
|
|
50
|
-
* if popup was opened:
|
|
51
|
-
* - add esc event listener
|
|
52
|
-
* - add overflow fix class to body
|
|
53
|
-
* - remove focus from focused element (e.g. remove focus from btn after click, cuz popup was opened)
|
|
54
|
-
*/
|
|
55
|
-
if (isOpen) {
|
|
56
|
-
document.addEventListener('keydown', handleEsc);
|
|
57
|
-
if (document.activeElement instanceof HTMLElement) document.activeElement.blur();
|
|
58
|
-
document.body.classList.add('body-modal-fix');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return () => {
|
|
62
|
-
/**
|
|
63
|
-
* if popup was closed:
|
|
64
|
-
* - remove esc event listener
|
|
65
|
-
* - remove overflow fix class from body
|
|
66
|
-
* - reset popup states
|
|
67
|
-
*/
|
|
68
|
-
if (!document.querySelector('.pure-modal')) {
|
|
69
|
-
document.removeEventListener('keydown', handleEsc);
|
|
70
|
-
removeClassBody();
|
|
71
|
-
setX(null);
|
|
72
|
-
setY(null);
|
|
73
|
-
setDeltaX(0);
|
|
74
|
-
setDeltaY(0);
|
|
75
|
-
setMouseOffsetX(0);
|
|
76
|
-
setMouseOffsetY(0);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}, [isOpen]);
|
|
80
|
-
|
|
81
|
-
const handleEsc = useCallback(
|
|
82
|
-
event => {
|
|
83
|
-
const allModals = document.querySelectorAll('.pure-modal');
|
|
84
|
-
const isManyModalsOpen = allModals.length > 1; // open modal in modal
|
|
85
|
-
const firstModalData = allModals[allModals.length - 1];
|
|
86
|
-
|
|
87
|
-
if (isManyModalsOpen && !firstModalData.className.includes(hash)) {
|
|
88
|
-
return false; // closing only current modal
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (event.key === 'Escape' && document.activeElement) {
|
|
92
|
-
close(event);
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return false;
|
|
97
|
-
},
|
|
98
|
-
[close, hash],
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
if (!isOpen) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* method that will be called when some of the closing elements are beeing interacted with
|
|
107
|
-
*
|
|
108
|
-
* click on close btn, click on backdrop, press on esc
|
|
109
|
-
*/
|
|
110
|
-
function close(event?: MouseOrTouch) {
|
|
111
|
-
if (event) {
|
|
112
|
-
event.stopPropagation();
|
|
113
|
-
event.preventDefault();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
onClose?.({ isPassive: Boolean(event) });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function getCoords(e: MouseOrTouch) {
|
|
120
|
-
if (e instanceof TouchEvent && e.changedTouches.length > 0) {
|
|
121
|
-
return {
|
|
122
|
-
pageX: e.changedTouches[0].pageX,
|
|
123
|
-
pageY: e.changedTouches[0].pageY,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
if (e instanceof MouseEvent) {
|
|
127
|
-
return {
|
|
128
|
-
pageX: e.pageX,
|
|
129
|
-
pageY: e.pageY,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
return {
|
|
133
|
-
pageX: 0,
|
|
134
|
-
pageY: 0,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function handleStartDrag(e: MouseOrTouch) {
|
|
139
|
-
if (e instanceof TouchEvent && e.changedTouches && e.changedTouches.length > 1) return;
|
|
140
|
-
|
|
141
|
-
e.preventDefault();
|
|
142
|
-
|
|
143
|
-
const { pageX, pageY } = getCoords(e);
|
|
144
|
-
const { top, left } = e.currentTarget.getBoundingClientRect();
|
|
145
|
-
|
|
146
|
-
setIsDragged(true);
|
|
147
|
-
setX(typeof x === 'number' ? x : left);
|
|
148
|
-
setY(typeof y === 'number' ? y : top);
|
|
149
|
-
setMouseOffsetX(pageX - left);
|
|
150
|
-
setMouseOffsetY(pageY - top);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function handleDrag(e: MouseOrTouch) {
|
|
154
|
-
if (e instanceof TouchEvent && e.changedTouches && e.changedTouches.length > 1) {
|
|
155
|
-
return handleEndDrag();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
e.preventDefault();
|
|
159
|
-
|
|
160
|
-
const { pageX, pageY } = getCoords(e);
|
|
161
|
-
|
|
162
|
-
if (typeof x === 'number' && typeof y === 'number') {
|
|
163
|
-
setDeltaX(pageX - x - mouseOffsetX);
|
|
164
|
-
setDeltaY(pageY - y - mouseOffsetY);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function handleEndDrag() {
|
|
169
|
-
return setIsDragged(false);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function handleBackdropClick(event: MouseOrTouch) {
|
|
173
|
-
if (event) {
|
|
174
|
-
if (!(event.target as Element).classList.contains('pure-modal-backdrop')) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
event.stopPropagation();
|
|
178
|
-
event.preventDefault();
|
|
179
|
-
}
|
|
180
|
-
close(event);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const {
|
|
184
|
-
children,
|
|
185
|
-
replace = false,
|
|
186
|
-
className,
|
|
187
|
-
header,
|
|
188
|
-
footer,
|
|
189
|
-
scrollable = true,
|
|
190
|
-
draggable = false,
|
|
191
|
-
width,
|
|
192
|
-
closeButton,
|
|
193
|
-
closeButtonPosition,
|
|
194
|
-
portal = false,
|
|
195
|
-
} = props;
|
|
196
|
-
|
|
197
|
-
let backdropclasses = ['pure-modal-backdrop'];
|
|
198
|
-
let modalclasses = ['pure-modal', hash];
|
|
199
|
-
let bodyClasses = ['panel-body'];
|
|
200
|
-
|
|
201
|
-
if (className) {
|
|
202
|
-
modalclasses = modalclasses.concat(className);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (scrollable) {
|
|
206
|
-
bodyClasses = bodyClasses.concat('scrollable');
|
|
207
|
-
} else {
|
|
208
|
-
backdropclasses = backdropclasses.concat('scrollable');
|
|
209
|
-
modalclasses = modalclasses.concat('auto-height');
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (draggable) {
|
|
213
|
-
backdropclasses = backdropclasses.concat('backdrop-overflow-hidden');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const modalContent = (
|
|
217
|
-
<div
|
|
218
|
-
className={backdropclasses.join(' ')}
|
|
219
|
-
onMouseDown={handleBackdropClick}
|
|
220
|
-
onTouchMove={isDragged ? handleDrag : undefined}
|
|
221
|
-
onMouseMove={isDragged ? handleDrag : undefined}
|
|
222
|
-
>
|
|
223
|
-
<div
|
|
224
|
-
className={modalclasses.join(' ')}
|
|
225
|
-
style={{
|
|
226
|
-
transform: `translate(${deltaX}px, ${deltaY}px)`,
|
|
227
|
-
transition: 'none',
|
|
228
|
-
width,
|
|
229
|
-
}}
|
|
230
|
-
>
|
|
231
|
-
<PureModalContent
|
|
232
|
-
replace={replace}
|
|
233
|
-
header={header}
|
|
234
|
-
footer={footer}
|
|
235
|
-
onDragStart={draggable ? handleStartDrag : undefined}
|
|
236
|
-
onDragEnd={draggable ? handleEndDrag : undefined}
|
|
237
|
-
onClose={close}
|
|
238
|
-
bodyClass={bodyClasses.join(' ')}
|
|
239
|
-
closeButton={closeButton}
|
|
240
|
-
closeButtonPosition={closeButtonPosition}
|
|
241
|
-
>
|
|
242
|
-
{children}
|
|
243
|
-
</PureModalContent>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
if (portal) {
|
|
249
|
-
return createPortal(modalContent, document.body);
|
|
250
|
-
}
|
|
251
|
-
return modalContent;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export default React.memo(PureModal);
|
package/src/types.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type MouseOrTouch = React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>;
|
package/tsconfig.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"include": ["src/*.tsx"],
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"emitDeclarationOnly": true,
|
|
7
|
-
"sourceMap": true,
|
|
8
|
-
"noImplicitAny": true,
|
|
9
|
-
"module": "commonjs",
|
|
10
|
-
"target": "es2016",
|
|
11
|
-
"jsx": "react",
|
|
12
|
-
"lib": ["es2018", "dom"],
|
|
13
|
-
"esModuleInterop": true,
|
|
14
|
-
"strict": true,
|
|
15
|
-
"importsNotUsedAsValues": "error",
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"allowSyntheticDefaultImports": true,
|
|
18
|
-
"typeRoots": ["./@types/**", "./node_modules/@types"],
|
|
19
|
-
"types": ["node", "jest"]
|
|
20
|
-
}
|
|
21
|
-
}
|
package/webpack.config.dev.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const TerserPlugin = require('terser-webpack-plugin');
|
|
2
|
-
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const webpack = require('webpack');
|
|
5
|
-
|
|
6
|
-
const config = {
|
|
7
|
-
mode: process.env.NODE_ENV || 'development',
|
|
8
|
-
optimization: {
|
|
9
|
-
minimize: process.env.NODE_ENV !== 'development',
|
|
10
|
-
minimizer:
|
|
11
|
-
process.env.NODE_ENV !== 'development'
|
|
12
|
-
? [
|
|
13
|
-
new TerserPlugin({
|
|
14
|
-
cache: true,
|
|
15
|
-
parallel: true,
|
|
16
|
-
sourceMap: true, // Must be set to true if using source-maps in production
|
|
17
|
-
terserOptions: {},
|
|
18
|
-
}),
|
|
19
|
-
new CssMinimizerPlugin(),
|
|
20
|
-
]
|
|
21
|
-
: [],
|
|
22
|
-
},
|
|
23
|
-
entry: {
|
|
24
|
-
example: path.join(__dirname, 'example/example.tsx'),
|
|
25
|
-
},
|
|
26
|
-
devtool: process.env.NODE_ENV !== 'development' ? false : 'inline-source-map',
|
|
27
|
-
module: {
|
|
28
|
-
rules: [
|
|
29
|
-
{
|
|
30
|
-
test: /\.(js|ts|tsx)$/,
|
|
31
|
-
exclude: /(node_modules)/,
|
|
32
|
-
use: {
|
|
33
|
-
loader: 'babel-loader',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
test: /\.css$/,
|
|
38
|
-
exclude: /(node_modules)/,
|
|
39
|
-
use: ['style-loader', 'css-loader'],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
devServer: {
|
|
44
|
-
contentBase: path.resolve(__dirname, 'examples/'),
|
|
45
|
-
compress: true,
|
|
46
|
-
port: 8000,
|
|
47
|
-
stats: 'errors-only',
|
|
48
|
-
open: true,
|
|
49
|
-
},
|
|
50
|
-
output: {
|
|
51
|
-
path: path.join(__dirname, 'example/'),
|
|
52
|
-
filename: '[name].min.js',
|
|
53
|
-
},
|
|
54
|
-
plugins: [
|
|
55
|
-
new webpack.DefinePlugin({
|
|
56
|
-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
|
57
|
-
}),
|
|
58
|
-
],
|
|
59
|
-
resolve: {
|
|
60
|
-
extensions: ['.tsx', '.ts', '.js'],
|
|
61
|
-
modules: [path.join(__dirname, './src'), path.join(__dirname, './node_modules')],
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
module.exports = config;
|
package/webpack.config.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
const TerserPlugin = require('terser-webpack-plugin');
|
|
2
|
-
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const webpack = require('webpack');
|
|
5
|
-
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
6
|
-
|
|
7
|
-
const config = {
|
|
8
|
-
mode: 'production',
|
|
9
|
-
optimization: {
|
|
10
|
-
minimize: true,
|
|
11
|
-
minimizer: [
|
|
12
|
-
new TerserPlugin({
|
|
13
|
-
cache: true,
|
|
14
|
-
parallel: true,
|
|
15
|
-
sourceMap: true, // Must be set to true if using source-maps in production
|
|
16
|
-
terserOptions: {},
|
|
17
|
-
}),
|
|
18
|
-
new CssMinimizerPlugin(),
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
entry: {
|
|
22
|
-
'react-pure-modal': path.join(__dirname, './src/react-pure-modal.tsx'),
|
|
23
|
-
},
|
|
24
|
-
module: {
|
|
25
|
-
rules: [
|
|
26
|
-
{
|
|
27
|
-
test: /\.(js|jsx|tsx|ts)$/,
|
|
28
|
-
exclude: /(node_modules|dist)/,
|
|
29
|
-
use: {
|
|
30
|
-
loader: 'babel-loader',
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
test: /\.css$/,
|
|
35
|
-
exclude: /(node_modules|dist)/,
|
|
36
|
-
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
output: {
|
|
41
|
-
path: path.join(__dirname, 'dist/'),
|
|
42
|
-
filename: '[name].min.js',
|
|
43
|
-
libraryTarget: 'umd',
|
|
44
|
-
globalObject: 'this',
|
|
45
|
-
},
|
|
46
|
-
plugins: [
|
|
47
|
-
new webpack.DefinePlugin({
|
|
48
|
-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
|
|
49
|
-
}),
|
|
50
|
-
new MiniCssExtractPlugin({ filename: '[name].min.css' }),
|
|
51
|
-
],
|
|
52
|
-
resolve: {
|
|
53
|
-
modules: ['node_modules'],
|
|
54
|
-
extensions: ['.tsx', '.ts', '.js'],
|
|
55
|
-
},
|
|
56
|
-
externals: {
|
|
57
|
-
react: 'umd react',
|
|
58
|
-
'react-dom': 'umd react-dom',
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
module.exports = config;
|