@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvrd/dvr-controls",
3
- "version": "1.0.43",
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, {PureComponent, useMemo, useState} from '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
- class Picker extends PureComponent<PickerProps> {
98
- private ref: HTMLDivElement | null = null;
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
- getPickerValue = (): Moment => toMoment(this.props.value);
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
- onReduce = (key: 'year' | 'month') => () => {
103
- const {onChange} = this.props, pickerValue = this.getPickerValue();
104
- pickerValue.add(-1, key);
105
- pickerValue.date(Math.min(pickerValue.daysInMonth(), pickerValue.date()))
106
- onChange(false)(pickerValue);
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 = (key: 'year' | 'month') => () => {
110
- const {onChange} = this.props, pickerValue = this.getPickerValue();
111
- pickerValue.add(1, key);
112
- pickerValue.date(Math.min(pickerValue.daysInMonth(), pickerValue.date()))
113
- onChange(false)(pickerValue);
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 = (key: 'year' | 'month') => () => {
117
- const {onChange} = this.props, pickerValue = this.getPickerValue();
118
- if (key === 'year') pickerValue.year(toMoment().year());
119
- else pickerValue.month(toMoment().month());
120
- pickerValue.date(Math.min(pickerValue.daysInMonth(), pickerValue.date()))
121
- onChange(false)(pickerValue);
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 = (day: number, month?: number, year?: number) => () => {
130
- const {onChange, value} = this.props, pickerValue = this.getPickerValue();
131
- if (day || value === null) {
132
- pickerValue.date(day);
133
- if (month !== undefined) pickerValue.month(month);
134
- if (year !== undefined) pickerValue.year(year);
135
- onChange(true)(pickerValue);
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 = (day: number, kind: 'prev' | 'next') => () => {
140
- const {onChange} = this.props, pickerValue = this.getPickerValue();
141
- const value = pickerValue.clone();
142
- if (kind === 'prev') value.add(-1, 'month');
143
- else value.add(1, 'month');
144
- value.date(day);
145
- onChange(true)(value);
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 = (evt: KeyboardEvent) => {
149
- const {key, shiftKey, ctrlKey} = evt, {onClose} = this.props;
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
- this.onLeftKey(shiftKey, ctrlKey);
155
- } else if (key === 'ArrowRight') {
156
- this.onRightKey(shiftKey, ctrlKey);
157
- } else if (key === 'ArrowUp') {
158
- this.onUpKey();
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 = (shiftKey: boolean, ctrlKey: boolean) => {
167
- const {onChange} = this.props, pickerValue = this.getPickerValue()
197
+ function onLeftKey(shiftKey: boolean, ctrlKey: boolean) {
198
+ const value = pickerValue.clone();
168
199
  if (shiftKey) {
169
- if (ctrlKey) this.onReduce('year')();
170
- else this.onReduce('month')();
171
- } else onChange(false)(pickerValue.add(-1, 'd'));
200
+ if (ctrlKey) onReduce('year')();
201
+ else onReduce('month')();
202
+ } else onChange(false)(value.add(-1, 'days'));
172
203
  }
173
204
 
174
- onRightKey = (shiftKey: boolean, ctrlKey: boolean) => {
175
- const {onChange} = this.props, pickerValue = this.getPickerValue();
205
+ function onRightKey(shiftKey: boolean, ctrlKey: boolean) {
206
+ const value = pickerValue.clone();
176
207
  if (shiftKey) {
177
- if (ctrlKey) this.onAdd('year')();
178
- else this.onAdd('month')();
179
- } else onChange(false)(pickerValue.add(1, 'd'));
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 {onChange} = this.props, pickerValue = this.getPickerValue();
184
- onChange(false)(pickerValue.add(-7, 'd'));
213
+ function onUpKey() {
214
+ const value = pickerValue.clone();
215
+ onChange(false)(value.add(-7, 'days'));
185
216
  }
186
217
 
187
- onDownKey = () => {
188
- const {onChange} = this.props, pickerValue = this.getPickerValue();
189
- onChange(false)(pickerValue.add(7, 'd'));
218
+ function onDownKey() {
219
+ const value = pickerValue.clone();
220
+ onChange(false)(value.add(7, 'days'));
190
221
  }
191
222
 
192
- addMountClass = () => {
193
- if (!this.ref?.classList.contains('switch-mount'))
194
- this.ref?.classList.add('switch-mount');
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 (!this.props.alwaysShowArrows)
199
- this.ref?.classList.remove('switch-mount');
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 = (key: 'year' | 'month', kind: 'add' | 'reduce') => {
203
- const icon = kind === 'add' ? 'chevron-right' : 'chevron-left',
204
- title = kind === 'add' ? 'Volgende' : 'Vorige',
205
- onClick = kind === 'add' ? this.onAdd(key) : this.onReduce(key);
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
- componentDidUpdate = (prevProps: PickerProps) => {
273
- const {open} = this.props, prevOpen = prevProps.open;
274
- if (open && !prevOpen) {
275
- document.addEventListener('keydown', this.keyListener);
276
- this.addMountClass();
277
- window.setTimeout(this.removeMountClass, 1000);
278
- } else if (!open && prevOpen) document.removeEventListener('keydown', this.keyListener);
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
- <WithBackground active={open} onClose={onClose}>
310
- <div className='picker' ref={(ref: HTMLDivElement) => {
311
- this.ref = ref
312
- }}>
313
- <div className='switcher year'>
314
- {this.renderSwitcher('year', 'reduce')}
315
- <label className='switcher-label'
316
- onClick={this.onResetSwitcher('year')}>{pickerValue.year()}</label>
317
- {this.renderSwitcher('year', 'add')}
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='switcher month'>
320
- {this.renderSwitcher('month', 'reduce')}
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='current-date-container'>
326
- <label className='current-date-label'>{pickerValue.format('dddd D MMMM YYYY')}</label>
327
- {this.renderTooltipContainer()}
371
+ <div className='day no-select'>
372
+ <span className='day-label'>Wo</span>
328
373
  </div>
329
- <div className='days-container'>
330
- <div className='day no-select'>
331
- <span className='day-label'>Ma</span>
332
- </div>
333
- <div className='day no-select'>
334
- <span className='day-label'>Di</span>
335
- </div>
336
- <div className='day no-select'>
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='actions-container'>
374
- <DvrdButton onClick={this.onClickToday} label='Vandaag' className='action'/>
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
- </WithBackground>
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
  }
@@ -254,6 +254,12 @@
254
254
  &:hover {
255
255
  background-color: rgba($color-blue-1, .2);
256
256
  }
257
+
258
+ &.disabled {
259
+ color: $color-gray-4;
260
+ background-color: unset;
261
+ cursor: default;
262
+ }
257
263
  }
258
264
 
259
265
  .extra-row {
@@ -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
- return (
90
- <div key={id} className={cls} onClick={_onClickItem(item)} id={id}>
91
- {renderIcon(isActive, isChild, label, icon)}
89
+
90
+ const content = (
91
+ <>
92
+ {renderIcon(isChild, label, icon)}
92
93
  {mode === SideMenuMode.COMPACT && <div className='active-indicator'/>}
93
- <span className={classNames('item-label', isActive && 'active')}>{label}</span>
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(isActive: boolean, isChild: boolean, label: string, icon?: IconName | ReactNode): ReactNode {
117
- const className = classNames('item-icon', isActive && 'active');
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
- &.active {
124
- font-weight: 600;
125
- color: black;
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 };