@dvrd/dvr-controls 1.0.52 → 1.0.54

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.
Files changed (164) hide show
  1. package/index.ts +2 -0
  2. package/package.json +1 -1
  3. package/src/js/button/button.tsx +1 -1
  4. package/src/js/button/buttonController.tsx +1 -1
  5. package/src/js/button/closeButton.tsx +1 -1
  6. package/src/js/button/dvrdButton.tsx +1 -1
  7. package/src/js/button/outlinedButton.tsx +1 -1
  8. package/src/js/button/simpleButton.tsx +1 -1
  9. package/src/js/button/style/button.scss +1 -1
  10. package/src/js/button/style/closeButton.scss +1 -1
  11. package/src/js/button/style/dvrdButton.scss +1 -1
  12. package/src/js/button/style/outlinedButton.scss +1 -1
  13. package/src/js/button/style/simpleButton.scss +1 -1
  14. package/src/js/carousel/DVRCarousel.tsx +1 -1
  15. package/src/js/carousel/DVRCarouselController.tsx +1 -1
  16. package/src/js/carousel/style/DVRCarousel.scss +1 -1
  17. package/src/js/checkbox/checkbox.tsx +1 -1
  18. package/src/js/checkbox/checkboxController.tsx +1 -1
  19. package/src/js/checkbox/style/checkbox.scss +1 -1
  20. package/src/js/colorPicker/colorPicker.tsx +1 -1
  21. package/src/js/colorPicker/style/colorPicker.scss +1 -1
  22. package/src/js/date/dvrdDatePicker.tsx +1 -1
  23. package/src/js/date/style/dvrdDatePicker.scss +1 -1
  24. package/src/js/dialog/dialog.tsx +1 -1
  25. package/src/js/dialog/dialogController.tsx +1 -1
  26. package/src/js/dialog/inlineDialog.tsx +1 -1
  27. package/src/js/dialog/style/dialog.scss +1 -1
  28. package/src/js/events/withEvents.tsx +1 -1
  29. package/src/js/fileUpload/fileUpload.tsx +1 -1
  30. package/src/js/fileUpload/style/fileUpload.scss +1 -1
  31. package/src/js/head/DVRHead.tsx +1 -1
  32. package/src/js/header/DVRHeader.tsx +1 -1
  33. package/src/js/header/style/header.scss +1 -1
  34. package/src/js/header/v2/dvrdHeader.tsx +4 -0
  35. package/src/js/header/v2/dvrdHeaderController.tsx +4 -0
  36. package/src/js/icon/awesomeIcon.tsx +1 -1
  37. package/src/js/image/imageUpload.tsx +1 -1
  38. package/src/js/image/style/imageUpload.scss +1 -1
  39. package/src/js/info/info.tsx +1 -1
  40. package/src/js/info/style/info.scss +1 -1
  41. package/src/js/input/animated/animatedTextField.tsx +1 -1
  42. package/src/js/input/date/dateField.tsx +1 -1
  43. package/src/js/input/date/dateFieldController.tsx +1 -1
  44. package/src/js/input/date/datePicker/datePicker.tsx +1 -1
  45. package/src/js/input/date/datePicker/style/datePicker.scss +1 -1
  46. package/src/js/input/date/input/dateInput.tsx +1 -1
  47. package/src/js/input/date/style/dateField.scss +1 -1
  48. package/src/js/input/date/timePicker/style/timePicker.scss +1 -1
  49. package/src/js/input/date/timePicker/timePicker.tsx +1 -1
  50. package/src/js/input/editor/DVREditor.tsx +1 -1
  51. package/src/js/input/number/numberInput.tsx +1 -1
  52. package/src/js/input/password/passwordInput.tsx +1 -1
  53. package/src/js/input/password/passwordRules.tsx +1 -1
  54. package/src/js/input/password/style/passwordInput.scss +1 -1
  55. package/src/js/input/password/style/passwordRules.scss +1 -1
  56. package/src/js/input/simple/style/simpleInput.scss +1 -1
  57. package/src/js/input/simple/v2/simpleInputV2.tsx +1 -1
  58. package/src/js/input/style/input.scss +1 -1
  59. package/src/js/input/v2/inputController_v2.tsx +1 -1
  60. package/src/js/input/v2/input_v2.tsx +1 -1
  61. package/src/js/label/label.tsx +1 -1
  62. package/src/js/label/style/label.scss +1 -1
  63. package/src/js/link/link.tsx +1 -1
  64. package/src/js/link/style/link.scss +1 -1
  65. package/src/js/loader/loader.tsx +1 -1
  66. package/src/js/loader/loaderController.tsx +1 -1
  67. package/src/js/loader/style/loader.scss +1 -1
  68. package/src/js/media/media.tsx +1 -1
  69. package/src/js/navigation/mobileNavigation.tsx +4 -0
  70. package/src/js/navigation/style/mobileNavigation.scss +4 -0
  71. package/src/js/navigator/navigator.tsx +1 -1
  72. package/src/js/optionsList/dvrdOptionsList.tsx +1 -1
  73. package/src/js/optionsList/style/dvrdOptionsList.scss +1 -1
  74. package/src/js/optionsMenu/optionsMenu.tsx +1 -1
  75. package/src/js/optionsMenu/style/optionsMenu.scss +1 -1
  76. package/src/js/pdf/element/pdfElement.tsx +1 -1
  77. package/src/js/pdf/element/style/pdfElement.scss +1 -1
  78. package/src/js/pdf/history/pdfHistory.ts +1 -1
  79. package/src/js/pdf/image/pdfImage.tsx +1 -1
  80. package/src/js/pdf/image/style/pdfImage.scss +1 -1
  81. package/src/js/pdf/invoiceTable/pdfInvoiceTable.tsx +1 -1
  82. package/src/js/pdf/invoiceTable/style/pdfInvoiceTable.scss +1 -1
  83. package/src/js/pdf/pdfTemplateCreator.tsx +1 -1
  84. package/src/js/pdf/settings/buttons/iconButton.tsx +1 -1
  85. package/src/js/pdf/settings/buttons/style/iconButton.scss +1 -1
  86. package/src/js/pdf/settings/image/pdfImageSettings.tsx +1 -1
  87. package/src/js/pdf/settings/image/style/pdfImageSettings.scss +1 -1
  88. package/src/js/pdf/settings/invoiceTable/pdfInvoiceTableSettings.tsx +1 -1
  89. package/src/js/pdf/settings/invoiceTable/style/pdfInvoiceTableSettings.scss +1 -1
  90. package/src/js/pdf/settings/pdfElementSettings.tsx +1 -1
  91. package/src/js/pdf/settings/style/pdfElementSettings.scss +1 -1
  92. package/src/js/pdf/settings/text/pdfTextSettings.tsx +1 -1
  93. package/src/js/pdf/settings/text/style/pdfTextSettings.scss +1 -1
  94. package/src/js/pdf/style/pdfTemplateCreator.scss +1 -1
  95. package/src/js/pdf/text/pdfText.tsx +1 -1
  96. package/src/js/pdf/text/style/pdfText.scss +1 -1
  97. package/src/js/pdf/v2/pdfElement/pdfDraggableElement.tsx +1 -1
  98. package/src/js/pdf/v2/types/pdfTemplateTypes.ts +1 -1
  99. package/src/js/popup/style/withBackground.scss +1 -1
  100. package/src/js/popup/withBackground.tsx +1 -1
  101. package/src/js/radio/dvrdRadio.tsx +1 -1
  102. package/src/js/radio/dvrdRadioController.tsx +1 -1
  103. package/src/js/radio/style/dvrdRadio.scss +1 -1
  104. package/src/js/select/async/asyncSelect.tsx +1 -1
  105. package/src/js/select/async/style/asyncSelect.scss +1 -1
  106. package/src/js/select/dvrdGroupedSelect.tsx +220 -0
  107. package/src/js/select/dvrdSelect.tsx +1 -1
  108. package/src/js/select/dvrdSelectController.tsx +1 -1
  109. package/src/js/select/select.tsx +1 -1
  110. package/src/js/select/selectController.tsx +1 -1
  111. package/src/js/select/style/dvrdGroupedSelect.scss +176 -0
  112. package/src/js/select/style/dvrdSelect.scss +1 -1
  113. package/src/js/select/style/select.scss +1 -1
  114. package/src/js/sidebarMenu/sidebarMenu.tsx +1 -1
  115. package/src/js/sidebarMenu/style/sidebarMenu.scss +1 -1
  116. package/src/js/slider/DVRSlider.tsx +1 -1
  117. package/src/js/slider/style/DVRSlider.scss +1 -1
  118. package/src/js/snackbar/snackbar.tsx +1 -1
  119. package/src/js/snackbar/snackbarController.tsx +1 -1
  120. package/src/js/snackbar/style/snackbar.scss +1 -1
  121. package/src/js/switch/dvrdSwitch.tsx +1 -1
  122. package/src/js/switch/style/dvrdSwitch.scss +1 -1
  123. package/src/js/switch/style/switch.scss +1 -1
  124. package/src/js/switch/switch.tsx +1 -1
  125. package/src/js/switch/switchController.tsx +1 -1
  126. package/src/js/textField/dvrdInput.tsx +1 -1
  127. package/src/js/textField/dvrdInputController.tsx +1 -1
  128. package/src/js/textField/dvrdNumberInput.tsx +1 -1
  129. package/src/js/textField/dvrdPasswordInput.tsx +1 -1
  130. package/src/js/textField/style/dvrdInput.scss +1 -1
  131. package/src/js/textField/style/dvrdPassword.scss +1 -1
  132. package/src/js/topButton/style/topButton.scss +1 -1
  133. package/src/js/topButton/topButton.tsx +1 -1
  134. package/src/js/util/analyticsUtil.ts +1 -1
  135. package/src/js/util/colorUtil.ts +1 -1
  136. package/src/js/util/componentUtil.tsx +1 -1
  137. package/src/js/util/constants.ts +1 -1
  138. package/src/js/util/controlContext.tsx +1 -1
  139. package/src/js/util/controlUtil.ts +1 -1
  140. package/src/js/util/cookieUtil.ts +1 -1
  141. package/src/js/util/eventUtil.ts +1 -1
  142. package/src/js/util/googleUtil.ts +1 -1
  143. package/src/js/util/interfaces.ts +13 -2
  144. package/src/js/util/jwtUtil.ts +1 -1
  145. package/src/js/util/miscUtil.ts +1 -1
  146. package/src/js/util/pdfUtil.ts +1 -1
  147. package/src/js/util/requestUtil.ts +3 -2
  148. package/src/js/util/responsiveUtil.ts +1 -1
  149. package/src/js/util/validationUtil.ts +1 -1
  150. package/src/style/common-icons-variables.scss +1 -1
  151. package/src/style/common-icons.scss +1 -1
  152. package/src/style/common-variables.scss +1 -1
  153. package/src/style/display-breakpoints.scss +1 -1
  154. package/src/style/fonts/common-icons.svg +4 -0
  155. package/src/style/fonts/fontAwesome/css/all.css +2 -4
  156. package/src/style/fonts/fontAwesome/css/brands.css +2 -4
  157. package/src/style/fonts/fontAwesome/css/fontawesome.css +2 -4
  158. package/src/style/fonts/fontAwesome/css/regular.css +2 -4
  159. package/src/style/fonts/fontAwesome/css/solid.css +2 -4
  160. package/src/style/fonts/fontAwesome/css/svg-with-js.css +2 -4
  161. package/src/style/fonts/fontAwesome/css/v4-font-face.css +2 -4
  162. package/src/style/fonts/fontAwesome/css/v4-shims.css +2 -4
  163. package/src/style/fonts/fontAwesome/css/v5-font-face.css +2 -4
  164. package/src/style/variables.scss +1 -1
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfElement.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import {PDFElementParams, PdfFont} from "../../util/interfaces";
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfImage.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfInvoiceTable.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfTemplateCreator.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/iconButton.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfImageSettings.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfInvoiceTableSettings.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfElementSettings.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfTextSettings.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/pdfText.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) Dave van Rijn Development 2022.
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import React, {
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) Dave van Rijn Development 2022.
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import {Position} from "react-rnd";
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import './style/withBackground.scss';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) Dave van Rijn Development 2023.
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/dvrdRadio.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) Dave van Rijn Development 2023.
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import React, {useCallback, useContext, useRef, useState} from 'react';
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) Dave van Rijn Development 2023.
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../style/variables';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/asyncSelect.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  @import '../../../../style/variables';
@@ -0,0 +1,220 @@
1
+ /*
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
+ */
4
+
5
+ import './style/dvrdGroupedSelect.scss';
6
+ import React, {ForwardedRef, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
7
+ import {ErrorType, GroupedSelectItem, SelectValueType} from "../util/interfaces";
8
+ import classNames from 'classnames';
9
+ import AwesomeIcon from "../icon/awesomeIcon";
10
+ import defer from 'lodash.defer';
11
+
12
+
13
+ interface Props {
14
+ onChange: (value: SelectValueType, evt: React.MouseEvent) => void;
15
+ items: Array<GroupedSelectItem>;
16
+ value: SelectValueType;
17
+ label?: string;
18
+ disabled?: boolean;
19
+ error?: ErrorType;
20
+ className?: string;
21
+ labelClassName?: string;
22
+ valueClassName?: string;
23
+ itemContainerClassName?: string;
24
+ itemClassName?: string;
25
+ errorClassName?: string;
26
+ itemsPosition?: 'top' | 'bottom';
27
+ maxItemsHeight?: number | string;
28
+ highlightSelected?: true;
29
+ placeholder?: string;
30
+ }
31
+
32
+ export type GroupedSelectRef = { open: VoidFunction; close: VoidFunction; }
33
+
34
+ function findInItems(items: Array<GroupedSelectItem>, value: string | number): GroupedSelectItem | null {
35
+ for (const item of items) {
36
+ if (item.value === value) return item;
37
+ if (item.children) {
38
+ const childItem = findInItems(item.children, value);
39
+ if (childItem) return childItem;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+
45
+ function DVRDGroupedSelect(props: Props, ref: ForwardedRef<GroupedSelectRef>) {
46
+ const {
47
+ className, label, labelClassName, value, placeholder, valueClassName, error, itemContainerClassName,
48
+ onChange, items, itemClassName, disabled, errorClassName, highlightSelected
49
+ } = props;
50
+ const [open, setOpen] = useState(false);
51
+ const maxItemsHeight: string | undefined = useMemo(() => {
52
+ const {maxItemsHeight} = props;
53
+ if (maxItemsHeight) {
54
+ if (typeof maxItemsHeight === 'string') return maxItemsHeight;
55
+ return maxItemsHeight + 'px';
56
+ }
57
+ return undefined;
58
+ }, [props.maxItemsHeight]);
59
+ const itemsPosition = useMemo(() => {
60
+ return props.itemsPosition ?? 'bottom';
61
+ }, [props.itemsPosition]);
62
+ const selectedLabel: string | number | React.ReactElement | null = useMemo(() => {
63
+ const selectedItem = findInItems(items, value);
64
+ if (!selectedItem) return null;
65
+ return selectedItem.valueLabel ?? selectedItem.label ?? '';
66
+ }, [value, items]);
67
+ const itemsContainer = useRef<HTMLDivElement>(null);
68
+
69
+ function onSelectItem(item: GroupedSelectItem) {
70
+ return function (evt: React.MouseEvent) {
71
+ evt.stopPropagation();
72
+ if (item.value !== undefined) {
73
+ if (item.value !== value)
74
+ onChange(item.value, evt);
75
+ onToggleOpen(false);
76
+ }
77
+ }
78
+ }
79
+
80
+ function onToggleOpen(forcedValue?: boolean) {
81
+ if (disabled) forcedValue = false;
82
+ setOpen(forcedValue ?? !open);
83
+ }
84
+
85
+ function onClickRoot(evt: React.MouseEvent) {
86
+ evt.stopPropagation();
87
+ onToggleOpen();
88
+ }
89
+
90
+ function onOpen() {
91
+ onToggleOpen(true);
92
+ }
93
+
94
+ function onClose() {
95
+ onToggleOpen(false);
96
+ }
97
+
98
+ function clickListener() {
99
+ setOpen(false);
100
+ }
101
+
102
+ function scrollSelectedInView() {
103
+ itemsContainer.current?.scrollTo({top: 0});
104
+ if (!highlightSelected || selectedLabel === null) return;
105
+ const selectedItem = findInItems(items, value);
106
+ if (!selectedItem || !selectedItem.value) return;
107
+ const itemID = `dvrd-grouped-item-${selectedItem.value}`;
108
+ const element = document.getElementById(itemID);
109
+ if (!element) return;
110
+ element.scrollIntoView({behavior: 'smooth'});
111
+ }
112
+
113
+ function renderLabel() {
114
+ if (!label) return null;
115
+ return <label className={classNames('grouped-select-label', labelClassName)}>{label}</label>;
116
+ }
117
+
118
+ function renderValue() {
119
+ const hasValue = selectedLabel !== null;
120
+ const canRender = hasValue && !['string', 'number'].includes(typeof selectedLabel)
121
+ const chevIcon = itemsPosition === 'bottom' ? 'chevron-down' : 'chevron-up';
122
+ const placeholderHidden = !placeholder?.length;
123
+ return (
124
+ <div className={classNames('grouped-select-value-container', valueClassName)}>
125
+ {hasValue ?
126
+ canRender ? renderCustomValue(selectedLabel as React.ReactElement) :
127
+ <label className='grouped-select-value'>{selectedLabel}</label> :
128
+ <label className={classNames('grouped-select-placeholder', placeholderHidden && 'hidden')}>
129
+ {placeholderHidden ? 'placeholder' : placeholder}</label>
130
+ }
131
+ <AwesomeIcon name={chevIcon} className='chev-icon'/>
132
+ </div>
133
+ );
134
+ }
135
+
136
+ function renderCustomValue(value: React.ReactElement) {
137
+ return React.cloneElement(value, {
138
+ ...value.props,
139
+ className: classNames(value.props?.className, 'grouped-select-value')
140
+ });
141
+ }
142
+
143
+ function renderItemsContainer() {
144
+ return (
145
+ <div className={classNames('grouped-select-items', itemContainerClassName)}
146
+ style={{maxHeight: maxItemsHeight}} ref={itemsContainer}>
147
+ {items.map(renderItem())}
148
+ </div>
149
+ )
150
+ }
151
+
152
+ function renderItem(layer: number = 0) {
153
+ return function (item: GroupedSelectItem, index: number) {
154
+ if (item.selectable !== undefined) return null;
155
+ const isGroupHead = !!item.children?.length;
156
+ const isElement = !['string', 'number'].includes(typeof item.label);
157
+ const padding = `${layer + .5}rem`;
158
+ const isSelectable = item.value !== undefined;
159
+ const isSelected = item.value === value;
160
+ return (
161
+ <div id={`dvrd-grouped-item-${item.value}`} key={index}
162
+ className={classNames('dvrd-grouped-item', itemClassName)}
163
+ onClick={onSelectItem(item)}>
164
+ {isElement ? renderCustomLabel(item.label as React.ReactElement, padding, isGroupHead, isSelectable) :
165
+ <label className={classNames('grouped-item-label', isGroupHead && 'group-head',
166
+ isSelectable && 'selectable', (isSelected && highlightSelected) && 'selected')}
167
+ style={{paddingLeft: padding}}>{item.label}</label>}
168
+ {!!item.children && (
169
+ <div className='dvrd-grouped-item-children'>
170
+ {item.children.map(renderItem(layer + 1))}
171
+ </div>
172
+ )}
173
+ </div>
174
+ )
175
+ }
176
+ }
177
+
178
+ function renderCustomLabel(label: React.ReactElement, padding: string, isGroupHead: boolean, isSelectable: boolean) {
179
+ const style = label.props?.style ?? {};
180
+ return React.cloneElement(label, {
181
+ ...label.props,
182
+ style: {...style, paddingLeft: padding},
183
+ className: classNames('grouped-item-label', isGroupHead && 'group-head', isSelectable && 'selectable',
184
+ label.props?.className)
185
+ });
186
+ }
187
+
188
+ function renderError() {
189
+ if (!error) return null;
190
+ return (
191
+ <label className={classNames('dvrd-grouped-select-error', errorClassName)}>{error}</label>
192
+ );
193
+ }
194
+
195
+ useEffect(() => {
196
+ if (open) {
197
+ document.body.addEventListener('click', clickListener);
198
+ defer(scrollSelectedInView);
199
+ } else document.body.removeEventListener('click', clickListener);
200
+ }, [open]);
201
+
202
+ useImperativeHandle(ref, () => ({
203
+ open: onOpen, close: onClose
204
+ }));
205
+
206
+ return (
207
+ <div className={classNames('dvrd-grouped-select', !!error && 'error', disabled && 'disabled', itemsPosition,
208
+ (open && !disabled) && 'open', className)}
209
+ onClick={onClickRoot}>
210
+ {renderLabel()}
211
+ <div className='dvrd-grouped-select-content'>
212
+ {renderValue()}
213
+ {renderItemsContainer()}
214
+ </div>
215
+ {renderError()}
216
+ </div>
217
+ )
218
+ }
219
+
220
+ export default forwardRef<GroupedSelectRef, Props>(DVRDGroupedSelect);
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
  import './style/dvrdSelect.scss';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import React, {useEffect, useMemo, useState} from 'react';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import './style/select.scss';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2021. Dave van Rijn Development
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
3
  */
4
4
 
5
5
  import React, {FocusEventHandler, KeyboardEventHandler, MouseEventHandler} from 'react';
@@ -0,0 +1,176 @@
1
+ /*!
2
+ * Copyright (c) 2024. Dave van Rijn Development
3
+ */
4
+
5
+ @import '../../../style/variables';
6
+
7
+ .dvrd-grouped-select {
8
+ display: grid;
9
+ grid-row-gap: .25rem;
10
+ position: relative;
11
+
12
+ .grouped-select-label {
13
+ color: $color-blue-text;
14
+ font-size: .9rem;
15
+ transition: color .2s ease-in-out;
16
+ cursor: pointer;
17
+ user-select: none;
18
+ margin-left: 1px;
19
+ }
20
+
21
+ .dvrd-grouped-select-content {
22
+ position: relative;
23
+
24
+ .grouped-select-value-container {
25
+ border: 1px solid #D9D9D9;
26
+ border-radius: 4px;
27
+ transition: border-color .2s ease-in-out, border-radius .2s ease-in-out;
28
+ display: grid;
29
+ grid-template-columns: 1fr fit-content(100%);
30
+ grid-column-gap: .5rem;
31
+ align-items: center;
32
+ padding: .75rem;
33
+ cursor: pointer;
34
+ background-color: white;
35
+
36
+ .grouped-select-placeholder, .grouped-select-value {
37
+ font-family: avenir-light, sans-serif;
38
+ user-select: none;
39
+ vertical-align: middle;
40
+ }
41
+
42
+ .grouped-select-placeholder {
43
+ color: $color-gray-2;
44
+
45
+ &.hidden {
46
+ visibility: hidden;
47
+ }
48
+ }
49
+
50
+ .grouped-select-value {
51
+ color: $color-blue-text;
52
+ }
53
+
54
+ .chev-icon {
55
+ font-size: .9rem;
56
+ transition: transform .2s ease-in-out;
57
+ color: $color-gray-3;
58
+ }
59
+ }
60
+
61
+ .grouped-select-items {
62
+ @include backgroundShadow3($borderRadius: 0);
63
+ background-color: white;
64
+ position: absolute;
65
+ left: 1px;
66
+ width: calc(100% - 2px);
67
+ transition: visibility .2s ease-in-out, opacity .2s ease-in-out;
68
+ visibility: hidden;
69
+ opacity: 0;
70
+ z-index: 1;
71
+ overflow-y: auto;
72
+
73
+ .dvrd-grouped-item {
74
+ .grouped-item-label {
75
+ padding: .5rem;
76
+ display: block;
77
+ transition: background-color .2s ease-in-out;
78
+ cursor: default;
79
+ user-select: none;
80
+ color: $color-blue-text;
81
+
82
+ &.selectable {
83
+ cursor: pointer;
84
+
85
+ &:not(&.selected):hover {
86
+ background-color: rgba($color-blue-1, .2);
87
+ }
88
+ }
89
+
90
+ &.selected {
91
+ background-color: rgba($color-blue-1, .3);
92
+ }
93
+
94
+ &.group-head {
95
+ font-weight: 500;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ .dvrd-grouped-select-error {
103
+ color: red;
104
+ font-size: .9rem;
105
+ margin-left: 1px;
106
+ }
107
+
108
+ &.bottom {
109
+ .grouped-select-items {
110
+ bottom: 0;
111
+ transform: translateY(100%);
112
+ border-bottom-left-radius: 4px;
113
+ border-bottom-right-radius: 4px;
114
+ }
115
+ }
116
+
117
+ &.top {
118
+ .grouped-select-items {
119
+ top: 0;
120
+ transform: translateY(calc(-100%));
121
+ border-top-left-radius: 4px;
122
+ border-top-right-radius: 4px;
123
+ }
124
+ }
125
+
126
+ &.open, &:hover:not(&.disabled):not(&.error) {
127
+ .grouped-select-value-container {
128
+ border-color: $color-blue-1;
129
+ }
130
+ }
131
+
132
+ &.open {
133
+ .grouped-select-label {
134
+ color: $color-blue-1;
135
+ }
136
+
137
+ .grouped-select-value-container .chev-icon {
138
+ transform: rotateX(180deg);
139
+ }
140
+
141
+ .grouped-select-items {
142
+ visibility: visible;
143
+ opacity: 1;
144
+ }
145
+
146
+ &.bottom {
147
+ .grouped-select-value-container {
148
+ border-bottom-left-radius: 0;
149
+ border-bottom-right-radius: 0;
150
+ }
151
+ }
152
+
153
+ &.top {
154
+ .grouped-select-value-container {
155
+ border-top-left-radius: 0;
156
+ border-top-right-radius: 0;
157
+ }
158
+ }
159
+ }
160
+
161
+ &.error {
162
+ .grouped-select-label {
163
+ color: red;
164
+ }
165
+
166
+ .grouped-select-value-container {
167
+ border-color: red;
168
+ }
169
+ }
170
+
171
+ &.disabled {
172
+ &, * {
173
+ cursor: default;
174
+ }
175
+ }
176
+ }