@dvrd/dvr-controls 1.0.77 → 1.0.79

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.77",
3
+ "version": "1.0.79",
4
4
  "description": "Custom web controls",
5
5
  "main": "index.ts",
6
6
  "files": [
@@ -30,7 +30,7 @@
30
30
  "react-router-dom": "6.15.0"
31
31
  },
32
32
  "dependencies": {
33
- "@dvrd/idate": "^1.8.4",
33
+ "@dvrd/idate": "^1.8.6",
34
34
  "@fortawesome/fontawesome-svg-core": "6.5.2",
35
35
  "@fortawesome/free-brands-svg-icons": "6.5.2",
36
36
  "@fortawesome/free-regular-svg-icons": "6.5.2",
@@ -47,6 +47,7 @@
47
47
  "@types/react": "^18.2.28",
48
48
  "@types/react-color": "2.13.5",
49
49
  "@types/react-dom": "^18.0.11",
50
+ "@types/swiper": "^6.0.0",
50
51
  "@types/uuid": "9.0.0",
51
52
  "classnames": "2.5.1",
52
53
  "dompurify": "3.0.0",
@@ -58,6 +59,7 @@
58
59
  "lodash.mergewith": "^4.6.2",
59
60
  "react-color": "2.19.3",
60
61
  "react-rnd": "10.4.1",
62
+ "swiper": "^11.1.4",
61
63
  "typescript": "4.9.5",
62
64
  "uuid": "9.0.0"
63
65
  }
@@ -21,9 +21,11 @@ import WithBackground from '../popup/withBackground';
21
21
  import DvrdButton from "../button/dvrdButton";
22
22
  import {generateComponentId} from "../util/componentUtil";
23
23
  import IDate from '@dvrd/idate';
24
- import {pad, padNum, voidFunction} from "../util/controlUtil";
25
- import {DvrdNumberInput} from "../../../index";
24
+ import {pad} from "../util/controlUtil";
26
25
  import defer from 'lodash.defer';
26
+ import {Swiper, SwiperClass, SwiperSlide} from 'swiper/react';
27
+ import {FreeMode, Mousewheel} from 'swiper/modules';
28
+ import 'swiper/css';
27
29
 
