@dvrd/dvr-controls 1.0.57 → 1.0.59
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/package.json +1 -1
- package/src/js/date/dvrdDatePicker.tsx +171 -11
- package/src/js/date/style/dvrdDatePicker.scss +25 -0
- package/src/js/select/dvrdGroupedSelect.tsx +7 -5
- package/src/js/textField/dvrdInput.tsx +3 -2
- package/src/js/textField/dvrdInputController.tsx +3 -2
- package/src/js/textField/dvrdNumberInput.tsx +1 -0
- package/src/js/util/controlUtil.ts +5 -1
- package/src/js/util/interfaces.ts +2 -0
package/package.json
CHANGED
|
@@ -4,19 +4,23 @@
|
|
|
4
4
|
import './style/dvrdDatePicker.scss';
|
|
5
5
|
|
|
6
6
|
import classNames from 'classnames';
|
|
7
|
-
import React, {MouseEventHandler, useEffect, useMemo, useRef, useState} from 'react';
|
|
8
|
-
import {ChangeFunction, ErrorType} from '../util/interfaces';
|
|
7
|
+
import React, {Fragment, MouseEventHandler, useEffect, useMemo, useRef, useState} from 'react';
|
|
8
|
+
import {ChangeFunction, DatePickerTimeMode, ErrorType} from '../util/interfaces';
|
|
9
9
|
import AwesomeIcon from '../icon/awesomeIcon';
|
|
10
10
|
import WithBackground from '../popup/withBackground';
|
|
11
11
|
import DvrdButton from "../button/dvrdButton";
|
|
12
12
|
import {generateComponentId} from "../util/componentUtil";
|
|
13
13
|
import IDate from '@dvrd/idate';
|
|
14
|
+
import {pad, padNum, voidFunction} from "../util/controlUtil";
|
|
15
|
+
import {DvrdNumberInput} from "../../../index";
|
|
16
|
+
import defer from 'lodash.defer';
|
|
14
17
|
|
|
15
18
|
interface Props {
|
|
16
19
|
onChange: ChangeFunction<IDate>;
|
|
17
20
|
closeOnChange?: boolean;
|
|
18
21
|
value: IDate | null;
|
|
19
22
|
label: string;
|
|
23
|
+
timeMode?: DatePickerTimeMode;
|
|
20
24
|
error?: ErrorType;
|
|
21
25
|
className?: string;
|
|
22
26
|
placeholder?: string;
|
|
@@ -32,12 +36,20 @@ interface Props {
|
|
|
32
36
|
export default function DvrdDatePicker(props: Props) {
|
|
33
37
|
const {
|
|
34
38
|
onChange, className, closeOnChange, error, label, value, placeholder, disabled, alwaysShowArrows,
|
|
35
|
-
useMobileNative, max, min
|
|
39
|
+
useMobileNative, max, min, timeMode
|
|
36
40
|
} = props;
|
|
37
41
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
42
|
+
const [timePickerOpen, setTimePickerOpen] = useState(false);
|
|
38
43
|
const dateFormat = useMemo(() => {
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
if (props.dateFormat) return props.dateFormat;
|
|
45
|
+
let format = 'YYYY-MM-DD';
|
|
46
|
+
if (timeMode === DatePickerTimeMode.FULL) format += ' HH:mm:ss';
|
|
47
|
+
else if (timeMode === DatePickerTimeMode.HOURS_MINUTES) format += ' HH:mm';
|
|
48
|
+
else if (timeMode === DatePickerTimeMode.HOURS_ONLY) format += ' HH';
|
|
49
|
+
else if (timeMode === DatePickerTimeMode.MINUTES_ONLY) format += ' mm';
|
|
50
|
+
else if (timeMode === DatePickerTimeMode.SECONDS_ONLY) format += ' ss';
|
|
51
|
+
return format;
|
|
52
|
+
}, [props.dateFormat, timeMode]);
|
|
41
53
|
const id = useMemo(() => {
|
|
42
54
|
return generateComponentId(props.id);
|
|
43
55
|
}, [props.id]);
|
|
@@ -53,11 +65,19 @@ export default function DvrdDatePicker(props: Props) {
|
|
|
53
65
|
|
|
54
66
|
const onChangePicker = (daySelected: boolean) => (value: IDate) => {
|
|
55
67
|
onChange(value.clone());
|
|
56
|
-
if (closeOnChange && daySelected)
|
|
68
|
+
if (closeOnChange && daySelected) {
|
|
69
|
+
onClosePicker();
|
|
70
|
+
if (!!timeMode) setTimePickerOpen(true);
|
|
71
|
+
}
|
|
57
72
|
};
|
|
58
73
|
|
|
74
|
+
function onChangeTimePicker(value: IDate) {
|
|
75
|
+
onChange(value.clone());
|
|
76
|
+
setTimePickerOpen(false);
|
|
77
|
+
}
|
|
78
|
+
|
|
59
79
|
function onClosePicker() {
|
|
60
|
-
setPickerOpen(false)
|
|
80
|
+
setPickerOpen(false);
|
|
61
81
|
}
|
|
62
82
|
|
|
63
83
|
function renderMobilePicker() {
|
|
@@ -80,14 +100,17 @@ export default function DvrdDatePicker(props: Props) {
|
|
|
80
100
|
placeholder ?? ''}</label>
|
|
81
101
|
<AwesomeIcon name='calendar-alt' className='calendar-icon'/>
|
|
82
102
|
</div>
|
|
83
|
-
<
|
|
84
|
-
|
|
103
|
+
<DatePicker onClose={onClosePicker} onChange={onChangePicker} open={pickerOpen} value={value}
|
|
104
|
+
alwaysShowArrows={alwaysShowArrows} max={max} min={min}/>
|
|
105
|
+
{!!timeMode &&
|
|
106
|
+
<TimePicker onChange={onChangeTimePicker} onClose={onClosePicker} value={value}
|
|
107
|
+
open={timePickerOpen} timeMode={timeMode}/>}
|
|
85
108
|
<label className='error-label'>{error}</label>
|
|
86
109
|
</div>
|
|
87
110
|
)
|
|
88
111
|
}
|
|
89
112
|
|
|
90
|
-
interface
|
|
113
|
+
interface DatePickerProps {
|
|
91
114
|
onChange: (daySelected: boolean) => ChangeFunction<IDate>;
|
|
92
115
|
onClose: VoidFunction;
|
|
93
116
|
value: IDate | null;
|
|
@@ -97,7 +120,7 @@ interface PickerProps {
|
|
|
97
120
|
min?: IDate | string;
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
function
|
|
123
|
+
function DatePicker(props: DatePickerProps) {
|
|
101
124
|
const {min, max, alwaysShowArrows, open, onClose, value, onChange} = props;
|
|
102
125
|
const divRef = useRef<HTMLDivElement>(null);
|
|
103
126
|
const pickerValue = useMemo(() => new IDate(value), [value]);
|
|
@@ -401,4 +424,141 @@ function Picker(props: PickerProps) {
|
|
|
401
424
|
</div>
|
|
402
425
|
</WithBackground>
|
|
403
426
|
)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
interface TimePickerProps {
|
|
430
|
+
onChange: ChangeFunction<IDate>;
|
|
431
|
+
onClose: VoidFunction;
|
|
432
|
+
value: IDate | null;
|
|
433
|
+
open: boolean;
|
|
434
|
+
timeMode: DatePickerTimeMode;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
type TimePartValues = [string, string, string, string, string, string];
|
|
438
|
+
|
|
439
|
+
function dateToTimeParts(value: IDate | null): TimePartValues {
|
|
440
|
+
if (!value) return ['', '', '', '', '', ''];
|
|
441
|
+
const hours = padNum(value.hours());
|
|
442
|
+
const minutes = padNum(value.minutes());
|
|
443
|
+
const seconds = padNum(value.seconds());
|
|
444
|
+
return [...hours.split(''), ...minutes.split(''), ...seconds.split('')] as TimePartValues;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function timePartsToNumber(part1: string, part2: string): number {
|
|
448
|
+
const num = Number(part1 + part2);
|
|
449
|
+
return Number.isNaN(num) ? 0 : num;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function TimePicker(props: TimePickerProps) {
|
|
453
|
+
const {onChange, value, open, onClose, timeMode} = props;
|
|
454
|
+
const [timeParts, setTimeParts] = useState<TimePartValues>(dateToTimeParts(value));
|
|
455
|
+
const secondHourMax = useMemo(() => {
|
|
456
|
+
if (Number(timeParts[0]) === 2) return 3;
|
|
457
|
+
return 9;
|
|
458
|
+
}, timeParts);
|
|
459
|
+
const compID = useRef(generateComponentId());
|
|
460
|
+
|
|
461
|
+
function onClickNow() {
|
|
462
|
+
setTimeParts(dateToTimeParts(new IDate()));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function onSubmit() {
|
|
466
|
+
console.log(timeParts);
|
|
467
|
+
const hours = timePartsToNumber(timeParts[0], timeParts[1]);
|
|
468
|
+
const minutes = timePartsToNumber(timeParts[2], timeParts[3]);
|
|
469
|
+
const seconds = timePartsToNumber(timeParts[4], timeParts[5]);
|
|
470
|
+
console.log(hours, minutes, seconds);
|
|
471
|
+
const _value = value?.clone() ?? new IDate();
|
|
472
|
+
onChange(_value.set({hours, minutes, seconds}));
|
|
473
|
+
onClose();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function onKeyDown(index: number) {
|
|
477
|
+
return function (evt: React.KeyboardEvent) {
|
|
478
|
+
const {key} = evt;
|
|
479
|
+
if (/\d/.test(key) && index < 5) {
|
|
480
|
+
onChangePickerPart(index)(key);
|
|
481
|
+
defer(() => onFocusElement(index + 1));
|
|
482
|
+
}
|
|
483
|
+
if (key.toLowerCase() === 'backspace')
|
|
484
|
+
if ((evt.target as HTMLInputElement).value) {
|
|
485
|
+
onChangePickerPart(index)('');
|
|
486
|
+
} else if (index > 0) {
|
|
487
|
+
onChangePickerPart(index - 1)('');
|
|
488
|
+
defer(() => onFocusElement(index - 1));
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function onChangePickerPart(index: number) {
|
|
494
|
+
return function (value: string) {
|
|
495
|
+
const parts = [...timeParts];
|
|
496
|
+
parts[index] = value;
|
|
497
|
+
setTimeParts(parts as TimePartValues);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function onFocusElement(index: number) {
|
|
502
|
+
const input = document.getElementById(`${compID.current}-${index}-input`);
|
|
503
|
+
input?.focus();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function renderTimeControls() {
|
|
507
|
+
const renderHours = [DatePickerTimeMode.FULL, DatePickerTimeMode.HOURS_MINUTES, DatePickerTimeMode.HOURS_ONLY].includes(timeMode);
|
|
508
|
+
const renderMinutes = [DatePickerTimeMode.FULL, DatePickerTimeMode.HOURS_MINUTES, DatePickerTimeMode.MINUTES_ONLY].includes(timeMode);
|
|
509
|
+
const renderSeconds = [DatePickerTimeMode.FULL, DatePickerTimeMode.SECONDS_ONLY].includes(timeMode);
|
|
510
|
+
const timeControls: Array<React.ReactElement> = [];
|
|
511
|
+
if (renderHours) timeControls.push(renderTimeControl([0, 1], 2, secondHourMax, true));
|
|
512
|
+
if (renderMinutes) timeControls.push(renderTimeControl([2, 3], 5, 9, !renderHours));
|
|
513
|
+
if (renderSeconds) timeControls.push(renderTimeControl([4, 5], 5, 9, !renderHours && !renderMinutes));
|
|
514
|
+
return (
|
|
515
|
+
<div className='time-controls'>
|
|
516
|
+
{timeControls.map((control: React.ReactElement, index: number) => {
|
|
517
|
+
return (
|
|
518
|
+
<Fragment key={index}>
|
|
519
|
+
{control}
|
|
520
|
+
{index < timeControls.length - 1 && <span className='sep'>:</span>}
|
|
521
|
+
</Fragment>
|
|
522
|
+
)
|
|
523
|
+
})}
|
|
524
|
+
</div>
|
|
525
|
+
)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function renderTimeControl(timePartIndexes: [number, number], firstMax: number, secondMax: number = 9,
|
|
529
|
+
autoFocus: boolean = false) {
|
|
530
|
+
return (
|
|
531
|
+
<div className='time-control'>
|
|
532
|
+
<DvrdNumberInput value={timeParts[timePartIndexes[0]]} onChange={voidFunction}
|
|
533
|
+
inputProps={{min: 0, max: firstMax, tabIndex: timePartIndexes[0] + 1, maxLength: 1}}
|
|
534
|
+
className='time-control-part' id={`${compID.current}-${timePartIndexes[0]}`}
|
|
535
|
+
onKeyDown={onKeyDown(timePartIndexes[0])} placeholder='0' autoFocus={autoFocus}
|
|
536
|
+
autoSelect wholeNumbers/>
|
|
537
|
+
<DvrdNumberInput value={timeParts[timePartIndexes[1]]} onChange={voidFunction}
|
|
538
|
+
inputProps={{min: 0, max: secondMax, tabIndex: timePartIndexes[1] + 1, maxLength: 1}}
|
|
539
|
+
onKeyDown={onKeyDown(timePartIndexes[1])} className='time-control-part'
|
|
540
|
+
id={`${compID.current}-${timePartIndexes[1]}`} placeholder='0' autoSelect
|
|
541
|
+
wholeNumbers/>
|
|
542
|
+
</div>
|
|
543
|
+
)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
useEffect(() => {
|
|
547
|
+
setTimeParts(dateToTimeParts(value));
|
|
548
|
+
}, [value]);
|
|
549
|
+
|
|
550
|
+
return (
|
|
551
|
+
<WithBackground active={open} onClose={onClose}>
|
|
552
|
+
<div className='picker time'>
|
|
553
|
+
<div className='switcher'>
|
|
554
|
+
<label className='switcher-label'>Tijdstip</label>
|
|
555
|
+
</div>
|
|
556
|
+
{renderTimeControls()}
|
|
557
|
+
<div className='actions-container'>
|
|
558
|
+
<DvrdButton onClick={onClickNow} label='Huidig tijdstip' secondary className='action'/>
|
|
559
|
+
<DvrdButton onClick={onSubmit} label='Oké' className='action'/>
|
|
560
|
+
</div>
|
|
561
|
+
</div>
|
|
562
|
+
</WithBackground>
|
|
563
|
+
);
|
|
404
564
|
}
|
|
@@ -293,6 +293,31 @@
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
.picker.time {
|
|
297
|
+
width: 20rem;
|
|
298
|
+
|
|
299
|
+
.time-controls {
|
|
300
|
+
display: flex;
|
|
301
|
+
column-gap: .5rem;
|
|
302
|
+
align-items: center;
|
|
303
|
+
justify-content: center;
|
|
304
|
+
padding: 1rem 0;
|
|
305
|
+
|
|
306
|
+
.time-control {
|
|
307
|
+
display: flex;
|
|
308
|
+
column-gap: .25rem;
|
|
309
|
+
|
|
310
|
+
.time-control-part {
|
|
311
|
+
width: 2.5rem;
|
|
312
|
+
|
|
313
|
+
.dvrd-input {
|
|
314
|
+
text-align: center;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
296
321
|
.error-label {
|
|
297
322
|
position: absolute;
|
|
298
323
|
bottom: 0;
|
|
@@ -11,7 +11,7 @@ import defer from 'lodash.defer';
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
interface Props {
|
|
14
|
-
onChange: (value: SelectValueType, evt
|
|
14
|
+
onChange: (value: SelectValueType, evt?: React.MouseEvent | React.ChangeEvent) => void;
|
|
15
15
|
items: Array<GroupedSelectItem>;
|
|
16
16
|
value: SelectValueType;
|
|
17
17
|
label?: string;
|
|
@@ -77,8 +77,7 @@ function DVRDGroupedSelect(props: Props, ref: ForwardedRef<GroupedSelectRef>) {
|
|
|
77
77
|
return function (evt: React.MouseEvent) {
|
|
78
78
|
evt.stopPropagation();
|
|
79
79
|
if (item.value !== undefined) {
|
|
80
|
-
|
|
81
|
-
onChange(item.value, evt);
|
|
80
|
+
onChange(item.value, evt);
|
|
82
81
|
onToggleOpen(false);
|
|
83
82
|
}
|
|
84
83
|
}
|
|
@@ -169,7 +168,8 @@ function DVRDGroupedSelect(props: Props, ref: ForwardedRef<GroupedSelectRef>) {
|
|
|
169
168
|
<div id={`dvrd-grouped-item-${item.value}`} key={index}
|
|
170
169
|
className={classNames('dvrd-grouped-item', itemClassName)}
|
|
171
170
|
onClick={onSelectItem(item)}>
|
|
172
|
-
{isElement ? renderCustomLabel(item.label as React.ReactElement, padding, isGroupHead,
|
|
171
|
+
{isElement ? renderCustomLabel(item.label as React.ReactElement, padding, isGroupHead,
|
|
172
|
+
isSelectable, isSelected) :
|
|
173
173
|
<label className={classNames('grouped-item-label', isGroupHead && 'group-head',
|
|
174
174
|
isSelectable && 'selectable', (isSelected && highlightSelected) && 'selected')}
|
|
175
175
|
style={{paddingLeft: padding}}>{item.label}</label>}
|
|
@@ -183,12 +183,14 @@ function DVRDGroupedSelect(props: Props, ref: ForwardedRef<GroupedSelectRef>) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
function renderCustomLabel(label: React.ReactElement, padding: string, isGroupHead: boolean, isSelectable: boolean
|
|
186
|
+
function renderCustomLabel(label: React.ReactElement, padding: string, isGroupHead: boolean, isSelectable: boolean,
|
|
187
|
+
isSelected: boolean) {
|
|
187
188
|
const style = label.props?.style ?? {};
|
|
188
189
|
return React.cloneElement(label, {
|
|
189
190
|
...label.props,
|
|
190
191
|
style: {...style, paddingLeft: padding},
|
|
191
192
|
className: classNames('grouped-item-label', isGroupHead && 'group-head', isSelectable && 'selectable',
|
|
193
|
+
(isSelected && highlightSelected && 'selected'),
|
|
192
194
|
label.props?.className)
|
|
193
195
|
});
|
|
194
196
|
}
|
|
@@ -27,6 +27,7 @@ interface Props {
|
|
|
27
27
|
onFocus?: FocusEventHandler;
|
|
28
28
|
onBlur?: FocusEventHandler;
|
|
29
29
|
onKeyDown: KeyboardEventHandler;
|
|
30
|
+
onKeyUp?: KeyboardEventHandler;
|
|
30
31
|
onClearInput?: MouseEventHandler;
|
|
31
32
|
value: string | number;
|
|
32
33
|
disabled?: boolean;
|
|
@@ -52,7 +53,7 @@ export default function DvrdInput(props: Props) {
|
|
|
52
53
|
const {
|
|
53
54
|
area, id, label, labelClassName, errorClassName, inputClassName, className, ornamentClassName, inputProps,
|
|
54
55
|
disabled, onBlur, value, onChange, onFocus, autoSelect, autoFocus, onClearInput, noResize, onKeyDown, fullWidth,
|
|
55
|
-
ornaments, error
|
|
56
|
+
ornaments, error, onKeyUp
|
|
56
57
|
} = props;
|
|
57
58
|
const inputRef = useRef<HTMLInputElement & HTMLTextAreaElement>(null);
|
|
58
59
|
const [active, setActive] = useState(props.autoFocus ?? false);
|
|
@@ -128,7 +129,7 @@ export default function DvrdInput(props: Props) {
|
|
|
128
129
|
const elementProps = {
|
|
129
130
|
...inputProps, value, onChange, onFocus: onFocusInput, onBlur: onBlurInput, onKeyDown, disabled,
|
|
130
131
|
className: classNames('dvrd-input', inputClassName, noResize && 'no-resize'), id: `${id}-input`,
|
|
131
|
-
ref: inputRef,
|
|
132
|
+
ref: inputRef, onKeyUp,
|
|
132
133
|
};
|
|
133
134
|
if (area) return <textarea {...elementProps}/>;
|
|
134
135
|
return <input {...elementProps}/>
|
|
@@ -22,6 +22,7 @@ export interface InputControllerProps {
|
|
|
22
22
|
onFocus?: FocusEventHandler;
|
|
23
23
|
onBlur?: FocusEventHandler;
|
|
24
24
|
onKeyDown?: KeyboardEventHandler;
|
|
25
|
+
onKeyUp?: KeyboardEventHandler;
|
|
25
26
|
onEnter?: KeyboardEventHandler;
|
|
26
27
|
onClearInput?: MouseEventHandler;
|
|
27
28
|
value: string | number;
|
|
@@ -53,7 +54,7 @@ export default function DvrdInputController(props: InputControllerProps) {
|
|
|
53
54
|
const {
|
|
54
55
|
disabled, onChange, onEnter, onKeyDown, inputProps, placeholder, type, max, min, step, onFocus, onBlur,
|
|
55
56
|
autoFocus, error, label, ornaments, className, inputClassName, labelClassName, ornamentClassName, fullWidth,
|
|
56
|
-
errorClassName, autoSelect, area, noResize, onClearInput, unControlled
|
|
57
|
+
errorClassName, autoSelect, area, noResize, onClearInput, unControlled, onKeyUp
|
|
57
58
|
} = props,
|
|
58
59
|
componentId = useRef(generateComponentId(props.id)),
|
|
59
60
|
[value, setValue] = useState(props.value);
|
|
@@ -92,6 +93,6 @@ export default function DvrdInputController(props: InputControllerProps) {
|
|
|
92
93
|
inputProps={getInputProps()} className={className} inputClassName={inputClassName}
|
|
93
94
|
labelClassName={labelClassName} ornamentClassName={ornamentClassName} fullWidth={fullWidth}
|
|
94
95
|
errorClassName={errorClassName} id={componentId.current} onBlur={onBlur} autoSelect={autoSelect}
|
|
95
|
-
area={area} noResize={noResize} onClearInput={onClearInput}/>
|
|
96
|
+
area={area} noResize={noResize} onClearInput={onClearInput} onKeyUp={onKeyUp}/>
|
|
96
97
|
);
|
|
97
98
|
}
|
|
@@ -26,7 +26,7 @@ export const isNotNull = (obj: any): boolean => {
|
|
|
26
26
|
export const isNull = (obj: any): boolean => !isNotNull(obj);
|
|
27
27
|
|
|
28
28
|
export const hasHover = (element: HTMLElement | null): boolean => {
|
|
29
|
-
if(!element) return false;
|
|
29
|
+
if (!element) return false;
|
|
30
30
|
if (isNotNull(element) && element.parentElement !== null) {
|
|
31
31
|
return element.parentElement.querySelector(':hover') === element;
|
|
32
32
|
}
|
|
@@ -93,6 +93,10 @@ export const calculateTextWidth = (text: string, fontSize?: number, fontFamily?:
|
|
|
93
93
|
|
|
94
94
|
export const pad = (num: string | number): string => ('0' + num).slice(-2);
|
|
95
95
|
|
|
96
|
+
export function padNum(num: string | number, maxLength: number = 2): string {
|
|
97
|
+
return num.toString().padStart(maxLength, '0');
|
|
98
|
+
}
|
|
99
|
+
|
|
96
100
|
export const stopPropagation = (evt: Event | React.SyntheticEvent) => {
|
|
97
101
|
evt.stopPropagation();
|
|
98
102
|
};
|
|
@@ -150,6 +150,8 @@ export enum SideMenuMode {COMPACT, FULL}
|
|
|
150
150
|
|
|
151
151
|
export enum PDFDisplay {FIRST_PAGE = 'first_page', LAST_PAGE = 'last_page', ALL_PAGES = 'all_pages'}
|
|
152
152
|
|
|
153
|
+
export enum DatePickerTimeMode {FULL = 1, HOURS_MINUTES, HOURS_ONLY, MINUTES_ONLY, SECONDS_ONLY}
|
|
154
|
+
|
|
153
155
|
// =========== TYPES
|
|
154
156
|
export type OptionsMenuItem = {
|
|
155
157
|
label: string;
|