diginet-core-ui 1.4.21 → 1.4.22
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/assets/images/menu/dhr/MHRP39N0020.svg +9 -0
- package/assets/images/menu/dhr/MHRP39N0021.svg +7 -0
- package/components/accordion/details.js +12 -14
- package/components/accordion/group.js +12 -14
- package/components/accordion/index.js +36 -38
- package/components/accordion/summary.js +50 -51
- package/components/form-control/time-picker/v2/index.js +792 -0
- package/components/image/index.js +22 -24
- package/components/index.js +1 -1
- package/components/modal/body.js +9 -11
- package/components/modal/footer.js +8 -10
- package/components/modal/header.js +27 -25
- package/components/modal/modal.js +33 -32
- package/components/tab/tab-container.js +57 -49
- package/components/tab/tab-header.js +70 -64
- package/components/tab/tab-panel.js +38 -32
- package/components/tab/tab.js +69 -61
- package/global/index.js +4 -0
- package/package.json +1 -1
- package/readme.md +13 -4
- package/theme/settings.js +54 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/** @jsxRuntime classic */
|
|
2
|
+
/** @jsx jsx */
|
|
3
|
+
import { css, jsx } from '@emotion/core';
|
|
4
|
+
import { Button, ButtonIcon, Divider, HelperText, InputBase, Label, NumberInput, Popover, Typography } from "../../..";
|
|
5
|
+
import { getGlobal } from "../../../../global";
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
8
|
+
import { bgColor, border, borderColor, borderNone, borderRadius4px, displayFlex, flexCol, itemsCenter, justifyBetween, justifyCenter, parseHeight, parseMinHeight, parseWidth, parseWidthHeight, positionRelative, textCenter, textColor } from "../../../../styles/general";
|
|
9
|
+
import { useTheme } from "../../../../theme";
|
|
10
|
+
import useThemeProps from "../../../../theme/utils/useThemeProps";
|
|
11
|
+
import { classNames, date, getProp, hexToRGBA } from "../../../../utils";
|
|
12
|
+
const TimePicker = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((inProps, reference) => {
|
|
13
|
+
if (!reference) reference = useRef(null);
|
|
14
|
+
|
|
15
|
+
// props priority: `inProps` > `themeDefaultProps`
|
|
16
|
+
const props = useThemeProps({
|
|
17
|
+
props: inProps,
|
|
18
|
+
name: 'TimePicker'
|
|
19
|
+
});
|
|
20
|
+
const {
|
|
21
|
+
action = {},
|
|
22
|
+
actionIconAt,
|
|
23
|
+
className,
|
|
24
|
+
disabled,
|
|
25
|
+
displayFormat,
|
|
26
|
+
error,
|
|
27
|
+
errorProps,
|
|
28
|
+
inputProps,
|
|
29
|
+
inputStyle,
|
|
30
|
+
placeholder: placeholderProp,
|
|
31
|
+
onChange,
|
|
32
|
+
mode12h,
|
|
33
|
+
min,
|
|
34
|
+
max,
|
|
35
|
+
minuteStep,
|
|
36
|
+
label,
|
|
37
|
+
labelProps,
|
|
38
|
+
style,
|
|
39
|
+
value: valueProp,
|
|
40
|
+
viewType,
|
|
41
|
+
returnFormat,
|
|
42
|
+
readOnly,
|
|
43
|
+
required,
|
|
44
|
+
...other
|
|
45
|
+
} = props;
|
|
46
|
+
const placeholder = placeholderProp !== null && placeholderProp !== void 0 ? placeholderProp : displayFormat;
|
|
47
|
+
let value = valueProp;
|
|
48
|
+
|
|
49
|
+
// ref
|
|
50
|
+
const ref = useRef(null);
|
|
51
|
+
const timePickerRef = useRef(null);
|
|
52
|
+
|
|
53
|
+
// states
|
|
54
|
+
const [currentInputFocus, setCurrentInputFocus] = useState(null);
|
|
55
|
+
const [displayTime, setDisplayTime] = useState(value);
|
|
56
|
+
const [minValue, setMinValue] = useState(min);
|
|
57
|
+
const [maxValue, setMaxValue] = useState(max);
|
|
58
|
+
const [timeValue, setTimeValue] = useState({
|
|
59
|
+
hour: mode12h ? 1 : 0,
|
|
60
|
+
minute: 0,
|
|
61
|
+
second: 0,
|
|
62
|
+
text: 'AM'
|
|
63
|
+
});
|
|
64
|
+
const theme = useTheme();
|
|
65
|
+
|
|
66
|
+
// css
|
|
67
|
+
const _TimePickerBodyCSS = TimePickerBodyCSS(currentInputFocus, theme);
|
|
68
|
+
const _TimePickerAMPMCSS = TimePickerAMPMCSS(timeValue === null || timeValue === void 0 ? void 0 : timeValue.text, theme);
|
|
69
|
+
const _TimePickerCSS = TimePickerCSS(theme);
|
|
70
|
+
const _TimePickerFooterCSS = TimePickerFooterCSS(theme);
|
|
71
|
+
|
|
72
|
+
// variables
|
|
73
|
+
const isError = !!error && !value;
|
|
74
|
+
const currentHour = Number(timeValue === null || timeValue === void 0 ? void 0 : timeValue.hour);
|
|
75
|
+
const currentMinute = Number(timeValue === null || timeValue === void 0 ? void 0 : timeValue.minute);
|
|
76
|
+
const currentSecond = Number(timeValue === null || timeValue === void 0 ? void 0 : timeValue.second);
|
|
77
|
+
const currentTime = new Date(new Date().getFullYear(), 0, 1, currentHour, currentMinute, currentSecond);
|
|
78
|
+
const maxHour = maxValue.slice(0, 2) ? Number(maxValue.slice(0, 2)) : mode12h ? 12 : 23;
|
|
79
|
+
const maxMinute = maxValue.slice(3, 5) ? Number(maxValue.slice(3, 5)) : 59;
|
|
80
|
+
const maxSecond = maxValue.slice(6, 8) ? Number(maxValue.slice(6, 8)) : 59;
|
|
81
|
+
const minHour = minValue.slice(0, 2) ? Number(minValue.slice(0, 2)) : mode12h ? 1 : 0;
|
|
82
|
+
const minMinute = minValue.slice(3, 5) ? Number(minValue.slice(3, 5)) : 0;
|
|
83
|
+
const minSecond = minValue.slice(6, 8) ? Number(minValue.slice(6, 8)) : 0;
|
|
84
|
+
const startHour = minHour ? minHour : mode12h ? 1 : 0;
|
|
85
|
+
const startMinute = currentHour === minHour ? minMinute : 0;
|
|
86
|
+
const startSecond = currentHour === minHour && currentMinute === minMinute ? minSecond : 0;
|
|
87
|
+
const lastHour = maxHour ? maxHour : mode12h ? 12 : 23;
|
|
88
|
+
const lastMinute = currentHour === maxHour ? maxMinute : 59;
|
|
89
|
+
const lastSecond = currentHour === maxHour && currentMinute === maxMinute ? maxSecond : 59;
|
|
90
|
+
const saveText = getGlobal(['save']);
|
|
91
|
+
const nowText = getGlobal(['now']);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* onChange handler with condition base on min max
|
|
95
|
+
* @param {*} e
|
|
96
|
+
* @param {String} key one of ['hour', 'minute', 'second']
|
|
97
|
+
*/
|
|
98
|
+
const onChangeHandler = (e, key) => {
|
|
99
|
+
var _e$target;
|
|
100
|
+
if (!e) return;
|
|
101
|
+
value = +(e === null || e === void 0 ? void 0 : (_e$target = e.target) === null || _e$target === void 0 ? void 0 : _e$target.value) || 0;
|
|
102
|
+
if (key === 'hour') {
|
|
103
|
+
if (maxHour === value && maxMinute <= currentMinute) {
|
|
104
|
+
if (maxSecond <= currentSecond) {
|
|
105
|
+
setTimeValue({
|
|
106
|
+
...timeValue,
|
|
107
|
+
hour: maxHour,
|
|
108
|
+
minute: maxMinute,
|
|
109
|
+
second: maxSecond
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
setTimeValue({
|
|
114
|
+
...timeValue,
|
|
115
|
+
hour: maxHour,
|
|
116
|
+
minute: maxMinute
|
|
117
|
+
});
|
|
118
|
+
} else if (minHour >= value && minMinute >= currentMinute && minSecond >= currentSecond) {
|
|
119
|
+
setTimeValue({
|
|
120
|
+
...timeValue,
|
|
121
|
+
hour: minHour,
|
|
122
|
+
minute: minMinute,
|
|
123
|
+
second: minSecond
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
setTimeValue({
|
|
127
|
+
...timeValue,
|
|
128
|
+
[key]: value
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} else if (key === 'minute') {
|
|
132
|
+
if (currentHour === maxHour && maxMinute <= value && currentSecond >= maxSecond) {
|
|
133
|
+
setTimeValue({
|
|
134
|
+
...timeValue,
|
|
135
|
+
minute: maxMinute,
|
|
136
|
+
second: maxSecond
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
setTimeValue({
|
|
140
|
+
...timeValue,
|
|
141
|
+
[key]: value
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
setTimeValue({
|
|
146
|
+
...timeValue,
|
|
147
|
+
[key]: value
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
*
|
|
154
|
+
* @param {String} key
|
|
155
|
+
* @param {Number} value
|
|
156
|
+
*/
|
|
157
|
+
const setTimeAfterChange = (key, value) => {
|
|
158
|
+
setTimeValue({
|
|
159
|
+
...timeValue,
|
|
160
|
+
[key]: value
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
*
|
|
166
|
+
* Arrow up hour input onClick in the following cases:
|
|
167
|
+
* (1): Increase current hour by 1
|
|
168
|
+
* (2): If current hour is equal to max hour value, set current hour equal to min hour
|
|
169
|
+
* (3): If current hour plus 1 is equal to max hour, set current minute equal to max minute if current minute greater than max minute value
|
|
170
|
+
* (4): If current hour plus 1 is equal to max hour, set current second equal to max second if current second greater than max second value
|
|
171
|
+
* (5): Set current minute, second to min minute, second if current hour is greater than max hour value and current minute, second is greater than min minute, second value
|
|
172
|
+
*/
|
|
173
|
+
const onIncreaseHour = () => {
|
|
174
|
+
if (maxHour === currentHour + 1 && maxMinute < currentMinute) {
|
|
175
|
+
// (3)
|
|
176
|
+
if (maxSecond < currentSecond) {
|
|
177
|
+
// (4)
|
|
178
|
+
setTimeValue({
|
|
179
|
+
...timeValue,
|
|
180
|
+
hour: maxHour,
|
|
181
|
+
minute: maxMinute,
|
|
182
|
+
second: maxSecond
|
|
183
|
+
});
|
|
184
|
+
} else {
|
|
185
|
+
setTimeValue({
|
|
186
|
+
...timeValue,
|
|
187
|
+
hour: maxHour,
|
|
188
|
+
minute: maxMinute
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
} else if (maxHour <= currentHour) {
|
|
192
|
+
// (2)
|
|
193
|
+
if (minMinute <= currentMinute) {
|
|
194
|
+
// (5)
|
|
195
|
+
setTimeValue({
|
|
196
|
+
...timeValue,
|
|
197
|
+
hour: minHour
|
|
198
|
+
});
|
|
199
|
+
} else {
|
|
200
|
+
setTimeValue({
|
|
201
|
+
...timeValue,
|
|
202
|
+
hour: minHour,
|
|
203
|
+
minute: minMinute,
|
|
204
|
+
second: minSecond
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
setTimeAfterChange('hour', currentHour + 1); // (1)
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
*
|
|
214
|
+
* @constant {Number} minuteStep
|
|
215
|
+
* @constant {Number} lastMinute
|
|
216
|
+
* Arrow up minute input onClick in the following cases:
|
|
217
|
+
* (1): Increase current minute by minute step (default 1).
|
|
218
|
+
* (2): If current minute plus minute step is greater than lastMinute, set current minute equal to min minute.
|
|
219
|
+
* (3): If current second greater than max second value, set current second equal to max second.
|
|
220
|
+
* (4): (3) and current second is greater than max second value, set current second equal to max second.
|
|
221
|
+
*/
|
|
222
|
+
const onIncreaseMinute = () => {
|
|
223
|
+
if (lastMinute < currentMinute + minuteStep) {
|
|
224
|
+
// (2)
|
|
225
|
+
setTimeAfterChange('minute', startMinute);
|
|
226
|
+
} else if (lastMinute === currentMinute + minuteStep) {
|
|
227
|
+
if (currentSecond > maxSecond) {
|
|
228
|
+
// (4)
|
|
229
|
+
setTimeValue({
|
|
230
|
+
...timeValue,
|
|
231
|
+
minute: currentMinute + minuteStep,
|
|
232
|
+
second: maxSecond
|
|
233
|
+
});
|
|
234
|
+
} else {
|
|
235
|
+
// (3)
|
|
236
|
+
setTimeValue({
|
|
237
|
+
...timeValue,
|
|
238
|
+
minute: currentMinute + minuteStep
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
// (1)
|
|
243
|
+
setTimeAfterChange('minute', currentMinute + minuteStep);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
*
|
|
249
|
+
* Arrow up second input onClick in the following cases:
|
|
250
|
+
* (1): Increase current second by 1
|
|
251
|
+
* (2): If current second plus 1 equal to max second value, set current second to min second
|
|
252
|
+
*/
|
|
253
|
+
const onIncreaseSecond = () => {
|
|
254
|
+
if (lastSecond < currentSecond + 1) {
|
|
255
|
+
// (2)
|
|
256
|
+
setTimeAfterChange('second', startSecond);
|
|
257
|
+
} else {
|
|
258
|
+
// (1)
|
|
259
|
+
setTimeAfterChange('second', currentSecond + 1);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
*
|
|
265
|
+
* Arrow down hour input onClick in the following cases:
|
|
266
|
+
* (1): Decrease current hour by 1
|
|
267
|
+
* (2): If current hour is equal to min hour value, set current hour equal to max hour
|
|
268
|
+
* (3): (2) and current minute is greater than max minute value, set minute to max minute value
|
|
269
|
+
* (4): (3) and current second is greater than min second value, set second to max second value
|
|
270
|
+
* (5): If current hour minus 1 is equal to min hour and current minute greater than min minute value, set current minute equal to min minute
|
|
271
|
+
* (6): (5) and current second is greater than min second value, set current second equal to min second
|
|
272
|
+
*/
|
|
273
|
+
const onDecreaseHour = () => {
|
|
274
|
+
if (minHour === currentHour - 1 && minMinute > currentMinute) {
|
|
275
|
+
if (minSecond > currentSecond) {
|
|
276
|
+
// (6)
|
|
277
|
+
setTimeValue({
|
|
278
|
+
...timeValue,
|
|
279
|
+
hour: minHour,
|
|
280
|
+
minute: minMinute,
|
|
281
|
+
second: minSecond
|
|
282
|
+
});
|
|
283
|
+
} else {
|
|
284
|
+
// (5)
|
|
285
|
+
setTimeValue({
|
|
286
|
+
...timeValue,
|
|
287
|
+
hour: minHour,
|
|
288
|
+
minute: minMinute
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
} else if (minHour >= currentHour) {
|
|
292
|
+
if (maxMinute < currentMinute) {
|
|
293
|
+
if (maxSecond < currentSecond) {
|
|
294
|
+
// (4)
|
|
295
|
+
setTimeValue({
|
|
296
|
+
...timeValue,
|
|
297
|
+
hour: maxHour,
|
|
298
|
+
minute: maxMinute,
|
|
299
|
+
second: maxSecond
|
|
300
|
+
});
|
|
301
|
+
} else {
|
|
302
|
+
// (3)
|
|
303
|
+
setTimeValue({
|
|
304
|
+
...timeValue,
|
|
305
|
+
hour: maxHour,
|
|
306
|
+
minute: maxMinute
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
// (2)
|
|
311
|
+
setTimeValue({
|
|
312
|
+
...timeValue,
|
|
313
|
+
hour: maxHour
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
// (1)
|
|
318
|
+
setTimeAfterChange('hour', currentHour - 1);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
*
|
|
324
|
+
* @constant {Number} minuteStep
|
|
325
|
+
* @constant {Number} startMinute
|
|
326
|
+
* @constant {Number} lastMinute
|
|
327
|
+
* Arrow down minute input onClick in the following cases:
|
|
328
|
+
* (1): Decrease current minute by @minuteStep
|
|
329
|
+
* (2): If current minute minus @minuteStep is smaller than @startMinute , set current minute to @lastMinute - @lastMinute % @minuteStep
|
|
330
|
+
* (3): (2) and current second is greater than max second, set current second to max second
|
|
331
|
+
*/
|
|
332
|
+
const onDecreaseMinute = () => {
|
|
333
|
+
if (startMinute > currentMinute - minuteStep) {
|
|
334
|
+
if (currentHour === maxHour && currentSecond > maxSecond) {
|
|
335
|
+
// (3)
|
|
336
|
+
setTimeValue({
|
|
337
|
+
...timeValue,
|
|
338
|
+
minute: lastMinute - lastMinute % minuteStep,
|
|
339
|
+
second: maxSecond
|
|
340
|
+
});
|
|
341
|
+
} else {
|
|
342
|
+
// (2)
|
|
343
|
+
setTimeAfterChange('minute', lastMinute - lastMinute % minuteStep);
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
// (1)
|
|
347
|
+
setTimeAfterChange('minute', currentMinute - minuteStep);
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
*
|
|
353
|
+
* @constant {Number} startSecond
|
|
354
|
+
* @constant {Number} lastSecond
|
|
355
|
+
* Arrow down second input onClick in the following cases:
|
|
356
|
+
* (1): Decrease current second by 1
|
|
357
|
+
* (2): If current second minus 1 is smaller than start second, set current second to last second
|
|
358
|
+
*/
|
|
359
|
+
const onDecreaseSecond = () => {
|
|
360
|
+
if (startSecond >= currentSecond - 1) {
|
|
361
|
+
// (2)
|
|
362
|
+
setTimeAfterChange('second', lastSecond);
|
|
363
|
+
} else {
|
|
364
|
+
// (1)
|
|
365
|
+
setTimeAfterChange('second', currentSecond - 1);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
*
|
|
371
|
+
* onClose Popover Timepicker when click Save button
|
|
372
|
+
*/
|
|
373
|
+
const onCloseTimePicker = () => {
|
|
374
|
+
timePickerRef.current.close();
|
|
375
|
+
setCurrentInputFocus(null);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
*
|
|
380
|
+
* Format value using date().format() in utils
|
|
381
|
+
* @param {Date} value
|
|
382
|
+
* @param {String} outputFormat
|
|
383
|
+
* @returns
|
|
384
|
+
*/
|
|
385
|
+
const formatTime = (value, outputFormat) => {
|
|
386
|
+
return mode12h ? date(value).format(`hh${outputFormat.slice(2)} A`) : date(value).format(outputFormat);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
*
|
|
391
|
+
* Button Save onClick
|
|
392
|
+
* @param {Boolean} now
|
|
393
|
+
*/
|
|
394
|
+
const onSelectTime = (now = false) => {
|
|
395
|
+
let displayTimeValue = '00:00:00';
|
|
396
|
+
let returnTimeValue = '00:00:00';
|
|
397
|
+
if (now) {
|
|
398
|
+
displayTimeValue = formatTime(null, displayFormat);
|
|
399
|
+
returnTimeValue = formatTime(null, returnFormat);
|
|
400
|
+
setTimeValue({
|
|
401
|
+
hour: displayTimeValue.slice(0, 2).includes(':') ? displayTimeValue.slice(0, 1) : displayTimeValue.slice(0, 2),
|
|
402
|
+
minute: displayTimeValue.slice(0, 2).includes(':') ? displayTimeValue.slice(2, 4) : displayTimeValue.slice(3, 5),
|
|
403
|
+
second: displayTimeValue.slice(0, 2).includes(':') ? displayTimeValue.slice(5, 7) : displayTimeValue.slice(6, 8),
|
|
404
|
+
text: displayTimeValue.slice(0, 2).includes(':') ? displayTimeValue.slice(9, 11) : displayTimeValue.slice(10, 12)
|
|
405
|
+
});
|
|
406
|
+
} else {
|
|
407
|
+
displayTimeValue = `${date(currentTime).format(displayFormat)} ${mode12h ? timeValue === null || timeValue === void 0 ? void 0 : timeValue.text : ''}`;
|
|
408
|
+
returnTimeValue = `${date(currentTime).format(returnFormat)} ${mode12h ? timeValue === null || timeValue === void 0 ? void 0 : timeValue.text : ''}`;
|
|
409
|
+
}
|
|
410
|
+
if (!now) {
|
|
411
|
+
setDisplayTime(displayTimeValue);
|
|
412
|
+
const e = {
|
|
413
|
+
value: returnTimeValue
|
|
414
|
+
};
|
|
415
|
+
!!onChange && onChange(e);
|
|
416
|
+
onCloseTimePicker();
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// useEffect for prop value
|
|
421
|
+
useEffect(() => {
|
|
422
|
+
if (!value) {
|
|
423
|
+
setTimeValue({
|
|
424
|
+
hour: min ? min.slice(0, 2) : mode12h ? 1 : 0,
|
|
425
|
+
minute: min ? min.slice(3, 5) : 0,
|
|
426
|
+
second: min ? min.slice(6, 8) : 0,
|
|
427
|
+
text: min ? min.slice(10, 12) || 'AM' : 'AM'
|
|
428
|
+
});
|
|
429
|
+
setDisplayTime(null);
|
|
430
|
+
} else {
|
|
431
|
+
let displayTimeValue = '00:00:00';
|
|
432
|
+
const valueHour = Number(value.slice(0, 2)) || '00';
|
|
433
|
+
const valueMinute = Number(value.slice(3, 5)) || '00';
|
|
434
|
+
const valueSecond = Number(value.slice(6, 8)) || '00';
|
|
435
|
+
const valueTime = new Date(new Date().getFullYear(), 0, 1, valueHour, valueMinute, valueSecond);
|
|
436
|
+
displayTimeValue = formatTime(valueTime, displayFormat);
|
|
437
|
+
setTimeValue({
|
|
438
|
+
hour: value.slice(0, 2),
|
|
439
|
+
minute: value.slice(3, 5),
|
|
440
|
+
second: value.slice(6, 8),
|
|
441
|
+
text: value.slice(10, 12)
|
|
442
|
+
});
|
|
443
|
+
setDisplayTime(displayTimeValue);
|
|
444
|
+
}
|
|
445
|
+
}, [value, displayFormat, returnFormat, mode12h, min, max]);
|
|
446
|
+
|
|
447
|
+
// useEffect for prop min/max
|
|
448
|
+
useEffect(() => {
|
|
449
|
+
setMinValue(min);
|
|
450
|
+
setMaxValue(max);
|
|
451
|
+
}, [min, max]);
|
|
452
|
+
useImperativeHandle(reference, () => {
|
|
453
|
+
const currentRef = ref.current || {};
|
|
454
|
+
currentRef.element = ref.current;
|
|
455
|
+
const _instance = {
|
|
456
|
+
...action
|
|
457
|
+
}; // methods
|
|
458
|
+
_instance.__proto__ = {}; // hidden methods
|
|
459
|
+
currentRef.instance = _instance;
|
|
460
|
+
return currentRef;
|
|
461
|
+
});
|
|
462
|
+
const IconComp = jsx(ButtonIcon, {
|
|
463
|
+
disabled: disabled || readOnly,
|
|
464
|
+
viewType: 'ghost',
|
|
465
|
+
viewBox: true,
|
|
466
|
+
name: 'clock'
|
|
467
|
+
});
|
|
468
|
+
const endIcon = actionIconAt === 'end' ? IconComp : null;
|
|
469
|
+
const startIcon = actionIconAt === 'start' ? IconComp : null;
|
|
470
|
+
return jsx("div", {
|
|
471
|
+
ref: ref,
|
|
472
|
+
css: positionRelative,
|
|
473
|
+
style: style,
|
|
474
|
+
className: classNames('DGN-UI-TimePicker-Root', className, disabled && 'disabled'),
|
|
475
|
+
...other
|
|
476
|
+
}, label && jsx(Label, {
|
|
477
|
+
disabled: disabled,
|
|
478
|
+
required: required,
|
|
479
|
+
...labelProps
|
|
480
|
+
}, label), jsx(Popover, {
|
|
481
|
+
css: _TimePickerCSS,
|
|
482
|
+
anchor: jsx(InputBase, {
|
|
483
|
+
inputProps: {
|
|
484
|
+
placeholder: !readOnly && !disabled ? placeholder : '',
|
|
485
|
+
...inputProps
|
|
486
|
+
},
|
|
487
|
+
disabled: disabled,
|
|
488
|
+
viewType: viewType,
|
|
489
|
+
inputStyle: {
|
|
490
|
+
...inputStyle
|
|
491
|
+
},
|
|
492
|
+
value: displayTime,
|
|
493
|
+
endIcon: endIcon,
|
|
494
|
+
startIcon: startIcon,
|
|
495
|
+
onKeyDown: e => e.preventDefault(),
|
|
496
|
+
status: error ? 'danger' : 'default',
|
|
497
|
+
readOnly: true
|
|
498
|
+
}),
|
|
499
|
+
ref: timePickerRef,
|
|
500
|
+
transformOrigin: {
|
|
501
|
+
vertical: 'top',
|
|
502
|
+
horizontal: 'left'
|
|
503
|
+
},
|
|
504
|
+
anchorOrigin: {
|
|
505
|
+
vertical: 'bottom',
|
|
506
|
+
horizontal: 'left'
|
|
507
|
+
}
|
|
508
|
+
}, jsx("div", {
|
|
509
|
+
className: "DGN-UI-TimePicker"
|
|
510
|
+
}, jsx("div", {
|
|
511
|
+
className: "DGN-UI-TimePicker-Body",
|
|
512
|
+
css: _TimePickerBodyCSS
|
|
513
|
+
}, jsx("div", {
|
|
514
|
+
className: "DGN-UI-TimePicker-Input",
|
|
515
|
+
css: TimePickerInputCSS
|
|
516
|
+
}, currentInputFocus === 1 && jsx(ButtonIcon, {
|
|
517
|
+
viewType: "ghost",
|
|
518
|
+
name: "ArrowUp",
|
|
519
|
+
onClick: onIncreaseHour
|
|
520
|
+
}), jsx(NumberInput, {
|
|
521
|
+
delayOnChange: 0,
|
|
522
|
+
onFocus: () => setCurrentInputFocus(1),
|
|
523
|
+
viewType: "outlined",
|
|
524
|
+
placeholder: "",
|
|
525
|
+
value: currentHour,
|
|
526
|
+
onChange: e => onChangeHandler(e, 'hour'),
|
|
527
|
+
onKeyDown: e => onChangeHandler(e, 'hour'),
|
|
528
|
+
min: startHour,
|
|
529
|
+
max: lastHour,
|
|
530
|
+
disabledNegative: true
|
|
531
|
+
}), currentInputFocus === 1 && jsx(ButtonIcon, {
|
|
532
|
+
viewType: "ghost",
|
|
533
|
+
name: "ArrowDown",
|
|
534
|
+
onClick: onDecreaseHour
|
|
535
|
+
})), jsx(Typography, {
|
|
536
|
+
type: "title1"
|
|
537
|
+
}, ":"), jsx("div", {
|
|
538
|
+
className: "DGN-UI-TimePicker-Input",
|
|
539
|
+
css: TimePickerInputCSS
|
|
540
|
+
}, currentInputFocus === 2 && jsx(ButtonIcon, {
|
|
541
|
+
viewType: "ghost",
|
|
542
|
+
name: "ArrowUp",
|
|
543
|
+
onClick: onIncreaseMinute
|
|
544
|
+
}), jsx(NumberInput, {
|
|
545
|
+
delayOnChange: 0,
|
|
546
|
+
onFocus: () => setCurrentInputFocus(2),
|
|
547
|
+
viewType: "outlined",
|
|
548
|
+
placeholder: "",
|
|
549
|
+
value: currentMinute || 0,
|
|
550
|
+
onChange: e => onChangeHandler(e, 'minute'),
|
|
551
|
+
onKeyDown: e => onChangeHandler(e, 'minute'),
|
|
552
|
+
min: startMinute,
|
|
553
|
+
max: lastMinute,
|
|
554
|
+
disabledNegative: true
|
|
555
|
+
}), currentInputFocus === 2 && jsx(ButtonIcon, {
|
|
556
|
+
viewType: "ghost",
|
|
557
|
+
name: "ArrowDown",
|
|
558
|
+
onClick: onDecreaseMinute
|
|
559
|
+
})), displayFormat === 'HH:mm:ss' && jsx(React.Fragment, null, jsx(Typography, {
|
|
560
|
+
type: "title1"
|
|
561
|
+
}, ":"), jsx("div", {
|
|
562
|
+
className: "DGN-UI-TimePicker-Input",
|
|
563
|
+
css: TimePickerInputCSS
|
|
564
|
+
}, currentInputFocus === 3 && jsx(ButtonIcon, {
|
|
565
|
+
viewType: "ghost",
|
|
566
|
+
name: "ArrowUp",
|
|
567
|
+
onClick: onIncreaseSecond
|
|
568
|
+
}), jsx(NumberInput, {
|
|
569
|
+
delayOnChange: 0,
|
|
570
|
+
onFocus: () => setCurrentInputFocus(3),
|
|
571
|
+
viewType: "outlined",
|
|
572
|
+
placeholder: "",
|
|
573
|
+
value: currentSecond || 0,
|
|
574
|
+
onChange: e => onChangeHandler(e, 'second'),
|
|
575
|
+
onKeyDown: e => onChangeHandler(e, 'second'),
|
|
576
|
+
min: startSecond,
|
|
577
|
+
max: lastSecond,
|
|
578
|
+
disabledNegative: true
|
|
579
|
+
}), currentInputFocus === 3 && jsx(ButtonIcon, {
|
|
580
|
+
viewType: "ghost",
|
|
581
|
+
name: "ArrowDown",
|
|
582
|
+
onClick: onDecreaseSecond
|
|
583
|
+
}))), mode12h && jsx("div", {
|
|
584
|
+
className: "TimePicker-AM/PM",
|
|
585
|
+
css: _TimePickerAMPMCSS
|
|
586
|
+
}, jsx(Button, {
|
|
587
|
+
onClick: () => setTimeValue({
|
|
588
|
+
...timeValue,
|
|
589
|
+
text: 'AM'
|
|
590
|
+
}),
|
|
591
|
+
label: "AM",
|
|
592
|
+
labelProps: {
|
|
593
|
+
type: 'heading4'
|
|
594
|
+
}
|
|
595
|
+
}), jsx(Button, {
|
|
596
|
+
onClick: () => setTimeValue({
|
|
597
|
+
...timeValue,
|
|
598
|
+
text: 'PM'
|
|
599
|
+
}),
|
|
600
|
+
label: "PM",
|
|
601
|
+
labelProps: {
|
|
602
|
+
type: 'heading4'
|
|
603
|
+
}
|
|
604
|
+
}))), jsx(Divider, null), jsx("div", {
|
|
605
|
+
className: "DGN-UI-TimePicker-Footer",
|
|
606
|
+
css: _TimePickerFooterCSS
|
|
607
|
+
}, jsx(Button, {
|
|
608
|
+
viewType: "link",
|
|
609
|
+
size: "medium",
|
|
610
|
+
label: nowText,
|
|
611
|
+
onClick: () => onSelectTime(true),
|
|
612
|
+
labelProps: {
|
|
613
|
+
format: ['sentence']
|
|
614
|
+
},
|
|
615
|
+
color: "system/rest"
|
|
616
|
+
}), jsx(Button, {
|
|
617
|
+
viewType: "link",
|
|
618
|
+
size: "medium",
|
|
619
|
+
label: saveText,
|
|
620
|
+
onClick: () => onSelectTime(false),
|
|
621
|
+
labelProps: {
|
|
622
|
+
format: ['sentence']
|
|
623
|
+
},
|
|
624
|
+
color: "info"
|
|
625
|
+
})))), isError && jsx(HelperText, {
|
|
626
|
+
...errorProps,
|
|
627
|
+
style: {
|
|
628
|
+
minHeight: 16,
|
|
629
|
+
position: 'absolute',
|
|
630
|
+
top: '100%'
|
|
631
|
+
},
|
|
632
|
+
disabled: disabled
|
|
633
|
+
}, error));
|
|
634
|
+
}));
|
|
635
|
+
const TimePickerCSS = ({
|
|
636
|
+
spacing
|
|
637
|
+
}) => css`
|
|
638
|
+
margin-top: ${spacing([1])};
|
|
639
|
+
`;
|
|
640
|
+
const TimePickerBodyCSS = (currentInputFocus, {
|
|
641
|
+
colors,
|
|
642
|
+
spacing,
|
|
643
|
+
typography
|
|
644
|
+
}) => css`
|
|
645
|
+
${typography.body1};
|
|
646
|
+
margin: ${spacing([2, 4])};
|
|
647
|
+
${displayFlex};
|
|
648
|
+
${justifyCenter};
|
|
649
|
+
${itemsCenter};
|
|
650
|
+
${parseMinHeight(88)};
|
|
651
|
+
.DGN-UI-NumberInput {
|
|
652
|
+
margin: ${spacing([0])};
|
|
653
|
+
.DGN-UI-InputBase {
|
|
654
|
+
${parseHeight(40)};
|
|
655
|
+
${parseWidth(48)};
|
|
656
|
+
margin: ${spacing([0])};
|
|
657
|
+
padding: ${spacing([0])};
|
|
658
|
+
${bgColor(hexToRGBA(getProp(colors, 'system/active'), 0.1))}
|
|
659
|
+
${borderNone};
|
|
660
|
+
${borderColor(getProp(colors, 'semantic/info'))};
|
|
661
|
+
input {
|
|
662
|
+
${parseWidthHeight('100%')};
|
|
663
|
+
${textCenter};
|
|
664
|
+
${typography.body1};
|
|
665
|
+
&:hover,
|
|
666
|
+
&:focus {
|
|
667
|
+
${bgColor(hexToRGBA(getProp(colors, 'semantic/info'), 0.2))};
|
|
668
|
+
${textColor(getProp(colors, 'semantic/info'))};
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
.DGN-UI-TimePicker-Input:nth-of-type(${currentInputFocus}) {
|
|
674
|
+
.DGN-UI-NumberInput {
|
|
675
|
+
.DGN-UI-InputBase {
|
|
676
|
+
${border(2)};
|
|
677
|
+
${borderColor(getProp(colors, 'semantic/info'))};
|
|
678
|
+
input {
|
|
679
|
+
${borderRadius4px};
|
|
680
|
+
${bgColor(hexToRGBA(getProp(colors, 'semantic/info'), 0.2))};
|
|
681
|
+
${textColor(getProp(colors, 'semantic/info'))};
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
.DGN-UI-Typography {
|
|
687
|
+
padding: ${spacing([0, 0.5])};
|
|
688
|
+
}
|
|
689
|
+
`;
|
|
690
|
+
const TimePickerInputCSS = css`
|
|
691
|
+
${flexCol};
|
|
692
|
+
${itemsCenter};
|
|
693
|
+
`;
|
|
694
|
+
const TimePickerFooterCSS = ({
|
|
695
|
+
spacing
|
|
696
|
+
}) => css`
|
|
697
|
+
${displayFlex};
|
|
698
|
+
${justifyBetween};
|
|
699
|
+
${itemsCenter};
|
|
700
|
+
.DGN-UI-Button {
|
|
701
|
+
padding: ${spacing([2, 4])};
|
|
702
|
+
}
|
|
703
|
+
`;
|
|
704
|
+
const TimePickerAMPMCSS = (currentText, {
|
|
705
|
+
colors,
|
|
706
|
+
spacing
|
|
707
|
+
}) => css`
|
|
708
|
+
${flexCol};
|
|
709
|
+
${parseHeight(40)};
|
|
710
|
+
${justifyBetween};
|
|
711
|
+
margin-left: ${spacing([2])};
|
|
712
|
+
button:nth-of-type(${currentText === 'AM' ? 1 : 2}) {
|
|
713
|
+
${bgColor(hexToRGBA(getProp(colors, 'semantic/info'), 0.2))};
|
|
714
|
+
${textColor(getProp(colors, 'semantic/info'))};
|
|
715
|
+
}
|
|
716
|
+
button {
|
|
717
|
+
&:hover,
|
|
718
|
+
&:focus {
|
|
719
|
+
${bgColor(hexToRGBA(getProp(colors, 'semantic/info'), 0.2))};
|
|
720
|
+
${textColor(getProp(colors, 'semantic/info'))};
|
|
721
|
+
}
|
|
722
|
+
padding: ${spacing([0])};
|
|
723
|
+
${parseHeight(18)};
|
|
724
|
+
${parseMinHeight(18)};
|
|
725
|
+
${parseWidth(32)};
|
|
726
|
+
}
|
|
727
|
+
`;
|
|
728
|
+
|
|
729
|
+
// TimePicker.defaultProps = {
|
|
730
|
+
// actionIconAt: 'end',
|
|
731
|
+
// className: '',
|
|
732
|
+
// disabled: false,
|
|
733
|
+
// displayFormat: 'HH:mm:ss',
|
|
734
|
+
// mode12h: false,
|
|
735
|
+
// readOnly: false,
|
|
736
|
+
// required: false,
|
|
737
|
+
// returnFormat: 'HH:mm:ss',
|
|
738
|
+
// error: '',
|
|
739
|
+
// minuteStep: 1,
|
|
740
|
+
// min: '',
|
|
741
|
+
// max: '',
|
|
742
|
+
// label: '',
|
|
743
|
+
// value: '',
|
|
744
|
+
// };
|
|
745
|
+
|
|
746
|
+
TimePicker.propTypes = {
|
|
747
|
+
/** CSS class for the component. ({container: '', header: '', body: '', footer: ''}) */
|
|
748
|
+
className: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
|
749
|
+
/** If `true`, the form control will be disabled. */
|
|
750
|
+
disabled: PropTypes.bool,
|
|
751
|
+
/** Format to display value. */
|
|
752
|
+
displayFormat: PropTypes.oneOfType([PropTypes.oneOf(['HH:mm', 'HH:mm:ss']), PropTypes.string]),
|
|
753
|
+
/** The default value of the component. */
|
|
754
|
+
defaultValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string, PropTypes.object]),
|
|
755
|
+
/** Error of the form control. */
|
|
756
|
+
error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
757
|
+
/** [Props](https://core.diginet.com.vn/ui/?path=/story/form-control-text-helpertext) of helper text. */
|
|
758
|
+
errorProps: PropTypes.object,
|
|
759
|
+
/** [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes) applied to the input element. */
|
|
760
|
+
inputProps: PropTypes.object,
|
|
761
|
+
/** Inline style of the input element. */
|
|
762
|
+
inputStyle: PropTypes.object,
|
|
763
|
+
/** Hints for the input. */
|
|
764
|
+
placeholder: PropTypes.string,
|
|
765
|
+
/** Components style mode */
|
|
766
|
+
mode12h: PropTypes.bool,
|
|
767
|
+
/** Minimum value of the time picker. */
|
|
768
|
+
min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string, PropTypes.object]),
|
|
769
|
+
/** Maximum value of the time picker. */
|
|
770
|
+
max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string, PropTypes.object]),
|
|
771
|
+
/** Step of the minute. */
|
|
772
|
+
minuteStep: PropTypes.number,
|
|
773
|
+
/** Content of the label element. */
|
|
774
|
+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
775
|
+
/** [Props](https://core.diginet.com.vn/ui/?path=/docs/form-control-text-label--simple) of label. */
|
|
776
|
+
labelProps: PropTypes.object,
|
|
777
|
+
/** A callback function when the value input changes. */
|
|
778
|
+
onChange: PropTypes.func,
|
|
779
|
+
/** Inline style of the component. */
|
|
780
|
+
style: PropTypes.object,
|
|
781
|
+
/** The value of the input element, required for a controlled component. */
|
|
782
|
+
value: PropTypes.oneOfType([PropTypes.string]),
|
|
783
|
+
/** View type of the form control. */
|
|
784
|
+
viewType: PropTypes.oneOf(['outlined', 'underlined']),
|
|
785
|
+
/** If `true`, the component is readonly. */
|
|
786
|
+
readOnly: PropTypes.bool,
|
|
787
|
+
/** If `true`, the input element is required. */
|
|
788
|
+
required: PropTypes.bool,
|
|
789
|
+
/** Format to display value. */
|
|
790
|
+
returnFormat: PropTypes.oneOfType([PropTypes.oneOf(['HH:mm', 'HH:mm:ss']), PropTypes.string])
|
|
791
|
+
};
|
|
792
|
+
export default TimePicker;
|