funda-ui 1.0.272

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 (246) hide show
  1. package/BackToTop/index.css +34 -0
  2. package/BackToTop/index.d.ts +11 -0
  3. package/BackToTop/index.js +458 -0
  4. package/CascadingSelect/index.css +159 -0
  5. package/CascadingSelect/index.d.ts +56 -0
  6. package/CascadingSelect/index.js +958 -0
  7. package/CascadingSelectE2E/index.css +159 -0
  8. package/CascadingSelectE2E/index.d.ts +60 -0
  9. package/CascadingSelectE2E/index.js +1126 -0
  10. package/Checkbox/index.d.ts +30 -0
  11. package/Checkbox/index.js +226 -0
  12. package/ColorPicker/index.css +38 -0
  13. package/ColorPicker/index.d.ts +27 -0
  14. package/ColorPicker/index.js +246 -0
  15. package/DigitalClock/index.d.ts +7 -0
  16. package/DigitalClock/index.js +208 -0
  17. package/DropdownMenu/index.css +127 -0
  18. package/DropdownMenu/index.d.ts +37 -0
  19. package/DropdownMenu/index.js +237 -0
  20. package/DynamicFields/index.d.ts +26 -0
  21. package/DynamicFields/index.js +412 -0
  22. package/File/index.d.ts +36 -0
  23. package/File/index.js +473 -0
  24. package/Input/index.d.ts +42 -0
  25. package/Input/index.js +286 -0
  26. package/LiveSearch/index.d.ts +37 -0
  27. package/LiveSearch/index.js +1195 -0
  28. package/ModalDialog/index.d.ts +60 -0
  29. package/ModalDialog/index.js +725 -0
  30. package/ModeSwitch/index.d.ts +17 -0
  31. package/ModeSwitch/index.js +202 -0
  32. package/MultiFuncSelect/index.css +178 -0
  33. package/MultiFuncSelect/index.d.ts +67 -0
  34. package/MultiFuncSelect/index.js +1826 -0
  35. package/MultilevelDropdownMenu/index.css +35 -0
  36. package/MultilevelDropdownMenu/index.d.ts +25 -0
  37. package/MultilevelDropdownMenu/index.js +464 -0
  38. package/Pagination/index.d.ts +49 -0
  39. package/Pagination/index.js +341 -0
  40. package/README.md +108 -0
  41. package/Radio/index.d.ts +31 -0
  42. package/Radio/index.js +246 -0
  43. package/RangeSlider/index.css +149 -0
  44. package/RangeSlider/index.d.ts +21 -0
  45. package/RangeSlider/index.js +730 -0
  46. package/ScrollReveal/index.css +23 -0
  47. package/ScrollReveal/index.d.ts +21 -0
  48. package/ScrollReveal/index.js +216 -0
  49. package/Scrollbar/index.css +168 -0
  50. package/Scrollbar/index.d.ts +15 -0
  51. package/Scrollbar/index.js +605 -0
  52. package/SearchBar/index.d.ts +32 -0
  53. package/SearchBar/index.js +246 -0
  54. package/Select/index.d.ts +34 -0
  55. package/Select/index.js +331 -0
  56. package/ShowMoreLess/index.css +23 -0
  57. package/ShowMoreLess/index.d.ts +30 -0
  58. package/ShowMoreLess/index.js +202 -0
  59. package/Switch/index.d.ts +29 -0
  60. package/Switch/index.js +211 -0
  61. package/Table/index.css +533 -0
  62. package/Table/index.d.ts +25 -0
  63. package/Table/index.js +2113 -0
  64. package/Tabs/index.d.ts +3 -0
  65. package/Tabs/index.js +323 -0
  66. package/TagInput/index.css +90 -0
  67. package/TagInput/index.d.ts +28 -0
  68. package/TagInput/index.js +370 -0
  69. package/Textarea/index.d.ts +30 -0
  70. package/Textarea/index.js +242 -0
  71. package/Toast/index.css +95 -0
  72. package/Toast/index.d.ts +35 -0
  73. package/Toast/index.js +340 -0
  74. package/Tooltip/index.css +240 -0
  75. package/Tooltip/index.d.ts +19 -0
  76. package/Tooltip/index.js +200 -0
  77. package/Tree/index.css +225 -0
  78. package/Tree/index.d.ts +37 -0
  79. package/Tree/index.js +1406 -0
  80. package/all.d.ts +33 -0
  81. package/all.js +35 -0
  82. package/lib/cjs/BackToTop/index.d.ts +11 -0
  83. package/lib/cjs/BackToTop/index.js +458 -0
  84. package/lib/cjs/CascadingSelect/index.d.ts +56 -0
  85. package/lib/cjs/CascadingSelect/index.js +958 -0
  86. package/lib/cjs/CascadingSelectE2E/index.d.ts +60 -0
  87. package/lib/cjs/CascadingSelectE2E/index.js +1126 -0
  88. package/lib/cjs/Checkbox/index.d.ts +30 -0
  89. package/lib/cjs/Checkbox/index.js +226 -0
  90. package/lib/cjs/ColorPicker/index.d.ts +27 -0
  91. package/lib/cjs/ColorPicker/index.js +246 -0
  92. package/lib/cjs/DigitalClock/index.d.ts +7 -0
  93. package/lib/cjs/DigitalClock/index.js +208 -0
  94. package/lib/cjs/DropdownMenu/index.d.ts +37 -0
  95. package/lib/cjs/DropdownMenu/index.js +237 -0
  96. package/lib/cjs/DynamicFields/index.d.ts +26 -0
  97. package/lib/cjs/DynamicFields/index.js +412 -0
  98. package/lib/cjs/File/index.d.ts +36 -0
  99. package/lib/cjs/File/index.js +473 -0
  100. package/lib/cjs/Input/index.d.ts +42 -0
  101. package/lib/cjs/Input/index.js +286 -0
  102. package/lib/cjs/LiveSearch/index.d.ts +37 -0
  103. package/lib/cjs/LiveSearch/index.js +1195 -0
  104. package/lib/cjs/ModalDialog/index.d.ts +60 -0
  105. package/lib/cjs/ModalDialog/index.js +725 -0
  106. package/lib/cjs/ModeSwitch/index.d.ts +17 -0
  107. package/lib/cjs/ModeSwitch/index.js +202 -0
  108. package/lib/cjs/MultiFuncSelect/index.d.ts +67 -0
  109. package/lib/cjs/MultiFuncSelect/index.js +1826 -0
  110. package/lib/cjs/MultilevelDropdownMenu/index.d.ts +25 -0
  111. package/lib/cjs/MultilevelDropdownMenu/index.js +464 -0
  112. package/lib/cjs/Pagination/index.d.ts +49 -0
  113. package/lib/cjs/Pagination/index.js +341 -0
  114. package/lib/cjs/Radio/index.d.ts +31 -0
  115. package/lib/cjs/Radio/index.js +246 -0
  116. package/lib/cjs/RangeSlider/index.d.ts +21 -0
  117. package/lib/cjs/RangeSlider/index.js +730 -0
  118. package/lib/cjs/ScrollReveal/index.d.ts +21 -0
  119. package/lib/cjs/ScrollReveal/index.js +216 -0
  120. package/lib/cjs/Scrollbar/index.d.ts +15 -0
  121. package/lib/cjs/Scrollbar/index.js +605 -0
  122. package/lib/cjs/SearchBar/index.d.ts +32 -0
  123. package/lib/cjs/SearchBar/index.js +246 -0
  124. package/lib/cjs/Select/index.d.ts +34 -0
  125. package/lib/cjs/Select/index.js +331 -0
  126. package/lib/cjs/ShowMoreLess/index.d.ts +30 -0
  127. package/lib/cjs/ShowMoreLess/index.js +202 -0
  128. package/lib/cjs/Switch/index.d.ts +29 -0
  129. package/lib/cjs/Switch/index.js +211 -0
  130. package/lib/cjs/Table/index.d.ts +25 -0
  131. package/lib/cjs/Table/index.js +2113 -0
  132. package/lib/cjs/Tabs/index.d.ts +3 -0
  133. package/lib/cjs/Tabs/index.js +323 -0
  134. package/lib/cjs/TagInput/index.d.ts +28 -0
  135. package/lib/cjs/TagInput/index.js +370 -0
  136. package/lib/cjs/Textarea/index.d.ts +30 -0
  137. package/lib/cjs/Textarea/index.js +242 -0
  138. package/lib/cjs/Toast/index.d.ts +35 -0
  139. package/lib/cjs/Toast/index.js +340 -0
  140. package/lib/cjs/Tooltip/index.d.ts +19 -0
  141. package/lib/cjs/Tooltip/index.js +200 -0
  142. package/lib/cjs/Tree/index.d.ts +37 -0
  143. package/lib/cjs/Tree/index.js +1406 -0
  144. package/lib/cjs/index.d.ts +33 -0
  145. package/lib/cjs/index.js +35 -0
  146. package/lib/css/BackToTop/index.css +34 -0
  147. package/lib/css/CascadingSelect/index.css +159 -0
  148. package/lib/css/CascadingSelectE2E/index.css +159 -0
  149. package/lib/css/ColorPicker/index.css +38 -0
  150. package/lib/css/DropdownMenu/index.css +127 -0
  151. package/lib/css/MultiFuncSelect/index.css +178 -0
  152. package/lib/css/MultilevelDropdownMenu/index.css +35 -0
  153. package/lib/css/RangeSlider/index.css +149 -0
  154. package/lib/css/ScrollReveal/index.css +23 -0
  155. package/lib/css/Scrollbar/index.css +168 -0
  156. package/lib/css/ShowMoreLess/index.css +23 -0
  157. package/lib/css/Table/index.css +533 -0
  158. package/lib/css/TagInput/index.css +90 -0
  159. package/lib/css/Toast/index.css +95 -0
  160. package/lib/css/Tooltip/index.css +240 -0
  161. package/lib/css/Tree/index.css +225 -0
  162. package/lib/esm/BackToTop/index.scss +47 -0
  163. package/lib/esm/BackToTop/index.tsx +182 -0
  164. package/lib/esm/BackToTop/utils/easing.js +200 -0
  165. package/lib/esm/BackToTop/utils/performance.js +52 -0
  166. package/lib/esm/CascadingSelect/Group.tsx +39 -0
  167. package/lib/esm/CascadingSelect/index.scss +214 -0
  168. package/lib/esm/CascadingSelect/index.tsx +922 -0
  169. package/lib/esm/CascadingSelect/utils/performance.js +52 -0
  170. package/lib/esm/CascadingSelectE2E/Group.tsx +39 -0
  171. package/lib/esm/CascadingSelectE2E/index.scss +214 -0
  172. package/lib/esm/CascadingSelectE2E/index.tsx +1091 -0
  173. package/lib/esm/CascadingSelectE2E/utils/performance.js +52 -0
  174. package/lib/esm/Checkbox/index.tsx +160 -0
  175. package/lib/esm/ColorPicker/index.scss +48 -0
  176. package/lib/esm/ColorPicker/index.tsx +187 -0
  177. package/lib/esm/DigitalClock/index.tsx +72 -0
  178. package/lib/esm/DigitalClock/utils/useInterval.js +43 -0
  179. package/lib/esm/DropdownMenu/Option.tsx +27 -0
  180. package/lib/esm/DropdownMenu/index.scss +180 -0
  181. package/lib/esm/DropdownMenu/index.tsx +148 -0
  182. package/lib/esm/DynamicFields/index.tsx +386 -0
  183. package/lib/esm/File/index.tsx +302 -0
  184. package/lib/esm/Input/index.tsx +233 -0
  185. package/lib/esm/LiveSearch/index.tsx +582 -0
  186. package/lib/esm/LiveSearch/utils/performance.js +52 -0
  187. package/lib/esm/LiveSearch/utils/useThrottle.js +36 -0
  188. package/lib/esm/ModalDialog/index.tsx +479 -0
  189. package/lib/esm/ModalDialog/plugins/BSL/bodyScrollLock.es6.js +262 -0
  190. package/lib/esm/ModalDialog/plugins/BSL/index.ts +2 -0
  191. package/lib/esm/ModeSwitch/index.tsx +82 -0
  192. package/lib/esm/MultiFuncSelect/index.scss +269 -0
  193. package/lib/esm/MultiFuncSelect/index.tsx +1597 -0
  194. package/lib/esm/MultiFuncSelect/utils/performance.js +52 -0
  195. package/lib/esm/MultiFuncSelect/utils/tree.js +103 -0
  196. package/lib/esm/MultiFuncSelect/utils/useThrottle.js +36 -0
  197. package/lib/esm/MultilevelDropdownMenu/MenuList.tsx +230 -0
  198. package/lib/esm/MultilevelDropdownMenu/index.scss +75 -0
  199. package/lib/esm/MultilevelDropdownMenu/index.tsx +71 -0
  200. package/lib/esm/MultilevelDropdownMenu/utils/dom.js +81 -0
  201. package/lib/esm/Pagination/index.tsx +230 -0
  202. package/lib/esm/Pagination/pagination-navigators.tsx +60 -0
  203. package/lib/esm/Radio/index.tsx +201 -0
  204. package/lib/esm/RangeSlider/index.scss +184 -0
  205. package/lib/esm/RangeSlider/index.tsx +223 -0
  206. package/lib/esm/ScrollReveal/index.scss +27 -0
  207. package/lib/esm/ScrollReveal/index.tsx +146 -0
  208. package/lib/esm/Scrollbar/index.scss +217 -0
  209. package/lib/esm/Scrollbar/index.tsx +497 -0
  210. package/lib/esm/Scrollbar/utils/performance.js +52 -0
  211. package/lib/esm/SearchBar/index.tsx +181 -0
  212. package/lib/esm/Select/index.tsx +276 -0
  213. package/lib/esm/ShowMoreLess/index.scss +27 -0
  214. package/lib/esm/ShowMoreLess/index.tsx +144 -0
  215. package/lib/esm/Switch/index.tsx +143 -0
  216. package/lib/esm/Table/TableColgroup.tsx +29 -0
  217. package/lib/esm/Table/TableField.tsx +40 -0
  218. package/lib/esm/Table/TableFieldRow.tsx +212 -0
  219. package/lib/esm/Table/TableHeaders.tsx +146 -0
  220. package/lib/esm/Table/TableRow.tsx +127 -0
  221. package/lib/esm/Table/TableSummaries.tsx +36 -0
  222. package/lib/esm/Table/index.scss +364 -0
  223. package/lib/esm/Table/index.tsx +576 -0
  224. package/lib/esm/Table/table-utils.ts +65 -0
  225. package/lib/esm/Table/utils/dom.js +81 -0
  226. package/lib/esm/Table/utils/performance.js +52 -0
  227. package/lib/esm/Tabs/TabList.tsx +42 -0
  228. package/lib/esm/Tabs/TabPanel.tsx +34 -0
  229. package/lib/esm/Tabs/Tabs.tsx +232 -0
  230. package/lib/esm/Tabs/index.tsx +3 -0
  231. package/lib/esm/TagInput/index.scss +125 -0
  232. package/lib/esm/TagInput/index.tsx +314 -0
  233. package/lib/esm/Textarea/index.tsx +178 -0
  234. package/lib/esm/Toast/Item.tsx +75 -0
  235. package/lib/esm/Toast/index.scss +120 -0
  236. package/lib/esm/Toast/index.tsx +249 -0
  237. package/lib/esm/Tooltip/index.scss +327 -0
  238. package/lib/esm/Tooltip/index.tsx +142 -0
  239. package/lib/esm/Tree/TreeList.tsx +503 -0
  240. package/lib/esm/Tree/index.scss +375 -0
  241. package/lib/esm/Tree/index.tsx +301 -0
  242. package/lib/esm/Tree/init-height.tsx +27 -0
  243. package/lib/esm/Tree/utils/convert-tree.js +29 -0
  244. package/lib/esm/Tree/utils/dom.js +81 -0
  245. package/lib/esm/index.js +31 -0
  246. package/package.json +40 -0