28
30
  interface Props {
29
31
  onChange: ChangeFunction<IDate>;
@@ -354,7 +356,7 @@ function DatePicker(props: DatePickerProps) {
354
356
  useEffect(() => {
355
357
  if (open) {
356
358
  document.addEventListener('keydown', keyListener);
357
- addMountClass();
359
+ defer(addMountClass);
358
360
  window.setTimeout(removeMountClass, 1000);
359
361
  } else {
360
362
  document.removeEventListener('keydown', keyListener);
@@ -384,7 +386,7 @@ function DatePicker(props: DatePickerProps) {
384
386
 
385
387
  return (
386
388
  <WithBackground active={open} onClose={onClose}>
387
- <div className='picker' ref={divRef}>
389
+ <div className={classNames('picker', alwaysShowArrows && 'switch-mount')} ref={divRef}>
388
390
  <div className='switcher year'>
389
391
  {renderSwitcher('year', 'reduce')}
390
392
  <label className='switcher-label'
@@ -453,85 +455,40 @@ interface TimePickerProps {
453
455
  closeOnChange?: boolean;
454
456
  }
455
457
 
456
- type TimePartValues = [string, string, string, string, string, string];
457
-
458
- function dateToTimeParts(value: IDate | null): TimePartValues {
459
- if (!value) return ['', '', '', '', '', ''];
460
- const hours = padNum(value.hours());
461
- const minutes = padNum(value.minutes());
462
- const seconds = padNum(value.seconds());
463
- return [...hours.split(''), ...minutes.split(''), ...seconds.split('')] as TimePartValues;
464
- }
465
-
466
- function timePartsToNumber(part1: string, part2: string): number {
467
- const num = Number(part1 + part2);
468
- return Number.isNaN(num) ? 0 : num;
469
- }
470
-
471
458
  function TimePicker(props: TimePickerProps) {
472
459
  const {onChange, value, open, onClose, timeMode, closeOnChange} = props;
473
- const [timeParts, setTimeParts] = useState<TimePartValues>(dateToTimeParts(value));
474
- const secondHourMax = useMemo(() => {
475
- if (Number(timeParts[0]) === 2) return 3;
476
- return 9;
477
- }, timeParts);
478
- const compID = useRef(generateComponentId());
460
+ const internalValue = useRef<IDate>(value ?? new IDate('00:00:00', 'HH:mm:ss'));
479
461
 
480
462
  function onClickNow() {
481
- setTimeParts(dateToTimeParts(new IDate()));
463
+ internalValue.current = IDate.now();
482
464
  if (closeOnChange)
483
465
  onSubmit();
484
466
  }
485
467
 
486
- function onSubmit() {
487
- const hours = timePartsToNumber(timeParts[0], timeParts[1]);
488
- const minutes = timePartsToNumber(timeParts[2], timeParts[3]);
489
- const seconds = timePartsToNumber(timeParts[4], timeParts[5]);
490
- const _value = value?.clone() ?? new IDate();
491
- onChange(_value.set({hours, minutes, seconds}));
492
- onClose();
493
- }
494
-
495
- function onKeyDown(index: number) {
496
- return function (evt: React.KeyboardEvent) {
497
- const {key} = evt;
498
- if (/\d/.test(key) && index < 5) {
499
- onChangePickerPart(index)(key);
500
- defer(() => onFocusElement(index + 1));
501
- }
502
- if (key.toLowerCase() === 'backspace')
503
- if ((evt.target as HTMLInputElement).value) {
504
- onChangePickerPart(index)('');
505
- } else if (index > 0) {
506
- onChangePickerPart(index - 1)('');
507
- defer(() => onFocusElement(index - 1));
508
- }
509
- }
510
- }
511
-
512
- function onChangePickerPart(index: number) {
513
- return function (value: string) {
514
- const parts = [...timeParts];
515
- parts[index] = value;
516
- setTimeParts(parts as TimePartValues);
468
+ function onSlideChange(key: 'hour' | 'minute' | 'second') {
469
+ return function (swiper: SwiperClass) {
470
+ if (key === 'hour') internalValue.current = internalValue.current.hours(swiper.realIndex);
471
+ if (key === 'minute') internalValue.current = internalValue.current.minutes(swiper.realIndex);
472
+ if (key === 'second') internalValue.current = internalValue.current.seconds(swiper.realIndex);
517
473
  }
518
474
  }
519
475
 
520
- function onFocusElement(index: number) {
521
- const input = document.getElementById(`${compID.current}-${index}-input`);
522
- input?.focus();
476
+ function onSubmit() {
477
+ onChange(internalValue.current.clone());
478
+ onClose();
523
479
  }
524
480
 
525
- function renderTimeControls() {
481
+ function renderTimeContainer() {
526
482
  const renderHours = [DatePickerTimeMode.FULL, DatePickerTimeMode.HOURS_MINUTES, DatePickerTimeMode.HOURS_ONLY].includes(timeMode);
527
483
  const renderMinutes = [DatePickerTimeMode.FULL, DatePickerTimeMode.HOURS_MINUTES, DatePickerTimeMode.MINUTES_ONLY].includes(timeMode);
528
484
  const renderSeconds = [DatePickerTimeMode.FULL, DatePickerTimeMode.SECONDS_ONLY].includes(timeMode);
529
485
  const timeControls: Array<React.ReactElement> = [];
530
- if (renderHours) timeControls.push(renderTimeControl([0, 1], 2, secondHourMax, true));
531
- if (renderMinutes) timeControls.push(renderTimeControl([2, 3], 5, 9, !renderHours));
532
- if (renderSeconds) timeControls.push(renderTimeControl([4, 5], 5, 9, !renderHours && !renderMinutes));
486
+ if (renderHours) timeControls.push(renderTimeSwiper('hour'));
487
+ if (renderMinutes) timeControls.push(renderTimeSwiper('minute'));
488
+ if (renderSeconds) timeControls.push(renderTimeSwiper('second'));
533
489
  return (
534
- <div className='time-controls'>
490
+ <div className='time-swiper-container'>
491
+ <div className='vizor top'/>
535
492
  {timeControls.map((control: React.ReactElement, index: number) => {
536
493
  return (
537
494
  <Fragment key={index}>
@@ -540,39 +497,47 @@ function TimePicker(props: TimePickerProps) {
540
497
  </Fragment>
541
498
  )
542
499
  })}
500
+ <div className='vizor bottom'/>
543
501
  </div>
544
502
  )
545
503
  }
546
504
 
547
- function renderTimeControl(timePartIndexes: [number, number], firstMax: number, secondMax: number = 9,
548
- autoFocus: boolean = false) {
505
+ function renderTimeSwiper(key: 'hour' | 'minute' | 'second') {
506
+ const _value = value ?? new IDate('00:00:00', 'HH:mm:ss');
507
+ let timeValue: number, numSlides: number;
508
+ if (key === 'hour') {
509
+ timeValue = _value.hours();
510
+ numSlides = 24;
511
+ } else if (key === 'minute') {
512
+ timeValue = _value.minutes();
513
+ numSlides = 60;
514
+ } else {
515
+ timeValue = _value.seconds();
516
+ numSlides = 60;
517
+ }
518
+ const slideValues: Array<string> = [];
519
+ for (let i = 0; i < numSlides; i++) slideValues.push(pad(i));
549
520
  return (
550
- <div className='time-control'>
551
- <DvrdNumberInput value={timeParts[timePartIndexes[0]]} onChange={voidFunction}
552
- inputProps={{min: 0, max: firstMax, tabIndex: timePartIndexes[0] + 1, maxLength: 1}}
553
- className='time-control-part' id={`${compID.current}-${timePartIndexes[0]}`}
554
- onKeyDown={onKeyDown(timePartIndexes[0])} placeholder='0' autoFocus={autoFocus}
555
- autoSelect wholeNumbers/>
556
- <DvrdNumberInput value={timeParts[timePartIndexes[1]]} onChange={voidFunction}
557
- inputProps={{min: 0, max: secondMax, tabIndex: timePartIndexes[1] + 1, maxLength: 1}}
558
- onKeyDown={onKeyDown(timePartIndexes[1])} className='time-control-part'
559
- id={`${compID.current}-${timePartIndexes[1]}`} placeholder='0' autoSelect
560
- wholeNumbers/>
561
- </div>
521
+ <Swiper modules={[Mousewheel, FreeMode]} slidesPerView={3} direction='vertical' initialSlide={timeValue}
522
+ onTransitionEnd={onSlideChange(key)} mousewheel={{enabled: true, sensitivity: .5}} freeMode={{
523
+ enabled: true,
524
+ sticky: true,
525
+ minimumVelocity: .1,
526
+ momentumVelocityRatio: .25,
527
+ momentumRatio: .25
528
+ }} loop slideToClickedSlide centeredSlides>
529
+ {slideValues.map((value: string, index: number) => <SwiperSlide key={index}>{value}</SwiperSlide>)}
530
+ </Swiper>
562
531
  )
563
532
  }
564
533
 
565
- useEffect(() => {
566
- setTimeParts(dateToTimeParts(value));
567
- }, [value]);
568
-
569
534
  return (
570
535
  <WithBackground active={open} onClose={onClose}>
571
536
  <div className='picker time'>
572
537
  <div className='switcher'>
573
538
  <label className='switcher-label'>Tijdstip</label>
574
539
  </div>
575
- {renderTimeControls()}
540
+ {renderTimeContainer()}
576
541
  <div className='actions-container'>
577
542
  <DvrdButton onClick={onClickNow} label='Huidig tijdstip' secondary className='action'/>
578
543
  <DvrdButton onClick={onSubmit} label='Oké' className='action'/>
@@ -296,6 +296,48 @@
296
296
  .picker.time {
297
297
  width: 20rem;
298
298
 
299
+ .time-swiper-container {
300
+ height: 10rem;
301
+ display: flex;
302
+ align-items: center;
303
+ column-gap: 1rem;
304
+ position: relative;
305
+ justify-content: center;
306
+
307
+ .swiper {
308
+ max-height: 100%;
309
+ margin: 0;
310
+
311
+ .swiper-slide {
312
+ display: flex;
313
+ align-items: center;
314
+ font-size: 1.2rem;
315
+ font-weight: 500;
316
+ }
317
+ }
318
+
319
+ .sep {
320
+ font-size: 1.2rem;
321
+ height: 1.2rem;
322
+ }
323
+
324
+ .vizor {
325
+ position: absolute;
326
+ background-color: $color-gray-4;
327
+ width: 100%;
328
+ height: 1px;
329
+ z-index: 1;
330
+
331
+ &.top {
332
+ top: 35%;
333
+ }
334
+
335
+ &.bottom {
336
+ top: 65%;
337
+ }
338
+ }
339
+ }
340
+
299
341
  .time-controls {
300
342
  display: flex;
301
343
  column-gap: .5rem;