funda-ui 4.7.615 → 4.7.624

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 (564) hide show
  1. package/.gitattributes +2 -0
  2. package/README.md +116 -2
  3. package/README_PUBLISH.md +328 -0
  4. package/lib/cjs/Date/index.js +39 -2
  5. package/lib/cjs/DynamicFields/index.js +11 -3
  6. package/lib/esm/Date/index.tsx +47 -2
  7. package/lib/esm/DynamicFields/index.tsx +9 -4
  8. package/logo.png +0 -0
  9. package/package.json +589 -43
  10. package/preview.png +0 -0
  11. package/{Date → publish/Date}/index.js +39 -2
  12. package/{DynamicFields → publish/DynamicFields}/index.js +11 -3
  13. package/publish/LICENSE +21 -0
  14. package/publish/README.md +328 -0
  15. package/publish/lib/cjs/Accordion/index.d.ts +2 -0
  16. package/publish/lib/cjs/Accordion/index.js +667 -0
  17. package/publish/lib/cjs/BackToTop/index.d.ts +17 -0
  18. package/publish/lib/cjs/BackToTop/index.js +904 -0
  19. package/publish/lib/cjs/CascadingSelect/index.d.ts +80 -0
  20. package/publish/lib/cjs/CascadingSelect/index.js +3383 -0
  21. package/publish/lib/cjs/CascadingSelectE2E/index.d.ts +91 -0
  22. package/publish/lib/cjs/CascadingSelectE2E/index.js +3988 -0
  23. package/publish/lib/cjs/Chatbox/index.d.ts +101 -0
  24. package/publish/lib/cjs/Chatbox/index.js +7037 -0
  25. package/publish/lib/cjs/Checkbox/index.d.ts +28 -0
  26. package/publish/lib/cjs/Checkbox/index.js +673 -0
  27. package/publish/lib/cjs/ColorPicker/index.d.ts +27 -0
  28. package/publish/lib/cjs/ColorPicker/index.js +662 -0
  29. package/publish/lib/cjs/Date/index.d.ts +70 -0
  30. package/publish/lib/cjs/Date/index.js +6368 -0
  31. package/publish/lib/cjs/DigitalClock/index.d.ts +7 -0
  32. package/publish/lib/cjs/DigitalClock/index.js +402 -0
  33. package/publish/lib/cjs/DragDropList/index.d.ts +45 -0
  34. package/publish/lib/cjs/DragDropList/index.js +1586 -0
  35. package/publish/lib/cjs/DropdownMenu/index.d.ts +38 -0
  36. package/publish/lib/cjs/DropdownMenu/index.js +1507 -0
  37. package/publish/lib/cjs/DynamicFields/index.d.ts +40 -0
  38. package/publish/lib/cjs/DynamicFields/index.js +818 -0
  39. package/publish/lib/cjs/EventCalendar/index.d.ts +61 -0
  40. package/publish/lib/cjs/EventCalendar/index.js +3789 -0
  41. package/publish/lib/cjs/EventCalendarTimeline/index.d.ts +100 -0
  42. package/publish/lib/cjs/EventCalendarTimeline/index.js +6141 -0
  43. package/publish/lib/cjs/File/index.d.ts +40 -0
  44. package/publish/lib/cjs/File/index.js +1751 -0
  45. package/publish/lib/cjs/HorizontalScrollContent/index.d.ts +14 -0
  46. package/publish/lib/cjs/HorizontalScrollContent/index.js +426 -0
  47. package/publish/lib/cjs/Input/index.d.ts +59 -0
  48. package/publish/lib/cjs/Input/index.js +1486 -0
  49. package/publish/lib/cjs/LiveSearch/index.d.ts +70 -0
  50. package/publish/lib/cjs/LiveSearch/index.js +4180 -0
  51. package/publish/lib/cjs/MasonryLayout/index.d.ts +14 -0
  52. package/publish/lib/cjs/MasonryLayout/index.js +689 -0
  53. package/publish/lib/cjs/ModalDialog/index.d.ts +83 -0
  54. package/publish/lib/cjs/ModalDialog/index.js +1719 -0
  55. package/publish/lib/cjs/ModeSwitch/index.d.ts +17 -0
  56. package/publish/lib/cjs/ModeSwitch/index.js +202 -0
  57. package/publish/lib/cjs/MultilevelDropdownMenu/index.d.ts +20 -0
  58. package/publish/lib/cjs/MultilevelDropdownMenu/index.js +930 -0
  59. package/publish/lib/cjs/MultipleCheckboxes/index.d.ts +66 -0
  60. package/publish/lib/cjs/MultipleCheckboxes/index.js +2337 -0
  61. package/publish/lib/cjs/MultipleSelect/index.d.ts +65 -0
  62. package/publish/lib/cjs/MultipleSelect/index.js +4197 -0
  63. package/publish/lib/cjs/NativeSelect/index.d.ts +37 -0
  64. package/publish/lib/cjs/NativeSelect/index.js +2052 -0
  65. package/publish/lib/cjs/NumberInput/index.d.ts +40 -0
  66. package/publish/lib/cjs/NumberInput/index.js +1191 -0
  67. package/publish/lib/cjs/Pagination/index.d.ts +51 -0
  68. package/publish/lib/cjs/Pagination/index.js +612 -0
  69. package/publish/lib/cjs/Radio/index.d.ts +45 -0
  70. package/publish/lib/cjs/Radio/index.js +1838 -0
  71. package/publish/lib/cjs/RangeSlider/index.d.ts +22 -0
  72. package/publish/lib/cjs/RangeSlider/index.js +2696 -0
  73. package/publish/lib/cjs/Refresher/index.d.ts +22 -0
  74. package/publish/lib/cjs/Refresher/index.js +564 -0
  75. package/publish/lib/cjs/RootPortal/index.d.ts +9 -0
  76. package/publish/lib/cjs/RootPortal/index.js +148 -0
  77. package/publish/lib/cjs/ScrollReveal/index.d.ts +21 -0
  78. package/publish/lib/cjs/ScrollReveal/index.js +401 -0
  79. package/publish/lib/cjs/Scrollbar/index.d.ts +17 -0
  80. package/publish/lib/cjs/Scrollbar/index.js +1107 -0
  81. package/publish/lib/cjs/SearchBar/index.d.ts +41 -0
  82. package/publish/lib/cjs/SearchBar/index.js +701 -0
  83. package/publish/lib/cjs/Select/index.d.ts +107 -0
  84. package/publish/lib/cjs/Select/index.js +6540 -0
  85. package/publish/lib/cjs/ShowMoreLess/index.d.ts +36 -0
  86. package/publish/lib/cjs/ShowMoreLess/index.js +387 -0
  87. package/publish/lib/cjs/SplitterPanel/index.d.ts +20 -0
  88. package/publish/lib/cjs/SplitterPanel/index.js +800 -0
  89. package/publish/lib/cjs/Stepper/index.d.ts +26 -0
  90. package/publish/lib/cjs/Stepper/index.js +568 -0
  91. package/publish/lib/cjs/Switch/index.d.ts +25 -0
  92. package/publish/lib/cjs/Switch/index.js +630 -0
  93. package/publish/lib/cjs/Table/index.d.ts +12 -0
  94. package/publish/lib/cjs/Table/index.js +2311 -0
  95. package/publish/lib/cjs/Tabs/index.d.ts +3 -0
  96. package/publish/lib/cjs/Tabs/index.js +771 -0
  97. package/publish/lib/cjs/TagInput/index.d.ts +37 -0
  98. package/publish/lib/cjs/TagInput/index.js +1227 -0
  99. package/publish/lib/cjs/Textarea/index.d.ts +50 -0
  100. package/publish/lib/cjs/Textarea/index.js +1795 -0
  101. package/publish/lib/cjs/Toast/index.d.ts +3 -0
  102. package/publish/lib/cjs/Toast/index.js +1345 -0
  103. package/publish/lib/cjs/Tooltip/index.d.ts +38 -0
  104. package/publish/lib/cjs/Tooltip/index.js +1778 -0
  105. package/publish/lib/cjs/Tree/index.d.ts +78 -0
  106. package/publish/lib/cjs/Tree/index.js +2330 -0
  107. package/publish/lib/cjs/Utils/anim.d.ts +11 -0
  108. package/publish/lib/cjs/Utils/anim.js +846 -0
  109. package/publish/lib/cjs/Utils/bodyScrollLock.d.ts +8 -0
  110. package/publish/lib/cjs/Utils/bodyScrollLock.js +311 -0
  111. package/publish/lib/cjs/Utils/buffer.d.ts +67 -0
  112. package/publish/lib/cjs/Utils/buffer.js +343 -0
  113. package/publish/lib/cjs/Utils/cls.d.ts +15 -0
  114. package/publish/lib/cjs/Utils/cls.js +124 -0
  115. package/publish/lib/cjs/Utils/convert.d.ts +25 -0
  116. package/publish/lib/cjs/Utils/convert.js +109 -0
  117. package/publish/lib/cjs/Utils/date.d.ts +227 -0
  118. package/publish/lib/cjs/Utils/date.js +587 -0
  119. package/publish/lib/cjs/Utils/dom.d.ts +13 -0
  120. package/publish/lib/cjs/Utils/dom.js +215 -0
  121. package/publish/lib/cjs/Utils/easing.d.ts +29 -0
  122. package/publish/lib/cjs/Utils/easing.js +221 -0
  123. package/publish/lib/cjs/Utils/extract.d.ts +66 -0
  124. package/publish/lib/cjs/Utils/extract.js +195 -0
  125. package/publish/lib/cjs/Utils/format-string.d.ts +65 -0
  126. package/publish/lib/cjs/Utils/format-string.js +167 -0
  127. package/publish/lib/cjs/Utils/formdata.d.ts +13 -0
  128. package/publish/lib/cjs/Utils/formdata.js +131 -0
  129. package/publish/lib/cjs/Utils/getElementProperty.d.ts +52 -0
  130. package/publish/lib/cjs/Utils/getElementProperty.js +189 -0
  131. package/publish/lib/cjs/Utils/guid.d.ts +7 -0
  132. package/publish/lib/cjs/Utils/guid.js +67 -0
  133. package/publish/lib/cjs/Utils/initDefaultOptions.d.ts +10 -0
  134. package/publish/lib/cjs/Utils/initDefaultOptions.js +607 -0
  135. package/publish/lib/cjs/Utils/inputsCalculation.d.ts +28 -0
  136. package/publish/lib/cjs/Utils/inputsCalculation.js +188 -0
  137. package/publish/lib/cjs/Utils/math.d.ts +77 -0
  138. package/publish/lib/cjs/Utils/math.js +305 -0
  139. package/publish/lib/cjs/Utils/object.d.ts +18 -0
  140. package/publish/lib/cjs/Utils/object.js +120 -0
  141. package/publish/lib/cjs/Utils/os.d.ts +2 -0
  142. package/publish/lib/cjs/Utils/os.js +104 -0
  143. package/publish/lib/cjs/Utils/performance.d.ts +3 -0
  144. package/publish/lib/cjs/Utils/performance.js +94 -0
  145. package/publish/lib/cjs/Utils/sanitize.d.ts +14 -0
  146. package/publish/lib/cjs/Utils/sanitize.js +87 -0
  147. package/publish/lib/cjs/Utils/time.d.ts +40 -0
  148. package/publish/lib/cjs/Utils/time.js +177 -0
  149. package/publish/lib/cjs/Utils/tree.d.ts +40 -0
  150. package/publish/lib/cjs/Utils/tree.js +195 -0
  151. package/publish/lib/cjs/Utils/useAutosizeTextArea.d.ts +10 -0
  152. package/publish/lib/cjs/Utils/useAutosizeTextArea.js +231 -0
  153. package/publish/lib/cjs/Utils/useBoundedDrag.d.ts +125 -0
  154. package/publish/lib/cjs/Utils/useBoundedDrag.js +380 -0
  155. package/publish/lib/cjs/Utils/useClickOutside.d.ts +33 -0
  156. package/publish/lib/cjs/Utils/useClickOutside.js +166 -0
  157. package/publish/lib/cjs/Utils/useComId.d.ts +6 -0
  158. package/publish/lib/cjs/Utils/useComId.js +114 -0
  159. package/publish/lib/cjs/Utils/useDebounce.d.ts +20 -0
  160. package/publish/lib/cjs/Utils/useDebounce.js +138 -0
  161. package/publish/lib/cjs/Utils/useDragDropPosition.d.ts +166 -0
  162. package/publish/lib/cjs/Utils/useDragDropPosition.js +453 -0
  163. package/publish/lib/cjs/Utils/useDraggable.d.ts +62 -0
  164. package/publish/lib/cjs/Utils/useDraggable.js +348 -0
  165. package/publish/lib/cjs/Utils/useHistoryTracker.d.ts +166 -0
  166. package/publish/lib/cjs/Utils/useHistoryTracker.js +649 -0
  167. package/publish/lib/cjs/Utils/useInterval.d.ts +5 -0
  168. package/publish/lib/cjs/Utils/useInterval.js +168 -0
  169. package/publish/lib/cjs/Utils/useIsMobile.d.ts +2 -0
  170. package/publish/lib/cjs/Utils/useIsMobile.js +232 -0
  171. package/publish/lib/cjs/Utils/useKeyPress.d.ts +44 -0
  172. package/publish/lib/cjs/Utils/useKeyPress.js +200 -0
  173. package/publish/lib/cjs/Utils/useSessionStorageListener.d.ts +2 -0
  174. package/publish/lib/cjs/Utils/useSessionStorageListener.js +157 -0
  175. package/publish/lib/cjs/Utils/useStreamController.d.ts +71 -0
  176. package/publish/lib/cjs/Utils/useStreamController.js +494 -0
  177. package/publish/lib/cjs/Utils/useThrottle.d.ts +2 -0
  178. package/publish/lib/cjs/Utils/useThrottle.js +136 -0
  179. package/publish/lib/cjs/Utils/useWindowScroll.d.ts +12 -0
  180. package/publish/lib/cjs/Utils/useWindowScroll.js +217 -0
  181. package/publish/lib/cjs/Utils/validate.d.ts +53 -0
  182. package/publish/lib/cjs/Utils/validate.js +536 -0
  183. package/publish/lib/cjs/Utils/viewport.d.ts +7 -0
  184. package/publish/lib/cjs/Utils/viewport.js +64 -0
  185. package/publish/lib/cjs/index.d.ts +49 -0
  186. package/publish/lib/cjs/index.js +50 -0
  187. package/publish/lib/css/BackToTop/index.css +34 -0
  188. package/publish/lib/css/CascadingSelect/index.css +245 -0
  189. package/publish/lib/css/CascadingSelectE2E/index.css +245 -0
  190. package/publish/lib/css/Chatbox/index.css +774 -0
  191. package/publish/lib/css/ColorPicker/index.css +58 -0
  192. package/publish/lib/css/Date/index.css +434 -0
  193. package/publish/lib/css/DragDropList/index.css +188 -0
  194. package/publish/lib/css/DropdownMenu/index.css +151 -0
  195. package/publish/lib/css/EventCalendar/index.css +300 -0
  196. package/publish/lib/css/EventCalendarTimeline/index.css +694 -0
  197. package/publish/lib/css/HorizontalScrollContent/index.css +70 -0
  198. package/publish/lib/css/LiveSearch/index.css +88 -0
  199. package/publish/lib/css/MultilevelDropdownMenu/index.css +38 -0
  200. package/publish/lib/css/MultipleSelect/index.css +313 -0
  201. package/publish/lib/css/RangeSlider/index.css +150 -0
  202. package/publish/lib/css/Scrollbar/index.css +176 -0
  203. package/publish/lib/css/Select/index.css +434 -0
  204. package/publish/lib/css/ShowMoreLess/index.css +23 -0
  205. package/publish/lib/css/SplitterPanel/index.css +63 -0
  206. package/publish/lib/css/Stepper/index.css +250 -0
  207. package/publish/lib/css/Table/index.css +584 -0
  208. package/publish/lib/css/TagInput/index.css +91 -0
  209. package/publish/lib/css/Toast/index.css +149 -0
  210. package/publish/lib/css/Tooltip/index.css +198 -0
  211. package/publish/lib/css/Tree/index.css +237 -0
  212. package/publish/lib/esm/Accordion/Accordion.tsx +185 -0
  213. package/publish/lib/esm/Accordion/AccordionItem.tsx +248 -0
  214. package/publish/lib/esm/Accordion/index.tsx +2 -0
  215. package/publish/lib/esm/BackToTop/index.scss +47 -0
  216. package/publish/lib/esm/BackToTop/index.tsx +177 -0
  217. package/publish/lib/esm/CascadingSelect/Group.tsx +83 -0
  218. package/publish/lib/esm/CascadingSelect/index.scss +330 -0
  219. package/publish/lib/esm/CascadingSelect/index.tsx +1397 -0
  220. package/publish/lib/esm/CascadingSelectE2E/Group.tsx +87 -0
  221. package/publish/lib/esm/CascadingSelectE2E/index.scss +333 -0
  222. package/publish/lib/esm/CascadingSelectE2E/index.tsx +1684 -0
  223. package/publish/lib/esm/Chatbox/PureLoader.tsx +47 -0
  224. package/publish/lib/esm/Chatbox/TypingEffect.tsx +56 -0
  225. package/publish/lib/esm/Chatbox/index.scss +966 -0
  226. package/publish/lib/esm/Chatbox/index.tsx +1742 -0
  227. package/publish/lib/esm/Chatbox/utils/func.ts +180 -0
  228. package/publish/lib/esm/Checkbox/index.tsx +206 -0
  229. package/publish/lib/esm/ColorPicker/index.scss +91 -0
  230. package/publish/lib/esm/ColorPicker/index.tsx +204 -0
  231. package/publish/lib/esm/Date/Calendar.tsx +723 -0
  232. package/publish/lib/esm/Date/index.scss +567 -0
  233. package/publish/lib/esm/Date/index.tsx +1797 -0
  234. package/publish/lib/esm/Date/localization/en_US.js +13 -0
  235. package/publish/lib/esm/Date/localization/zh_CN.js +12 -0
  236. package/publish/lib/esm/DigitalClock/index.tsx +74 -0
  237. package/publish/lib/esm/DragDropList/index.scss +245 -0
  238. package/publish/lib/esm/DragDropList/index.tsx +504 -0
  239. package/publish/lib/esm/DropdownMenu/Option.tsx +55 -0
  240. package/publish/lib/esm/DropdownMenu/index.scss +205 -0
  241. package/publish/lib/esm/DropdownMenu/index.tsx +378 -0
  242. package/publish/lib/esm/DynamicFields/index.tsx +409 -0
  243. package/publish/lib/esm/EventCalendar/index.scss +407 -0
  244. package/publish/lib/esm/EventCalendar/index.tsx +1005 -0
  245. package/publish/lib/esm/EventCalendarTimeline/index.scss +926 -0
  246. package/publish/lib/esm/EventCalendarTimeline/index.tsx +2686 -0
  247. package/publish/lib/esm/File/index.tsx +477 -0
  248. package/publish/lib/esm/HorizontalScrollContent/index.scss +87 -0
  249. package/publish/lib/esm/HorizontalScrollContent/index.tsx +171 -0
  250. package/publish/lib/esm/Input/index.tsx +641 -0
  251. package/publish/lib/esm/LiveSearch/index.scss +129 -0
  252. package/publish/lib/esm/LiveSearch/index.tsx +1058 -0
  253. package/publish/lib/esm/MasonryLayout/index.tsx +326 -0
  254. package/publish/lib/esm/ModalDialog/index.tsx +572 -0
  255. package/publish/lib/esm/ModeSwitch/index.tsx +82 -0
  256. package/publish/lib/esm/MultilevelDropdownMenu/ItemList.tsx +265 -0
  257. package/publish/lib/esm/MultilevelDropdownMenu/index.scss +79 -0
  258. package/publish/lib/esm/MultilevelDropdownMenu/index.tsx +77 -0
  259. package/publish/lib/esm/MultipleCheckboxes/index.tsx +849 -0
  260. package/publish/lib/esm/MultipleSelect/index.scss +398 -0
  261. package/publish/lib/esm/MultipleSelect/index.tsx +769 -0
  262. package/publish/lib/esm/MultipleSelect/utils/func.ts +63 -0
  263. package/publish/lib/esm/NativeSelect/index.tsx +396 -0
  264. package/publish/lib/esm/NativeSelect/utils/func.ts +51 -0
  265. package/publish/lib/esm/NumberInput/index.tsx +425 -0
  266. package/publish/lib/esm/Pagination/index.tsx +286 -0
  267. package/publish/lib/esm/Pagination/pagination-navigators.tsx +60 -0
  268. package/publish/lib/esm/Radio/index.tsx +694 -0
  269. package/publish/lib/esm/RangeSlider/index.scss +186 -0
  270. package/publish/lib/esm/RangeSlider/index.tsx +241 -0
  271. package/publish/lib/esm/Refresher/index.tsx +121 -0
  272. package/publish/lib/esm/RootPortal/index.tsx +59 -0
  273. package/publish/lib/esm/ScrollReveal/index.tsx +148 -0
  274. package/publish/lib/esm/Scrollbar/index.scss +221 -0
  275. package/publish/lib/esm/Scrollbar/index.tsx +561 -0
  276. package/publish/lib/esm/SearchBar/index.tsx +252 -0
  277. package/publish/lib/esm/Select/index.scss +639 -0
  278. package/publish/lib/esm/Select/index.tsx +3104 -0
  279. package/publish/lib/esm/Select/utils/func.ts +98 -0
  280. package/publish/lib/esm/ShowMoreLess/index.scss +27 -0
  281. package/publish/lib/esm/ShowMoreLess/index.tsx +145 -0
  282. package/publish/lib/esm/SplitterPanel/index.scss +82 -0
  283. package/publish/lib/esm/SplitterPanel/index.tsx +174 -0
  284. package/publish/lib/esm/Stepper/index.scss +315 -0
  285. package/publish/lib/esm/Stepper/index.tsx +325 -0
  286. package/publish/lib/esm/Switch/index.tsx +149 -0
  287. package/publish/lib/esm/Table/Table.tsx +351 -0
  288. package/publish/lib/esm/Table/TableBody.tsx +41 -0
  289. package/publish/lib/esm/Table/TableCaption.tsx +34 -0
  290. package/publish/lib/esm/Table/TableCell.tsx +126 -0
  291. package/publish/lib/esm/Table/TableColgroup.tsx +38 -0
  292. package/publish/lib/esm/Table/TableContext.tsx +26 -0
  293. package/publish/lib/esm/Table/TableFoot.tsx +28 -0
  294. package/publish/lib/esm/Table/TableHead.tsx +28 -0
  295. package/publish/lib/esm/Table/TableRow.tsx +76 -0
  296. package/publish/lib/esm/Table/index.scss +418 -0
  297. package/publish/lib/esm/Table/index.tsx +14 -0
  298. package/publish/lib/esm/Table/utils/DragHandleSprite.tsx +46 -0
  299. package/publish/lib/esm/Table/utils/SortSprite.tsx +63 -0
  300. package/publish/lib/esm/Table/utils/TableFilter.tsx +56 -0
  301. package/publish/lib/esm/Table/utils/ToggleSelection.tsx +255 -0
  302. package/publish/lib/esm/Table/utils/func.ts +182 -0
  303. package/publish/lib/esm/Table/utils/hooks/useTableDraggable.tsx +342 -0
  304. package/publish/lib/esm/Table/utils/hooks/useTableKeyPress.tsx +255 -0
  305. package/publish/lib/esm/Table/utils/hooks/useTableResponsive.tsx +92 -0
  306. package/publish/lib/esm/Table/utils/hooks/useTableSort.tsx +187 -0
  307. package/publish/lib/esm/Tabs/TabList.tsx +50 -0
  308. package/publish/lib/esm/Tabs/TabPanel.tsx +44 -0
  309. package/publish/lib/esm/Tabs/Tabs.tsx +282 -0
  310. package/publish/lib/esm/Tabs/index.tsx +3 -0
  311. package/publish/lib/esm/TagInput/index.scss +126 -0
  312. package/publish/lib/esm/TagInput/index.tsx +379 -0
  313. package/publish/lib/esm/Textarea/index.tsx +621 -0
  314. package/publish/lib/esm/Toast/Item.tsx +165 -0
  315. package/publish/lib/esm/Toast/Toast.tsx +391 -0
  316. package/publish/lib/esm/Toast/ToastContext.tsx +104 -0
  317. package/publish/lib/esm/Toast/__toast.vanilla.js +422 -0
  318. package/publish/lib/esm/Toast/index.scss +197 -0
  319. package/publish/lib/esm/Toast/index.tsx +3 -0
  320. package/publish/lib/esm/Toast/types.ts +60 -0
  321. package/publish/lib/esm/Toast/useToast.tsx +72 -0
  322. package/publish/lib/esm/Tooltip/index.scss +272 -0
  323. package/publish/lib/esm/Tooltip/index.tsx +416 -0
  324. package/publish/lib/esm/Tree/TreeList.tsx +600 -0
  325. package/publish/lib/esm/Tree/index.scss +384 -0
  326. package/publish/lib/esm/Tree/index.tsx +661 -0
  327. package/publish/lib/esm/Tree/init-height.tsx +40 -0
  328. package/publish/lib/esm/Tree/utils/func.ts +15 -0
  329. package/publish/lib/esm/Utils/hooks/useAutosizeTextArea.tsx +131 -0
  330. package/publish/lib/esm/Utils/hooks/useBoundedDrag.tsx +301 -0
  331. package/publish/lib/esm/Utils/hooks/useClickOutside.tsx +69 -0
  332. package/publish/lib/esm/Utils/hooks/useComId.tsx +13 -0
  333. package/publish/lib/esm/Utils/hooks/useDebounce.tsx +40 -0
  334. package/publish/lib/esm/Utils/hooks/useDragDropPosition.tsx +417 -0
  335. package/publish/lib/esm/Utils/hooks/useDraggable.tsx +265 -0
  336. package/publish/lib/esm/Utils/hooks/useHistoryTracker.tsx +554 -0
  337. package/publish/lib/esm/Utils/hooks/useInterval.tsx +74 -0
  338. package/publish/lib/esm/Utils/hooks/useIsMobile.tsx +139 -0
  339. package/publish/lib/esm/Utils/hooks/useKeyPress.tsx +104 -0
  340. package/publish/lib/esm/Utils/hooks/useSessionStorageListener.tsx +45 -0
  341. package/publish/lib/esm/Utils/hooks/useStreamController.tsx +277 -0
  342. package/publish/lib/esm/Utils/hooks/useThrottle.tsx +39 -0
  343. package/publish/lib/esm/Utils/hooks/useWindowScroll.tsx +83 -0
  344. package/publish/lib/esm/Utils/libs/anim.ts +96 -0
  345. package/publish/lib/esm/Utils/libs/buffer.ts +262 -0
  346. package/publish/lib/esm/Utils/libs/cls.ts +64 -0
  347. package/publish/lib/esm/Utils/libs/convert.ts +59 -0
  348. package/publish/lib/esm/Utils/libs/date.ts +598 -0
  349. package/publish/lib/esm/Utils/libs/dom.ts +150 -0
  350. package/publish/lib/esm/Utils/libs/easing.ts +201 -0
  351. package/publish/lib/esm/Utils/libs/extract.ts +160 -0
  352. package/publish/lib/esm/Utils/libs/format-string.ts +116 -0
  353. package/publish/lib/esm/Utils/libs/formdata.ts +93 -0
  354. package/publish/lib/esm/Utils/libs/getElementProperty.ts +150 -0
  355. package/publish/lib/esm/Utils/libs/guid.ts +16 -0
  356. package/publish/lib/esm/Utils/libs/initDefaultOptions.ts +43 -0
  357. package/publish/lib/esm/Utils/libs/inputsCalculation.ts +160 -0
  358. package/publish/lib/esm/Utils/libs/math.ts +276 -0
  359. package/publish/lib/esm/Utils/libs/object.ts +68 -0
  360. package/publish/lib/esm/Utils/libs/os.ts +63 -0
  361. package/publish/lib/esm/Utils/libs/performance.ts +47 -0
  362. package/publish/lib/esm/Utils/libs/sanitize.ts +55 -0
  363. package/publish/lib/esm/Utils/libs/time.ts +139 -0
  364. package/publish/lib/esm/Utils/libs/tree.ts +119 -0
  365. package/publish/lib/esm/Utils/libs/validate.ts +434 -0
  366. package/publish/lib/esm/Utils/libs/viewport.ts +20 -0
  367. package/publish/lib/esm/Utils/plugins/bodyScrollLock.ts +286 -0
  368. package/publish/lib/esm/index.js +47 -0
  369. package/publish/package.json +1 -0
  370. /package/{Accordion → publish/Accordion}/index.d.ts +0 -0
  371. /package/{Accordion → publish/Accordion}/index.js +0 -0
  372. /package/{BackToTop → publish/BackToTop}/index.css +0 -0
  373. /package/{BackToTop → publish/BackToTop}/index.d.ts +0 -0
  374. /package/{BackToTop → publish/BackToTop}/index.js +0 -0
  375. /package/{CascadingSelect → publish/CascadingSelect}/index.css +0 -0
  376. /package/{CascadingSelect → publish/CascadingSelect}/index.d.ts +0 -0
  377. /package/{CascadingSelect → publish/CascadingSelect}/index.js +0 -0
  378. /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.css +0 -0
  379. /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.d.ts +0 -0
  380. /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.js +0 -0
  381. /package/{Chatbox → publish/Chatbox}/index.css +0 -0
  382. /package/{Chatbox → publish/Chatbox}/index.d.ts +0 -0
  383. /package/{Chatbox → publish/Chatbox}/index.js +0 -0
  384. /package/{Checkbox → publish/Checkbox}/index.d.ts +0 -0
  385. /package/{Checkbox → publish/Checkbox}/index.js +0 -0
  386. /package/{ColorPicker → publish/ColorPicker}/index.css +0 -0
  387. /package/{ColorPicker → publish/ColorPicker}/index.d.ts +0 -0
  388. /package/{ColorPicker → publish/ColorPicker}/index.js +0 -0
  389. /package/{Date → publish/Date}/index.css +0 -0
  390. /package/{Date → publish/Date}/index.d.ts +0 -0
  391. /package/{DigitalClock → publish/DigitalClock}/index.d.ts +0 -0
  392. /package/{DigitalClock → publish/DigitalClock}/index.js +0 -0
  393. /package/{DragDropList → publish/DragDropList}/index.css +0 -0
  394. /package/{DragDropList → publish/DragDropList}/index.d.ts +0 -0
  395. /package/{DragDropList → publish/DragDropList}/index.js +0 -0
  396. /package/{DropdownMenu → publish/DropdownMenu}/index.css +0 -0
  397. /package/{DropdownMenu → publish/DropdownMenu}/index.d.ts +0 -0
  398. /package/{DropdownMenu → publish/DropdownMenu}/index.js +0 -0
  399. /package/{DynamicFields → publish/DynamicFields}/index.d.ts +0 -0
  400. /package/{EventCalendar → publish/EventCalendar}/index.css +0 -0
  401. /package/{EventCalendar → publish/EventCalendar}/index.d.ts +0 -0
  402. /package/{EventCalendar → publish/EventCalendar}/index.js +0 -0
  403. /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.css +0 -0
  404. /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.d.ts +0 -0
  405. /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.js +0 -0
  406. /package/{File → publish/File}/index.d.ts +0 -0
  407. /package/{File → publish/File}/index.js +0 -0
  408. /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.css +0 -0
  409. /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.d.ts +0 -0
  410. /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.js +0 -0
  411. /package/{Input → publish/Input}/index.d.ts +0 -0
  412. /package/{Input → publish/Input}/index.js +0 -0
  413. /package/{LiveSearch → publish/LiveSearch}/index.css +0 -0
  414. /package/{LiveSearch → publish/LiveSearch}/index.d.ts +0 -0
  415. /package/{LiveSearch → publish/LiveSearch}/index.js +0 -0
  416. /package/{MasonryLayout → publish/MasonryLayout}/index.d.ts +0 -0
  417. /package/{MasonryLayout → publish/MasonryLayout}/index.js +0 -0
  418. /package/{ModalDialog → publish/ModalDialog}/index.d.ts +0 -0
  419. /package/{ModalDialog → publish/ModalDialog}/index.js +0 -0
  420. /package/{ModeSwitch → publish/ModeSwitch}/index.d.ts +0 -0
  421. /package/{ModeSwitch → publish/ModeSwitch}/index.js +0 -0
  422. /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.css +0 -0
  423. /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.d.ts +0 -0
  424. /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.js +0 -0
  425. /package/{MultipleCheckboxes → publish/MultipleCheckboxes}/index.d.ts +0 -0
  426. /package/{MultipleCheckboxes → publish/MultipleCheckboxes}/index.js +0 -0
  427. /package/{MultipleSelect → publish/MultipleSelect}/index.css +0 -0
  428. /package/{MultipleSelect → publish/MultipleSelect}/index.d.ts +0 -0
  429. /package/{MultipleSelect → publish/MultipleSelect}/index.js +0 -0
  430. /package/{NativeSelect → publish/NativeSelect}/index.d.ts +0 -0
  431. /package/{NativeSelect → publish/NativeSelect}/index.js +0 -0
  432. /package/{NumberInput → publish/NumberInput}/index.d.ts +0 -0
  433. /package/{NumberInput → publish/NumberInput}/index.js +0 -0
  434. /package/{Pagination → publish/Pagination}/index.d.ts +0 -0
  435. /package/{Pagination → publish/Pagination}/index.js +0 -0
  436. /package/{Radio → publish/Radio}/index.d.ts +0 -0
  437. /package/{Radio → publish/Radio}/index.js +0 -0
  438. /package/{RangeSlider → publish/RangeSlider}/index.css +0 -0
  439. /package/{RangeSlider → publish/RangeSlider}/index.d.ts +0 -0
  440. /package/{RangeSlider → publish/RangeSlider}/index.js +0 -0
  441. /package/{Refresher → publish/Refresher}/index.d.ts +0 -0
  442. /package/{Refresher → publish/Refresher}/index.js +0 -0
  443. /package/{RootPortal → publish/RootPortal}/index.d.ts +0 -0
  444. /package/{RootPortal → publish/RootPortal}/index.js +0 -0
  445. /package/{ScrollReveal → publish/ScrollReveal}/index.d.ts +0 -0
  446. /package/{ScrollReveal → publish/ScrollReveal}/index.js +0 -0
  447. /package/{Scrollbar → publish/Scrollbar}/index.css +0 -0
  448. /package/{Scrollbar → publish/Scrollbar}/index.d.ts +0 -0
  449. /package/{Scrollbar → publish/Scrollbar}/index.js +0 -0
  450. /package/{SearchBar → publish/SearchBar}/index.d.ts +0 -0
  451. /package/{SearchBar → publish/SearchBar}/index.js +0 -0
  452. /package/{Select → publish/Select}/index.css +0 -0
  453. /package/{Select → publish/Select}/index.d.ts +0 -0
  454. /package/{Select → publish/Select}/index.js +0 -0
  455. /package/{ShowMoreLess → publish/ShowMoreLess}/index.css +0 -0
  456. /package/{ShowMoreLess → publish/ShowMoreLess}/index.d.ts +0 -0
  457. /package/{ShowMoreLess → publish/ShowMoreLess}/index.js +0 -0
  458. /package/{SplitterPanel → publish/SplitterPanel}/index.css +0 -0
  459. /package/{SplitterPanel → publish/SplitterPanel}/index.d.ts +0 -0
  460. /package/{SplitterPanel → publish/SplitterPanel}/index.js +0 -0
  461. /package/{Stepper → publish/Stepper}/index.css +0 -0
  462. /package/{Stepper → publish/Stepper}/index.d.ts +0 -0
  463. /package/{Stepper → publish/Stepper}/index.js +0 -0
  464. /package/{Switch → publish/Switch}/index.d.ts +0 -0
  465. /package/{Switch → publish/Switch}/index.js +0 -0
  466. /package/{Table → publish/Table}/index.css +0 -0
  467. /package/{Table → publish/Table}/index.d.ts +0 -0
  468. /package/{Table → publish/Table}/index.js +0 -0
  469. /package/{Tabs → publish/Tabs}/index.d.ts +0 -0
  470. /package/{Tabs → publish/Tabs}/index.js +0 -0
  471. /package/{TagInput → publish/TagInput}/index.css +0 -0
  472. /package/{TagInput → publish/TagInput}/index.d.ts +0 -0
  473. /package/{TagInput → publish/TagInput}/index.js +0 -0
  474. /package/{Textarea → publish/Textarea}/index.d.ts +0 -0
  475. /package/{Textarea → publish/Textarea}/index.js +0 -0
  476. /package/{Toast → publish/Toast}/index.css +0 -0
  477. /package/{Toast → publish/Toast}/index.d.ts +0 -0
  478. /package/{Toast → publish/Toast}/index.js +0 -0
  479. /package/{Tooltip → publish/Tooltip}/index.css +0 -0
  480. /package/{Tooltip → publish/Tooltip}/index.d.ts +0 -0
  481. /package/{Tooltip → publish/Tooltip}/index.js +0 -0
  482. /package/{Tree → publish/Tree}/index.css +0 -0
  483. /package/{Tree → publish/Tree}/index.d.ts +0 -0
  484. /package/{Tree → publish/Tree}/index.js +0 -0
  485. /package/{Utils → publish/Utils}/anim.d.ts +0 -0
  486. /package/{Utils → publish/Utils}/anim.js +0 -0
  487. /package/{Utils → publish/Utils}/bodyScrollLock.d.ts +0 -0
  488. /package/{Utils → publish/Utils}/bodyScrollLock.js +0 -0
  489. /package/{Utils → publish/Utils}/buffer.d.ts +0 -0
  490. /package/{Utils → publish/Utils}/buffer.js +0 -0
  491. /package/{Utils → publish/Utils}/cls.d.ts +0 -0
  492. /package/{Utils → publish/Utils}/cls.js +0 -0
  493. /package/{Utils → publish/Utils}/convert.d.ts +0 -0
  494. /package/{Utils → publish/Utils}/convert.js +0 -0
  495. /package/{Utils → publish/Utils}/date.d.ts +0 -0
  496. /package/{Utils → publish/Utils}/date.js +0 -0
  497. /package/{Utils → publish/Utils}/dom.d.ts +0 -0
  498. /package/{Utils → publish/Utils}/dom.js +0 -0
  499. /package/{Utils → publish/Utils}/easing.d.ts +0 -0
  500. /package/{Utils → publish/Utils}/easing.js +0 -0
  501. /package/{Utils → publish/Utils}/extract.d.ts +0 -0
  502. /package/{Utils → publish/Utils}/extract.js +0 -0
  503. /package/{Utils → publish/Utils}/format-string.d.ts +0 -0
  504. /package/{Utils → publish/Utils}/format-string.js +0 -0
  505. /package/{Utils → publish/Utils}/formdata.d.ts +0 -0
  506. /package/{Utils → publish/Utils}/formdata.js +0 -0
  507. /package/{Utils → publish/Utils}/getElementProperty.d.ts +0 -0
  508. /package/{Utils → publish/Utils}/getElementProperty.js +0 -0
  509. /package/{Utils → publish/Utils}/guid.d.ts +0 -0
  510. /package/{Utils → publish/Utils}/guid.js +0 -0
  511. /package/{Utils → publish/Utils}/initDefaultOptions.d.ts +0 -0
  512. /package/{Utils → publish/Utils}/initDefaultOptions.js +0 -0
  513. /package/{Utils → publish/Utils}/inputsCalculation.d.ts +0 -0
  514. /package/{Utils → publish/Utils}/inputsCalculation.js +0 -0
  515. /package/{Utils → publish/Utils}/math.d.ts +0 -0
  516. /package/{Utils → publish/Utils}/math.js +0 -0
  517. /package/{Utils → publish/Utils}/object.d.ts +0 -0
  518. /package/{Utils → publish/Utils}/object.js +0 -0
  519. /package/{Utils → publish/Utils}/os.d.ts +0 -0
  520. /package/{Utils → publish/Utils}/os.js +0 -0
  521. /package/{Utils → publish/Utils}/performance.d.ts +0 -0
  522. /package/{Utils → publish/Utils}/performance.js +0 -0
  523. /package/{Utils → publish/Utils}/sanitize.d.ts +0 -0
  524. /package/{Utils → publish/Utils}/sanitize.js +0 -0
  525. /package/{Utils → publish/Utils}/time.d.ts +0 -0
  526. /package/{Utils → publish/Utils}/time.js +0 -0
  527. /package/{Utils → publish/Utils}/tree.d.ts +0 -0
  528. /package/{Utils → publish/Utils}/tree.js +0 -0
  529. /package/{Utils → publish/Utils}/useAutosizeTextArea.d.ts +0 -0
  530. /package/{Utils → publish/Utils}/useAutosizeTextArea.js +0 -0
  531. /package/{Utils → publish/Utils}/useBoundedDrag.d.ts +0 -0
  532. /package/{Utils → publish/Utils}/useBoundedDrag.js +0 -0
  533. /package/{Utils → publish/Utils}/useClickOutside.d.ts +0 -0
  534. /package/{Utils → publish/Utils}/useClickOutside.js +0 -0
  535. /package/{Utils → publish/Utils}/useComId.d.ts +0 -0
  536. /package/{Utils → publish/Utils}/useComId.js +0 -0
  537. /package/{Utils → publish/Utils}/useDebounce.d.ts +0 -0
  538. /package/{Utils → publish/Utils}/useDebounce.js +0 -0
  539. /package/{Utils → publish/Utils}/useDragDropPosition.d.ts +0 -0
  540. /package/{Utils → publish/Utils}/useDragDropPosition.js +0 -0
  541. /package/{Utils → publish/Utils}/useDraggable.d.ts +0 -0
  542. /package/{Utils → publish/Utils}/useDraggable.js +0 -0
  543. /package/{Utils → publish/Utils}/useHistoryTracker.d.ts +0 -0
  544. /package/{Utils → publish/Utils}/useHistoryTracker.js +0 -0
  545. /package/{Utils → publish/Utils}/useInterval.d.ts +0 -0
  546. /package/{Utils → publish/Utils}/useInterval.js +0 -0
  547. /package/{Utils → publish/Utils}/useIsMobile.d.ts +0 -0
  548. /package/{Utils → publish/Utils}/useIsMobile.js +0 -0
  549. /package/{Utils → publish/Utils}/useKeyPress.d.ts +0 -0
  550. /package/{Utils → publish/Utils}/useKeyPress.js +0 -0
  551. /package/{Utils → publish/Utils}/useSessionStorageListener.d.ts +0 -0
  552. /package/{Utils → publish/Utils}/useSessionStorageListener.js +0 -0
  553. /package/{Utils → publish/Utils}/useStreamController.d.ts +0 -0
  554. /package/{Utils → publish/Utils}/useStreamController.js +0 -0
  555. /package/{Utils → publish/Utils}/useThrottle.d.ts +0 -0
  556. /package/{Utils → publish/Utils}/useThrottle.js +0 -0
  557. /package/{Utils → publish/Utils}/useWindowScroll.d.ts +0 -0
  558. /package/{Utils → publish/Utils}/useWindowScroll.js +0 -0
  559. /package/{Utils → publish/Utils}/validate.d.ts +0 -0
  560. /package/{Utils → publish/Utils}/validate.js +0 -0
  561. /package/{Utils → publish/Utils}/viewport.d.ts +0 -0
  562. /package/{Utils → publish/Utils}/viewport.js +0 -0
  563. /package/{all.d.ts → publish/all.d.ts} +0 -0
  564. /package/{all.js → publish/all.js} +0 -0
