diginet-core-ui 1.3.55 → 1.3.56
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/components/button/icon.js +21 -21
- package/components/form-control/dropdown/index.js +313 -340
- package/components/form-control/number-input/index2.js +3 -1
- package/components/index.js +1 -1
- package/components/modal/body.js +58 -48
- package/components/modal/footer.js +43 -41
- package/components/modal/header.js +22 -18
- package/components/modal/modal.js +70 -48
- package/components/paging/page-selector2.js +373 -0
- package/package.json +1 -1
- package/readme.md +7 -0
- package/utils/useElementSize.js +48 -0
- package/utils/useEventListener.js +45 -0
- package/utils/useInput.js +1 -1
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/** @jsxRuntime classic */
|
|
2
|
+
|
|
3
|
+
/** @jsx jsx */
|
|
4
|
+
import { memo, useState, useRef, useEffect, useMemo, forwardRef, useImperativeHandle } from 'react';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import { jsx, css } from '@emotion/core';
|
|
7
|
+
import { getGlobal } from '../../global';
|
|
8
|
+
import theme from '../../theme/settings';
|
|
9
|
+
import { alignCenter, borderBox, flexRow, parseHeight } from '../../styles/general';
|
|
10
|
+
import { ButtonIcon } from '..';
|
|
11
|
+
import { useElementSize } from '../../utils/useElementSize';
|
|
12
|
+
const {
|
|
13
|
+
colors: {
|
|
14
|
+
system: {
|
|
15
|
+
white
|
|
16
|
+
},
|
|
17
|
+
line: {
|
|
18
|
+
system
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
typography: {
|
|
22
|
+
paragraph2
|
|
23
|
+
},
|
|
24
|
+
spacing
|
|
25
|
+
} = theme;
|
|
26
|
+
|
|
27
|
+
const getLastPage = (totalItems, itemsPerPage) => {
|
|
28
|
+
let _lastPage = 0;
|
|
29
|
+
|
|
30
|
+
if (totalItems && totalItems >= 0 && itemsPerPage && itemsPerPage > 0) {
|
|
31
|
+
_lastPage = Math.ceil(totalItems / itemsPerPage);
|
|
32
|
+
return _lastPage;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return _lastPage + 1;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const delayOnInput = getGlobal('delayOnInput');
|
|
39
|
+
const PagingSelector = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
40
|
+
className,
|
|
41
|
+
currentPage,
|
|
42
|
+
hideEllipsis,
|
|
43
|
+
id,
|
|
44
|
+
itemsPerPage,
|
|
45
|
+
onChangePage,
|
|
46
|
+
onChangePerPage,
|
|
47
|
+
onChangingPage,
|
|
48
|
+
onChangingPerPage,
|
|
49
|
+
style,
|
|
50
|
+
totalItems
|
|
51
|
+
}, reference) => {
|
|
52
|
+
const ref = useRef(null);
|
|
53
|
+
const timer = useRef(null);
|
|
54
|
+
const currentPageRef = useRef(null);
|
|
55
|
+
const [totalItemsState, setTotalItemsState] = useState(totalItems);
|
|
56
|
+
const [itemsPerPageState, setItemsPerPageState] = useState(itemsPerPage || 10);
|
|
57
|
+
const [currentPageState, setCurrentPageState] = useState(currentPage);
|
|
58
|
+
const [disablePrevState, setDisablePrevState] = useState(true);
|
|
59
|
+
const [disableNextState, setDisableNextState] = useState(!(totalItems > itemsPerPage));
|
|
60
|
+
const [refSize, {
|
|
61
|
+
width: componentWidth
|
|
62
|
+
}] = useElementSize();
|
|
63
|
+
const lastPage = getLastPage(totalItemsState, itemsPerPageState);
|
|
64
|
+
|
|
65
|
+
const _onChangePage = async (page, isInit = false, e) => {
|
|
66
|
+
let disablePrev = false;
|
|
67
|
+
let disableNext = false; // If last page = 1. Disable all
|
|
68
|
+
|
|
69
|
+
if (lastPage === 1) {
|
|
70
|
+
disablePrev = true;
|
|
71
|
+
disableNext = true;
|
|
72
|
+
} // If current page = last page. Disable Next and Last
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if (page + 1 >= lastPage) {
|
|
76
|
+
disableNext = true;
|
|
77
|
+
} // If current page = 0. Disable Previous and First
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if (page === 0) {
|
|
81
|
+
disablePrev = true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (onChangingPage && !isInit) {
|
|
85
|
+
const event = { ...e,
|
|
86
|
+
cancel: false,
|
|
87
|
+
prevPage: currentPageState,
|
|
88
|
+
newPage: page
|
|
89
|
+
};
|
|
90
|
+
await onChangingPage(event);
|
|
91
|
+
|
|
92
|
+
if (event.cancel) {
|
|
93
|
+
if (e !== null && e !== void 0 && e.reset) e.reset();
|
|
94
|
+
setCurrentPageState(currentPageState);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
currentPageRef.current = page;
|
|
100
|
+
setCurrentPageState(page);
|
|
101
|
+
setDisablePrevState(disablePrev);
|
|
102
|
+
setDisableNextState(disableNext);
|
|
103
|
+
if (onChangePage && !isInit) onChangePage(page);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const _onChangePerPage = async per => {
|
|
107
|
+
const lastPage = getLastPage(totalItemsState, per);
|
|
108
|
+
per = parseInt(per, 10);
|
|
109
|
+
let disableNext = false; // If last page = 1. Disable all
|
|
110
|
+
|
|
111
|
+
if (lastPage === 1) {
|
|
112
|
+
disableNext = true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (onChangingPerPage) {
|
|
116
|
+
const event = {
|
|
117
|
+
cancel: false,
|
|
118
|
+
prevPerPage: itemsPerPageState,
|
|
119
|
+
newPerPage: per
|
|
120
|
+
};
|
|
121
|
+
await onChangingPerPage(event);
|
|
122
|
+
|
|
123
|
+
if (event.cancel) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
currentPageRef.current = 0;
|
|
129
|
+
setItemsPerPageState(per);
|
|
130
|
+
setCurrentPageState(0);
|
|
131
|
+
setDisablePrevState(true);
|
|
132
|
+
setDisableNextState(disableNext);
|
|
133
|
+
if (onChangePerPage) onChangePerPage(per);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
setTotalItemsState(totalItems);
|
|
138
|
+
}, [totalItems]);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (timer.current) {
|
|
141
|
+
clearTimeout(timer.current);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
timer.current = setTimeout(() => {
|
|
145
|
+
_onChangePage(currentPageState !== null && currentPageState !== void 0 ? currentPageState : 0, true);
|
|
146
|
+
}, delayOnInput);
|
|
147
|
+
}, [totalItemsState, itemsPerPageState]);
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
setItemsPerPageState(itemsPerPage);
|
|
150
|
+
}, [itemsPerPage]);
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
setCurrentPageState(currentPage);
|
|
153
|
+
|
|
154
|
+
if (timer.current) {
|
|
155
|
+
clearTimeout(timer.current);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
timer.current = setTimeout(() => {
|
|
159
|
+
_onChangePage(currentPage, true);
|
|
160
|
+
}, delayOnInput);
|
|
161
|
+
}, [currentPage]);
|
|
162
|
+
useImperativeHandle(reference, () => {
|
|
163
|
+
const currentRef = ref.current || {};
|
|
164
|
+
const _instance = {
|
|
165
|
+
onChangePage: page => _onChangePage(page),
|
|
166
|
+
onChangePerPage: per => _onChangePerPage(per),
|
|
167
|
+
setTotalItems: items => setTotalItemsState(items)
|
|
168
|
+
}; // methods
|
|
169
|
+
|
|
170
|
+
_instance.__proto__ = {}; // hidden methods
|
|
171
|
+
|
|
172
|
+
currentRef.instance = _instance;
|
|
173
|
+
|
|
174
|
+
currentRef.onChangePage = page => _onChangePage(page);
|
|
175
|
+
|
|
176
|
+
currentRef.onChangePerPage = per => _onChangePerPage(per);
|
|
177
|
+
|
|
178
|
+
currentRef.setTotalItems = items => setTotalItemsState(items);
|
|
179
|
+
|
|
180
|
+
return currentRef;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const renderButton = (key, page, isSelected, customDisplay) => {
|
|
184
|
+
if (page >= lastPage || page < 0) return;
|
|
185
|
+
return jsx(ButtonIcon, {
|
|
186
|
+
key: key,
|
|
187
|
+
css: ButtonIconCSS,
|
|
188
|
+
circular: true,
|
|
189
|
+
viewType: isSelected ? 'filled' : 'text',
|
|
190
|
+
size: 'small',
|
|
191
|
+
color: 'primary',
|
|
192
|
+
style: {
|
|
193
|
+
fontWeight: 'normal'
|
|
194
|
+
},
|
|
195
|
+
onClick: e => page !== currentPageState && _onChangePage(page, false, e)
|
|
196
|
+
}, customDisplay || page + 1);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return useMemo(() => {
|
|
200
|
+
const count = componentWidth >= 368 ? 10 : componentWidth >= 208 ? 5 : 1;
|
|
201
|
+
const pageArr = Array.from(Array(count).keys());
|
|
202
|
+
const halfArrLength = Math.floor(count / 2);
|
|
203
|
+
const quarterArrLength = Math.floor(count / 2.5);
|
|
204
|
+
const showEllipsis = !hideEllipsis && count !== lastPage && count >= 5;
|
|
205
|
+
return jsx("div", {
|
|
206
|
+
css: PageSelectorCSS,
|
|
207
|
+
ref: node => {
|
|
208
|
+
ref.current = node;
|
|
209
|
+
refSize(node);
|
|
210
|
+
},
|
|
211
|
+
id: id,
|
|
212
|
+
style: style,
|
|
213
|
+
className: ['DGN-UI-PagingSelector', className].join(' ').trim().replace(/\s+/g, ' ')
|
|
214
|
+
}, jsx(ButtonIcon, {
|
|
215
|
+
circular: true,
|
|
216
|
+
viewType: 'text',
|
|
217
|
+
size: 'small',
|
|
218
|
+
name: 'ArrowLeft',
|
|
219
|
+
disabled: disablePrevState,
|
|
220
|
+
onClick: e => {
|
|
221
|
+
currentPageRef.current = currentPageRef.current - 1;
|
|
222
|
+
|
|
223
|
+
if (timer.current) {
|
|
224
|
+
clearTimeout(timer.current);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
timer.current = setTimeout(() => {
|
|
228
|
+
_onChangePage(currentPageRef.current, false, e);
|
|
229
|
+
}, delayOnInput);
|
|
230
|
+
}
|
|
231
|
+
}), pageArr.map((_, idx) => {
|
|
232
|
+
if (currentPageState < halfArrLength) {
|
|
233
|
+
// các trang đầu
|
|
234
|
+
if (showEllipsis) {
|
|
235
|
+
if (idx === count - 1 && lastPage - 1 >= 10) {
|
|
236
|
+
return renderButton(idx, lastPage - 1);
|
|
237
|
+
} else {
|
|
238
|
+
return renderButton(idx, idx, idx === currentPageState, idx === count - 2 && '...');
|
|
239
|
+
}
|
|
240
|
+
} else return renderButton(idx, idx, idx === currentPageState);
|
|
241
|
+
} else if (currentPageState >= lastPage - halfArrLength) {
|
|
242
|
+
// các trang cuối
|
|
243
|
+
if (showEllipsis) {
|
|
244
|
+
if (idx === 0) {
|
|
245
|
+
return renderButton(idx, idx);
|
|
246
|
+
} else {
|
|
247
|
+
return renderButton(idx, lastPage - count + idx, lastPage - count + idx === currentPageState, idx === 1 && '...');
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
return renderButton(idx, lastPage - count + idx, lastPage - count + idx === currentPageState);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
// các trang giữa
|
|
254
|
+
if (idx < quarterArrLength) {
|
|
255
|
+
if (showEllipsis) {
|
|
256
|
+
if (idx === 0) {
|
|
257
|
+
return renderButton(idx, idx);
|
|
258
|
+
} else {
|
|
259
|
+
return renderButton(idx, currentPageState - quarterArrLength + idx, false, idx === 1 && '...');
|
|
260
|
+
}
|
|
261
|
+
} else return renderButton(idx, currentPageState - quarterArrLength + idx);
|
|
262
|
+
} else if (idx === quarterArrLength) {
|
|
263
|
+
return renderButton(idx, currentPageState, true);
|
|
264
|
+
} else {
|
|
265
|
+
if (showEllipsis) {
|
|
266
|
+
if (idx === count - 1) {
|
|
267
|
+
return renderButton(idx, lastPage - 1);
|
|
268
|
+
} else {
|
|
269
|
+
return renderButton(idx, currentPageState - quarterArrLength + idx, false, idx === count - 2 && '...');
|
|
270
|
+
}
|
|
271
|
+
} else return renderButton(idx, currentPageState - quarterArrLength + idx);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}), jsx(ButtonIcon, {
|
|
275
|
+
circular: true,
|
|
276
|
+
viewType: 'text',
|
|
277
|
+
size: 'small',
|
|
278
|
+
name: 'ArrowRight',
|
|
279
|
+
disabled: disableNextState,
|
|
280
|
+
onClick: e => {
|
|
281
|
+
currentPageRef.current = currentPageRef.current + 1;
|
|
282
|
+
|
|
283
|
+
if (timer.current) {
|
|
284
|
+
clearTimeout(timer.current);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
timer.current = setTimeout(() => {
|
|
288
|
+
_onChangePage(currentPageRef.current, false, e);
|
|
289
|
+
}, delayOnInput);
|
|
290
|
+
}
|
|
291
|
+
}));
|
|
292
|
+
}, [id, style, className, hideEllipsis, totalItemsState, itemsPerPageState, currentPageState, disablePrevState, disableNextState, componentWidth]);
|
|
293
|
+
}));
|
|
294
|
+
const PageSelectorCSS = css`
|
|
295
|
+
${flexRow};
|
|
296
|
+
${alignCenter};
|
|
297
|
+
${borderBox};
|
|
298
|
+
${parseHeight(40)};
|
|
299
|
+
padding: ${spacing([1])};
|
|
300
|
+
background: ${white};
|
|
301
|
+
width: 100%;
|
|
302
|
+
border-top: 1px solid ${system};
|
|
303
|
+
`;
|
|
304
|
+
const ButtonIconCSS = css`
|
|
305
|
+
${paragraph2};
|
|
306
|
+
`;
|
|
307
|
+
PagingSelector.defaultProps = {
|
|
308
|
+
style: {},
|
|
309
|
+
className: '',
|
|
310
|
+
totalItems: 0,
|
|
311
|
+
currentPage: 0,
|
|
312
|
+
hideEllipsis: false
|
|
313
|
+
};
|
|
314
|
+
PagingSelector.propTypes = {
|
|
315
|
+
/** Class for component. */
|
|
316
|
+
className: PropTypes.string,
|
|
317
|
+
|
|
318
|
+
/** Specifies the current page. */
|
|
319
|
+
currentPage: PropTypes.number,
|
|
320
|
+
|
|
321
|
+
/** If `true`, hide ellipsis. */
|
|
322
|
+
hideEllipsis: PropTypes.bool,
|
|
323
|
+
|
|
324
|
+
/** The quantity of items per page. */
|
|
325
|
+
itemsPerPage: PropTypes.number,
|
|
326
|
+
|
|
327
|
+
/** Callback fired when page number changed. */
|
|
328
|
+
onChangePage: PropTypes.func,
|
|
329
|
+
|
|
330
|
+
/** Callback fired when quantity on per page changed. */
|
|
331
|
+
onChangePerPage: PropTypes.func,
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Callback fired when page number is changing.
|
|
335
|
+
*
|
|
336
|
+
* * prevPage: Page before changed
|
|
337
|
+
* * newPage: Page after changed
|
|
338
|
+
* * cancel(value): Function cancel change page
|
|
339
|
+
* * @param {value} - bool
|
|
340
|
+
*/
|
|
341
|
+
onChangingPage: PropTypes.func,
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Callback fired when quantity on item per page is changing.
|
|
345
|
+
*
|
|
346
|
+
* * prevPerPage: Items per page before changed
|
|
347
|
+
* * newPerPage: Items per page after changed
|
|
348
|
+
* * cancel(value): Function cancel change items per page
|
|
349
|
+
* * @param {value} - bool
|
|
350
|
+
*/
|
|
351
|
+
onChangingPerPage: PropTypes.func,
|
|
352
|
+
|
|
353
|
+
/** Style inline of component. */
|
|
354
|
+
style: PropTypes.object,
|
|
355
|
+
|
|
356
|
+
/** Total items. */
|
|
357
|
+
totalItems: PropTypes.number,
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* ref methods (ref.current.instance.*method*)
|
|
361
|
+
*
|
|
362
|
+
* * onChangePage(page): Change page number
|
|
363
|
+
* * @param {page} - number
|
|
364
|
+
* * onChangePerPage(per): Change quantity on per page
|
|
365
|
+
* * @param {per} - number
|
|
366
|
+
* * setTotalItems(items): Set total items
|
|
367
|
+
* * @param {items} - number
|
|
368
|
+
*/
|
|
369
|
+
reference: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
|
|
370
|
+
current: PropTypes.instanceOf(Element)
|
|
371
|
+
})])
|
|
372
|
+
};
|
|
373
|
+
export default PagingSelector;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -38,6 +38,13 @@ npm test
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## Changelog
|
|
41
|
+
## 1.3.56
|
|
42
|
+
- \[Changed\]: PagingSelector – Update PagingSelector with new design
|
|
43
|
+
- \[Changed\]: NumberInput – Return e.valueString
|
|
44
|
+
- \[Fixed\]: Modal – Fix bug not set overflow when close
|
|
45
|
+
- \[Fixed\]: Dropdown – Replace keyExpr with renderSelectedItem; Fix clear icon show wrong when not use prop value
|
|
46
|
+
- \[Fixed\]: Dropdown – Fix bug search, load more
|
|
47
|
+
|
|
41
48
|
## 1.3.55
|
|
42
49
|
- \[Added\]: MenuIcon – MHRM09N1040
|
|
43
50
|
- \[Added\]: Icon – CalendarAdd
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useCallback, useLayoutEffect, useState } from 'react';
|
|
2
|
+
import { useEventListener } from './useEventListener'; // Usage:
|
|
3
|
+
// export const Component = () => {
|
|
4
|
+
// const [isVisible, setVisible] = useState(true);
|
|
5
|
+
// const [squareRef, { width, height }] = useElementSize();
|
|
6
|
+
// const toggleVisibility = () => setVisible(x => !x);
|
|
7
|
+
// return (
|
|
8
|
+
// <>
|
|
9
|
+
// <p>{`The square width is ${width}px and height ${height}px`}</p>
|
|
10
|
+
// <p>Try, resize your window and-or click on the button.</p>
|
|
11
|
+
// <button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'} square</button>
|
|
12
|
+
// {isVisible && (
|
|
13
|
+
// <div
|
|
14
|
+
// ref={squareRef}
|
|
15
|
+
// style={{
|
|
16
|
+
// width: '50%',
|
|
17
|
+
// paddingTop: '50%',
|
|
18
|
+
// backgroundColor: 'aquamarine',
|
|
19
|
+
// margin: 'auto',
|
|
20
|
+
// }}
|
|
21
|
+
// />
|
|
22
|
+
// )}
|
|
23
|
+
// </>
|
|
24
|
+
// );
|
|
25
|
+
// }
|
|
26
|
+
|
|
27
|
+
export const useElementSize = () => {
|
|
28
|
+
// Mutable values like 'ref.current' aren't valid dependencies
|
|
29
|
+
// because mutating them doesn't re-render the component.
|
|
30
|
+
// Instead, we use a state as a ref to be reactive.
|
|
31
|
+
const [ref, setRef] = useState(null);
|
|
32
|
+
const [size, setSize] = useState({
|
|
33
|
+
width: 0,
|
|
34
|
+
height: 0
|
|
35
|
+
}); // Prevent too many rendering using useCallback
|
|
36
|
+
|
|
37
|
+
const handleSize = useCallback(() => {
|
|
38
|
+
setSize({
|
|
39
|
+
width: (ref === null || ref === void 0 ? void 0 : ref.offsetWidth) || 0,
|
|
40
|
+
height: (ref === null || ref === void 0 ? void 0 : ref.offsetHeight) || 0
|
|
41
|
+
});
|
|
42
|
+
}, [ref === null || ref === void 0 ? void 0 : ref.offsetHeight, ref === null || ref === void 0 ? void 0 : ref.offsetWidth]);
|
|
43
|
+
useEventListener('resize', handleSize);
|
|
44
|
+
useLayoutEffect(() => {
|
|
45
|
+
handleSize();
|
|
46
|
+
}, [ref === null || ref === void 0 ? void 0 : ref.offsetHeight, ref === null || ref === void 0 ? void 0 : ref.offsetWidth]);
|
|
47
|
+
return [setRef, size];
|
|
48
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef } from 'react'; // Usage:
|
|
2
|
+
// export const Component = () => {
|
|
3
|
+
// // Define button ref
|
|
4
|
+
// const buttonRef = useRef < HTMLButtonElement > null;
|
|
5
|
+
// const onScroll = (event: Event) => {
|
|
6
|
+
// console.log("window scrolled!", event);
|
|
7
|
+
// };
|
|
8
|
+
// const onClick = (event: Event) => {
|
|
9
|
+
// console.log("button clicked!", event);
|
|
10
|
+
// };
|
|
11
|
+
// // example with window based event
|
|
12
|
+
// useEventListener("scroll", onScroll);
|
|
13
|
+
// // example with element based event
|
|
14
|
+
// useEventListener("click", onClick, buttonRef);
|
|
15
|
+
// return (
|
|
16
|
+
// <div style={{ minHeight: "200vh" }}>
|
|
17
|
+
// <button ref={buttonRef}>Click me</button>
|
|
18
|
+
// </div>
|
|
19
|
+
// );
|
|
20
|
+
// };
|
|
21
|
+
|
|
22
|
+
export const useEventListener = (eventName, handler, element) => {
|
|
23
|
+
// Create a ref that stores handler
|
|
24
|
+
const savedHandler = useRef(handler);
|
|
25
|
+
useLayoutEffect(() => {
|
|
26
|
+
savedHandler.current = handler;
|
|
27
|
+
}, [handler]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
// Define the listening target
|
|
30
|
+
const targetElement = (element === null || element === void 0 ? void 0 : element.current) || window;
|
|
31
|
+
|
|
32
|
+
if (!(targetElement && targetElement.addEventListener)) {
|
|
33
|
+
return;
|
|
34
|
+
} // Create event listener that calls handler function stored in ref
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const eventListener = event => savedHandler.current(event);
|
|
38
|
+
|
|
39
|
+
targetElement.addEventListener(eventName, eventListener); // Remove event listener on cleanup
|
|
40
|
+
|
|
41
|
+
return () => {
|
|
42
|
+
targetElement.removeEventListener(eventName, eventListener);
|
|
43
|
+
};
|
|
44
|
+
}, [eventName, element]);
|
|
45
|
+
};
|
package/utils/useInput.js
CHANGED