@dvrd/dvr-controls 1.0.43 → 1.0.45
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 +10 -10
- package/src/js/date/dvrdDatePicker.tsx +210 -186
- package/src/js/date/style/dvrdDatePicker.scss +6 -0
- package/src/js/sidebarMenu/sidebarMenu.tsx +20 -8
- package/src/js/sidebarMenu/style/sidebarMenu.scss +19 -7
- package/src/js/textField/dvrdNumberInput.tsx +1 -1
- package/src/js/util/interfaces.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dvrd/dvr-controls",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"description": "Custom web controls",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"files": [
|
|
@@ -25,11 +25,16 @@
|
|
|
25
25
|
]
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"react": "18.2.0",
|
|
29
|
-
"react-dom": "18.2.0",
|
|
28
|
+
"react": "^18.2.0",
|
|
29
|
+
"react-dom": "^18.2.0",
|
|
30
30
|
"react-router-dom": "6.15.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@fortawesome/fontawesome-svg-core": "6.3.0",
|
|
34
|
+
"@fortawesome/free-brands-svg-icons": "6.3.0",
|
|
35
|
+
"@fortawesome/free-regular-svg-icons": "6.3.0",
|
|
36
|
+
"@fortawesome/free-solid-svg-icons": "6.3.0",
|
|
37
|
+
"@fortawesome/react-fontawesome": "0.2.0",
|
|
33
38
|
"@types/dompurify": "2.4.0",
|
|
34
39
|
"@types/js-cookie": "3.0.3",
|
|
35
40
|
"@types/lodash.defer": "^4.1.7",
|
|
@@ -40,14 +45,8 @@
|
|
|
40
45
|
"@types/node": "18.14.0",
|
|
41
46
|
"@types/react": "^18.2.28",
|
|
42
47
|
"@types/react-color": "2.13.5",
|
|
43
|
-
"@types/react-dom": "18.0.11",
|
|
48
|
+
"@types/react-dom": "^18.0.11",
|
|
44
49
|
"@types/uuid": "9.0.0",
|
|
45
|
-
"typescript": "4.9.5",
|
|
46
|
-
"@fortawesome/fontawesome-svg-core": "6.3.0",
|
|
47
|
-
"@fortawesome/free-brands-svg-icons": "6.3.0",
|
|
48
|
-
"@fortawesome/free-regular-svg-icons": "6.3.0",
|
|
49
|
-
"@fortawesome/free-solid-svg-icons": "6.3.0",
|
|
50
|
-
"@fortawesome/react-fontawesome": "0.2.0",
|
|
51
50
|
"classnames": "2.3.2",
|
|
52
51
|
"dompurify": "3.0.0",
|
|
53
52
|
"js-cookie": "3.0.1",
|
|
@@ -59,6 +58,7 @@
|
|
|
59
58
|
"moment": "2.29.4",
|
|
60
59
|
"react-color": "2.19.3",
|
|
61
60
|
"react-rnd": "10.4.1",
|
|
61
|
+
"typescript": "4.9.5",
|
|
62
62
|
"uuid": "9.0.0"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -5,7 +5,7 @@ import './style/dvrdDatePicker.scss';
|
|
|
5
5
|
|
|
6
6
|
import classNames from 'classnames';
|
|
7
7
|
import {Moment} from 'moment';
|
|
8
|
-
import React, {
|
|
8
|
+
import React, {MouseEventHandler, useEffect, useMemo, useRef, useState} from 'react';
|
|
9
9
|
import {ChangeFunction, ErrorType} from '../util/interfaces';
|
|
10
10
|
import AwesomeIcon from '../icon/awesomeIcon';
|
|
11
11
|
import {toMoment} from '../util/momentUtil';
|
|
@@ -26,12 +26,14 @@ interface Props {
|
|
|
26
26
|
alwaysShowArrows?: boolean;
|
|
27
27
|
useMobileNative?: boolean;
|
|
28
28
|
id?: string;
|
|
29
|
+
max?: Moment | string;
|
|
30
|
+
min?: Moment | string;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export default function DvrdDatePicker(props: Props) {
|
|
32
34
|
const {
|
|
33
35
|
onChange, className, closeOnChange, error, label, value, placeholder, disabled, alwaysShowArrows,
|
|
34
|
-
useMobileNative
|
|
36
|
+
useMobileNative, max, min
|
|
35
37
|
} = props;
|
|
36
38
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
37
39
|
const dateFormat = useMemo(() => {
|
|
@@ -80,7 +82,7 @@ export default function DvrdDatePicker(props: Props) {
|
|
|
80
82
|
<AwesomeIcon name='calendar-alt' className='calendar-icon'/>
|
|
81
83
|
</div>
|
|
82
84
|
<Picker onClose={onClosePicker} onChange={onChangePicker} open={pickerOpen} value={value}
|
|
83
|
-
alwaysShowArrows={alwaysShowArrows}/>
|
|
85
|
+
alwaysShowArrows={alwaysShowArrows} max={max} min={min}/>
|
|
84
86
|
<label className='error-label'>{error}</label>
|
|
85
87
|
</div>
|
|
86
88
|
)
|
|
@@ -92,121 +94,162 @@ interface PickerProps {
|
|
|
92
94
|
value: Moment | null;
|
|
93
95
|
open: boolean;
|
|
94
96
|
alwaysShowArrows?: boolean;
|
|
97
|
+
max?: Moment | string;
|
|
98
|
+
min?: Moment | string;
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
function Picker(props: PickerProps) {
|
|
102
|
+
const {min, max, alwaysShowArrows, open, onClose, value, onChange} = props;
|
|
103
|
+
const divRef = useRef<HTMLDivElement>(null);
|
|
104
|
+
const pickerValue = useMemo(() => toMoment(value), [value]);
|
|
105
|
+
const [padBeforeDays, days, padAfterDays] = useMemo(() => {
|
|
106
|
+
const daysInMonth = pickerValue.daysInMonth();
|
|
107
|
+
const days: number[] = [];
|
|
108
|
+
const padBeforeDays: number[] = [];
|
|
109
|
+
const padAfterDays: number[] = [];
|
|
110
|
+
for (let i = 1; i <= daysInMonth; i++) days.push(i);
|
|
111
|
+
let firstMonthDay = pickerValue.clone().date(1).day();
|
|
112
|
+
if (!firstMonthDay) firstMonthDay = 7;
|
|
113
|
+
const padDaysBefore = firstMonthDay - 1;
|
|
114
|
+
let dayBefore = pickerValue.clone().add(-1, 'month').daysInMonth()
|
|
115
|
+
for (let i = 0; i < padDaysBefore; i++)
|
|
116
|
+
padBeforeDays.splice(0, 0, dayBefore--);
|
|
99
117
|
|
|
100
|
-
|
|
118
|
+
const lastWeekDay = pickerValue.clone().date(daysInMonth).day();
|
|
119
|
+
const padDaysAfter = 7 - lastWeekDay;
|
|
120
|
+
for (let i = 0; i < padDaysAfter; i++)
|
|
121
|
+
padAfterDays.push(i + 1);
|
|
101
122
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
if (Math.ceil(padAfterDays.concat(days).concat(padBeforeDays).length / 7) < 6) {
|
|
124
|
+
let dayAfter = padAfterDays[padAfterDays.length - 1] + 1;
|
|
125
|
+
for (let i = 0; i < 7; i++)
|
|
126
|
+
padAfterDays.push(dayAfter++);
|
|
127
|
+
}
|
|
128
|
+
return [padBeforeDays, days, padAfterDays];
|
|
129
|
+
}, [pickerValue]);
|
|
130
|
+
|
|
131
|
+
function onReduce(key: 'year' | 'month') {
|
|
132
|
+
return function () {
|
|
133
|
+
const value = pickerValue.clone();
|
|
134
|
+
value.add(-1, key);
|
|
135
|
+
value.date(Math.min(value.daysInMonth(), value.date()))
|
|
136
|
+
onChange(false)(value);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
108
139
|
|
|
109
|
-
onAdd
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
140
|
+
function onAdd(key: 'year' | 'month') {
|
|
141
|
+
return function () {
|
|
142
|
+
const value = pickerValue.clone();
|
|
143
|
+
value.add(1, key);
|
|
144
|
+
value.date(Math.min(value.daysInMonth(), value.date()))
|
|
145
|
+
onChange(false)(value);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
115
148
|
|
|
116
|
-
onResetSwitcher
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
149
|
+
function onResetSwitcher(key: 'year' | 'month') {
|
|
150
|
+
return function () {
|
|
151
|
+
const value = pickerValue.clone();
|
|
152
|
+
if (key === 'year') value.year(toMoment().year());
|
|
153
|
+
else value.month(toMoment().month());
|
|
154
|
+
value.date(Math.min(value.daysInMonth(), value.date()))
|
|
155
|
+
onChange(false)(value);
|
|
156
|
+
}
|
|
122
157
|
}
|
|
123
158
|
|
|
124
|
-
onClickToday
|
|
125
|
-
const {onChange} = this.props;
|
|
159
|
+
function onClickToday() {
|
|
126
160
|
onChange(true)(toMoment());
|
|
127
|
-
}
|
|
161
|
+
}
|
|
128
162
|
|
|
129
|
-
onSelectDay
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
163
|
+
function onSelectDay(day: number, month?: number, year?: number) {
|
|
164
|
+
return function () {
|
|
165
|
+
const pickValue = pickerValue.clone();
|
|
166
|
+
if (day || value === null) {
|
|
167
|
+
pickValue.date(day);
|
|
168
|
+
if (month !== undefined) pickValue.month(month);
|
|
169
|
+
if (year !== undefined) pickValue.year(year);
|
|
170
|
+
onChange(true)(pickValue);
|
|
171
|
+
}
|
|
136
172
|
}
|
|
137
173
|
}
|
|
138
174
|
|
|
139
|
-
onSelectPadDay
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
175
|
+
function onSelectPadDay(day: number, kind: 'prev' | 'next') {
|
|
176
|
+
return function () {
|
|
177
|
+
const value = pickerValue.clone();
|
|
178
|
+
if (kind === 'prev') value.add(-1, 'month');
|
|
179
|
+
else value.add(1, 'month');
|
|
180
|
+
value.date(day);
|
|
181
|
+
onChange(true)(value);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
147
184
|
|
|
148
|
-
keyListener
|
|
149
|
-
const {key, shiftKey, ctrlKey} = evt
|
|
185
|
+
function keyListener(evt: KeyboardEvent) {
|
|
186
|
+
const {key, shiftKey, ctrlKey} = evt;
|
|
150
187
|
if (['ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown', 'Enter'].includes(key)) {
|
|
151
188
|
evt.preventDefault();
|
|
152
189
|
}
|
|
153
|
-
if (key === 'ArrowLeft')
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
} else if (key === 'ArrowDown') {
|
|
160
|
-
this.onDownKey();
|
|
161
|
-
} else if (key === 'Enter') {
|
|
162
|
-
onClose();
|
|
163
|
-
}
|
|
164
|
-
};
|
|
190
|
+
if (key === 'ArrowLeft') onLeftKey(shiftKey, ctrlKey);
|
|
191
|
+
else if (key === 'ArrowRight') onRightKey(shiftKey, ctrlKey);
|
|
192
|
+
else if (key === 'ArrowUp') onUpKey();
|
|
193
|
+
else if (key === 'ArrowDown') onDownKey();
|
|
194
|
+
else if (key === 'Enter') onClose();
|
|
195
|
+
}
|
|
165
196
|
|
|
166
|
-
onLeftKey
|
|
167
|
-
const
|
|
197
|
+
function onLeftKey(shiftKey: boolean, ctrlKey: boolean) {
|
|
198
|
+
const value = pickerValue.clone();
|
|
168
199
|
if (shiftKey) {
|
|
169
|
-
if (ctrlKey)
|
|
170
|
-
else
|
|
171
|
-
} else onChange(false)(
|
|
200
|
+
if (ctrlKey) onReduce('year')();
|
|
201
|
+
else onReduce('month')();
|
|
202
|
+
} else onChange(false)(value.add(-1, 'days'));
|
|
172
203
|
}
|
|
173
204
|
|
|
174
|
-
onRightKey
|
|
175
|
-
const
|
|
205
|
+
function onRightKey(shiftKey: boolean, ctrlKey: boolean) {
|
|
206
|
+
const value = pickerValue.clone();
|
|
176
207
|
if (shiftKey) {
|
|
177
|
-
if (ctrlKey)
|
|
178
|
-
else
|
|
179
|
-
} else onChange(false)(
|
|
208
|
+
if (ctrlKey) onAdd('year')();
|
|
209
|
+
else onAdd('month')();
|
|
210
|
+
} else onChange(false)(value.add(1, 'days'));
|
|
180
211
|
}
|
|
181
212
|
|
|
182
|
-
onUpKey
|
|
183
|
-
const
|
|
184
|
-
onChange(false)(
|
|
213
|
+
function onUpKey() {
|
|
214
|
+
const value = pickerValue.clone();
|
|
215
|
+
onChange(false)(value.add(-7, 'days'));
|
|
185
216
|
}
|
|
186
217
|
|
|
187
|
-
onDownKey
|
|
188
|
-
const
|
|
189
|
-
onChange(false)(
|
|
218
|
+
function onDownKey() {
|
|
219
|
+
const value = pickerValue.clone();
|
|
220
|
+
onChange(false)(value.add(7, 'days'));
|
|
190
221
|
}
|
|
191
222
|
|
|
192
|
-
addMountClass
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
function addMountClass() {
|
|
224
|
+
const div = divRef.current;
|
|
225
|
+
if (div?.classList.contains('switch-mount'))
|
|
226
|
+
div.classList.add('switch-mount');
|
|
227
|
+
}
|
|
196
228
|
|
|
197
|
-
removeMountClass
|
|
198
|
-
if (!
|
|
199
|
-
|
|
200
|
-
}
|
|
229
|
+
function removeMountClass() {
|
|
230
|
+
if (!alwaysShowArrows)
|
|
231
|
+
divRef.current?.classList.remove('switch-mount');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function dateIsDisabled(day: number, month?: number, year?: number) {
|
|
235
|
+
if (!min && !max) return false;
|
|
236
|
+
const pickValue = pickerValue.clone();
|
|
237
|
+
pickValue.date(day);
|
|
238
|
+
if (month !== undefined) pickValue.month(month);
|
|
239
|
+
if (year !== undefined) pickValue.year(year);
|
|
240
|
+
if (min && toMoment(min).isAfter(pickValue, 'date')) return true;
|
|
241
|
+
else if (max && toMoment(max).isBefore(pickValue, 'date')) return true;
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
201
244
|
|
|
202
|
-
renderSwitcher
|
|
203
|
-
const icon = kind === 'add' ? 'chevron-right' : 'chevron-left'
|
|
204
|
-
|
|
205
|
-
|
|
245
|
+
function renderSwitcher(key: 'year' | 'month', kind: 'add' | 'reduce') {
|
|
246
|
+
const icon = kind === 'add' ? 'chevron-right' : 'chevron-left';
|
|
247
|
+
const title = kind === 'add' ? 'Volgende' : 'Vorige';
|
|
248
|
+
const onClick = kind === 'add' ? onAdd(key) : onReduce(key);
|
|
206
249
|
return <AwesomeIcon name={icon} title={title} className={classNames('switcher-icon', kind)} onClick={onClick}/>
|
|
207
250
|
}
|
|
208
251
|
|
|
209
|
-
renderTooltipContainer
|
|
252
|
+
function renderTooltipContainer() {
|
|
210
253
|
return (
|
|
211
254
|
<div className='tooltip-container'>
|
|
212
255
|
<AwesomeIcon name='question-circle' className='tooltip-icon' prefix='far'/>
|
|
@@ -269,113 +312,94 @@ class Picker extends PureComponent<PickerProps> {
|
|
|
269
312
|
)
|
|
270
313
|
}
|
|
271
314
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
componentWillUnmount = () => {
|
|
282
|
-
document.removeEventListener('keydown', this.keyListener);
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
render = () => {
|
|
286
|
-
const {open, onClose} = this.props, pickerValue = this.getPickerValue(),
|
|
287
|
-
daysInMonth = pickerValue.daysInMonth(), days: number[] = [], padBeforeDays: number[] = [],
|
|
288
|
-
padAfterDays: number[] = [];
|
|
289
|
-
for (let i = 1; i <= daysInMonth; i++) days.push(i);
|
|
290
|
-
let firstMonthDay = pickerValue.clone().date(1).day();
|
|
291
|
-
if (!firstMonthDay) firstMonthDay = 7;
|
|
292
|
-
const padDaysBefore = firstMonthDay - 1;
|
|
293
|
-
let dayBefore = pickerValue.clone().add(-1, 'month').daysInMonth()
|
|
294
|
-
for (let i = 0; i < padDaysBefore; i++)
|
|
295
|
-
padBeforeDays.splice(0, 0, dayBefore--);
|
|
296
|
-
|
|
297
|
-
const lastWeekDay = pickerValue.clone().date(daysInMonth).day();
|
|
298
|
-
const padDaysAfter = 7 - lastWeekDay;
|
|
299
|
-
for (let i = 0; i < padDaysAfter; i++)
|
|
300
|
-
padAfterDays.push(i + 1);
|
|
301
|
-
|
|
302
|
-
if (Math.ceil(padAfterDays.concat(days).concat(padBeforeDays).length / 7) < 6) {
|
|
303
|
-
let dayAfter = padAfterDays[padAfterDays.length - 1] + 1;
|
|
304
|
-
for (let i = 0; i < 7; i++)
|
|
305
|
-
padAfterDays.push(dayAfter++);
|
|
315
|
+
useEffect(() => {
|
|
316
|
+
if (open) {
|
|
317
|
+
document.addEventListener('keydown', keyListener);
|
|
318
|
+
addMountClass();
|
|
319
|
+
window.setTimeout(removeMountClass, 1000);
|
|
320
|
+
} else {
|
|
321
|
+
document.removeEventListener('keydown', keyListener);
|
|
306
322
|
}
|
|
307
|
-
|
|
323
|
+
return function () {
|
|
324
|
+
document.removeEventListener('keydown', keyListener);
|
|
325
|
+
}
|
|
326
|
+
}, [open]);
|
|
327
|
+
|
|
328
|
+
function renderDay(day: number, index: number, onClick: MouseEventHandler, className?: string, type?: 'prev' | 'next') {
|
|
329
|
+
let pickValue = pickerValue.clone();
|
|
330
|
+
if (type === 'prev')
|
|
331
|
+
pickValue = pickValue.subtract(1, 'month');
|
|
332
|
+
else if (type === 'next')
|
|
333
|
+
pickValue = pickValue.add(1, 'month');
|
|
334
|
+
const month = pickValue.month();
|
|
335
|
+
const year = pickValue.year();
|
|
336
|
+
const disabled = dateIsDisabled(day, month, year);
|
|
308
337
|
return (
|
|
309
|
-
<
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
338
|
+
<div className={classNames('day', disabled && 'disabled', className)}
|
|
339
|
+
onClick={disabled ? undefined : onClick} key={index}>
|
|
340
|
+
<span className='day-label'>{day}</span>
|
|
341
|
+
</div>
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return (
|
|
346
|
+
<WithBackground active={open} onClose={onClose}>
|
|
347
|
+
<div className='picker' ref={divRef}>
|
|
348
|
+
<div className='switcher year'>
|
|
349
|
+
{renderSwitcher('year', 'reduce')}
|
|
350
|
+
<label className='switcher-label'
|
|
351
|
+
onClick={onResetSwitcher('year')}>{pickerValue.year()}</label>
|
|
352
|
+
{renderSwitcher('year', 'add')}
|
|
353
|
+
</div>
|
|
354
|
+
<div className='switcher month'>
|
|
355
|
+
{renderSwitcher('month', 'reduce')}
|
|
356
|
+
<label className='switcher-label' onClick={onResetSwitcher('month')}>{pickerValue.format(
|
|
357
|
+
'MMMM')}</label>
|
|
358
|
+
{renderSwitcher('month', 'add')}
|
|
359
|
+
</div>
|
|
360
|
+
<div className='current-date-container'>
|
|
361
|
+
<label className='current-date-label'>{pickerValue.format('dddd D MMMM YYYY')}</label>
|
|
362
|
+
{renderTooltipContainer()}
|
|
363
|
+
</div>
|
|
364
|
+
<div className='days-container'>
|
|
365
|
+
<div className='day no-select'>
|
|
366
|
+
<span className='day-label'>Ma</span>
|
|
318
367
|
</div>
|
|
319
|
-
<div className='
|
|
320
|
-
|
|
321
|
-
<label className='switcher-label' onClick={this.onResetSwitcher('month')}>{pickerValue.format(
|
|
322
|
-
'MMMM')}</label>
|
|
323
|
-
{this.renderSwitcher('month', 'add')}
|
|
368
|
+
<div className='day no-select'>
|
|
369
|
+
<span className='day-label'>Di</span>
|
|
324
370
|
</div>
|
|
325
|
-
<div className='
|
|
326
|
-
<
|
|
327
|
-
{this.renderTooltipContainer()}
|
|
371
|
+
<div className='day no-select'>
|
|
372
|
+
<span className='day-label'>Wo</span>
|
|
328
373
|
</div>
|
|
329
|
-
<div className='
|
|
330
|
-
<
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
<
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
<
|
|
337
|
-
<span className='day-label'>Wo</span>
|
|
338
|
-
</div>
|
|
339
|
-
<div className='day no-select'>
|
|
340
|
-
<span className='day-label'>Do</span>
|
|
341
|
-
</div>
|
|
342
|
-
<div className='day no-select'>
|
|
343
|
-
<span className='day-label'>Vr</span>
|
|
344
|
-
</div>
|
|
345
|
-
<div className='day no-select'>
|
|
346
|
-
<span className='day-label'>Za</span>
|
|
347
|
-
</div>
|
|
348
|
-
<div className='day no-select'>
|
|
349
|
-
<span className='day-label'>Zo</span>
|
|
350
|
-
</div>
|
|
351
|
-
{padBeforeDays.map((day: number, index: number) => (
|
|
352
|
-
<div className={classNames('day', 'pad')} onClick={this.onSelectPadDay(day, 'prev')}
|
|
353
|
-
key={index}>
|
|
354
|
-
<span className='day-label'>{day}</span>
|
|
355
|
-
</div>
|
|
356
|
-
))}
|
|
357
|
-
{days.map((day: number, index: number) => {
|
|
358
|
-
const isSelected = day === pickerValue.date();
|
|
359
|
-
return (
|
|
360
|
-
<div className={classNames('day', isSelected && 'selected', day === 0 && 'hide')}
|
|
361
|
-
key={index} onClick={this.onSelectDay(day)}>
|
|
362
|
-
<span className='day-label'>{day}</span>
|
|
363
|
-
</div>
|
|
364
|
-
)
|
|
365
|
-
})}
|
|
366
|
-
{padAfterDays.map((day: number, index: number) => (
|
|
367
|
-
<div className={classNames('day', 'pad')} onClick={this.onSelectPadDay(day, 'next')}
|
|
368
|
-
key={index}>
|
|
369
|
-
<span className='day-label'>{day}</span>
|
|
370
|
-
</div>
|
|
371
|
-
))}
|
|
374
|
+
<div className='day no-select'>
|
|
375
|
+
<span className='day-label'>Do</span>
|
|
376
|
+
</div>
|
|
377
|
+
<div className='day no-select'>
|
|
378
|
+
<span className='day-label'>Vr</span>
|
|
379
|
+
</div>
|
|
380
|
+
<div className='day no-select'>
|
|
381
|
+
<span className='day-label'>Za</span>
|
|
372
382
|
</div>
|
|
373
|
-
<div className='
|
|
374
|
-
<
|
|
375
|
-
<DvrdButton onClick={onClose} label='Sluiten' secondary className='action'/>
|
|
383
|
+
<div className='day no-select'>
|
|
384
|
+
<span className='day-label'>Zo</span>
|
|
376
385
|
</div>
|
|
386
|
+
{padBeforeDays.map((day: number, index: number) => {
|
|
387
|
+
return renderDay(day, index, onSelectPadDay(day, 'prev'), 'pad', 'prev');
|
|
388
|
+
})}
|
|
389
|
+
{days.map((day: number, index: number) => {
|
|
390
|
+
const isSelected = day === pickerValue.date();
|
|
391
|
+
return renderDay(day, index, onSelectDay(day),
|
|
392
|
+
classNames(isSelected && 'selected', day === 0 && 'hide'));
|
|
393
|
+
})}
|
|
394
|
+
{padAfterDays.map((day: number, index: number) => {
|
|
395
|
+
return renderDay(day, index, onSelectPadDay(day, 'next'), 'pad', 'next');
|
|
396
|
+
})}
|
|
377
397
|
</div>
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
398
|
+
<div className='actions-container'>
|
|
399
|
+
<DvrdButton onClick={onClickToday} label='Vandaag' className='action'/>
|
|
400
|
+
<DvrdButton onClick={onClose} label='Sluiten' secondary className='action'/>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</WithBackground>
|
|
404
|
+
)
|
|
381
405
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import './style/sidebarMenu.scss';
|
|
5
5
|
|
|
6
6
|
import React, {MouseEventHandler, ReactNode, useContext, useEffect, useRef, useState} from 'react';
|
|
7
|
-
import {useLocation} from 'react-router-dom';
|
|
7
|
+
import {NavLink, useLocation} from 'react-router-dom';
|
|
8
8
|
import {SidebarItem, SideMenuMode} from "../util/interfaces";
|
|
9
9
|
import classNames from 'classnames';
|
|
10
10
|
import {AwesomeIcon, generateComponentId, isAbsoluteLink} from "../../../index";
|
|
@@ -82,21 +82,33 @@ export default function SidebarMenu(props: Props) {
|
|
|
82
82
|
|
|
83
83
|
function renderItem(isChild: boolean = false) {
|
|
84
84
|
return function (item: SidebarItem) {
|
|
85
|
-
const {className, icon, id, label, children} = item,
|
|
85
|
+
const {className, icon, id, label, children, asNavLink} = item,
|
|
86
86
|
isActive = itemHasActiveId(item, activeItem),
|
|
87
87
|
cls = classNames(className, mode === SideMenuMode.COMPACT ? 'side-bar-item' : 'side-bar-item-full',
|
|
88
88
|
isChild && 'child', children !== undefined && 'with-children');
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
|
|
90
|
+
const content = (
|
|
91
|
+
<>
|
|
92
|
+
{renderIcon(isChild, label, icon)}
|
|
92
93
|
{mode === SideMenuMode.COMPACT && <div className='active-indicator'/>}
|
|
93
|
-
<span className=
|
|
94
|
+
<span className='item-label'>{label}</span>
|
|
94
95
|
{children !== undefined && (
|
|
95
96
|
<>
|
|
96
97
|
{isActive && <div className='line'/>}
|
|
97
98
|
{renderChildren(isActive)(children)}
|
|
98
99
|
</>
|
|
99
100
|
)}
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (asNavLink) return (
|
|
105
|
+
<NavLink key={id} to={item.route as string} className={cls} id={id}>
|
|
106
|
+
{content}
|
|
107
|
+
</NavLink>
|
|
108
|
+
);
|
|
109
|
+
return (
|
|
110
|
+
<div key={id} className={classNames(cls, isActive && 'active')} onClick={_onClickItem(item)} id={id}>
|
|
111
|
+
{content}
|
|
100
112
|
</div>
|
|
101
113
|
)
|
|
102
114
|
}
|
|
@@ -113,8 +125,8 @@ export default function SidebarMenu(props: Props) {
|
|
|
113
125
|
}
|
|
114
126
|
}
|
|
115
127
|
|
|
116
|
-
function renderIcon(
|
|
117
|
-
const className =
|
|
128
|
+
function renderIcon(isChild: boolean, label: string, icon?: IconName | ReactNode): ReactNode {
|
|
129
|
+
const className = 'item-icon'
|
|
118
130
|
if (icon) {
|
|
119
131
|
if (typeof icon === 'string') return <AwesomeIcon name={icon as IconName} className={className}/>;
|
|
120
132
|
else if (React.isValidElement(icon))
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
@import '../../../style/variables';
|
|
6
6
|
|
|
7
7
|
.dvr-side-bar-menu {
|
|
8
|
-
//--base-color: white;
|
|
9
|
-
//--contrast-color: $color-blue-1;
|
|
10
8
|
@include backgroundShadow;
|
|
11
9
|
display: flex;
|
|
12
10
|
flex-direction: column;
|
|
@@ -30,6 +28,7 @@
|
|
|
30
28
|
background-color: var(--contrast-color-color);
|
|
31
29
|
transition: background-color .2s ease-in-out;
|
|
32
30
|
color: var(--base-color);
|
|
31
|
+
text-decoration: none;
|
|
33
32
|
|
|
34
33
|
.item-icon {
|
|
35
34
|
color: $color-gray-4;
|
|
@@ -100,6 +99,7 @@
|
|
|
100
99
|
align-items: center;
|
|
101
100
|
cursor: pointer;
|
|
102
101
|
position: relative;
|
|
102
|
+
text-decoration: none;
|
|
103
103
|
|
|
104
104
|
.item-icon {
|
|
105
105
|
color: #686869;
|
|
@@ -119,11 +119,11 @@
|
|
|
119
119
|
transition: color .2s ease-in-out;
|
|
120
120
|
white-space: nowrap;
|
|
121
121
|
user-select: none;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
122
|
+
//
|
|
123
|
+
//&.active {
|
|
124
|
+
// font-weight: 600;
|
|
125
|
+
// color: black;
|
|
126
|
+
//}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
.line {
|
|
@@ -164,6 +164,18 @@
|
|
|
164
164
|
&.with-children {
|
|
165
165
|
margin-bottom: -.5rem;
|
|
166
166
|
}
|
|
167
|
+
|
|
168
|
+
&.active {
|
|
169
|
+
.item-icon {
|
|
170
|
+
color: var(--base-color);
|
|
171
|
+
opacity: 1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.item-label {
|
|
175
|
+
font-weight: 600;
|
|
176
|
+
color: black;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
167
179
|
}
|
|
168
180
|
}
|
|
169
181
|
}
|
|
@@ -62,7 +62,7 @@ export default class DvrdNumberInput extends PureComponent<Props, State> {
|
|
|
62
62
|
const {key, target} = evt;
|
|
63
63
|
let numValue = Number(value);
|
|
64
64
|
// Allow only number and simple edit keys
|
|
65
|
-
if (!/\d|Backspace|ArrowRight|ArrowLeft|ArrowUp|ArrowDown|Escape|Esc|Enter|[,.\-+]|Tab/.test(key) &&
|
|
65
|
+
if (!/\d|Backspace|ArrowRight|ArrowLeft|ArrowUp|ArrowDown|Escape|Esc|Enter|[,.\-+]|Tab|Delete|Del/.test(key) &&
|
|
66
66
|
!this.isPasting(evt))
|
|
67
67
|
evt.preventDefault();
|
|
68
68
|
|
|
@@ -224,6 +224,7 @@ export type SidebarItem = {
|
|
|
224
224
|
route?: string | string[];
|
|
225
225
|
exactRoute?: boolean;
|
|
226
226
|
children?: SidebarItem[];
|
|
227
|
+
asNavLink?: true;
|
|
227
228
|
}
|
|
228
229
|
export type ResponseCallback = (data: ResponseData) => void;
|
|
229
230
|
export type RNDDimensions = { x: number, y: number, height: number, width: number };
|