@@ -0,0 +1,3104 @@
1
+ import React, { useEffect, useState, useRef, KeyboardEvent, forwardRef, useImperativeHandle } from 'react';
2
+
3
+ import {
4
+ formatIndentVal,
5
+ removeItemOnce,
6
+ optionsCustomSelectFlat,
7
+ isObject
8
+ } from './utils/func';
9
+
10
+
11
+ import RootPortal from 'funda-root-portal';
12
+
13
+
14
+ import useComId from 'funda-utils/dist/cjs/useComId';
15
+ import {
16
+ isJSON
17
+ } from 'funda-utils/dist/cjs/validate';
18
+ import useDebounce from 'funda-utils/dist/cjs/useDebounce';
19
+ import useClickOutside from 'funda-utils/dist/cjs/useClickOutside';
20
+ import useWindowScroll from 'funda-utils/dist/cjs/useWindowScroll';
21
+ import {
22
+ convertArrToValByBrackets
23
+ } from 'funda-utils/dist/cjs/convert';
24
+ import {
25
+ getAbsolutePositionOfStage
26
+ } from 'funda-utils/dist/cjs/getElementProperty';
27
+ import {
28
+ addTreeDepth,
29
+ addTreeIndent,
30
+ } from 'funda-utils/dist/cjs/tree';
31
+ import {
32
+ getTextWidth
33
+ } from 'funda-utils/dist/cjs/inputsCalculation';
34
+ import {
35
+ removeArrDuplicateItems
36
+ } from 'funda-utils/dist/cjs/object';
37
+
38
+ // Destroys body scroll locking
39
+ import {
40
+ clearAllBodyScrollLocks,
41
+ disableBodyScroll,
42
+ enableBodyScroll,
43
+ } from 'funda-utils/dist/cjs/bodyScrollLock';
44
+ import {
45
+ stripTagsAndContent
46
+ } from 'funda-utils/dist/cjs/format-string';
47
+ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
48
+
49
+
50
+ export interface MultiSelectValue {
51
+ items: { label: string; value: string }[];
52
+ labels: string[];
53
+ values: string[];
54
+ labelsOfString: string;
55
+ valuesOfString: string;
56
+ }
57
+
58
+ export type SelectOptionChangeFnType = (
59
+ element: HTMLElement,
60
+ valueElement: HTMLElement,
61
+ value: OptionConfig | MultiSelectValue
62
+ ) => void | Promise<void>;
63
+
64
+
65
+ export interface MultiSelectControlValConfig {
66
+ values: string[];
67
+ labels: string[];
68
+ }
69
+
70
+ export interface OptionConfig {
71
+ disabled?: boolean;
72
+ optgroup?: any[];
73
+ group?: boolean;
74
+ label: string;
75
+ listItemLabel?: string;
76
+ value: string | number | boolean;
77
+ queryString: string | number;
78
+ callback?: () => void | Promise<void>;
79
+ [key: string]: string | number | boolean | any[] | (() => void | Promise<void>) | undefined;
80
+ }
81
+
82
+
83
+ export interface MultiSelectConfig {
84
+ valid: boolean;
85
+ selectAll: boolean;
86
+ selectAllLabel?: string;
87
+ deselectAllLabel?: string;
88
+ }
89
+
90
+ export interface multiSelectSelectedItemOnlyStatusConfig {
91
+ itemsLabel?: string;
92
+ allItemsLabel?: string;
93
+ noneLabel?: string;
94
+ }
95
+
96
+
97
+
98
+ export interface ClearTriggerConfig {
99
+ valid: boolean;
100
+ clearValueLabel?: string;
101
+ }
102
+
103
+
104
+ export type SelectProps = {
105
+ contentRef?: React.ForwardedRef<any>; // could use "Array" on contentRef.current, such as contentRef.current[0], contentRef.current[1]
106
+ popupRef?: React.ForwardedRef<any>; // could use "Array" on popupRef.current, such as popupRef.current[0], popupRef.current[1]
107
+ wrapperClassName?: string;
108
+ controlClassName?: string;
109
+ controlExClassName?: string;
110
+ optionsExClassName?: string;
111
+ customScrollContainer?: string | HTMLElement | React.RefObject<HTMLElement>;
112
+ exceededSidePosOffset?: number;
113
+ clearIcon?: boolean;
114
+ renderOption?: (optionData: OptionConfig, index: number) => React.ReactNode;
115
+ multiSelect?: MultiSelectConfig;
116
+ multiSelectEntireAreaTrigger?: boolean;
117
+ multiSelectSelectedItemOnlyStatus?: multiSelectSelectedItemOnlyStatusConfig;
118
+ renderSelectedValue?: (selectedData: MultiSelectControlValConfig, removeFunc: (e: React.MouseEvent) => void) => React.ReactNode;
119
+ clearTrigger?: ClearTriggerConfig;
120
+ defaultValue?: string | OptionConfig | OptionConfig[];
121
+ value?: string | OptionConfig | OptionConfig[];
122
+ label?: React.ReactNode | string;
123
+ name?: string;
124
+ disabled?: any;
125
+ required?: any;
126
+ readOnly?: any;
127
+ placeholder?: string;
128
+ options?: OptionConfig[] | string;
129
+ lockBodyScroll?: boolean;
130
+ loader?: React.ReactNode;
131
+ hierarchical?: boolean;
132
+ indentation?: string;
133
+ doubleIndent?: boolean;
134
+ winWidth?: string | Function;
135
+ controlArrow?: React.ReactNode;
136
+ firstRequestAutoExec?: boolean;
137
+ fetchTrigger?: boolean;
138
+ /** Set the depth value of the control to control the display of the pop-up layer appear above.
139
+ * Please set it when multiple controls are used at the same time. */
140
+ depth?: number;
141
+ /** Incoming data, you can set the third parameter of `onFetch` */
142
+ data?: any;
143
+ /** Whether to use square brackets to save result and initialize default value */
144
+ extractValueByBrackets?: boolean;
145
+ /** -- */
146
+ id?: string;
147
+ autoComplete?: string;
148
+ autoCapitalize?: string;
149
+ spellCheck?: boolean;
150
+ style?: React.CSSProperties;
151
+ tabIndex?: number;
152
+ [key: `data-${string}`]: string | undefined;
153
+ fetchNoneInfo?: string;
154
+ fetchUpdate?: boolean;
155
+ fetchFuncAsync?: any;
156
+ fetchFuncMethod?: string;
157
+ fetchFuncMethodParams?: any[];
158
+ fetchCallback?: (data: OptionConfig[]) => OptionConfig[];
159
+ onFetch?: (
160
+ event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
161
+ element: HTMLElement,
162
+ value: string,
163
+ data: OptionConfig[],
164
+ incomingData: string | null | undefined
165
+ ) => void;
166
+ onLoad?: (
167
+ event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
168
+ element: HTMLElement,
169
+ value: string | null | undefined
170
+ ) => void;
171
+ onSelect?: (data: OptionConfig) => void | Promise<void>;
172
+ onChange?: SelectOptionChangeFnType | null;
173
+ onBlur?: (event: React.FocusEvent<HTMLElement>) => void;
174
+ onFocus?: (event: React.FocusEvent<HTMLElement>) => void;
175
+ onKeyPressed?: (
176
+ event: React.KeyboardEvent<HTMLElement>,
177
+ element: HTMLElement,
178
+ value: string
179
+ ) => void;
180
+ };
181
+
182
+
183
+ const Select = forwardRef((props: SelectProps, externalRef: any) => {
184
+ const {
185
+ contentRef,
186
+ popupRef,
187
+ wrapperClassName,
188
+ controlClassName,
189
+ controlExClassName,
190
+ optionsExClassName,
191
+ customScrollContainer,
192
+ exceededSidePosOffset,
193
+ clearIcon,
194
+ renderOption,
195
+ multiSelect,
196
+ multiSelectEntireAreaTrigger,
197
+ multiSelectSelectedItemOnlyStatus,
198
+ renderSelectedValue,
199
+ disabled,
200
+ required,
201
+ defaultValue,
202
+ value,
203
+ label,
204
+ name,
205
+ readOnly,
206
+ placeholder,
207
+ id,
208
+ autoComplete,
209
+ autoCapitalize,
210
+ spellCheck,
211
+ options,
212
+ clearTrigger,
213
+ loader,
214
+ lockBodyScroll,
215
+ hierarchical,
216
+ indentation,
217
+ doubleIndent,
218
+ style,
219
+ depth,
220
+ controlArrow,
221
+ winWidth,
222
+ tabIndex,
223
+ firstRequestAutoExec,
224
+ fetchTrigger,
225
+ fetchNoneInfo = 'No match yet',
226
+ fetchUpdate,
227
+ fetchFuncAsync,
228
+ fetchFuncMethod,
229
+ fetchFuncMethodParams,
230
+ data,
231
+ extractValueByBrackets,
232
+ fetchCallback,
233
+ onFetch,
234
+ onLoad,
235
+ onSelect,
236
+ onChange,
237
+ onBlur,
238
+ onFocus,
239
+ onKeyPressed,
240
+ ...attributes
241
+ } = props;
242
+
243
+
244
+ const QUERY_STRING_PLACEHOLDER = '------'; // Invalid parameters for the first automatic request
245
+ const DEPTH = depth || 1055; // the default value same as bootstrap
246
+ const MANUAL_REQ = typeof fetchTrigger !== 'undefined' && fetchTrigger === true ? true : false; // Manual requests
247
+ const LIVE_SEARCH_DISABLED = !MANUAL_REQ && typeof window !== 'undefined' && typeof (window as any)['funda-ui__Select-disable-livesearch'] !== 'undefined' ? true : false; // Globally disable real-time search functionality (only valid for non-dynamic requests)
248
+
249
+ const CLEAR_ICON = typeof clearIcon === 'undefined' ? true : clearIcon;
250
+ const FIRST_REQUEST_AUTO = typeof firstRequestAutoExec === 'undefined' ? true : firstRequestAutoExec;
251
+ const INPUT_READONLY = LIVE_SEARCH_DISABLED ? true : (typeof readOnly === 'undefined' ? null : readOnly);
252
+ const VALUE_BY_BRACKETS = typeof extractValueByBrackets === 'undefined' ? true : extractValueByBrackets;
253
+ const LOCK_BODY_SCROLL = typeof lockBodyScroll === 'undefined' ? false : lockBodyScroll;
254
+ const WIN_WIDTH = typeof winWidth === 'function' ? winWidth() : winWidth ? winWidth : 'auto';
255
+ const INDENT_PLACEHOLDER = doubleIndent ? `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` : `&nbsp;&nbsp;&nbsp;&nbsp;`;
256
+ const INDENT_LAST_PLACEHOLDER = `${typeof indentation !== 'undefined' && indentation !== '' ? `${indentation}&nbsp;&nbsp;` : ''}`;
257
+ const POS_OFFSET = 0;
258
+ const EXCEEDED_SIDE_POS_OFFSET = Number(exceededSidePosOffset) || 15;
259
+ const uniqueID = useComId();
260
+ const idRes = id || uniqueID;
261
+ const rootRef = useRef<any>(null);
262
+ const rootMultiRef = useRef<any>(null);
263
+ const selectInputRef = useRef<any>(null);
264
+ const valueInputRef = useRef<any>(null);
265
+ const listRef = useRef<any>(null);
266
+ const listContentRef = useRef<any>(null);
267
+ const optionsRes = options ? (isJSON(options) ? JSON.parse(options as string) : options) : [];
268
+ const LIST_CONTAINER_MAX_HEIGHT = 300;
269
+ const MIN_SPACE_FOR_DROPDOWN = 200; // Minimum space needed to show dropdown below trigger
270
+
271
+ const keyboardSelectedItem = useRef<any>(null);
272
+
273
+
274
+ // loading
275
+ const [fetchLoading, setFetchLoading] = useState<boolean>(false);
276
+ const loadingOutput = <><div className="cus-select-loader">{loader || <svg height="12px" width="12px" viewBox="0 0 512 512"><g><path fill="inherit" d="M256,0c-23.357,0-42.297,18.932-42.297,42.288c0,23.358,18.94,42.288,42.297,42.288c23.357,0,42.279-18.93,42.279-42.288C298.279,18.932,279.357,0,256,0z" /><path fill="inherit" d="M256,427.424c-23.357,0-42.297,18.931-42.297,42.288C213.703,493.07,232.643,512,256,512c23.357,0,42.279-18.93,42.279-42.288C298.279,446.355,279.357,427.424,256,427.424z" /><path fill="inherit" d="M74.974,74.983c-16.52,16.511-16.52,43.286,0,59.806c16.52,16.52,43.287,16.52,59.806,0c16.52-16.511,16.52-43.286,0-59.806C118.261,58.463,91.494,58.463,74.974,74.983z" /><path fill="inherit" d="M377.203,377.211c-16.503,16.52-16.503,43.296,0,59.815c16.519,16.52,43.304,16.52,59.806,0c16.52-16.51,16.52-43.295,0-59.815C420.489,360.692,393.722,360.7,377.203,377.211z" /><path fill="inherit" d="M84.567,256c0.018-23.348-18.922-42.279-42.279-42.279c-23.357-0.009-42.297,18.932-42.279,42.288c-0.018,23.348,18.904,42.279,42.279,42.279C65.645,298.288,84.567,279.358,84.567,256z" /><path fill="inherit" d="M469.712,213.712c-23.357,0-42.279,18.941-42.297,42.288c0,23.358,18.94,42.288,42.297,42.297c23.357,0,42.297-18.94,42.279-42.297C512.009,232.652,493.069,213.712,469.712,213.712z" /><path fill="inherit" d="M74.991,377.22c-16.519,16.511-16.519,43.296,0,59.806c16.503,16.52,43.27,16.52,59.789,0c16.52-16.519,16.52-43.295,0-59.815C118.278,360.692,91.511,360.692,74.991,377.22z" /><path fill="inherit" d="M437.026,134.798c16.52-16.52,16.52-43.304,0-59.824c-16.519-16.511-43.304-16.52-59.823,0c-16.52,16.52-16.503,43.295,0,59.815C393.722,151.309,420.507,151.309,437.026,134.798z" /></g></svg>}</div></>;
277
+
278
+
279
+ // return a array of options
280
+ let staticOptionsData: OptionConfig[] = optionsRes;
281
+ const hasDefaultOptions = staticOptionsData.length > 0;
282
+
283
+ //
284
+ const [orginalData, setOrginalData] = useState<OptionConfig[]>(staticOptionsData);
285
+ const [optionsData, setOptionsData] = useState<OptionConfig[]>(staticOptionsData);
286
+ const [hasErr, setHasErr] = useState<boolean>(false);
287
+
288
+ // Set the final result
289
+ const [controlLabel, setControlLabel] = useState<string | undefined>('');
290
+ const [controlValue, setControlValue] = useState<string | undefined>('');
291
+
292
+ //
293
+ const [controlTempValue, setControlTempValue] = useState<string | null>(null); // Storage for temporary input
294
+ const [isOpen, setIsOpen] = useState<boolean>(false);
295
+ const [incomingData, setIncomingData] = useState<string | null | undefined>(null);
296
+ const [firstRequestExecuted, setFirstRequestExecuted] = useState<boolean>(false);
297
+ const [handleFirstFetchCompleted, setHandleFirstFetchCompleted] = useState<boolean>(false);
298
+
299
+ // Mark whether it is out of focus
300
+ // Fixed the issue that caused the pop-up window to still display due to
301
+ // the delayed close in handleBlur and the timing of the call to popwinPosInit
302
+ const isBlurringRef = useRef<boolean>(false);
303
+
304
+ // filter status
305
+ const [filterItemsHasNoMatchData, setFilterItemsHasNoMatchData] = useState<boolean>(false);
306
+
307
+
308
+ // blinking cursor
309
+ const BLINKING_CURSOR_STR = '|';
310
+ const [blinkingPosStart, setBlinkingPosStart] = useState<number>(0);
311
+ const blinkingPosFauxRef = useRef<any>(null);
312
+ const blinkingCursorPosDivRef = useRef<any>(null);
313
+
314
+ // Select All status (for "Single selection")
315
+ const [userInputboxIsAllSelected, setUserInputboxIsAllSelected] = useState(false);
316
+
317
+
318
+
319
+ const selectedSign = useRef<boolean>(false);
320
+ const MULTI_SEL_VALID = multiSelect ? multiSelect.valid : false;
321
+ const MULTI_SEL_ENTIRE_AREA_TRIGGER = typeof multiSelectEntireAreaTrigger === 'undefined' ? true : multiSelectEntireAreaTrigger;
322
+ const MULTI_SEL_LABEL = multiSelect ? multiSelect.selectAllLabel : 'Select all';
323
+ const MULTI_DESEL_LABEL = multiSelect ? multiSelect.deselectAllLabel : 'Deselect all';
324
+ const MULTI_SEL_SELECTED_STATUS: Record<string, string> = {
325
+ itemsLabel: '{num} Selected',
326
+ allItemsLabel: 'All Content ({num})',
327
+ noneLabel: 'No items selected',
328
+ };
329
+
330
+ const [controlArr, setControlArr] = useState<MultiSelectControlValConfig>({
331
+ labels: [],
332
+ values: []
333
+ });
334
+
335
+
336
+
337
+ // Only single symbols such as , #, and @ are allowed, and , a, a, , etc. are not allowed.
338
+ const isSingleSpecialChar = (str: string) => {
339
+ return typeof str === 'string' && /^[^\w\s]$/.test(str);
340
+ };
341
+
342
+
343
+ const chkValueExist = (v: any) => {
344
+ return typeof v !== 'undefined' && v !== '';
345
+ };
346
+
347
+
348
+ const listContainerHeightLimit = (num: number) => {
349
+ let res = num;
350
+ if (res > LIST_CONTAINER_MAX_HEIGHT) res = LIST_CONTAINER_MAX_HEIGHT;
351
+
352
+ // Avoid the height of the child div containing decimal points and scrollbars
353
+ res = res + 1;
354
+
355
+ return res;
356
+ };
357
+
358
+ const multiSelControlOptionExist = (arr: any[], val: any) => {
359
+ const _data = arr.filter(Boolean);
360
+ return _data.map((v: any) => v.toString()).includes(val.toString());
361
+ };
362
+
363
+ // clear trigger
364
+ const CLEAR_TRIGGER_VALID = typeof clearTrigger === 'undefined' ? false : (clearTrigger ? clearTrigger.valid : false);
365
+ const CLEAR_TRIGGER_LABEL = clearTrigger ? clearTrigger.clearValueLabel : 'Clear';
366
+
367
+
368
+ const optionsFormatGroupOpt = (allData: any[]) => {
369
+ allData.forEach((item: any) => {
370
+ if (typeof item.optgroup !== 'undefined') {
371
+ item.value = String(Math.random());
372
+ }
373
+ });
374
+ };
375
+
376
+ const finalRes = (val: any) => {
377
+ return isObject(val) ? val.value : val;
378
+ };
379
+
380
+ // exposes the following methods
381
+ useImperativeHandle(
382
+ popupRef,
383
+ () => ({
384
+ close: () => {
385
+ cancel();
386
+
387
+ if (MULTI_SEL_VALID) popwinPosHide();
388
+ },
389
+ open: () => {
390
+ activate();
391
+ },
392
+
393
+ }),
394
+ [popupRef],
395
+ );
396
+
397
+ useImperativeHandle(
398
+ contentRef,
399
+ () => ({
400
+ active: () => {
401
+ handleShowList();
402
+ selectInputRef.current?.select();
403
+ },
404
+
405
+ focus: () => {
406
+ selectInputRef.current?.select();
407
+ },
408
+ clear: (cb?: any) => {
409
+
410
+ if (MULTI_SEL_VALID) {
411
+ updateOptionCheckboxes('remove');
412
+
413
+ //
414
+ if (typeof onChange === 'function') {
415
+ onChange(
416
+ selectInputRef.current,
417
+ valueInputRef.current,
418
+ multipleSelectionCallback([], [])
419
+ );
420
+ }
421
+ } else {
422
+ handleClearValue();
423
+ }
424
+
425
+ selectInputRef.current?.blur();
426
+
427
+ cb?.();
428
+ },
429
+ /*
430
+ set([{"label": "Option 1","listItemLabel":"Option 1 (No: 001)","value": "value-1","queryString": "option1"}], () => { console.log('callback') }])
431
+ */
432
+ set: (value: any, cb?: any) => {
433
+
434
+ if (MULTI_SEL_VALID) {
435
+ updateOptionCheckboxesViaAddSingleItem({
436
+ labels: value.map((v: any) => v.label),
437
+ values: value.map((v: any) => v.value)
438
+ });
439
+
440
+ //
441
+ if (typeof onChange === 'function') {
442
+ onChange(
443
+ selectInputRef.current,
444
+ valueInputRef.current,
445
+ multipleSelectionCallback(
446
+ value.map((v: any) => v.value),
447
+ value.map((v: any) => v.label)
448
+ )
449
+ );
450
+ }
451
+ } else {
452
+ const _val = value[0];
453
+ handleSelect(null, (typeof _val === 'object' ? JSON.stringify(_val) : _val), [`${_val.value}`], [`${_val.label}`]);
454
+
455
+ //
456
+ if (typeof onChange === 'function') {
457
+ onChange(
458
+ selectInputRef.current,
459
+ valueInputRef.current,
460
+ _val
461
+ );
462
+ }
463
+ }
464
+
465
+
466
+ cb?.();
467
+ }
468
+ }),
469
+ [contentRef, selectInputRef],
470
+ );
471
+
472
+
473
+
474
+ // click outside
475
+ useClickOutside({
476
+ enabled: isOpen && rootRef.current && listRef.current,
477
+ isOutside: (event: any) => {
478
+
479
+ // close dropdown when other dropdown is opened
480
+ return (
481
+ (rootRef.current !== event.target && !rootRef.current.contains(event.target as HTMLElement)) &&
482
+ listRef.current !== event.target && !listRef.current.contains(event.target as HTMLElement)
483
+ )
484
+
485
+ },
486
+ handle: (event: any) => {
487
+ // cancel
488
+ cancel();
489
+ if (MULTI_SEL_VALID) popwinPosHide();
490
+ }
491
+ }, [isOpen, rootRef, listRef]);
492
+
493
+
494
+
495
+ // Add function to the element that should be used as the scrollable area.
496
+ const [scrollData, windowScrollUpdate] = useWindowScroll({
497
+ performance: ['debounce', 500], // "['debounce', 500]" or "['throttle', 500]"
498
+ handle: (scrollData: any) => {
499
+ // remove data-* attibutes
500
+ popwinContainerHeightReset();
501
+ }
502
+ });
503
+
504
+
505
+ // value of multiple selection callback
506
+ const multipleSelectionCallback = (valuesRes: any[], labelsRes: any[]) => {
507
+ return {
508
+ items: valuesRes.map((v: any, i: number) => (
509
+ {label: labelsRes[i].toString(), value: v.toString()}
510
+ )),
511
+ labels: labelsRes.map((v: any) => v.toString()),
512
+ values: valuesRes.map((v: any) => v.toString()),
513
+ labelsOfString: VALUE_BY_BRACKETS ? convertArrToValByBrackets(labelsRes.map((v: any) => v.toString())) : labelsRes.map((v: any) => v.toString()).join(','),
514
+ valuesOfString: VALUE_BY_BRACKETS ? convertArrToValByBrackets(valuesRes.map((v: any) => v.toString())) : valuesRes.map((v: any) => v.toString()).join(',')
515
+ };
516
+ };
517
+
518
+
519
+ //performance
520
+ const handleChangeFetchSafe = useDebounce((val: any) => {
521
+
522
+ setFetchLoading(true);
523
+
524
+ if (fetchUpdate) {
525
+
526
+ // update filter status
527
+ setFilterItemsHasNoMatchData(false);
528
+
529
+
530
+ // Make a request
531
+ handleFetch(val).then((response: any) => {
532
+
533
+ // pop win initalization
534
+ setTimeout(() => {
535
+ popwinPosInit();
536
+ popwinFilterItems(val);
537
+
538
+ }, 0);
539
+
540
+ setFetchLoading(false);
541
+ });
542
+ } else {
543
+
544
+
545
+ // pop win initalization
546
+ setTimeout(() => {
547
+ popwinPosInit();
548
+ popwinFilterItems(val);
549
+ }, 0);
550
+
551
+ setFetchLoading(false);
552
+
553
+ }
554
+
555
+
556
+ }, 350, [optionsData]);
557
+
558
+ async function fetchData(params: any, valueToInputDefault: any, inputDefault: any, init: boolean = true) {
559
+
560
+
561
+ // Determine whether the default value is user query input or default input
562
+ const defaultValue = init ? valueToInputDefault : '';
563
+
564
+ if (typeof fetchFuncAsync === 'object') {
565
+
566
+
567
+ const response: any = await fetchFuncAsync[`${fetchFuncMethod}`](...params.split(','));
568
+ let _ORGIN_DATA = response.data;
569
+
570
+
571
+ // reset data structure
572
+ if (typeof (fetchCallback) === 'function') {
573
+ _ORGIN_DATA = fetchCallback(_ORGIN_DATA);
574
+ }
575
+
576
+ // Determine whether the data structure matches
577
+ if (_ORGIN_DATA.length > 0 && typeof _ORGIN_DATA[0].value === 'undefined') {
578
+ console.warn('The data structure does not match, please refer to the example in the component documentation.');
579
+ setHasErr(true);
580
+ _ORGIN_DATA = [];
581
+ }
582
+
583
+
584
+ // STEP 1: ===========
585
+ // Set hierarchical categories ( with sub-categories )
586
+ if (hierarchical) {
587
+ _ORGIN_DATA = addTreeDepth(_ORGIN_DATA);
588
+ addTreeIndent(_ORGIN_DATA, INDENT_PLACEHOLDER, INDENT_LAST_PLACEHOLDER, 'label');
589
+ }
590
+
591
+
592
+ // STEP 2: ===========
593
+ // Flatten the group
594
+ _ORGIN_DATA = optionsCustomSelectFlat(_ORGIN_DATA);
595
+
596
+
597
+
598
+
599
+ // STEP 3: ===========
600
+ // value & label must be initialized
601
+ let filterRes: any = [];
602
+ // If the default value is label, match value
603
+ const filterResQueryValue = _ORGIN_DATA.filter((item: any) => item.value == defaultValue);
604
+ const filterResQueryLabel = _ORGIN_DATA.filter((item: any) => item.label == defaultValue);
605
+
606
+ filterRes = filterResQueryValue;
607
+ if (filterResQueryValue.length === 0) filterRes = filterResQueryLabel;
608
+
609
+ // if the default value is Object
610
+ if (isObject(inputDefault) && filterRes.length === 0) {
611
+ filterRes = [inputDefault];
612
+ }
613
+
614
+
615
+ // STEP 4: ===========
616
+ // ++++++++++++++++++++
617
+ // Single selection
618
+ // ++++++++++++++++++++
619
+ if (!chkValueExist(defaultValue)) { // Do not use `init`, otherwise the query will revert to the default value if there is no value
620
+ setControlValue('');
621
+ setControlLabel('');
622
+ } else {
623
+ if (filterRes.length > 0) {
624
+ setControlValue(filterRes[0].value);
625
+ setControlLabel(formatIndentVal(filterRes[0].label, INDENT_LAST_PLACEHOLDER) as string);
626
+ }
627
+
628
+ }
629
+
630
+
631
+ // ++++++++++++++++++++
632
+ // Multiple selection
633
+ // ++++++++++++++++++++
634
+ if (MULTI_SEL_VALID) {
635
+
636
+
637
+ if (!chkValueExist(defaultValue) && init) {
638
+ setControlArr({
639
+ labels: [],
640
+ values: []
641
+ });
642
+ }
643
+
644
+
645
+
646
+ if (chkValueExist(defaultValue) && Array.isArray(defaultValue)) {
647
+
648
+ // initialize default values of Multiple selection
649
+ const _currentData: OptionConfig[] = defaultValue;
650
+ const _defaultValues = _currentData.map((v: OptionConfig) => v.value as string);
651
+ const _defaultLabels = _currentData.map((v: OptionConfig) => v.label as string);
652
+
653
+ setControlArr({
654
+ labels: _defaultLabels,
655
+ values: _defaultValues,
656
+ });
657
+
658
+ }
659
+
660
+ // Appropriate multi-item container height
661
+ setTimeout(() => {
662
+ adjustMultiControlContainerHeight();
663
+ }, 0);
664
+
665
+
666
+ // hide disabled item
667
+ _ORGIN_DATA = _ORGIN_DATA.filter((v: any) => typeof v.disabled !== 'undefined' && v.disabled == true ? false : true);
668
+
669
+ }
670
+
671
+ // STEP 5: ===========
672
+ //
673
+ // remove Duplicate objects from JSON Array
674
+ optionsFormatGroupOpt(_ORGIN_DATA); // prevent the value from being filtered out
675
+ _ORGIN_DATA = removeArrDuplicateItems(_ORGIN_DATA, 'value');
676
+
677
+ setOptionsData(_ORGIN_DATA); // data must be initialized
678
+
679
+ //
680
+ setOrginalData(_ORGIN_DATA);
681
+
682
+
683
+ // STEP 6: ===========
684
+ //
685
+ onFetch?.(selectInputRef.current, valueInputRef.current, defaultValue, _ORGIN_DATA, incomingData);
686
+
687
+
688
+
689
+ //
690
+ return _ORGIN_DATA;
691
+
692
+
693
+ } else {
694
+
695
+
696
+ // STEP 1: ===========
697
+ // Set hierarchical categories ( with sub-categories )
698
+ if (hierarchical) {
699
+ staticOptionsData = addTreeDepth(staticOptionsData);
700
+ addTreeIndent(staticOptionsData, INDENT_PLACEHOLDER, INDENT_LAST_PLACEHOLDER, 'label');
701
+ }
702
+
703
+
704
+ // STEP 2: ===========
705
+ // Flatten the group
706
+ staticOptionsData = optionsCustomSelectFlat(staticOptionsData);
707
+
708
+
709
+ // STEP 3: ===========
710
+ // If the default value is label, match value
711
+ let filterRes: any = [];
712
+ const filterResQueryValue = staticOptionsData.filter((item: any) => item.value == defaultValue);
713
+ const filterResQueryLabel = staticOptionsData.filter((item: any) => item.label == defaultValue);
714
+
715
+ filterRes = filterResQueryValue;
716
+ if (filterResQueryValue.length === 0) filterRes = filterResQueryLabel;
717
+
718
+
719
+ // if the default value is Object
720
+ if (isObject(inputDefault) && filterRes.length === 0) {
721
+ filterRes = [inputDefault];
722
+ }
723
+
724
+
725
+
726
+ // STEP 4: ===========
727
+ // ++++++++++++++++++++
728
+ // Single selection
729
+ // ++++++++++++++++++++
730
+ if (!chkValueExist(defaultValue)) { // Do not use `init`, otherwise the query will revert to the default value if there is no value
731
+ setControlValue('');
732
+ setControlLabel('');
733
+ } else {
734
+ if (filterRes.length > 0) {
735
+ setControlValue(filterRes[0].value);
736
+ setControlLabel(formatIndentVal(filterRes[0].label, INDENT_LAST_PLACEHOLDER));
737
+ }
738
+
739
+ }
740
+
741
+
742
+
743
+ // ++++++++++++++++++++
744
+ // Multiple selection
745
+ // ++++++++++++++++++++
746
+ if (MULTI_SEL_VALID) {
747
+
748
+
749
+ if (!chkValueExist(defaultValue) && init) {
750
+ setControlArr({
751
+ labels: [],
752
+ values: []
753
+ });
754
+ }
755
+
756
+ if (chkValueExist(defaultValue) && Array.isArray(defaultValue)) {
757
+
758
+ // initialize default values of Multiple selection
759
+ const _currentData: OptionConfig[] = defaultValue;
760
+ const _defaultValues = _currentData.map((v: OptionConfig) => v.value as string);
761
+ const _defaultLabels = _currentData.map((v: OptionConfig) => v.label as string);
762
+
763
+ setControlArr({
764
+ labels: _defaultLabels,
765
+ values: _defaultValues,
766
+ });
767
+ }
768
+
769
+ // Appropriate multi-item container height
770
+ setTimeout(() => {
771
+ adjustMultiControlContainerHeight();
772
+ }, 0);
773
+
774
+
775
+ // hide disabled item
776
+ staticOptionsData = staticOptionsData.filter((v: any) => typeof v.disabled !== 'undefined' && v.disabled == true ? false : true);
777
+
778
+ }
779
+
780
+ // STEP 5: ===========
781
+ //
782
+ // remove Duplicate objects from JSON Array
783
+ optionsFormatGroupOpt(staticOptionsData); // prevent the value from being filtered out
784
+ staticOptionsData = removeArrDuplicateItems(staticOptionsData, 'value');
785
+
786
+
787
+ setOptionsData(staticOptionsData); // data must be initialized
788
+
789
+ //
790
+ setOrginalData(staticOptionsData);
791
+
792
+ // STEP 6: ===========
793
+ //
794
+ onFetch?.(selectInputRef.current, valueInputRef.current, defaultValue, staticOptionsData, incomingData);
795
+
796
+
797
+ //
798
+ return staticOptionsData;
799
+ }
800
+
801
+
802
+ }
803
+
804
+
805
+ function adjustMultiControlContainerHeight(scrollbarInit: boolean = true) {
806
+ if (rootMultiRef.current === null) return;
807
+
808
+ setTimeout(() => {
809
+
810
+
811
+ // Sometimes you may get 0, you need to judge
812
+ if (MULTI_SEL_VALID && rootMultiRef.current.clientHeight > 0) {
813
+ rootRef.current.style.height = rootMultiRef.current.clientHeight + 'px';
814
+ }
815
+
816
+ // popwin position update
817
+ const _modalRef: any = document.querySelector(`#custom-select__options-wrapper-${idRes}`);
818
+ if (MULTI_SEL_VALID && _modalRef !== null && _modalRef.classList.contains('active')) {
819
+ popwinPosInit(scrollbarInit);
820
+ }
821
+
822
+
823
+ }, 0);
824
+ }
825
+
826
+ function syncListContentScrollBody() {
827
+ const el: any = listContentRef.current;
828
+ if (el === null) return;
829
+
830
+ const activedItem = el.querySelectorAll(`.list-group-item.${!MULTI_SEL_VALID ? 'active' : 'item-selected'}`)[0];
831
+ if (typeof activedItem !== 'undefined') {
832
+
833
+ const clearItem = el.querySelector(`.list-group-item.${!MULTI_SEL_VALID ? 'custom-select-multi__control-option-item--clear' : 'custom-select-multi__control-option-item--select-all'}`);
834
+ const clearItemHeight = clearItem === null ? 0 : clearItem.clientHeight;
835
+ const _latestScrollTop = activedItem.offsetTop - clearItemHeight;
836
+
837
+ el.scrollTop = _latestScrollTop;
838
+ }
839
+
840
+ }
841
+
842
+
843
+ function popwinPosInit(scrollbarInit: boolean = true) {
844
+ if (listContentRef.current === null || rootRef.current === null || selectInputRef.current === null) return;
845
+
846
+ // If it is out of focus, do not perform position initialization
847
+ if (isBlurringRef.current) return;
848
+
849
+ //
850
+ let contentMaxHeight = 0;
851
+
852
+ // update modal position
853
+ const _modalRef: any = document.querySelector(`#custom-select__options-wrapper-${idRes}`);
854
+ const _triggerRef: any = selectInputRef.current;
855
+ const _triggerXaxisRef: any = rootRef.current;
856
+
857
+ // console.log(getAbsolutePositionOfStage(_triggerRef));
858
+
859
+ if (_modalRef === null) return;
860
+
861
+ const { x } = getAbsolutePositionOfStage(_triggerXaxisRef);
862
+ const { y, width, height } = getAbsolutePositionOfStage(_triggerRef);
863
+ const _triggerBox = _triggerRef.getBoundingClientRect();
864
+ let targetPos = '';
865
+
866
+
867
+
868
+ // STEP 1:
869
+ //-----------
870
+ // display wrapper
871
+ _modalRef.classList.add('active');
872
+
873
+
874
+
875
+
876
+ // STEP 2:
877
+ //-----------
878
+ // Detect content MAX HEIGHT and ACTUAL HEIGHT
879
+ const _contentBox = listContentRef.current.getBoundingClientRect();
880
+ let _contentOldHeight = listContentRef.current.clientHeight;
881
+
882
+ // height restrictions
883
+ _contentOldHeight = listContainerHeightLimit(_contentOldHeight);
884
+
885
+ // You need to wait for the height of the pop-up container to be set
886
+ // Detect position
887
+ let containerHeight = window.innerHeight;
888
+ let containerTop = 0;
889
+
890
+ // If custom scroll container is specified, use it instead of window
891
+ if (customScrollContainer) {
892
+ let customContainer: HTMLElement | null = null;
893
+
894
+ if (typeof customScrollContainer === 'string') {
895
+ // Handle selector string
896
+ customContainer = document.querySelector(customScrollContainer);
897
+ } else if (customScrollContainer instanceof HTMLElement) {
898
+ // Handle DOM element directly
899
+ customContainer = customScrollContainer;
900
+ } else if (customScrollContainer && 'current' in customScrollContainer) {
901
+ // Handle React ref
902
+ customContainer = customScrollContainer.current;
903
+ }
904
+
905
+ if (customContainer) {
906
+ const containerRect = customContainer.getBoundingClientRect();
907
+ containerHeight = containerRect.height;
908
+ containerTop = containerRect.top;
909
+ }
910
+ }
911
+
912
+ // Calculate available space below the trigger
913
+ const availableSpaceBelow = containerHeight - (_triggerBox.top - containerTop);
914
+
915
+ // Use a more reasonable threshold for position decision
916
+ // Consider the minimum space needed for a usable dropdown
917
+ if (availableSpaceBelow > MIN_SPACE_FOR_DROPDOWN) {
918
+ targetPos = 'bottom';
919
+ } else {
920
+ targetPos = 'top';
921
+ }
922
+
923
+ if (typeof listContentRef.current.dataset.pos === 'undefined') listContentRef.current.dataset.pos = targetPos;
924
+
925
+
926
+
927
+ // STEP 3:
928
+ //-----------
929
+ // Set the pop-up height
930
+ if (targetPos === 'top') {
931
+ // Calculate available space above the trigger
932
+ const availableSpaceAbove = _triggerBox.top - containerTop;
933
+ contentMaxHeight = availableSpaceAbove;
934
+
935
+ // height restrictions
936
+ contentMaxHeight = listContainerHeightLimit(contentMaxHeight);
937
+
938
+ // Calculate the final height with minimum height protection
939
+ const contentHeightOffset = 0;
940
+ const finalHeight = Math.max(contentMaxHeight - contentHeightOffset, 150); // Ensure minimum height of 150px
941
+
942
+ if (_contentBox.height > contentMaxHeight) {
943
+ listContentRef.current.style.height = finalHeight + 'px';
944
+ if (typeof listContentRef.current.dataset.height === 'undefined') listContentRef.current.dataset.height = finalHeight;
945
+
946
+ // has scrollbar
947
+ listContentRef.current.dataset.hasScrollbar = 'true';
948
+
949
+
950
+ } else {
951
+ if (_contentOldHeight > 50) {
952
+ listContentRef.current.style.height = _contentOldHeight + 'px';
953
+ if (typeof listContentRef.current.dataset.height === 'undefined') listContentRef.current.dataset.height = _contentOldHeight;
954
+ }
955
+
956
+ // has scrollbar
957
+ listContentRef.current.dataset.hasScrollbar = 'false';
958
+
959
+ }
960
+ }
961
+
962
+ if (targetPos === 'bottom') {
963
+ // Calculate available space below the trigger
964
+ const availableSpaceBelow = containerHeight - (_triggerBox.bottom - containerTop);
965
+ contentMaxHeight = availableSpaceBelow;
966
+
967
+ // height restrictions
968
+ contentMaxHeight = listContainerHeightLimit(contentMaxHeight);
969
+
970
+ // Calculate the final height with minimum height protection
971
+ const contentHeightOffset = 10;
972
+ const finalHeight = Math.max(contentMaxHeight - contentHeightOffset, 150); // Ensure minimum height of 150px
973
+
974
+ if (_contentBox.height > contentMaxHeight) {
975
+ listContentRef.current.style.height = finalHeight + 'px';
976
+ if (typeof listContentRef.current.dataset.height === 'undefined') listContentRef.current.dataset.height = finalHeight;
977
+
978
+ // has scrollbar
979
+ listContentRef.current.dataset.hasScrollbar = 'true';
980
+
981
+ } else {
982
+ if (_contentOldHeight > 50) {
983
+ listContentRef.current.style.height = _contentOldHeight + 'px';
984
+ if (typeof listContentRef.current.dataset.height === 'undefined') listContentRef.current.dataset.height = _contentOldHeight;
985
+ }
986
+
987
+ // has scrollbar
988
+ listContentRef.current.dataset.hasScrollbar = 'false';
989
+
990
+ }
991
+
992
+ }
993
+
994
+
995
+ // STEP 4:
996
+ //-----------
997
+ // Adjust position
998
+ if (targetPos === 'top') {
999
+ _modalRef.style.left = x + 'px';
1000
+ //_modalRef.style.top = y - POS_OFFSET - (listRef.current.clientHeight) - 2 + 'px';
1001
+ _modalRef.style.top = 'auto';
1002
+ _modalRef.style.bottom = (window.innerHeight - _triggerBox.top) + POS_OFFSET + 2 + 'px';
1003
+ _modalRef.style.setProperty('position', 'fixed', 'important');
1004
+ _modalRef.classList.add('pos-top');
1005
+
1006
+ }
1007
+
1008
+ if (targetPos === 'bottom') {
1009
+ _modalRef.style.left = x + 'px';
1010
+ _modalRef.style.bottom = 'auto';
1011
+ _modalRef.style.top = y + height + POS_OFFSET + 'px';
1012
+ _modalRef.style.setProperty('position', 'absolute', 'important');
1013
+ _modalRef.classList.remove('pos-top');
1014
+ }
1015
+
1016
+
1017
+
1018
+ // STEP 5:
1019
+ //-----------
1020
+ // Determine whether it exceeds the far right or left side of the screen
1021
+ const _modalContent = _modalRef;
1022
+ const _modalBox = _modalContent.getBoundingClientRect();
1023
+ if (typeof _modalContent.dataset.offset === 'undefined' && _modalBox.left > 0) {
1024
+
1025
+ // Get container width for boundary checking
1026
+ let containerWidth = window.innerWidth;
1027
+ let containerLeft = 0;
1028
+
1029
+ if (customScrollContainer) {
1030
+ let customContainer: HTMLElement | null = null;
1031
+
1032
+ if (typeof customScrollContainer === 'string') {
1033
+ // Handle selector string
1034
+ customContainer = document.querySelector(customScrollContainer);
1035
+ } else if (customScrollContainer instanceof HTMLElement) {
1036
+ // Handle DOM element directly
1037
+ customContainer = customScrollContainer;
1038
+ } else if (customScrollContainer && 'current' in customScrollContainer) {
1039
+ // Handle React ref
1040
+ customContainer = customScrollContainer.current;
1041
+ }
1042
+
1043
+ if (customContainer) {
1044
+ const containerRect = customContainer.getBoundingClientRect();
1045
+ containerWidth = containerRect.width;
1046
+ containerLeft = containerRect.left;
1047
+ }
1048
+ }
1049
+
1050
+ // 10 pixels is used to account for some bias in mobile devices
1051
+ if ((_modalBox.right + 10) > (containerLeft + containerWidth)) {
1052
+ const _modalOffsetPosition = _modalBox.right - (containerLeft + containerWidth) + EXCEEDED_SIDE_POS_OFFSET;
1053
+ _modalContent.dataset.offset = _modalOffsetPosition;
1054
+ _modalContent.style.marginLeft = `-${_modalOffsetPosition}px`;
1055
+ // console.log('_modalPosition: ', _modalOffsetPosition)
1056
+ }
1057
+
1058
+ if ((_modalBox.left - 10) < containerLeft) {
1059
+ const _modalOffsetPosition = Math.abs(_modalBox.left - containerLeft) + EXCEEDED_SIDE_POS_OFFSET;
1060
+ _modalContent.dataset.offset = _modalOffsetPosition;
1061
+ _modalContent.style.marginLeft = `${_modalOffsetPosition}px`;
1062
+ // console.log('_modalPosition: ', _modalOffsetPosition)
1063
+ }
1064
+
1065
+ }
1066
+
1067
+
1068
+
1069
+
1070
+ // STEP 6:
1071
+ //-----------
1072
+ // no data label
1073
+ popwinNoMatchInit();
1074
+
1075
+
1076
+
1077
+ // STEP 7:
1078
+ //-----------
1079
+ // Scrollbar position synchronization
1080
+ if (scrollbarInit) syncListContentScrollBody();
1081
+
1082
+
1083
+
1084
+ }
1085
+
1086
+
1087
+ function popwinPosHide() {
1088
+
1089
+ const _modalRef: any = document.querySelector(`#custom-select__options-wrapper-${idRes}`);
1090
+
1091
+ if (_modalRef !== null && listContentRef.current !== null) {
1092
+
1093
+
1094
+ // remove classnames and styles
1095
+ _modalRef.classList.remove('active');
1096
+ listContentRef.current.style.removeProperty('height');
1097
+
1098
+ // remove data-* attibutes
1099
+ popwinContainerHeightReset();
1100
+
1101
+
1102
+ // display all filtered items
1103
+ const _items = [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item'));
1104
+ _items.forEach((node: any) => {
1105
+ node.classList.remove('hide');
1106
+ });
1107
+
1108
+
1109
+ // nomatch & button of select all
1110
+ const _noDataDiv = listContentRef.current.querySelector('.custom-select-multi__control-option-item--nomatch');
1111
+ const _btnSelectAll = listContentRef.current.querySelector('.custom-select-multi__control-option-item--select-all');
1112
+ _noDataDiv.classList.add('hide');
1113
+ if (_btnSelectAll !== null) _btnSelectAll.classList.remove('hide');
1114
+
1115
+
1116
+ }
1117
+
1118
+
1119
+ }
1120
+
1121
+
1122
+ function popwinFilterItems(val: any) {
1123
+ if (listContentRef.current === null) return;
1124
+
1125
+ [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item')).forEach((node: any) => {
1126
+
1127
+ // Avoid fatal errors causing page crashes
1128
+ const _queryString = typeof node.dataset.querystring !== 'undefined' && node.dataset.querystring !== null ? node.dataset.querystring : '';
1129
+ const _val = typeof val !== 'undefined' && val !== null ? val : '';
1130
+
1131
+
1132
+ // STEP 1
1133
+ //========
1134
+ // @@@ This code is triggered only if a custom request is used to update "options" @@@
1135
+ // If the condition is true, skip the loop and move on to the next node.
1136
+ if (fetchUpdate && _val == ' ') {
1137
+ return;
1138
+ }
1139
+
1140
+
1141
+ // STEP 2
1142
+ //========
1143
+ // @@@ This code is triggered only if a custom request is used to update "options" @@@
1144
+ // If the condition is true, skip the loop and move on to the next node.
1145
+ if (fetchUpdate && _val != '' && isSingleSpecialChar(_val)) {
1146
+ return;
1147
+ }
1148
+
1149
+
1150
+ // STEP 3
1151
+ //========
1152
+ if (
1153
+ (
1154
+ _queryString.split(',').some((l: any) => l.charAt(0) === _val.toLowerCase()) ||
1155
+ _queryString.split(',').some((l: any) => l.replace(/ /g, '').indexOf(_val.toLowerCase()) >= 0) ||
1156
+ node.dataset.label.toLowerCase().indexOf(_val.toLowerCase()) >= 0
1157
+ ) &&
1158
+ _val != ''
1159
+ ) {
1160
+ node.classList.remove('hide');
1161
+ } else {
1162
+ node.classList.add('hide');
1163
+ }
1164
+
1165
+ });
1166
+
1167
+ // Determine if all options are hidden
1168
+ const allHidden = [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item'))
1169
+ .every((node: any) => node.classList.contains('hide'));
1170
+
1171
+
1172
+ // no data label
1173
+ popwinNoMatchInit();
1174
+
1175
+
1176
+ // display all filtered items
1177
+ const _btnSelectAll = listContentRef.current.querySelector('.custom-select-multi__control-option-item--select-all');
1178
+ const _noDataDiv = listContentRef.current.querySelector('.custom-select-multi__control-option-item--nomatch');
1179
+ if ((val === null ? '' : val).replace(/\s/g, "") === '') {
1180
+ [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item')).forEach((node: any) => {
1181
+ node.classList.remove('hide');
1182
+ });
1183
+ _noDataDiv.classList.add('hide');
1184
+ if (_btnSelectAll !== null) _btnSelectAll.classList.remove('hide');
1185
+ }
1186
+
1187
+ // filter status
1188
+ setFilterItemsHasNoMatchData(allHidden);
1189
+
1190
+
1191
+ // Appropriate list container height
1192
+ popwinContainerHeightAdjust();
1193
+
1194
+
1195
+ }
1196
+
1197
+ function popwinContainerHeightAdjust() {
1198
+ if (listContentRef.current === null) return;
1199
+
1200
+ let oldHeight = listContentRef.current.dataset.height;
1201
+ let filteredHeight = listContentRef.current.firstChild.clientHeight;
1202
+
1203
+ // height restrictions
1204
+ oldHeight = listContainerHeightLimit(oldHeight);
1205
+ filteredHeight = listContainerHeightLimit(filteredHeight);
1206
+
1207
+
1208
+ if (parseFloat(oldHeight) > filteredHeight) {
1209
+ listContentRef.current.style.height = filteredHeight + 'px';
1210
+ console.log('popwinContainerHeightAdjust - height changed to:', filteredHeight);
1211
+ } else {
1212
+ listContentRef.current.style.height = oldHeight + 'px';
1213
+ console.log('popwinContainerHeightAdjust - height kept as:', oldHeight);
1214
+ }
1215
+
1216
+ }
1217
+
1218
+
1219
+
1220
+
1221
+ function popwinNoMatchInit() {
1222
+ if (listContentRef.current === null) return;
1223
+
1224
+ const _btnSelectAll = listContentRef.current.querySelector('.custom-select-multi__control-option-item--select-all');
1225
+ const _noDataDiv = listContentRef.current.querySelector('.custom-select-multi__control-option-item--nomatch');
1226
+ const _items = [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item'));
1227
+ const itemsDoNotExist = _items.every((node: any) => {
1228
+ if (!node.classList.contains('hide')) {
1229
+ return false;
1230
+ }
1231
+ return true;
1232
+ });
1233
+
1234
+ if (itemsDoNotExist) {
1235
+ _noDataDiv.classList.remove('hide');
1236
+ if (_btnSelectAll !== null) _btnSelectAll.classList.add('hide');
1237
+ } else {
1238
+ _noDataDiv.classList.add('hide');
1239
+ if (_btnSelectAll !== null) _btnSelectAll.classList.remove('hide');
1240
+ }
1241
+
1242
+ }
1243
+
1244
+
1245
+ function popwinContainerHeightReset() {
1246
+ if (listContentRef.current === null) return;
1247
+
1248
+ // remove data-* attibutes
1249
+ listContentRef.current.removeAttribute('data-height');
1250
+ listContentRef.current.removeAttribute('data-pos');
1251
+
1252
+ //
1253
+ if (selectInputRef.current) selectInputRef.current.value = '';
1254
+
1255
+
1256
+ }
1257
+
1258
+
1259
+
1260
+ function cancel() {
1261
+ // hide list
1262
+ setIsOpen(false);
1263
+ if (!MULTI_SEL_VALID) popwinPosHide();
1264
+
1265
+ if (MANUAL_REQ) {
1266
+ // restore to static data
1267
+ setOptionsData(staticOptionsData);
1268
+ } else {
1269
+ setOptionsData(orginalData);
1270
+ }
1271
+
1272
+ // update temporary value
1273
+ setControlTempValue(null);
1274
+
1275
+ // update filter status
1276
+ setFilterItemsHasNoMatchData(false);
1277
+
1278
+
1279
+ // reset Select All status (for "Single selection")
1280
+ setUserInputboxIsAllSelected(false);
1281
+
1282
+
1283
+ // Unlocks the page
1284
+ if (LOCK_BODY_SCROLL) enableBodyScroll(document.querySelector('body'));
1285
+ }
1286
+
1287
+ function activate() {
1288
+
1289
+ // trigger the first asynchronous request when the options area is expanded
1290
+ if (!FIRST_REQUEST_AUTO && !firstRequestExecuted) {
1291
+ let curValue: any = defaultValue;
1292
+
1293
+ if (typeof curValue === 'undefined') {
1294
+ curValue = value;
1295
+ }
1296
+
1297
+ handleFirstFetch(curValue).then((response: any) => {
1298
+ if (response.length > 0) {
1299
+ // nomatch
1300
+ const _noDataDiv = listContentRef.current.querySelector('.custom-select-multi__control-option-item--nomatch');
1301
+ _noDataDiv.classList.add('hide');
1302
+
1303
+ // After the data is loaded, reinitialize the pop-up window position and height
1304
+ setTimeout(() => {
1305
+ popwinPosInit();
1306
+ }, 0);
1307
+ }
1308
+ });
1309
+
1310
+ //
1311
+ setFirstRequestExecuted(true);
1312
+ }
1313
+
1314
+ // show list
1315
+ setIsOpen(true);
1316
+
1317
+ // pop win initalization
1318
+ setTimeout(() => {
1319
+ popwinPosInit();
1320
+ }, 0);
1321
+
1322
+ // make sure the event handler is registered
1323
+ if (orginalData.length === 0) {
1324
+ setTimeout(() => {
1325
+ // no data label
1326
+ popwinNoMatchInit();
1327
+ }, 500);
1328
+
1329
+ }
1330
+
1331
+ if (MANUAL_REQ) {
1332
+ // display static data
1333
+ setOptionsData(staticOptionsData);
1334
+ } else {
1335
+ // restore data
1336
+ setOptionsData(orginalData);
1337
+ }
1338
+
1339
+
1340
+ // When you select multiple times, it automatically focuses on the search input box
1341
+ if (MULTI_SEL_VALID) {
1342
+ selectInputRef.current.select();
1343
+ }
1344
+
1345
+
1346
+ // Every time the input changes or the search button is clicked, a data request will be triggered
1347
+ // !!! If the default data is empty, the pop-up window is not displayed
1348
+ if (MANUAL_REQ && (controlTempValue === '' || controlTempValue === null) && !hasDefaultOptions) {
1349
+ setTimeout(() => {
1350
+ popwinPosHide();
1351
+ }, 0);
1352
+ }
1353
+
1354
+
1355
+ // update temporary value
1356
+ setControlTempValue('');
1357
+
1358
+
1359
+
1360
+
1361
+ // Locks the page
1362
+ //
1363
+ // Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
1364
+ // Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
1365
+ // This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
1366
+ if (LOCK_BODY_SCROLL) disableBodyScroll(document.querySelector('body'));
1367
+
1368
+
1369
+ }
1370
+
1371
+
1372
+ function fixFocusStatus() {
1373
+ // When selecting multiple times, in order to avoid losing
1374
+ if (MULTI_SEL_VALID) handleFocus(selectInputRef.current);
1375
+ }
1376
+
1377
+ async function handleSelect(el: any, dataInput: any = false, valueArr: any[] = [], labelArr: any[] = []) {
1378
+
1379
+ if (typeof el === 'undefined') return;
1380
+
1381
+ const curItem: any = el === null ? (isObject(dataInput) ? dataInput : JSON.parse(dataInput)) : optionsData[Number(el.currentTarget.dataset.index)];
1382
+
1383
+
1384
+ // get options
1385
+ const options = [].slice.call(listRef.current.querySelectorAll('.list-group-item:not(.hide):not(.no-match)'));
1386
+
1387
+
1388
+ // current control of some option
1389
+ const curBtn: any = options.filter((node: HTMLElement) => node.dataset.itemdata == JSON.stringify(curItem))[0];
1390
+
1391
+
1392
+ // Determine whether there is a callback
1393
+ const noCallback = typeof curItem.callback === 'undefined';
1394
+
1395
+ // ==========================================================================
1396
+ // Whether to cancel or not
1397
+ // ==========================================================================
1398
+ if (noCallback) {
1399
+ // cancel
1400
+ if (!MULTI_SEL_VALID) {
1401
+ cancel();
1402
+ }
1403
+
1404
+ //remove focus style
1405
+ if (!MULTI_SEL_VALID) {
1406
+ rootRef.current?.classList.remove('focus');
1407
+ }
1408
+ }
1409
+
1410
+
1411
+
1412
+ // update value * label
1413
+ if (dataInput) {
1414
+
1415
+ // ==========================================================================
1416
+ // Use the "keyboard" to trigger
1417
+ // ==========================================================================
1418
+
1419
+ const _data = isObject(dataInput) ? dataInput : JSON.parse(dataInput);
1420
+ const _value = _data.value;
1421
+ const _label = _data.label;
1422
+
1423
+ // ++++++++++++++++++++
1424
+ // Callback
1425
+ // ++++++++++++++++++++
1426
+ _data.callback?.();
1427
+
1428
+
1429
+ // ++++++++++++++++++++
1430
+ // Single selection
1431
+ // ++++++++++++++++++++
1432
+ // clear all active classes of options
1433
+ // (Avoid using the keyboard to select and two actives will appear after clicking on a non-selected option.)
1434
+ if (noCallback) {
1435
+ options.forEach((node: any) => {
1436
+ node.classList.remove('active');
1437
+ });
1438
+ }
1439
+
1440
+ // If there is a callback, delete the activated style
1441
+ if (!noCallback) {
1442
+ setTimeout(() => {
1443
+ curBtn.classList.remove('active', 'disabled');
1444
+ }, 0);
1445
+ }
1446
+
1447
+
1448
+
1449
+ //
1450
+ setControlValue(_value);
1451
+ setControlLabel(formatIndentVal(_label, INDENT_LAST_PLACEHOLDER));
1452
+
1453
+
1454
+ // ++++++++++++++++++++
1455
+ // Multiple selection
1456
+ // ++++++++++++++++++++
1457
+ let currentControlValueArr: any[] = JSON.parse(JSON.stringify(valueArr));
1458
+ let currentControlLabelArr: any[] = JSON.parse(JSON.stringify(labelArr));
1459
+
1460
+ if (MULTI_SEL_VALID) {
1461
+
1462
+ const $el = el === null ? curBtn : el.currentTarget;
1463
+
1464
+
1465
+ // update option checkboxes
1466
+ const _selected = $el.dataset.selected;
1467
+ const _selectedVal = _selected == 'true' ? true : false;
1468
+ if (_selectedVal) {
1469
+ //#########
1470
+ // remove item
1471
+ //#########
1472
+ $el.dataset.selected = 'false';
1473
+ $el.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.add('d-none');
1474
+ $el.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.remove('d-none');
1475
+
1476
+ //
1477
+ setControlArr((prevState: any) => {
1478
+
1479
+ // update temporary value
1480
+ setControlTempValue(prevState.labels.length >= 0 ? null : (VALUE_BY_BRACKETS ? convertArrToValByBrackets(prevState.labels) : prevState.labels.join(',')));
1481
+
1482
+ return {
1483
+ labels: removeItemOnce(prevState.labels, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER)),
1484
+ values: removeItemOnce(prevState.values, _value)
1485
+ }
1486
+ });
1487
+
1488
+
1489
+ currentControlValueArr = removeItemOnce(currentControlValueArr, _value);
1490
+ currentControlLabelArr = removeItemOnce(currentControlLabelArr, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER));
1491
+
1492
+
1493
+ } else {
1494
+ //#########
1495
+ // add item
1496
+ //#########
1497
+ $el.dataset.selected = 'true';
1498
+ $el.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.remove('d-none');
1499
+ $el.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.add('d-none');
1500
+
1501
+ //
1502
+ setControlArr((prevState: any) => {
1503
+
1504
+ // update temporary value
1505
+ setControlTempValue(prevState.labels.length >= 0 ? null : (VALUE_BY_BRACKETS ? convertArrToValByBrackets(prevState.labels) : prevState.labels.join(',')));
1506
+
1507
+ return {
1508
+ labels: [...prevState.labels, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER)],
1509
+ values: [...prevState.values, _value]
1510
+ }
1511
+ });
1512
+
1513
+ currentControlValueArr.push(_value);
1514
+ currentControlLabelArr.push(_label);
1515
+
1516
+ }
1517
+
1518
+ // Appropriate multi-item container height
1519
+ // !!!set `false` to prevents the scrollbar position from changing when multi-selecting the option is clicked
1520
+ adjustMultiControlContainerHeight(false);
1521
+
1522
+
1523
+ // active current option
1524
+ if (noCallback) {
1525
+ setTimeout(() => {
1526
+ $el.classList.add('active');
1527
+ }, 0);
1528
+
1529
+ }
1530
+
1531
+
1532
+
1533
+ }
1534
+
1535
+ //
1536
+ if (noCallback && typeof (onChange) === 'function') {
1537
+
1538
+ await onChange?.(
1539
+ selectInputRef.current,
1540
+ valueInputRef.current,
1541
+ !MULTI_SEL_VALID ? curItem : multipleSelectionCallback(currentControlValueArr, currentControlLabelArr)
1542
+ );
1543
+
1544
+
1545
+ //
1546
+ selectInputRef.current?.blur();
1547
+ }
1548
+
1549
+
1550
+
1551
+
1552
+ } else {
1553
+
1554
+ // ==========================================================================
1555
+ // Use the "mouse" to trigger
1556
+ // ==========================================================================
1557
+
1558
+ const _value = typeof curItem !== 'undefined' ? curItem.value : '';
1559
+ const _label = typeof curItem !== 'undefined' ? curItem.label : '';
1560
+
1561
+
1562
+
1563
+ // ++++++++++++++++++++
1564
+ // Callback
1565
+ // ++++++++++++++++++++
1566
+ curItem.callback?.();
1567
+
1568
+ // ++++++++++++++++++++
1569
+ // Single selection
1570
+ // ++++++++++++++++++++
1571
+
1572
+ // clear all active classes of options
1573
+ // (Avoid using the keyboard to select and two actives will appear after clicking on a non-selected option.)
1574
+ if (noCallback) {
1575
+ options.forEach((node: any) => {
1576
+ node.classList.remove('active');
1577
+ });
1578
+
1579
+ }
1580
+
1581
+
1582
+
1583
+ // If there is a callback, delete the activated style
1584
+ if (!noCallback) {
1585
+ setTimeout(() => {
1586
+ curBtn.classList.remove('active', 'disabled');
1587
+ }, 0);
1588
+ }
1589
+
1590
+
1591
+
1592
+ //
1593
+ setControlValue(_value);
1594
+ setControlLabel(formatIndentVal(_label, INDENT_LAST_PLACEHOLDER));
1595
+
1596
+
1597
+ // ++++++++++++++++++++
1598
+ // Multiple selection
1599
+ // ++++++++++++++++++++
1600
+ let currentControlValueArr: any[] = JSON.parse(JSON.stringify(controlArr.values));
1601
+ let currentControlLabelArr: any[] = JSON.parse(JSON.stringify(controlArr.labels));
1602
+
1603
+ if (MULTI_SEL_VALID) {
1604
+
1605
+
1606
+ const $el = el === null ? curBtn : el.currentTarget;
1607
+
1608
+
1609
+ // update option checkboxes
1610
+ const _selected = $el.dataset.selected;
1611
+ const _selectedVal = _selected == 'true' ? true : false;
1612
+ if (_selectedVal) {
1613
+ //#########
1614
+ // remove item
1615
+ //#########
1616
+ $el.dataset.selected = 'false';
1617
+ $el.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.add('d-none');
1618
+ $el.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.remove('d-none');
1619
+
1620
+
1621
+ //
1622
+ setControlArr((prevState: any) => {
1623
+
1624
+ // update temporary value
1625
+ setControlTempValue(prevState.labels.length >= 0 ? null : (VALUE_BY_BRACKETS ? convertArrToValByBrackets(prevState.labels) : prevState.labels.join(',')));
1626
+
1627
+ return {
1628
+ labels: removeItemOnce(prevState.labels, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER)),
1629
+ values: removeItemOnce(prevState.values, _value)
1630
+ }
1631
+ });
1632
+
1633
+ currentControlValueArr = removeItemOnce(currentControlValueArr, _value);
1634
+ currentControlLabelArr = removeItemOnce(currentControlLabelArr, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER));
1635
+
1636
+ } else {
1637
+ //#########
1638
+ // add item
1639
+ //#########
1640
+
1641
+ $el.dataset.selected = 'true';
1642
+ $el.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.remove('d-none');
1643
+ $el.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.add('d-none');
1644
+
1645
+
1646
+ //
1647
+ setControlArr((prevState: any) => {
1648
+
1649
+ // update temporary value
1650
+ setControlTempValue(prevState.labels.length >= 0 ? null : (VALUE_BY_BRACKETS ? convertArrToValByBrackets(prevState.labels) : prevState.labels.join(',')));
1651
+
1652
+ return {
1653
+ labels: [...prevState.labels, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER)],
1654
+ values: [...prevState.values, _value]
1655
+ }
1656
+ });
1657
+
1658
+
1659
+ currentControlValueArr.push(_value);
1660
+ currentControlLabelArr.push(_label);
1661
+
1662
+ }
1663
+
1664
+
1665
+ // Appropriate multi-item container height
1666
+ // !!!set `false` to prevents the scrollbar position from changing when multi-selecting the option is clicked
1667
+ adjustMultiControlContainerHeight(false);
1668
+
1669
+ // active current option
1670
+ if (noCallback) {
1671
+ setTimeout(() => {
1672
+ $el.classList.add('active');
1673
+ }, 0);
1674
+ }
1675
+
1676
+
1677
+
1678
+ }
1679
+
1680
+ //
1681
+ if (noCallback && typeof (onChange) === 'function') {
1682
+
1683
+ await onChange?.(
1684
+ selectInputRef.current,
1685
+ valueInputRef.current,
1686
+ !MULTI_SEL_VALID ? curItem : multipleSelectionCallback(currentControlValueArr, currentControlLabelArr)
1687
+ );
1688
+
1689
+
1690
+ //
1691
+ selectInputRef.current?.blur();
1692
+ }
1693
+ }
1694
+
1695
+ // Fixed an out-of-focus issue
1696
+ fixFocusStatus();
1697
+
1698
+ }
1699
+
1700
+
1701
+ function updateOptionCheckboxes(type: string) {
1702
+
1703
+ const _labels: any[] = [];
1704
+ const _values: any[] = [];
1705
+
1706
+ [].slice.call(listContentRef.current.querySelectorAll('.custom-select-multi__control-option-item:not(.hide)')).forEach((node: any) => {
1707
+
1708
+ const _label = node.dataset.label;
1709
+ const _value = node.dataset.value;
1710
+
1711
+
1712
+ if (type === 'remove') {
1713
+ //#########
1714
+ // remove item
1715
+ //#########
1716
+ node.dataset.selected = 'false';
1717
+ node.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.add('d-none');
1718
+ node.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.remove('d-none');
1719
+
1720
+ //
1721
+ const _indexLable = _labels.findIndex((item: any) => item == _label);
1722
+ const _indexValue = _values.findIndex((item: any) => item == _value);
1723
+ if (_indexLable !== -1) _labels.splice(_indexLable, 1);
1724
+ if (_indexValue !== -1) _values.splice(_indexValue, 1);
1725
+
1726
+
1727
+ } else {
1728
+ //#########
1729
+ // add item
1730
+ //#########
1731
+ node.dataset.selected = 'true';
1732
+ node.querySelector('.custom-select-multi__control-option-checkbox-selected').classList.remove('d-none');
1733
+ node.querySelector('.custom-select-multi__control-option-checkbox-placeholder').classList.add('d-none');
1734
+
1735
+ //
1736
+ _labels.push(_label);
1737
+ _values.push(_value);
1738
+
1739
+ }
1740
+
1741
+ });
1742
+
1743
+ setControlArr({
1744
+ labels: _labels,
1745
+ values: _values
1746
+ });
1747
+
1748
+
1749
+
1750
+ // Appropriate multi-item container height
1751
+ adjustMultiControlContainerHeight();
1752
+
1753
+ return {
1754
+ labels: _labels,
1755
+ values: _values
1756
+ }
1757
+
1758
+ };
1759
+
1760
+ function updateOptionCheckboxesViaAddSingleItem(data: any) {
1761
+
1762
+ const _labels: any[] = data.labels || [];
1763
+ const _values: any[] = data.values || [];
1764
+
1765
+ setControlArr({
1766
+ labels: _labels,
1767
+ values: _values
1768
+ });
1769
+
1770
+ // Appropriate multi-item container height
1771
+ adjustMultiControlContainerHeight();
1772
+
1773
+ };
1774
+
1775
+
1776
+
1777
+ async function handleSelectAll(event: any) {
1778
+ event.preventDefault();
1779
+ event.stopPropagation(); /* REQUIRED */
1780
+
1781
+ let _labels: any[] = [];
1782
+ let _values: any[] = [];
1783
+
1784
+ if (controlArr.values.length === optionsData.length) { // selected all items
1785
+ const { labels, values } = updateOptionCheckboxes('remove');
1786
+ selectedSign.current = false;
1787
+
1788
+ _labels = labels;
1789
+ _values = values;
1790
+ } else {
1791
+
1792
+ const { labels, values } = updateOptionCheckboxes(selectedSign.current ? 'remove' : 'add');
1793
+ selectedSign.current = !selectedSign.current;
1794
+
1795
+ _labels = labels;
1796
+ _values = values;
1797
+
1798
+ }
1799
+
1800
+ await onChange?.(
1801
+ selectInputRef.current,
1802
+ valueInputRef.current,
1803
+ multipleSelectionCallback(_values, _labels)
1804
+ );
1805
+
1806
+ // Fixed an out-of-focus issue
1807
+ fixFocusStatus();
1808
+
1809
+
1810
+ }
1811
+
1812
+ function handleClearValue(event?: any) {
1813
+ if (typeof event !== 'undefined') {
1814
+ event.preventDefault();
1815
+ event.stopPropagation(); /* REQUIRED */
1816
+ }
1817
+
1818
+ // It is valid when a single selection
1819
+ const emptyValue: Record<string, string> = { label: '', value: '', queryString: '' };
1820
+ handleSelect(null, JSON.stringify(emptyValue), [], []);
1821
+
1822
+ // update temporary value
1823
+ setControlTempValue(null);
1824
+
1825
+ // update filter status
1826
+ setFilterItemsHasNoMatchData(false);
1827
+
1828
+ }
1829
+
1830
+
1831
+
1832
+ async function handleMultiControlItemRemove(event: any) {
1833
+ event.preventDefault();
1834
+ event.stopPropagation(); /* REQUIRED */
1835
+
1836
+ const valueToRemove = String(event.currentTarget.dataset.value);
1837
+ const getCurrentIndex = controlArr.values.findIndex((item: any) => item.toString() === valueToRemove);
1838
+
1839
+ let currentControlValueArr: any[] = JSON.parse(JSON.stringify(controlArr.values));
1840
+ let currentControlLabelArr: any[] = JSON.parse(JSON.stringify(controlArr.labels));
1841
+
1842
+ const _value = valueToRemove;
1843
+ const _label = controlArr.labels[getCurrentIndex];
1844
+
1845
+
1846
+ setControlArr((prevState: any) => {
1847
+
1848
+ // update temporary value
1849
+ setControlTempValue(prevState.labels.length >= 0 ? null : (VALUE_BY_BRACKETS ? convertArrToValByBrackets(prevState.labels) : prevState.labels.join(',')));
1850
+
1851
+ return {
1852
+ labels: removeItemOnce(prevState.labels, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER)),
1853
+ values: removeItemOnce(prevState.values, _value)
1854
+ }
1855
+ });
1856
+
1857
+ currentControlValueArr = removeItemOnce(currentControlValueArr, _value);
1858
+ currentControlLabelArr = removeItemOnce(currentControlLabelArr, formatIndentVal(_label, INDENT_LAST_PLACEHOLDER));
1859
+
1860
+
1861
+ // Appropriate multi-item container height
1862
+ adjustMultiControlContainerHeight();
1863
+
1864
+
1865
+ //
1866
+ if (typeof (onChange) === 'function') {
1867
+
1868
+ await onChange?.(
1869
+ selectInputRef.current,
1870
+ valueInputRef.current,
1871
+ multipleSelectionCallback(currentControlValueArr, currentControlLabelArr)
1872
+ );
1873
+
1874
+
1875
+ //
1876
+ selectInputRef.current?.blur();
1877
+ }
1878
+
1879
+ }
1880
+
1881
+
1882
+
1883
+ function handleShowList() {
1884
+
1885
+ // Reset the out-of-focus marker
1886
+ isBlurringRef.current = false;
1887
+
1888
+ //
1889
+ if (!isOpen) {
1890
+ activate();
1891
+ } else {
1892
+ cancel();
1893
+ if (MULTI_SEL_VALID) popwinPosHide();
1894
+ }
1895
+
1896
+ }
1897
+
1898
+ async function handleFetch(inputVal: any = null) {
1899
+ setFetchLoading(true);
1900
+
1901
+ // data init
1902
+ const searchStr: string = typeof inputVal === 'string' ? inputVal : (controlTempValue || controlTempValue === '' ? controlTempValue : '');
1903
+ const _oparams: any[] = fetchFuncMethodParams || [];
1904
+ const _params: any[] = _oparams.map((item: any) => item !== '$QUERY_STRING' ? item : searchStr);
1905
+
1906
+
1907
+ const res = await fetchData((_params).join(','), '', '', false);
1908
+
1909
+ setFetchLoading(false);
1910
+
1911
+ return res;
1912
+ }
1913
+
1914
+
1915
+ async function handleFirstFetch(inputVal: any = null) {
1916
+
1917
+ const _oparams: any[] = fetchFuncMethodParams || [];
1918
+ const _params: any[] = _oparams.map((item: any) => item !== '$QUERY_STRING' ? item : (MANUAL_REQ ? QUERY_STRING_PLACEHOLDER : ''));
1919
+ const res = await fetchData((_params).join(','), finalRes(inputVal), inputVal);
1920
+
1921
+ // Set an identifier indicating that the first request has been completed
1922
+ if (!handleFirstFetchCompleted) setHandleFirstFetchCompleted(true);
1923
+
1924
+ return res;
1925
+ }
1926
+
1927
+
1928
+ function handleComposition(event: any) {
1929
+
1930
+ if (event.type === 'compositionstart' || event.type === 'compositionend') {
1931
+ //fire change method to update for Chrome v53
1932
+ handleChange(event);
1933
+ }
1934
+ }
1935
+
1936
+
1937
+
1938
+ function handleChange(event: any) {
1939
+
1940
+ const val = event.target.value;
1941
+
1942
+ //Calculates the position of the blinking cursor
1943
+ setBlinkingPosStart(getTextWidth(event.target, blinkingPosFauxRef.current, blinkingCursorPosDivRef.current));
1944
+
1945
+ // update temporary value
1946
+ setControlTempValue(val);
1947
+
1948
+ //
1949
+ handleChangeFetchSafe(val);
1950
+
1951
+ // Fixed an out-of-focus issue
1952
+ fixFocusStatus();
1953
+
1954
+ // Every time the input changes or the search button is clicked, a data request will be triggered
1955
+ if (MANUAL_REQ && val !== '') {
1956
+ popwinPosInit();
1957
+ }
1958
+
1959
+ }
1960
+
1961
+ //
1962
+ function handleFocus(event: any) {
1963
+
1964
+ rootRef.current?.classList.add('focus');
1965
+
1966
+ //
1967
+ onFocus?.(selectInputRef.current);
1968
+
1969
+ }
1970
+
1971
+ function handleBlur(event: any) {
1972
+
1973
+ // Set the out-of-focus marker
1974
+ isBlurringRef.current = true;
1975
+
1976
+
1977
+ // Fix the focus issue with using the "Tabs" and "Enter" keys
1978
+ //
1979
+ //
1980
+ rootRef.current?.classList.remove('focus');
1981
+
1982
+ if (!MULTI_SEL_VALID) {
1983
+ if (!isOpen) {
1984
+ cancel();
1985
+ if (MULTI_SEL_VALID) popwinPosHide();
1986
+ }
1987
+ } else {
1988
+ if (listContentRef.current) listContentRef.current.focus();
1989
+ }
1990
+
1991
+
1992
+ setTimeout(() => {
1993
+ onBlur?.(selectInputRef.current);
1994
+ }, 300);
1995
+ }
1996
+
1997
+
1998
+ function generateInputFocusStr() {
1999
+ return controlTempValue || controlTempValue === '' ? (controlTempValue.length === 0 ? BLINKING_CURSOR_STR : controlTempValue) : (placeholder || '');
2000
+ }
2001
+
2002
+ function hideBlinkingCursor() {
2003
+ return (generateInputFocusStr() === placeholder && placeholder !== '' && typeof placeholder !== 'undefined') || (controlTempValue === null || controlTempValue.length === 0);
2004
+ }
2005
+
2006
+ function optionFocus(type: string) {
2007
+
2008
+ return new Promise(function (resolve) {
2009
+
2010
+ // Determine the "active" class name to avoid listening to other unused components of the same type
2011
+ if (listRef.current === null || !rootRef.current.classList.contains('active')) return;
2012
+
2013
+
2014
+ // Avoid selecting options that are disabled
2015
+ const options = [].slice.call(listRef.current.querySelectorAll('.list-group-item:not(.hide):not(.custom-select-multi__control-option-item--select-all):not(.custom-select-multi__control-option-item--clear)'));
2016
+ const currentIndex = options.findIndex((e) => e === listRef.current.querySelector('.list-group-item.active'));
2017
+
2018
+
2019
+ // get the next element in the list, "%" will loop around to 0
2020
+ let nextIndex;
2021
+ if (type === 'increase') {
2022
+ nextIndex = currentIndex + 1 % options.length;
2023
+ } else {
2024
+ nextIndex = (currentIndex < 0 ? options.length : currentIndex) - 1 % options.length;
2025
+ }
2026
+
2027
+
2028
+
2029
+ //only one
2030
+ if (options.length === 1) nextIndex = 0;
2031
+
2032
+
2033
+ if (!isNaN(nextIndex)) {
2034
+ options.forEach((node: any, index: number) => {
2035
+ node?.classList.remove('active');
2036
+ });
2037
+
2038
+ const targetOption = options[nextIndex] as HTMLElement;
2039
+ if (typeof targetOption !== 'undefined' && !targetOption.classList.contains('no-match')) {
2040
+ targetOption.classList.add('active');
2041
+
2042
+ keyboardSelectedItem.current = targetOption;
2043
+ resolve(targetOption);
2044
+ }
2045
+
2046
+ }
2047
+ });
2048
+
2049
+
2050
+ }
2051
+
2052
+
2053
+ async function handleKeyPressed(event: KeyboardEvent<HTMLDivElement>) {
2054
+ const key = event.code;
2055
+
2056
+ //
2057
+ onKeyPressed?.(
2058
+ event,
2059
+ selectInputRef.current,
2060
+ valueInputRef.current
2061
+ );
2062
+
2063
+
2064
+ if (!isOpen) return;
2065
+
2066
+ let res: any = null;
2067
+
2068
+ if (key === 'Enter' || key === 'NumpadEnter') {
2069
+ event.preventDefault();
2070
+
2071
+ // Determine the "active" class name to avoid listening to other unused components of the same type
2072
+ if (listRef.current === null || !rootRef.current.classList.contains('active')) return;
2073
+
2074
+ // Avoid selecting options that are disabled
2075
+ if (keyboardSelectedItem.current !== null && keyboardSelectedItem.current.classList.contains('disabled')) return;
2076
+
2077
+ if (listRef.current !== null) {
2078
+ const currentIndex = await listRef.current.dataset.data;
2079
+
2080
+
2081
+ if (typeof currentIndex !== 'undefined') {
2082
+
2083
+
2084
+ const currentData = optionsData[Number(currentIndex)];
2085
+ const currentControlValueArr: any[] = [];
2086
+ const currentControlLabelArr: any[] = [];
2087
+
2088
+ const htmlOptions = [].slice.call(listRef.current.querySelectorAll('.list-group-item:not(.hide):not(.no-match)'));
2089
+
2090
+ htmlOptions.forEach((node: any) => {
2091
+ node.classList.remove('active');
2092
+
2093
+ // multiple options
2094
+ if (node.classList.contains('item-selected')) {
2095
+ currentControlValueArr.push(node.dataset.value);
2096
+ currentControlLabelArr.push(node.dataset.label);
2097
+ }
2098
+
2099
+ });
2100
+
2101
+
2102
+ handleSelect(null, currentData, currentControlValueArr, currentControlLabelArr);
2103
+
2104
+ //
2105
+ if (typeof (onChange) === 'function') {
2106
+
2107
+ await onChange?.(
2108
+ selectInputRef.current,
2109
+ valueInputRef.current,
2110
+ !MULTI_SEL_VALID ? currentData : multipleSelectionCallback(currentControlValueArr, currentControlLabelArr)
2111
+ );
2112
+
2113
+
2114
+ //
2115
+ selectInputRef.current?.blur();
2116
+ }
2117
+
2118
+ }
2119
+ }
2120
+ }
2121
+
2122
+ if (key === 'ArrowUp') {
2123
+ res = await optionFocus('decrease');
2124
+
2125
+ }
2126
+
2127
+ if (key === 'ArrowDown') {
2128
+ res = await optionFocus('increase');
2129
+ }
2130
+
2131
+
2132
+ // temporary data
2133
+ if (res !== null) listRef.current.dataset.data = res.dataset.index;
2134
+
2135
+
2136
+ }
2137
+
2138
+ function handleDocOut(e: any) {
2139
+
2140
+ if (e.target.closest('.custom-select__options-wrapper') === null && e.target.closest('.custom-select__wrapper') === null) {
2141
+ // cancel
2142
+ cancel();
2143
+ if (MULTI_SEL_VALID) popwinPosHide();
2144
+
2145
+ // DO NOT USE "handleBlur(null)"
2146
+ }
2147
+ }
2148
+
2149
+
2150
+ // Select all detection functions in the input box (for "Single selection")
2151
+ function checkUserInputboxIsAllSelected(e: any) {
2152
+ const input = e.target;
2153
+ if (input && typeof input.selectionStart === 'number' && typeof input.selectionEnd === 'number') {
2154
+ setUserInputboxIsAllSelected(input.selectionStart === 0 && input.selectionEnd === input.value.length && input.value.length > 0);
2155
+ } else {
2156
+ setUserInputboxIsAllSelected(false);
2157
+ }
2158
+ }
2159
+
2160
+
2161
+ useEffect(() => {
2162
+
2163
+ // Call a function when the component has been rendered completely
2164
+ //--------------
2165
+ onLoad?.(selectInputRef.current, valueInputRef.current, finalRes(value));
2166
+
2167
+
2168
+ // update incoming data
2169
+ //--------------
2170
+ setIncomingData(data);
2171
+
2172
+
2173
+ // data init
2174
+ //--------------
2175
+ if (FIRST_REQUEST_AUTO) {
2176
+ handleFirstFetch(value);
2177
+ } else {
2178
+ if (MULTI_SEL_VALID) {
2179
+ // Appropriate multi-item container height
2180
+ setTimeout(() => {
2181
+ adjustMultiControlContainerHeight();
2182
+ }, 0);
2183
+ }
2184
+ }
2185
+
2186
+ // Forced assignment does not depend on "fetch" or "firstRequestAutoExe"
2187
+ // Don't use "value.value && value.label" directly, if it is empty, it will be treated as FALSE
2188
+ if (chkValueExist(value)) {
2189
+ // ++++++++++++++++++++
2190
+ // Single selection
2191
+ // ++++++++++++++++++++
2192
+ if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
2193
+ if (typeof value.value !== 'undefined' && value.value !== null) setControlValue(value.value as string);
2194
+ if (typeof value.label !== 'undefined' && value.label !== null) setControlLabel(formatIndentVal(value.label, INDENT_LAST_PLACEHOLDER));
2195
+ }
2196
+
2197
+ // ++++++++++++++++++++
2198
+ // Multiple selection
2199
+ // ++++++++++++++++++++
2200
+ if (MULTI_SEL_VALID) {
2201
+ if (chkValueExist(value) && Array.isArray(value)) {
2202
+
2203
+ const _currentData: OptionConfig[] = value;
2204
+ const _defaultValues = _currentData.map((v: OptionConfig) => v.value as string);
2205
+ const _defaultLabels = _currentData.map((v: OptionConfig) => v.label as string);
2206
+
2207
+ setControlArr({
2208
+ labels: _defaultLabels,
2209
+ values: _defaultValues,
2210
+ });
2211
+ }
2212
+ }
2213
+
2214
+ } else {
2215
+ // ++++++++++++++++++++
2216
+ // Single selection & Multiple selection
2217
+ // ++++++++++++++++++++
2218
+ if (!FIRST_REQUEST_AUTO) {
2219
+ setControlValue('');
2220
+ setControlLabel('');
2221
+ setControlArr({
2222
+ labels: [],
2223
+ values: []
2224
+ });
2225
+ }
2226
+ }
2227
+
2228
+
2229
+
2230
+
2231
+
2232
+ //
2233
+ //--------------
2234
+ return () => {
2235
+ if (LOCK_BODY_SCROLL) clearAllBodyScrollLocks();
2236
+ }
2237
+
2238
+ }, [value, options, data]);
2239
+
2240
+
2241
+ useEffect(() => {
2242
+
2243
+ // update default value (It does not re-render the component because the incoming value changes.)
2244
+ //--------------
2245
+ if (typeof defaultValue !== 'undefined') { //REQUIRED
2246
+
2247
+ // Call a function when the component has been rendered completely
2248
+ //--------------
2249
+ onLoad?.(selectInputRef.current, valueInputRef.current, finalRes(defaultValue));
2250
+
2251
+
2252
+ // data init
2253
+ //--------------
2254
+ if (FIRST_REQUEST_AUTO) {
2255
+ handleFirstFetch(defaultValue);
2256
+ } else {
2257
+ if (MULTI_SEL_VALID) {
2258
+ // Appropriate multi-item container height
2259
+ setTimeout(() => {
2260
+ adjustMultiControlContainerHeight();
2261
+ }, 0);
2262
+ }
2263
+ }
2264
+
2265
+
2266
+ // Forced assignment does not depend on "fetch" or "firstRequestAutoExe"
2267
+ // Don't use "value.value && value.label" directly, if it is empty, it will be treated as FALSE
2268
+ if (chkValueExist(defaultValue)) {
2269
+ // ++++++++++++++++++++
2270
+ // Single selection
2271
+ // ++++++++++++++++++++
2272
+ if (typeof defaultValue === 'object' && !Array.isArray(defaultValue) && defaultValue !== null) {
2273
+ if (typeof defaultValue.value !== 'undefined' && defaultValue.value !== null) setControlValue(defaultValue.value as string);
2274
+ if (typeof defaultValue.label !== 'undefined' && defaultValue.label !== null) setControlLabel(formatIndentVal(defaultValue.label, INDENT_LAST_PLACEHOLDER));
2275
+ }
2276
+
2277
+ // ++++++++++++++++++++
2278
+ // Multiple selection
2279
+ // ++++++++++++++++++++
2280
+ if (MULTI_SEL_VALID) {
2281
+ if (chkValueExist(defaultValue) && Array.isArray(defaultValue)) {
2282
+
2283
+ const _currentData: OptionConfig[] = defaultValue;
2284
+ const _defaultValues = _currentData.map((v: OptionConfig) => v.value as string);
2285
+ const _defaultLabels = _currentData.map((v: OptionConfig) => v.label as string);
2286
+
2287
+ setControlArr({
2288
+ labels: _defaultLabels,
2289
+ values: _defaultValues,
2290
+ });
2291
+ }
2292
+ }
2293
+
2294
+ } else {
2295
+ // ++++++++++++++++++++
2296
+ // Single selection & Multiple selection
2297
+ // ++++++++++++++++++++
2298
+ if (!FIRST_REQUEST_AUTO) {
2299
+ setControlValue('');
2300
+ setControlLabel('');
2301
+ setControlArr({
2302
+ labels: [],
2303
+ values: []
2304
+ });
2305
+ }
2306
+ }
2307
+
2308
+
2309
+ }
2310
+
2311
+ }, []);
2312
+
2313
+
2314
+ // Fixed an out-of-focus issue
2315
+ //--------------
2316
+ // !!! TIPS:
2317
+ // Fixed: When `fixFocusStatus()` is triggered, the above judgment will be invalidated, and this judgment will be used
2318
+ // Fixed: The pop-up window is not closed due to the mixing of business components
2319
+ useEffect(() => {
2320
+ document.addEventListener('pointerdown', handleDocOut);
2321
+ return () => {
2322
+ document.removeEventListener('pointerdown', handleDocOut);
2323
+ };
2324
+ }, [orginalData]); // Avoid the issue that `setOptionsData(orginalData)` sets the original value to empty on the first entry
2325
+
2326
+
2327
+
2328
+
2329
+ return (
2330
+ <>
2331
+
2332
+ {label ? <><div className="custom-select__label">{typeof label === 'string' ? <label htmlFor={`label-${idRes}`} className="form-label" dangerouslySetInnerHTML={{ __html: `${label}` }}></label> : <label htmlFor={`label-${idRes}`} className="form-label">{label}</label>}</div></> : null}
2333
+
2334
+ <span ref={blinkingPosFauxRef}></span>
2335
+
2336
+ <div
2337
+ ref={rootRef}
2338
+ data-overlay-id={`custom-select__options-wrapper-${idRes}`}
2339
+ id={`custom-select__wrapper-${idRes}`}
2340
+ className={combinedCls(
2341
+ 'custom-select__wrapper',
2342
+ clsWrite(wrapperClassName, 'mb-3 position-relative'),
2343
+ {
2344
+ 'multiple-selection': MULTI_SEL_VALID,
2345
+ 'active focus': isOpen
2346
+ }
2347
+ )}
2348
+ onKeyDown={handleKeyPressed}
2349
+
2350
+ >
2351
+
2352
+
2353
+ {/* CLEAR ICON */}
2354
+ {CLEAR_ICON && (
2355
+ (!MULTI_SEL_VALID && controlValue) || // Single selection Control
2356
+ (MULTI_SEL_VALID && controlArr.values.length > 0 ) // Multiple selection Control
2357
+ ) ? (
2358
+ <span className={`custom-select-clear-icon ${MANUAL_REQ ? 'pos-offset' : ''}`}>
2359
+ <button
2360
+ tabIndex={-1}
2361
+ type="button"
2362
+ style={disabled ? {
2363
+ display: 'none'
2364
+ } : undefined}
2365
+ onClick={async (e: React.MouseEvent) => {
2366
+ e.preventDefault();
2367
+ e.stopPropagation();
2368
+
2369
+ if (MULTI_SEL_VALID) {
2370
+ updateOptionCheckboxes('remove');
2371
+
2372
+ await onChange?.(
2373
+ selectInputRef.current,
2374
+ valueInputRef.current,
2375
+ multipleSelectionCallback([], [])
2376
+ );
2377
+
2378
+ } else {
2379
+ handleClearValue();
2380
+ }
2381
+
2382
+ }}
2383
+ >
2384
+ <svg width="12px" height="12px" viewBox="0 0 1024 1024">
2385
+ <path fill="#000" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z" />
2386
+ </svg>
2387
+ </button>
2388
+ </span>
2389
+ ) : null}
2390
+ {/* CLEAR ICON */}
2391
+
2392
+
2393
+ {!MULTI_SEL_VALID ? <>
2394
+
2395
+ {/** INPUT */}
2396
+ <div className="position-relative">
2397
+ <input
2398
+ ref={(node) => {
2399
+ selectInputRef.current = node;
2400
+ if (typeof externalRef === 'function') {
2401
+ externalRef(node);
2402
+ } else if (externalRef) {
2403
+ externalRef.current = node;
2404
+ }
2405
+ }}
2406
+ tabIndex={tabIndex || 0}
2407
+ type="text"
2408
+ data-overlay-id={`custom-select__options-wrapper-${idRes}`}
2409
+ id={`label-${idRes}`}
2410
+
2411
+ // Don't use "name", it's just a container to display the label
2412
+ data-name={name?.match(/(\[.*?\])/gi) ? `${name.split('[')[0]}-label[]` : `${name}-label`}
2413
+ data-select
2414
+ className={combinedCls(
2415
+ clsWrite(controlClassName, 'form-control'),
2416
+ controlExClassName
2417
+ )}
2418
+ onFocus={handleFocus}
2419
+ onBlur={handleBlur}
2420
+ onClick={typeof readOnly === 'undefined' || !readOnly ? handleShowList : () => void (0)}
2421
+ onChange={handleChange}
2422
+ onCompositionStart={handleComposition}
2423
+ onCompositionUpdate={handleComposition}
2424
+ onCompositionEnd={handleComposition}
2425
+ disabled={disabled || null}
2426
+ required={required || null}
2427
+ readOnly={INPUT_READONLY}
2428
+ value={controlTempValue || controlTempValue === '' ? controlTempValue : (MULTI_SEL_VALID ? (VALUE_BY_BRACKETS ? convertArrToValByBrackets(formatIndentVal(controlArr.labels, INDENT_LAST_PLACEHOLDER).map((v: any) => stripTagsAndContent(v))) : formatIndentVal(controlArr.labels, INDENT_LAST_PLACEHOLDER).map((v: any) => stripTagsAndContent(v)).join(',')) : stripTagsAndContent(controlLabel as never))} // do not use `defaultValue`
2429
+
2430
+ style={{
2431
+ cursor: 'pointer',
2432
+ color: 'transparent',
2433
+ borderBottomWidth: MULTI_SEL_VALID ? '0' : '1px',
2434
+ ...style
2435
+ }}
2436
+ autoComplete={typeof autoComplete === 'undefined' ? 'off' : autoComplete}
2437
+ autoCapitalize={typeof autoCapitalize === 'undefined' ? 'off' : autoCapitalize}
2438
+ spellCheck={typeof spellCheck === 'undefined' ? false : spellCheck}
2439
+ {...attributes}
2440
+
2441
+ // Select all detection (for "Single selection")
2442
+ onSelect={(e) => { checkUserInputboxIsAllSelected(e); }}
2443
+ onKeyUp={(e) => { checkUserInputboxIsAllSelected(e); }}
2444
+ onMouseUp={(e) => { checkUserInputboxIsAllSelected(e); }}
2445
+ />
2446
+
2447
+ </div>
2448
+ </> : null}
2449
+
2450
+ {/* ========== RESULT CONTAINER ========== */}
2451
+ <input
2452
+ ref={valueInputRef}
2453
+ tabIndex={-1}
2454
+ type="hidden"
2455
+ id={idRes}
2456
+ name={name}
2457
+ value={MULTI_SEL_VALID ? (VALUE_BY_BRACKETS ? convertArrToValByBrackets(controlArr.values) : controlArr.values.join(',')) : controlValue} // do not use `defaultValue`
2458
+ onChange={() => void (0)}
2459
+ {...attributes}
2460
+ />
2461
+
2462
+
2463
+ {/* BLINKING CURSOR */}
2464
+ {!MULTI_SEL_VALID ? <>
2465
+ <span
2466
+ className={combinedCls(
2467
+ 'custom-select-multi__control-blinking-following-cursor animated',
2468
+ {
2469
+ 'd-none': hideBlinkingCursor()
2470
+ }
2471
+ )}
2472
+ style={{
2473
+ left: `${blinkingPosStart}px`
2474
+ }}
2475
+ >
2476
+ {BLINKING_CURSOR_STR}
2477
+ </span>
2478
+ </> : null}
2479
+ {/* /BLINKING CURSOR */}
2480
+
2481
+ {/* ========== /RESULT CONTAINER ========== */}
2482
+
2483
+
2484
+
2485
+ {/*
2486
+ // ++++++++++++++++++++
2487
+ // Single selection Control
2488
+ // ++++++++++++++++++++
2489
+ */}
2490
+ {!MULTI_SEL_VALID ? <div className="custom-select-single__inputplaceholder-wrapper">
2491
+
2492
+ {/* PLACEHOLDER */}
2493
+ <div className="custom-select-single__inputplaceholder-inner" style={style}>
2494
+ <input
2495
+ tabIndex={-1}
2496
+ type="text"
2497
+ className={combinedCls(
2498
+ clsWrite(controlClassName, 'form-control'),
2499
+ controlExClassName
2500
+ )}
2501
+ />
2502
+
2503
+ <span ref={blinkingCursorPosDivRef} className={combinedCls(
2504
+ 'custom-select-multi__control-blinking-cursor',
2505
+ {
2506
+ 'animated': generateInputFocusStr() === BLINKING_CURSOR_STR,
2507
+
2508
+ // Select all highlights (for "Single selection")
2509
+ 'selected': userInputboxIsAllSelected
2510
+ }
2511
+ )}>
2512
+ {controlTempValue || controlTempValue === '' ? (controlTempValue.length === 0 ? <span className={`${!hideBlinkingCursor() ? 'control-placeholder' : ''}`}>{generateInputFocusStr()}</span> : <span>{controlTempValue}</span>) : (stripTagsAndContent(controlLabel as never).length === 0 ? <span className={`${!hideBlinkingCursor() ? 'control-placeholder' : ''}`}>{generateInputFocusStr()}</span> : <span>{stripTagsAndContent(controlLabel as never)}</span>)}
2513
+ </span>
2514
+
2515
+ </div>
2516
+
2517
+
2518
+ {/* /PLACEHOLDER */}
2519
+
2520
+
2521
+ {/* ARROW */}
2522
+ <span className={combinedCls(
2523
+ 'custom-select-arrow',
2524
+ {
2525
+ 'reverse': isOpen
2526
+ }
2527
+ )} style={{display: MANUAL_REQ ? 'none' : 'inline-block' }}>
2528
+ {controlArrow ? controlArrow : <svg width="10px" height="10px" viewBox="0 -4.5 20 20">
2529
+ <g stroke="none" strokeWidth="1" fill="none">
2530
+ <g transform="translate(-180.000000, -6684.000000)" className="arrow-fill-g" fill="#a5a5a5">
2531
+ <g transform="translate(56.000000, 160.000000)">
2532
+ <path d="M144,6525.39 L142.594,6524 L133.987,6532.261 L133.069,6531.38 L133.074,6531.385 L125.427,6524.045 L124,6525.414 C126.113,6527.443 132.014,6533.107 133.987,6535 C135.453,6533.594 134.024,6534.965 144,6525.39">
2533
+ </path>
2534
+ </g>
2535
+ </g>
2536
+ </g>
2537
+ </svg>}
2538
+ </span>
2539
+
2540
+
2541
+ {/* /ARROW */}
2542
+
2543
+
2544
+
2545
+ {/* SEARCH BUTTON */}
2546
+ {MANUAL_REQ ? <>
2547
+ <span className="custom-select-multi__control-searchbtn">
2548
+ <button tabIndex={-1} type="button" className="btn border-end-0 rounded-pill" onClick={(e: React.MouseEvent) => {
2549
+ e.preventDefault();
2550
+ e.stopPropagation();
2551
+
2552
+ handleFetch().then((response: any) => {
2553
+
2554
+ // pop win initalization
2555
+ setTimeout(() => {
2556
+ popwinPosInit();
2557
+ popwinFilterItems(controlTempValue);
2558
+
2559
+ }, 0);
2560
+ });
2561
+
2562
+ }}>
2563
+ <svg width="1em" height="1em" fill="#a5a5a5" viewBox="0 0 16 16">
2564
+ <path d="M12.027 9.92L16 13.95 14 16l-4.075-3.976A6.465 6.465 0 0 1 6.5 13C2.91 13 0 10.083 0 6.5 0 2.91 2.917 0 6.5 0 10.09 0 13 2.917 13 6.5a6.463 6.463 0 0 1-.973 3.42zM1.997 6.452c0 2.48 2.014 4.5 4.5 4.5 2.48 0 4.5-2.015 4.5-4.5 0-2.48-2.015-4.5-4.5-4.5-2.48 0-4.5 2.014-4.5 4.5z" fillRule="evenodd" />
2565
+ </svg>
2566
+ </button>
2567
+
2568
+ </span>
2569
+ </> : null}
2570
+ {/* /SEARCH BUTTON */}
2571
+
2572
+
2573
+
2574
+ </div> : null}
2575
+
2576
+
2577
+
2578
+ {/*
2579
+ // ++++++++++++++++++++
2580
+ // Multiple selection Control
2581
+ // ++++++++++++++++++++
2582
+ */}
2583
+ {MULTI_SEL_VALID ? <div ref={rootMultiRef} className="custom-select-multi__inputplaceholder-wrapper">
2584
+
2585
+ {/* PLACEHOLDER */}
2586
+ <div className="custom-select-multi__inputplaceholder-inner">
2587
+ <div style={MULTI_SEL_ENTIRE_AREA_TRIGGER ? {pointerEvents: 'auto', cursor: 'pointer'} : undefined} onClick={(e: React.MouseEvent) => {
2588
+ if (MULTI_SEL_ENTIRE_AREA_TRIGGER) {
2589
+ if (typeof readOnly === 'undefined' || !readOnly) handleShowList();
2590
+ }
2591
+ }}>
2592
+ <ul className="custom-select-multi__list">
2593
+
2594
+ {typeof multiSelectSelectedItemOnlyStatus !== 'undefined' ? <>
2595
+
2596
+ <li className="custom-select-multi__list-item-statusstring" >
2597
+
2598
+
2599
+ {MANUAL_REQ ? <>
2600
+ {/* ===================== Manual requests ===================== */}
2601
+ {
2602
+ typeof multiSelectSelectedItemOnlyStatus.itemsLabel === 'string' &&
2603
+ controlArr.labels.length > 0
2604
+ ?
2605
+ multiSelectSelectedItemOnlyStatus.itemsLabel.replace('{num}', `${controlArr.labels.length}`)
2606
+ :
2607
+ null
2608
+ }
2609
+ {
2610
+ typeof multiSelectSelectedItemOnlyStatus.noneLabel === 'string' &&
2611
+ controlArr.labels.length === 0
2612
+ ?
2613
+ multiSelectSelectedItemOnlyStatus.noneLabel
2614
+ :
2615
+ null
2616
+ }
2617
+
2618
+ {/*-- DEFAULT VALUE ---*/}
2619
+ {
2620
+ typeof multiSelectSelectedItemOnlyStatus.itemsLabel !== 'string' &&
2621
+ controlArr.labels.length > 0
2622
+ ?
2623
+ MULTI_SEL_SELECTED_STATUS.itemsLabel.replace('{num}', `${controlArr.labels.length}`)
2624
+ :
2625
+ null
2626
+ }
2627
+ {
2628
+ typeof multiSelectSelectedItemOnlyStatus.noneLabel !== 'string' &&
2629
+ controlArr.labels.length === 0
2630
+ ?
2631
+ MULTI_SEL_SELECTED_STATUS.noneLabel
2632
+ :
2633
+ null
2634
+ }
2635
+
2636
+ {/* ===================== /Manual requests ===================== */}
2637
+
2638
+ </> : <>
2639
+ {/* ===================== Auto requests ===================== */}
2640
+
2641
+ {
2642
+ typeof multiSelectSelectedItemOnlyStatus.itemsLabel === 'string' &&
2643
+ controlArr.labels.length > 0 &&
2644
+ controlArr.labels.length < optionsData.length
2645
+ ?
2646
+ multiSelectSelectedItemOnlyStatus.itemsLabel.replace('{num}', `${controlArr.labels.length}`)
2647
+ :
2648
+ null
2649
+ }
2650
+ {
2651
+ typeof multiSelectSelectedItemOnlyStatus.noneLabel === 'string' &&
2652
+ controlArr.labels.length === 0
2653
+ ?
2654
+ multiSelectSelectedItemOnlyStatus.noneLabel
2655
+ :
2656
+ null
2657
+ }
2658
+
2659
+ {/* all */}
2660
+ {controlArr.labels.length > 0 ? <>
2661
+ {
2662
+ typeof multiSelectSelectedItemOnlyStatus.allItemsLabel === 'string' &&
2663
+ controlArr.labels.length === optionsData.length
2664
+ ?
2665
+ multiSelectSelectedItemOnlyStatus.allItemsLabel.replace('{num}', `${controlArr.labels.length}`)
2666
+ :
2667
+ null
2668
+ }
2669
+ </>: null}
2670
+
2671
+
2672
+ {/*-- DEFAULT VALUE ---*/}
2673
+ {
2674
+ typeof multiSelectSelectedItemOnlyStatus.itemsLabel !== 'string' &&
2675
+ controlArr.labels.length > 0
2676
+ ?
2677
+ MULTI_SEL_SELECTED_STATUS.itemsLabel.replace('{num}', `${controlArr.labels.length}`)
2678
+ :
2679
+ null
2680
+ }
2681
+ {
2682
+ typeof multiSelectSelectedItemOnlyStatus.noneLabel !== 'string' &&
2683
+ controlArr.labels.length === 0
2684
+ ?
2685
+ MULTI_SEL_SELECTED_STATUS.noneLabel
2686
+ :
2687
+ null
2688
+ }
2689
+
2690
+ {/* all */}
2691
+ {controlArr.labels.length > 0 ? <>
2692
+ {
2693
+ typeof multiSelectSelectedItemOnlyStatus.allItemsLabel !== 'string' &&
2694
+ controlArr.labels.length === optionsData.length
2695
+ ?
2696
+ MULTI_SEL_SELECTED_STATUS.allItemsLabel.replace('{num}', `${controlArr.labels.length}`)
2697
+ :
2698
+ null
2699
+ }
2700
+ </>: null}
2701
+ {/* ===================== /Auto requests ===================== */}
2702
+
2703
+ </>}
2704
+
2705
+ </li>
2706
+ </> : <>
2707
+
2708
+ {/* ITEMS LIST */}
2709
+ {typeof renderSelectedValue === 'function' ? <>
2710
+ {renderSelectedValue(controlArr, handleMultiControlItemRemove)}
2711
+ </> : <>
2712
+ {controlArr.labels.map((item: any, index: number) => (
2713
+ <li
2714
+ key={'selected-item-' + index}
2715
+ data-value={controlArr.values[index]}
2716
+ data-label-full={item}
2717
+ data-label-text={formatIndentVal(stripTagsAndContent(item), INDENT_LAST_PLACEHOLDER)}
2718
+ >
2719
+ {formatIndentVal(stripTagsAndContent(item), INDENT_LAST_PLACEHOLDER)}
2720
+
2721
+ <a
2722
+ href="#"
2723
+ tabIndex={-1}
2724
+ onClick={handleMultiControlItemRemove}
2725
+ data-value={controlArr.values[index]}
2726
+ ><svg width="10px" height="10px" viewBox="0 0 1024 1024"><path fill="#000" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z" /></svg></a>
2727
+ </li>
2728
+ ))}
2729
+ </>}
2730
+
2731
+
2732
+ </>}
2733
+
2734
+
2735
+ {/** INPUT */}
2736
+ <li className="custom-select-multi__list-item-add">
2737
+ <div className="position-relative">
2738
+ {/*
2739
+ // DO NOT USE following attributes in " Multiple selection Control":
2740
+ a) data-select
2741
+ b) value
2742
+ */}
2743
+ <input
2744
+ ref={(node) => {
2745
+ selectInputRef.current = node;
2746
+ if (typeof externalRef === 'function') {
2747
+ externalRef(node);
2748
+ } else if (externalRef) {
2749
+ externalRef.current = node;
2750
+ }
2751
+ }}
2752
+ tabIndex={tabIndex || 0}
2753
+ type="text"
2754
+ data-overlay-id={`custom-select__options-wrapper-${idRes}`}
2755
+ id={`label-${idRes}`}
2756
+
2757
+ // Don't use "name", it's just a container to display the label
2758
+ data-name={name?.match(/(\[.*?\])/gi) ? `${name.split('[')[0]}-label[]` : `${name}-label`}
2759
+ className={combinedCls(
2760
+ clsWrite(controlClassName, 'form-control'),
2761
+ controlExClassName
2762
+ )}
2763
+ onFocus={handleFocus}
2764
+ onBlur={handleBlur}
2765
+ onClick={typeof readOnly === 'undefined' || !readOnly ? handleShowList : () => void (0)}
2766
+ onChange={handleChange}
2767
+ onCompositionStart={handleComposition}
2768
+ onCompositionUpdate={handleComposition}
2769
+ onCompositionEnd={handleComposition}
2770
+ disabled={disabled || null}
2771
+ required={required || null}
2772
+ readOnly={INPUT_READONLY}
2773
+ placeholder={placeholder}
2774
+ style={style}
2775
+ autoComplete={typeof autoComplete === 'undefined' ? 'off' : autoComplete}
2776
+ autoCapitalize={typeof autoCapitalize === 'undefined' ? 'off' : autoCapitalize}
2777
+ spellCheck={typeof spellCheck === 'undefined' ? false : spellCheck}
2778
+ {...attributes}
2779
+ />
2780
+
2781
+ </div>
2782
+
2783
+
2784
+ </li>
2785
+
2786
+ </ul>
2787
+
2788
+ </div>
2789
+
2790
+ </div>
2791
+ {/* /PLACEHOLDER */}
2792
+
2793
+
2794
+
2795
+
2796
+ {/* ARROW */}
2797
+ <span className={combinedCls(
2798
+ 'custom-select-arrow',
2799
+ {
2800
+ 'reverse': isOpen
2801
+ }
2802
+ )} style={{display: MANUAL_REQ ? 'none' : 'inline-block' }}>
2803
+ {controlArrow ? controlArrow : <svg width="10px" height="10px" viewBox="0 -4.5 20 20">
2804
+ <g stroke="none" strokeWidth="1" fill="none">
2805
+ <g transform="translate(-180.000000, -6684.000000)" className="arrow-fill-g" fill="#a5a5a5">
2806
+ <g transform="translate(56.000000, 160.000000)">
2807
+ <path d="M144,6525.39 L142.594,6524 L133.987,6532.261 L133.069,6531.38 L133.074,6531.385 L125.427,6524.045 L124,6525.414 C126.113,6527.443 132.014,6533.107 133.987,6535 C135.453,6533.594 134.024,6534.965 144,6525.39">
2808
+ </path>
2809
+ </g>
2810
+ </g>
2811
+ </g>
2812
+ </svg>}
2813
+ </span>
2814
+ {/* /ARROW */}
2815
+
2816
+
2817
+
2818
+ {/* SEARCH BUTTON */}
2819
+ {MANUAL_REQ ? <>
2820
+ <span className="custom-select-multi__control-searchbtn">
2821
+ <button tabIndex={-1} type="button" className="btn border-end-0 rounded-pill" onClick={(e: React.MouseEvent) => {
2822
+ e.preventDefault();
2823
+ e.stopPropagation();
2824
+
2825
+ handleFetch().then((response: any) => {
2826
+
2827
+ // pop win initalization
2828
+ setTimeout(() => {
2829
+ popwinPosInit();
2830
+ popwinFilterItems(controlTempValue);
2831
+
2832
+ }, 0);
2833
+ });
2834
+ }}>
2835
+ <svg width="1em" height="1em" fill="#a5a5a5" viewBox="0 0 16 16">
2836
+ <path d="M12.027 9.92L16 13.95 14 16l-4.075-3.976A6.465 6.465 0 0 1 6.5 13C2.91 13 0 10.083 0 6.5 0 2.91 2.917 0 6.5 0 10.09 0 13 2.917 13 6.5a6.463 6.463 0 0 1-.973 3.42zM1.997 6.452c0 2.48 2.014 4.5 4.5 4.5 2.48 0 4.5-2.015 4.5-4.5 0-2.48-2.015-4.5-4.5-4.5-2.48 0-4.5 2.014-4.5 4.5z" fillRule="evenodd" />
2837
+ </svg>
2838
+ </button>
2839
+
2840
+ </span>
2841
+ </> : null}
2842
+
2843
+
2844
+ </div> : null}
2845
+ {/* /SEARCH BUTTON */}
2846
+
2847
+
2848
+
2849
+
2850
+ {optionsData && !hasErr ? <>
2851
+ <RootPortal show={true} containerClassName="Select">
2852
+
2853
+ <div
2854
+ ref={listRef}
2855
+ id={`custom-select__options-wrapper-${idRes}`}
2856
+ className={combinedCls(
2857
+ 'custom-select__options-wrapper list-group position-absolute border shadow small',
2858
+ optionsExClassName,
2859
+ {
2860
+ 'multiple-selection': MULTI_SEL_VALID
2861
+ }
2862
+ )}
2863
+ style={{ zIndex: DEPTH, width: WIN_WIDTH, display: 'none' }}
2864
+ role="tablist"
2865
+ >
2866
+
2867
+ <div
2868
+ className="custom-select__options-contentlist rounded"
2869
+ style={{ backgroundColor: 'var(--bs-list-group-bg)' }}
2870
+ tabIndex={0}
2871
+ ref={listContentRef}
2872
+ >
2873
+ <div className="custom-select__options-contentlist-inner">
2874
+
2875
+ {/* SELECT ALL BUTTON */}
2876
+ {MULTI_SEL_VALID ? <>
2877
+ <span
2878
+ tabIndex={-1}
2879
+ className="list-group-item list-group-item-action border-start-0 border-end-0 text-secondary bg-light custom-select-multi__control-option-item--select-all position-sticky top-0 z-3"
2880
+ role="tab"
2881
+ style={{ display: multiSelect?.selectAll ? 'block' : 'none' }}
2882
+ >
2883
+ <span
2884
+ tabIndex={-1}
2885
+ className="btn btn-secondary"
2886
+ dangerouslySetInnerHTML={{
2887
+ __html: controlArr.values.length === optionsData.length ? `${MULTI_DESEL_LABEL}` : `${MULTI_SEL_LABEL}`
2888
+ }}
2889
+ onClick={handleSelectAll}
2890
+ ></span>
2891
+ </span>
2892
+ </> : null}
2893
+ {/* /SELECT ALL BUTTON */}
2894
+
2895
+
2896
+
2897
+ {/* CLEAR BUTTON (Only Single selection) */}
2898
+ {!MULTI_SEL_VALID ? <>
2899
+ {CLEAR_TRIGGER_VALID ? <>
2900
+ <span
2901
+ tabIndex={-1}
2902
+ className="list-group-item list-group-item-action border-start-0 border-end-0 text-secondary bg-light custom-select-multi__control-option-item--clear position-sticky top-0 z-3"
2903
+ role="tab"
2904
+ >
2905
+ <span
2906
+ tabIndex={-1}
2907
+ className="btn btn-secondary"
2908
+ dangerouslySetInnerHTML={{
2909
+ __html: `${CLEAR_TRIGGER_LABEL}`
2910
+ }}
2911
+ onClick={handleClearValue}
2912
+ ></span>
2913
+ </span>
2914
+ </> : null}
2915
+ </> : null}
2916
+ {/* /CLEAR BUTTON (Only Single selection) */}
2917
+
2918
+
2919
+
2920
+ {/* OPTIONS LIST */}
2921
+ {fetchLoading && MANUAL_REQ && hasDefaultOptions ? (
2922
+ // only loading
2923
+ <><button tabIndex={-1} type="button" className="list-group-item list-group-item-action no-match border-0 custom-select-multi__control-option-item--nomatch" disabled>{loadingOutput}</button></>
2924
+ ) : (
2925
+ <>
2926
+
2927
+ {/* NO MATCH & LOADER */}
2928
+ <button tabIndex={-1} type="button" className="list-group-item list-group-item-action no-match border-0 custom-select-multi__control-option-item--nomatch hide" disabled>
2929
+ {
2930
+ // (1) Handling async data with the click event
2931
+ (!FIRST_REQUEST_AUTO && !handleFirstFetchCompleted) ||
2932
+
2933
+ // (2) Every time the input changes or the search button is clicked, a data request will be triggered
2934
+ (fetchUpdate && !filterItemsHasNoMatchData && controlTempValue !== '')
2935
+ ? <>{loadingOutput}</> : <>{fetchNoneInfo}</>}
2936
+ </button>
2937
+ {/* /NO MATCH & LOADER */}
2938
+
2939
+
2940
+ {optionsData ? optionsData.map((item, index) => {
2941
+ const startItemBorder = index === 0 ? 'border-top-0' : '';
2942
+ const endItemBorder = index === optionsData.length - 1 ? 'border-bottom-0' : '';
2943
+
2944
+
2945
+ // disable selected options (only single selection)
2946
+ let disabledCurrentOption: boolean = false;
2947
+ if (
2948
+ (typeof controlValue !== 'undefined' && controlValue !== null && controlValue !== '') &&
2949
+ (typeof item.value !== 'undefined' && item.value !== null && item.value !== '')
2950
+ ) {
2951
+
2952
+ if (!MULTI_SEL_VALID) {
2953
+ const _defaultValue = controlValue.toString();
2954
+ let filterRes: any = [];
2955
+ const filterResQueryValue = optionsData.filter((item: any) => item.value == _defaultValue);
2956
+ const filterResQueryLabel = optionsData.filter((item: any) => item.label == _defaultValue);
2957
+
2958
+ if (filterResQueryValue.length === 0 && filterResQueryLabel.length > 0) {
2959
+ filterRes = filterResQueryValue;
2960
+ if (filterResQueryValue.length === 0) filterRes = filterResQueryLabel;
2961
+ }
2962
+
2963
+ const _targetValue = filterRes.length > 0 ? filterRes[0].value : _defaultValue;
2964
+ const _realValue = item.value.toString();
2965
+
2966
+ if (_realValue === _targetValue && _targetValue !== '') {
2967
+ disabledCurrentOption = true;
2968
+ }
2969
+ }
2970
+
2971
+ }
2972
+
2973
+
2974
+
2975
+ if (!MULTI_SEL_VALID) {
2976
+
2977
+ // ++++++++++++++++++++
2978
+ // Single selection
2979
+ // ++++++++++++++++++++
2980
+ return <button
2981
+ tabIndex={-1}
2982
+ type="button"
2983
+ data-index={index}
2984
+ key={index}
2985
+ className={combinedCls(
2986
+ 'list-group-item list-group-item-action border-start-0 border-end-0 custom-select-multi__control-option-item border-bottom-0',
2987
+ startItemBorder,
2988
+ endItemBorder,
2989
+ {
2990
+ 'disabled': item.disabled,
2991
+ 'active disabled': disabledCurrentOption,
2992
+ 'custom-select-grouptitle': item.group
2993
+ }
2994
+
2995
+ )}
2996
+ data-value={`${item.value}`}
2997
+ data-label={`${item.label}`}
2998
+ data-querystring={`${typeof item.queryString === 'undefined' ? '' : item.queryString}`}
2999
+ data-itemdata={JSON.stringify(item)}
3000
+ data-list-item-label={`${typeof item.listItemLabel === 'undefined' ? '' : item.listItemLabel}`}
3001
+ role="tab"
3002
+ onClick={handleSelect}
3003
+ >
3004
+ {typeof renderOption === 'function' ? <>
3005
+ {renderOption(item, index)}
3006
+ </> : <>
3007
+ <span dangerouslySetInnerHTML={{
3008
+ __html: typeof item.listItemLabel === 'undefined' ? item.label : item.listItemLabel
3009
+ }}></span>
3010
+ </>}
3011
+ </button>
3012
+
3013
+ } else {
3014
+
3015
+ // ++++++++++++++++++++
3016
+ // Multiple selection
3017
+ // ++++++++++++++++++++
3018
+ const itemSelected = multiSelControlOptionExist(controlArr.values, item.value) ? true : false;
3019
+
3020
+ return <button
3021
+ tabIndex={-1}
3022
+ type="button"
3023
+ data-selected={`${itemSelected ? 'true' : 'false'}`}
3024
+ data-index={index}
3025
+ key={index}
3026
+ className={combinedCls(
3027
+ 'list-group-item list-group-item-action border-start-0 border-end-0 custom-select-multi__control-option-item border-bottom-0',
3028
+ startItemBorder,
3029
+ endItemBorder,
3030
+ {
3031
+ 'list-group-item-secondary item-selected': itemSelected,
3032
+ 'disabled': item.disabled,
3033
+ 'custom-select-grouptitle': item.group
3034
+
3035
+ }
3036
+ )}
3037
+ data-value={`${item.value}`}
3038
+ data-label={`${item.label}`}
3039
+ data-querystring={`${typeof item.queryString === 'undefined' ? '' : item.queryString}`}
3040
+ data-list-item-label={`${typeof item.listItemLabel === 'undefined' ? '' : item.listItemLabel}`}
3041
+ data-itemdata={JSON.stringify(item)}
3042
+ role="tab"
3043
+ onClick={handleSelect}
3044
+ >
3045
+ <var className={combinedCls(
3046
+ 'me-1 custom-select-multi__control-option-checkbox-selected',
3047
+ {
3048
+ 'd-none': !itemSelected
3049
+ }
3050
+
3051
+ )}>
3052
+ <svg width="1.2em" height="1.2em" fill="#000000" viewBox="0 0 24 24"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" /></svg>
3053
+
3054
+ </var>
3055
+
3056
+ <var className={combinedCls(
3057
+ 'me-1 custom-select-multi__control-option-checkbox-placeholder',
3058
+ {
3059
+ 'd-none': itemSelected
3060
+ }
3061
+ )}>
3062
+ <svg width="1.2em" height="1.2em" fill="#000000" viewBox="0 0 24 24"><path d="M4 7.2002V16.8002C4 17.9203 4 18.4801 4.21799 18.9079C4.40973 19.2842 4.71547 19.5905 5.0918 19.7822C5.5192 20 6.07899 20 7.19691 20H16.8031C17.921 20 18.48 20 18.9074 19.7822C19.2837 19.5905 19.5905 19.2842 19.7822 18.9079C20 18.4805 20 17.9215 20 16.8036V7.19691C20 6.07899 20 5.5192 19.7822 5.0918C19.5905 4.71547 19.2837 4.40973 18.9074 4.21799C18.4796 4 17.9203 4 16.8002 4H7.2002C6.08009 4 5.51962 4 5.0918 4.21799C4.71547 4.40973 4.40973 4.71547 4.21799 5.0918C4 5.51962 4 6.08009 4 7.2002Z" /></svg>
3063
+ </var>
3064
+
3065
+ {typeof renderOption === 'function' ? <>
3066
+ {renderOption(item, index)}
3067
+ </> : <>
3068
+ <span dangerouslySetInnerHTML={{
3069
+ __html: typeof item.listItemLabel === 'undefined' ? item.label : item.listItemLabel
3070
+ }}></span>
3071
+ </>}
3072
+
3073
+
3074
+ </button>
3075
+
3076
+ }
3077
+
3078
+
3079
+ }) : null}
3080
+ </>
3081
+ )}
3082
+ {/* /OPTIONS LIST */}
3083
+
3084
+ </div>
3085
+ </div>
3086
+
3087
+
3088
+ </div>
3089
+
3090
+ </RootPortal>
3091
+
3092
+ </> : null}
3093
+
3094
+
3095
+
3096
+
3097
+ </div>
3098
+
3099
+
3100
+ </>
3101
+ )
3102
+ });
3103
+
3104
+ export default Select;