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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diginet-core-ui",
3
- "version": "1.3.55",
3
+ "version": "1.3.56",
4
4
  "description": "The DigiNet core ui",
5
5
  "homepage": "https://diginet.com.vn",
6
6
  "main": "index.js",
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
@@ -7,7 +7,7 @@ const useInput = props => {
7
7
  delayOnChange,
8
8
  onChange,
9
9
  onInput
10
- } = props;
10
+ } = props || {};
11
11
  const [value, setValue] = useState(defaultValue || valueProp);
12
12
  const timer = useRef(null);
13
13
  delayOnChange = Number(delayOnChange || 0);