@@ -0,0 +1,180 @@
1
+ /* ======================================================
2
+ <!-- Dropdown Menu -->
3
+ /* ====================================================== */
4
+
5
+ /* Do not use <a> tag */
6
+ .dropdown-default {
7
+
8
+
9
+ --dropdown-ul-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
10
+ --dropdown-ul-bg: #fff;
11
+
12
+ --dropdown-ulbefore-box-shadow: 2px -2px 6px rgba(0, 0, 0, 0.05);
13
+ --dropdown-ulbefore-border-color: #fff;
14
+
15
+ --dropdown-li-bg: #fff;
16
+ --dropdown-li-hover-bg: #FAFAFA;
17
+
18
+ --dropdown-link-border-color: rgba(0, 0, 0, 0.05);
19
+ --dropdown-link-color: #333;
20
+
21
+
22
+
23
+ display: inline-block;
24
+ cursor: pointer;
25
+ position: relative;
26
+
27
+ ul, li {
28
+ margin: 0;
29
+ padding: 0;
30
+ list-style: none;
31
+ }
32
+
33
+ strong {
34
+ font-weight: normal;
35
+ display: inline-block;
36
+ margin-left: .3rem;
37
+ }
38
+
39
+ > ul {
40
+ display: none;
41
+ position: absolute;
42
+ top: 100%;
43
+ left: 0;
44
+ margin-top: 8px;
45
+ min-width: 50px;
46
+ white-space: nowrap;
47
+ border-radius: 4px;
48
+ text-align: left;
49
+ box-shadow: var(--dropdown-ul-box-shadow);
50
+ background: var(--dropdown-ul-bg);
51
+ transition: .1s ease-in-out;
52
+
53
+
54
+ &::before {
55
+ content: '';
56
+ position: absolute;
57
+ top: -3px;
58
+ left: 10px;
59
+ width: 0;
60
+ height: 0;
61
+ box-shadow: var(--dropdown-ulbefore-box-shadow);
62
+ border-top: 4px solid var(--dropdown-ulbefore-border-color);
63
+ border-right: 4px solid var(--dropdown-ulbefore-border-color);
64
+ border-bottom: 4px solid transparent;
65
+ border-left: 4px solid transparent;
66
+ transform: rotate(-45deg);
67
+ }
68
+
69
+ /* Prevent the hover threshold from failing */
70
+ &::after {
71
+ content: '';
72
+ display: block;
73
+ background-color: transparent;
74
+ position: absolute;
75
+ top: -10px;
76
+ left: 0;
77
+ width: 100%;
78
+ height: 20px;
79
+ }
80
+
81
+ li {
82
+ z-index: 1;
83
+ position: relative;
84
+ background: var(--dropdown-li-bg);
85
+ padding: 0 .75rem;
86
+
87
+
88
+ &:hover {
89
+ background: var(--dropdown-li-hover-bg);
90
+ }
91
+
92
+ a {
93
+ display: block;
94
+ border-bottom: 1px solid var(--dropdown-link-border-color);
95
+ padding: .75rem 0;
96
+ color: var(--dropdown-link-color);
97
+ font-size: 0.75rem;
98
+ text-decoration: none;
99
+
100
+ svg,
101
+ i {
102
+ display: none;
103
+ }
104
+
105
+
106
+ }
107
+
108
+
109
+ &:first-child {
110
+ border-radius: 4px 4px 0 0;
111
+ }
112
+ &:last-child {
113
+ border-radius: 0 0 4px 4px;
114
+
115
+ a {
116
+ border-bottom: 0;
117
+ }
118
+ }
119
+ }
120
+
121
+ }
122
+
123
+ &.dropdown-default--start {
124
+ // default
125
+ }
126
+
127
+ &.dropdown-default--center {
128
+ > ul {
129
+ left: 50%;
130
+ transform: translateX(-50%);
131
+
132
+ &::before {
133
+ left: 50%;
134
+ transform: translateX(-50%) rotate(-45deg);
135
+ }
136
+
137
+ }
138
+ }
139
+
140
+ &.dropdown-default--end {
141
+ > ul {
142
+ left: auto;
143
+ right: 0;
144
+
145
+ &::before {
146
+ left: auto;
147
+ right: 10px;
148
+ }
149
+
150
+ }
151
+
152
+ }
153
+
154
+ &.active {
155
+ > ul {
156
+ animation: dropdown-display 0.4s cubic-bezier(0.73, 0.005, 0.22, 1);
157
+ display: block !important;
158
+ }
159
+ }
160
+
161
+
162
+ }
163
+
164
+
165
+
166
+
167
+ @keyframes dropdown-display {
168
+ 0%{
169
+ opacity: 0;
170
+ transform: scale(0.98) translateY(-0.6em);
171
+ }
172
+
173
+ 100% {
174
+ opacity: 1;
175
+ transform: scale(1) translateY(0);
176
+ }
177
+ }
178
+
179
+
180
+
@@ -0,0 +1,148 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ import Option from './Option';
4
+
5
+ type OptionChangeFnType = (arg1: any) => void;
6
+
7
+ interface OptionConfig {
8
+ value?: string | undefined;
9
+ label?: string | undefined;
10
+ }
11
+
12
+ type DropdownMenuProps = {
13
+ wrapperClassName?: string;
14
+ listClassName?: string;
15
+ hyperlinkClassName?: string;
16
+ showClassName?: string;
17
+ hoverOn?: boolean;
18
+ hoverOff?: boolean;
19
+ hoverDelay?: number;
20
+ /** Set a name for the form field for this component */
21
+ name?: string;
22
+ /** Whether to use button style, otherwise use "div" */
23
+ triggerButton?: boolean;
24
+ /** Specify a class for this Node. */
25
+ triggerClassName?: string;
26
+ /** Set a piece of text or HTML code for the trigger */
27
+ triggerContent?: string;
28
+ /** When enabled, the corresponding option content will be displayed after selecting an option */
29
+ triggerSwitchActive?: boolean;
30
+ /** Center align the options layer in a drop-down field. By default it is left aligned "start". */
31
+ alignOptionsLayer?: string;
32
+ /** Specify data of Dropdown Menu as a JSON string format. */
33
+ options?: OptionConfig[];
34
+ /** This function is called whenever the data is updated.
35
+ * Exposes the JSON format data about the option as an argument.
36
+ */
37
+ /** -- */
38
+ tabIndex?: number;
39
+ onChange?: OptionChangeFnType | null;
40
+ };
41
+
42
+ const DropdownMenu = (props: DropdownMenuProps) => {
43
+
44
+ const {
45
+ wrapperClassName,
46
+ listClassName,
47
+ hyperlinkClassName,
48
+ showClassName,
49
+ hoverOn,
50
+ hoverOff,
51
+ hoverDelay,
52
+ name,
53
+ triggerButton,
54
+ triggerClassName,
55
+ triggerContent,
56
+ triggerSwitchActive,
57
+ alignOptionsLayer,
58
+ options,
59
+ tabIndex,
60
+ onChange
61
+ } = props;
62
+
63
+ const [isOpen, setIsOpen] = useState<boolean>(false);
64
+ const [selected, setSelected] = useState<any>(null);
65
+ const _hoverDelay = !isNaN(hoverDelay as never) && typeof hoverDelay !== 'undefined' ? hoverDelay : 150;
66
+
67
+
68
+ const defaultLabel = triggerContent === undefined ? '' : triggerContent;
69
+ const selectedLabel = triggerSwitchActive ? (selected ? selected.label : defaultLabel) : defaultLabel;
70
+ const selectOptionsListPresentation = options?.map((selectOption, index) => {
71
+ return <Option key={index} option={selectOption} onSelect={handleSelect} hyperlinkClassName={hyperlinkClassName ? hyperlinkClassName : 'dropdown-item-default'} />;
72
+ });
73
+
74
+
75
+ function handleClick(event: any) {
76
+ if (hoverOn) return;
77
+ setIsOpen(!isOpen);
78
+ }
79
+
80
+
81
+ function handleHoverOn(event: any) {
82
+ if (!hoverOn || typeof hoverOn === 'undefined') return;
83
+ setTimeout(() => {
84
+ setIsOpen(true);
85
+ }, _hoverDelay);
86
+
87
+ }
88
+
89
+ function handleHoverOff(event: any) {
90
+ if (!hoverOff || typeof hoverOff === 'undefined') return;
91
+ setTimeout(() => {
92
+ setIsOpen(false);
93
+ }, _hoverDelay);
94
+
95
+ }
96
+
97
+
98
+
99
+ function handleClose(event: any) {
100
+ if (event.target.closest(`.${wrapperClassName || wrapperClassName === '' ? wrapperClassName : 'dropdown__wrapper'}`) === null) {
101
+ setIsOpen(false);
102
+ }
103
+ }
104
+
105
+
106
+ function handleSelect(option) {
107
+ setIsOpen(false);
108
+ setSelected(option);
109
+
110
+ if (typeof (onChange) === 'function') {
111
+ onChange(option);
112
+ }
113
+
114
+ }
115
+
116
+ useEffect(() => {
117
+
118
+ document.removeEventListener('pointerdown', handleClose);
119
+ document.addEventListener('pointerdown', handleClose);
120
+
121
+ return () => {
122
+ document.removeEventListener('pointerdown', handleClose);
123
+ }
124
+
125
+ }, [options]);
126
+
127
+
128
+ return (
129
+ <>
130
+
131
+ <div className={`dropdown__wrapper ${wrapperClassName || wrapperClassName === '' ? wrapperClassName : `dropdown-default dropdown-default--${alignOptionsLayer ? alignOptionsLayer : 'center'}`} ${isOpen ? 'active' : ''}`} onMouseLeave={handleHoverOff} >
132
+
133
+ {triggerButton ? <button tabIndex={tabIndex || -1} className={triggerClassName ? `${triggerClassName}` : `d-inline w-auto`} type="button" onMouseEnter={handleHoverOn} onClick={handleClick} dangerouslySetInnerHTML={{ __html: selectedLabel }}></button> : <div className={triggerClassName ? `${triggerClassName}` : `d-inline w-auto`} onMouseEnter={handleHoverOn} onClick={handleClick} dangerouslySetInnerHTML={{ __html: selectedLabel }}></div>}
134
+
135
+ <input name={name || ''} type="hidden" value={selected?.value} />
136
+ <ul className={isOpen ? `${listClassName ? listClassName : 'dropdown-menu-default'} ${showClassName ? showClassName : 'show'}` : `${listClassName ? listClassName : 'dropdown-menu-default'}`}>
137
+ {selectOptionsListPresentation}
138
+ </ul>
139
+ </div>
140
+
141
+ </>
142
+ )
143
+ }
144
+
145
+
146
+
147
+
148
+ export default DropdownMenu;
@@ -0,0 +1,386 @@
1
+ import React, { useId, useState, useEffect, useRef } from 'react';
2
+
3
+ declare module 'react' {
4
+ interface ReactI18NextChildren<T> {
5
+ children?: any;
6
+ }
7
+ }
8
+
9
+ type DynamicFieldsProps = {
10
+ wrapperClassName?: string;
11
+ value?: string;
12
+ label?: React.ReactNode | string;
13
+ tempHtmlString?: any;
14
+ maxFields?: any;
15
+ confirmText?: string;
16
+ iconAddBefore?: React.ReactNode | string;
17
+ iconAddAfter?: React.ReactNode | string;
18
+ iconAdd?: React.ReactNode | string;
19
+ iconRemove?: React.ReactNode | string;
20
+ startFromZero?: boolean;
21
+ /** -- */
22
+ id?: string;
23
+ onAdd?: () => void;
24
+ onRemove?: () => void;
25
+ onComplete?: () => void;
26
+
27
+ };
28
+
29
+ const DynamicFields = (props: DynamicFieldsProps) => {
30
+ const {
31
+ wrapperClassName,
32
+ value,
33
+ label,
34
+ tempHtmlString,
35
+ maxFields,
36
+ iconAddBefore,
37
+ iconAddAfter,
38
+ iconAdd,
39
+ iconRemove,
40
+ startFromZero,
41
+ id,
42
+ confirmText,
43
+ onAdd,
44
+ onRemove,
45
+ onComplete
46
+ } = props;
47
+
48
+ const uniqueID = useId().replace(/\:/g, "-");
49
+ const idRes = id || uniqueID;
50
+ const rootRef = useRef<any>(null);
51
+ const fieldsRef = useRef<any>(null);
52
+ const addBtnRef = useRef<any>(null);
53
+ const [data, setData] = useState<any[]>([]);
54
+ const controlRefreshValDelay = 1000;
55
+
56
+ //timer
57
+ const timeoutIdRef = useRef<any>(null);
58
+ const startTimer = () => {
59
+
60
+ return new Promise(function (resolve, reject) {
61
+
62
+ //
63
+ timeoutIdRef.current = setTimeout(() => {
64
+
65
+ if ( fieldsRef.current !== null ) {
66
+ const _val: any[] = value ? JSON.parse( '[' + value + ']' ) : [];
67
+ const controls: HTMLFormElement[] = [].slice.call(document.querySelectorAll( `#${fieldsRef.current.id} > .dynamic-fields__append [name]` ));
68
+ const integratedControls: HTMLFormElement[] = [];
69
+
70
+ let hasRadio: boolean = false;
71
+ controls.forEach((node: any, i: number) => {
72
+
73
+
74
+ let controlType = '';
75
+ if (node.tagName == "INPUT" || node.tagName == "TEXTARTA") {
76
+
77
+ //not `radio`, `checkbox`
78
+ if (node.type != 'checkbox' && node.type != 'radio') {
79
+ controlType = 'input-textarea';
80
+ }
81
+
82
+ //`checkbox`
83
+ if (node.type == 'checkbox') {
84
+ controlType = 'checkbox';
85
+ }
86
+
87
+ //`radio`
88
+ if (node.type == 'radio') {
89
+ controlType = 'radio';
90
+ }
91
+
92
+ }
93
+
94
+ //`select`
95
+ if (node.tagName == "SELECT") {
96
+ controlType = 'select';
97
+ }
98
+
99
+ //
100
+ if ( controlType === 'radio' ) {
101
+ hasRadio = true;
102
+ }
103
+
104
+ integratedControls.push({
105
+ target: node,
106
+ type: controlType
107
+ } as never);
108
+
109
+ // replace placeholder string
110
+ replacePlaceholderStr(node);
111
+ });
112
+
113
+
114
+
115
+ if ( hasRadio ) {
116
+ console.error('<DynamicFields /> cannot use the "radio" type, because it will have multiple duplicate names! \nThe following components are recommended: <Input />, <Textarea />, <Checkbox />, <Switch />, <MultiFuncSelect />, <Select />, <CascadingSelectE2E />, <CascadingSelect />, <TagInput />, <RangeSlider />.');
117
+ return false;
118
+ }
119
+
120
+ const resControls: any = groupByNum(integratedControls, Math.floor(integratedControls.length / _val.length));
121
+
122
+ _val.forEach((row: string[], i: number) => {
123
+ row.forEach((val: any, j: number) => {
124
+
125
+ if ( typeof resControls[i] !== 'undefined' && typeof resControls[i][j] !== 'undefined' ) {
126
+ const _control: any = resControls[i][j];
127
+
128
+ // set default value
129
+ // It is generally used for `<CascadingSelect />` and cascading `<Select />`
130
+ _control.target.dataset.value = val;
131
+
132
+ switch (_control.type) {
133
+ case "input-textarea":
134
+
135
+ // normal
136
+ _control.target.value = val;
137
+
138
+ // if it is checkbox
139
+ if ( val === true ) {
140
+ const _checkbox = _control.target.parentElement.querySelector('[data-checkbox]');
141
+ _checkbox.checked = val == true ? true : false;
142
+ _control.target.value = _checkbox.value;
143
+ }
144
+
145
+
146
+ break;
147
+ case "checkbox":
148
+ _control.target.checked = val == true ? true : false;
149
+ break;
150
+ case "select":
151
+ _control.target.value = val;
152
+ _control.target.dispatchEvent(new Event('change'));
153
+
154
+ break;
155
+ default:
156
+ _control.target.value = val;
157
+
158
+ }//end switch
159
+ }
160
+
161
+
162
+ })
163
+
164
+ });
165
+
166
+ //button status
167
+ checkMaxStatus();
168
+
169
+ //
170
+ resolve(timeoutIdRef.current);
171
+
172
+ }
173
+
174
+
175
+ }, controlRefreshValDelay);
176
+
177
+
178
+
179
+ });
180
+ };
181
+
182
+ const stopTimer = () => {
183
+ clearTimeout(timeoutIdRef.current);
184
+ timeoutIdRef.current = null;
185
+ };
186
+
187
+
188
+ //timer add
189
+ const timeoutAddIdRef = useRef<any>(null);
190
+ const startTimerAdd = () => {
191
+ timeoutAddIdRef.current = setTimeout(() => {
192
+
193
+ if ( fieldsRef.current !== null ) {
194
+ const controls: HTMLFormElement[] = [].slice.call(document.querySelectorAll( `#${fieldsRef.current.id} > .dynamic-fields__append [name]` ));
195
+ controls.forEach((node: any, i: number) => {
196
+ // replace placeholder string
197
+ replacePlaceholderStr(node);
198
+ });
199
+
200
+ }
201
+ }, controlRefreshValDelay);
202
+ };
203
+
204
+ const stopTimerAdd = () => {
205
+ clearTimeout(timeoutAddIdRef.current);
206
+ timeoutAddIdRef.current = null;
207
+ };
208
+
209
+
210
+ //timer onComplete
211
+ const timeoutHandleCompleteIdRef = useRef<any>(null);
212
+ const startTimerHandleComplete = () => {
213
+ timeoutHandleCompleteIdRef.current = setTimeout(() => {
214
+
215
+ // Call a function when all dynamic components are rendered.
216
+ // It is usually used for cascading asynchronous components (can be triggered by routing updates)
217
+ onComplete?.();
218
+
219
+ }, 500);
220
+ };
221
+
222
+ const stopTimerHandleComplete = () => {
223
+ clearTimeout(timeoutHandleCompleteIdRef.current);
224
+ timeoutHandleCompleteIdRef.current = null;
225
+ };
226
+
227
+
228
+
229
+
230
+ //
231
+ function replacePlaceholderStr(node: any) {
232
+ const _wapper = node.closest('.dynamic-fields__tmpl__wrapper');
233
+ if ( _wapper === null ) return;
234
+
235
+ const perKey = _wapper.dataset.key;
236
+ if (typeof node.id !== 'undefined' ) node.id = node.id.replace('%i%', perKey);
237
+ if (typeof node.name !== 'undefined' ) node.name = node.name.replace('%i%', perKey);
238
+ if (typeof node.dataset.id !== 'undefined' ) node.dataset.id = node.dataset.id.replace('%i%', perKey);
239
+ if (typeof node.dataset.name !== 'undefined' ) node.dataset.name = node.dataset.name.replace('%i%', perKey);
240
+ }
241
+
242
+ function groupByNum(arr: any[], n: number) {
243
+ if ( n === 0 || n === Infinity ) return false;
244
+
245
+ let result: any[] = [];
246
+ for (let i = 0; i < arr.length; i += n) result.push(arr.slice(i, i + n) as never);
247
+ return result;
248
+ }
249
+
250
+
251
+ function checkMaxStatus() {
252
+ //button status
253
+ if (rootRef.current.querySelector('.dynamic-fields__append').children.length+1 >= parseFloat(maxFields)) {
254
+ addBtnRef.current.style.setProperty('display', 'none', 'important');
255
+ }
256
+ }
257
+
258
+
259
+ function handleClickAdd(event: any){
260
+ event.preventDefault();
261
+
262
+ //button status
263
+ checkMaxStatus();
264
+
265
+ //
266
+ setData((prevState: any[]) => {
267
+ return [...prevState, [""]];
268
+ });
269
+
270
+ //
271
+ onAdd?.();
272
+
273
+
274
+ // update placeholder string
275
+ startTimerAdd();
276
+
277
+
278
+ }
279
+
280
+
281
+ function handleClickRemove(param: any) { // param is the argument you passed to the function
282
+ return (e: any) => { // e is the event object that returned
283
+ e.preventDefault();
284
+
285
+ if ( confirm(confirmText || '') ) {
286
+
287
+ //button status
288
+ if (rootRef.current.querySelector('.dynamic-fields__append').children.length <= parseFloat(maxFields)) {
289
+ addBtnRef.current.style.setProperty('display', 'inline', 'important');
290
+ }
291
+
292
+
293
+ //
294
+ let newData = [...data];
295
+ newData.splice(param, 1);
296
+ //console.log(newData); //[[""],[""],[""],[""]]
297
+ setData(newData);
298
+
299
+ //
300
+ onRemove?.();
301
+ }
302
+
303
+ };
304
+
305
+ }
306
+
307
+ function updateDisplayedControls() {
308
+
309
+ // update values for all displayed controls
310
+ // You need to wait for the asynchronous component to render
311
+ startTimer().then(() => {
312
+ startTimerHandleComplete();
313
+ });
314
+
315
+ }
316
+
317
+ function generateList() {
318
+
319
+ return data.map((el: any, i: number) =>
320
+ <div key={i} className="dynamic-fields__tmpl__wrapper position-relative" data-key={i}>
321
+
322
+ {el.map((data: any, index: number) => {
323
+ return (
324
+ <React.Fragment key={index}>
325
+ {tempHtmlString}
326
+ </React.Fragment>
327
+ )
328
+ })
329
+ }
330
+
331
+ <a href="#" tabIndex={-1} className="dynamic-fields__removebtn align-middle" onClick={handleClickRemove(i)}>
332
+ {iconRemove ? <>{iconRemove}</> : <><svg width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path fillRule="evenodd" clipRule="evenodd" d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10ZM8 11a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2H8Z" fill="#000" /></svg></>}
333
+ </a>
334
+
335
+ </div>
336
+ );
337
+
338
+ }
339
+
340
+ useEffect(() => {
341
+
342
+ setData(value ? [...Array(JSON.parse('[' + value + ']').length - (!startFromZero ? 1 : 0))].map(() => [""]) : []);
343
+ updateDisplayedControls();
344
+
345
+ return () => {
346
+ stopTimer();
347
+ stopTimerAdd();
348
+ stopTimerHandleComplete();
349
+ };
350
+
351
+
352
+ }, [value]);
353
+
354
+
355
+ return (
356
+ <>
357
+
358
+
359
+ <div className={wrapperClassName || wrapperClassName === '' ? wrapperClassName : "mb-3 position-relative"} ref={rootRef}>
360
+ {label ? <><label className="form-label">{label}</label></> : null}
361
+
362
+ <div ref={fieldsRef} className="dynamic-fields-container" data-max-fields={maxFields || 10} id={idRes}>
363
+ <div className="dynamic-fields__append">
364
+ {!startFromZero ? tempHtmlString : null}
365
+ {generateList()}
366
+ </div>
367
+
368
+ <div className="dynamic-fields__btns">
369
+ {iconAddBefore ? iconAddBefore : null}
370
+ <a ref={addBtnRef} href="#" tabIndex={-1} className="dynamic-fields__addbtn align-middle" onClick={handleClickAdd}>
371
+ {iconAdd ? <>{iconAdd}</> : <><svg width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.49 2 2 6.49 2 12C2 17.51 6.49 22 12 22C17.51 22 22 17.51 22 12C22 6.49 17.51 2 12 2ZM16 12.75H12.75V16C12.75 16.41 12.41 16.75 12 16.75C11.59 16.75 11.25 16.41 11.25 16V12.75H8C7.59 12.75 7.25 12.41 7.25 12C7.25 11.59 7.59 11.25 8 11.25H11.25V8C11.25 7.59 11.59 7.25 12 7.25C12.41 7.25 12.75 7.59 12.75 8V11.25H16C16.41 11.25 16.75 11.59 16.75 12C16.75 12.41 16.41 12.75 16 12.75Z" fill="#000" /></svg></>}
372
+ </a>
373
+ {iconAddAfter ? iconAddAfter : null}
374
+ </div>
375
+
376
+ </div>
377
+
378
+ </div>
379
+
380
+
381
+
382
+ </>
383
+ )
384
+ };
385
+
386
+ export default DynamicFields;