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.
- package/.gitattributes +2 -0
- package/README.md +116 -2
- package/README_PUBLISH.md +328 -0
- package/lib/cjs/Date/index.js +39 -2
- package/lib/cjs/DynamicFields/index.js +11 -3
- package/lib/esm/Date/index.tsx +47 -2
- package/lib/esm/DynamicFields/index.tsx +9 -4
- package/logo.png +0 -0
- package/package.json +589 -43
- package/preview.png +0 -0
- package/{Date → publish/Date}/index.js +39 -2
- package/{DynamicFields → publish/DynamicFields}/index.js +11 -3
- package/publish/LICENSE +21 -0
- package/publish/README.md +328 -0
- package/publish/lib/cjs/Accordion/index.d.ts +2 -0
- package/publish/lib/cjs/Accordion/index.js +667 -0
- package/publish/lib/cjs/BackToTop/index.d.ts +17 -0
- package/publish/lib/cjs/BackToTop/index.js +904 -0
- package/publish/lib/cjs/CascadingSelect/index.d.ts +80 -0
- package/publish/lib/cjs/CascadingSelect/index.js +3383 -0
- package/publish/lib/cjs/CascadingSelectE2E/index.d.ts +91 -0
- package/publish/lib/cjs/CascadingSelectE2E/index.js +3988 -0
- package/publish/lib/cjs/Chatbox/index.d.ts +101 -0
- package/publish/lib/cjs/Chatbox/index.js +7037 -0
- package/publish/lib/cjs/Checkbox/index.d.ts +28 -0
- package/publish/lib/cjs/Checkbox/index.js +673 -0
- package/publish/lib/cjs/ColorPicker/index.d.ts +27 -0
- package/publish/lib/cjs/ColorPicker/index.js +662 -0
- package/publish/lib/cjs/Date/index.d.ts +70 -0
- package/publish/lib/cjs/Date/index.js +6368 -0
- package/publish/lib/cjs/DigitalClock/index.d.ts +7 -0
- package/publish/lib/cjs/DigitalClock/index.js +402 -0
- package/publish/lib/cjs/DragDropList/index.d.ts +45 -0
- package/publish/lib/cjs/DragDropList/index.js +1586 -0
- package/publish/lib/cjs/DropdownMenu/index.d.ts +38 -0
- package/publish/lib/cjs/DropdownMenu/index.js +1507 -0
- package/publish/lib/cjs/DynamicFields/index.d.ts +40 -0
- package/publish/lib/cjs/DynamicFields/index.js +818 -0
- package/publish/lib/cjs/EventCalendar/index.d.ts +61 -0
- package/publish/lib/cjs/EventCalendar/index.js +3789 -0
- package/publish/lib/cjs/EventCalendarTimeline/index.d.ts +100 -0
- package/publish/lib/cjs/EventCalendarTimeline/index.js +6141 -0
- package/publish/lib/cjs/File/index.d.ts +40 -0
- package/publish/lib/cjs/File/index.js +1751 -0
- package/publish/lib/cjs/HorizontalScrollContent/index.d.ts +14 -0
- package/publish/lib/cjs/HorizontalScrollContent/index.js +426 -0
- package/publish/lib/cjs/Input/index.d.ts +59 -0
- package/publish/lib/cjs/Input/index.js +1486 -0
- package/publish/lib/cjs/LiveSearch/index.d.ts +70 -0
- package/publish/lib/cjs/LiveSearch/index.js +4180 -0
- package/publish/lib/cjs/MasonryLayout/index.d.ts +14 -0
- package/publish/lib/cjs/MasonryLayout/index.js +689 -0
- package/publish/lib/cjs/ModalDialog/index.d.ts +83 -0
- package/publish/lib/cjs/ModalDialog/index.js +1719 -0
- package/publish/lib/cjs/ModeSwitch/index.d.ts +17 -0
- package/publish/lib/cjs/ModeSwitch/index.js +202 -0
- package/publish/lib/cjs/MultilevelDropdownMenu/index.d.ts +20 -0
- package/publish/lib/cjs/MultilevelDropdownMenu/index.js +930 -0
- package/publish/lib/cjs/MultipleCheckboxes/index.d.ts +66 -0
- package/publish/lib/cjs/MultipleCheckboxes/index.js +2337 -0
- package/publish/lib/cjs/MultipleSelect/index.d.ts +65 -0
- package/publish/lib/cjs/MultipleSelect/index.js +4197 -0
- package/publish/lib/cjs/NativeSelect/index.d.ts +37 -0
- package/publish/lib/cjs/NativeSelect/index.js +2052 -0
- package/publish/lib/cjs/NumberInput/index.d.ts +40 -0
- package/publish/lib/cjs/NumberInput/index.js +1191 -0
- package/publish/lib/cjs/Pagination/index.d.ts +51 -0
- package/publish/lib/cjs/Pagination/index.js +612 -0
- package/publish/lib/cjs/Radio/index.d.ts +45 -0
- package/publish/lib/cjs/Radio/index.js +1838 -0
- package/publish/lib/cjs/RangeSlider/index.d.ts +22 -0
- package/publish/lib/cjs/RangeSlider/index.js +2696 -0
- package/publish/lib/cjs/Refresher/index.d.ts +22 -0
- package/publish/lib/cjs/Refresher/index.js +564 -0
- package/publish/lib/cjs/RootPortal/index.d.ts +9 -0
- package/publish/lib/cjs/RootPortal/index.js +148 -0
- package/publish/lib/cjs/ScrollReveal/index.d.ts +21 -0
- package/publish/lib/cjs/ScrollReveal/index.js +401 -0
- package/publish/lib/cjs/Scrollbar/index.d.ts +17 -0
- package/publish/lib/cjs/Scrollbar/index.js +1107 -0
- package/publish/lib/cjs/SearchBar/index.d.ts +41 -0
- package/publish/lib/cjs/SearchBar/index.js +701 -0
- package/publish/lib/cjs/Select/index.d.ts +107 -0
- package/publish/lib/cjs/Select/index.js +6540 -0
- package/publish/lib/cjs/ShowMoreLess/index.d.ts +36 -0
- package/publish/lib/cjs/ShowMoreLess/index.js +387 -0
- package/publish/lib/cjs/SplitterPanel/index.d.ts +20 -0
- package/publish/lib/cjs/SplitterPanel/index.js +800 -0
- package/publish/lib/cjs/Stepper/index.d.ts +26 -0
- package/publish/lib/cjs/Stepper/index.js +568 -0
- package/publish/lib/cjs/Switch/index.d.ts +25 -0
- package/publish/lib/cjs/Switch/index.js +630 -0
- package/publish/lib/cjs/Table/index.d.ts +12 -0
- package/publish/lib/cjs/Table/index.js +2311 -0
- package/publish/lib/cjs/Tabs/index.d.ts +3 -0
- package/publish/lib/cjs/Tabs/index.js +771 -0
- package/publish/lib/cjs/TagInput/index.d.ts +37 -0
- package/publish/lib/cjs/TagInput/index.js +1227 -0
- package/publish/lib/cjs/Textarea/index.d.ts +50 -0
- package/publish/lib/cjs/Textarea/index.js +1795 -0
- package/publish/lib/cjs/Toast/index.d.ts +3 -0
- package/publish/lib/cjs/Toast/index.js +1345 -0
- package/publish/lib/cjs/Tooltip/index.d.ts +38 -0
- package/publish/lib/cjs/Tooltip/index.js +1778 -0
- package/publish/lib/cjs/Tree/index.d.ts +78 -0
- package/publish/lib/cjs/Tree/index.js +2330 -0
- package/publish/lib/cjs/Utils/anim.d.ts +11 -0
- package/publish/lib/cjs/Utils/anim.js +846 -0
- package/publish/lib/cjs/Utils/bodyScrollLock.d.ts +8 -0
- package/publish/lib/cjs/Utils/bodyScrollLock.js +311 -0
- package/publish/lib/cjs/Utils/buffer.d.ts +67 -0
- package/publish/lib/cjs/Utils/buffer.js +343 -0
- package/publish/lib/cjs/Utils/cls.d.ts +15 -0
- package/publish/lib/cjs/Utils/cls.js +124 -0
- package/publish/lib/cjs/Utils/convert.d.ts +25 -0
- package/publish/lib/cjs/Utils/convert.js +109 -0
- package/publish/lib/cjs/Utils/date.d.ts +227 -0
- package/publish/lib/cjs/Utils/date.js +587 -0
- package/publish/lib/cjs/Utils/dom.d.ts +13 -0
- package/publish/lib/cjs/Utils/dom.js +215 -0
- package/publish/lib/cjs/Utils/easing.d.ts +29 -0
- package/publish/lib/cjs/Utils/easing.js +221 -0
- package/publish/lib/cjs/Utils/extract.d.ts +66 -0
- package/publish/lib/cjs/Utils/extract.js +195 -0
- package/publish/lib/cjs/Utils/format-string.d.ts +65 -0
- package/publish/lib/cjs/Utils/format-string.js +167 -0
- package/publish/lib/cjs/Utils/formdata.d.ts +13 -0
- package/publish/lib/cjs/Utils/formdata.js +131 -0
- package/publish/lib/cjs/Utils/getElementProperty.d.ts +52 -0
- package/publish/lib/cjs/Utils/getElementProperty.js +189 -0
- package/publish/lib/cjs/Utils/guid.d.ts +7 -0
- package/publish/lib/cjs/Utils/guid.js +67 -0
- package/publish/lib/cjs/Utils/initDefaultOptions.d.ts +10 -0
- package/publish/lib/cjs/Utils/initDefaultOptions.js +607 -0
- package/publish/lib/cjs/Utils/inputsCalculation.d.ts +28 -0
- package/publish/lib/cjs/Utils/inputsCalculation.js +188 -0
- package/publish/lib/cjs/Utils/math.d.ts +77 -0
- package/publish/lib/cjs/Utils/math.js +305 -0
- package/publish/lib/cjs/Utils/object.d.ts +18 -0
- package/publish/lib/cjs/Utils/object.js +120 -0
- package/publish/lib/cjs/Utils/os.d.ts +2 -0
- package/publish/lib/cjs/Utils/os.js +104 -0
- package/publish/lib/cjs/Utils/performance.d.ts +3 -0
- package/publish/lib/cjs/Utils/performance.js +94 -0
- package/publish/lib/cjs/Utils/sanitize.d.ts +14 -0
- package/publish/lib/cjs/Utils/sanitize.js +87 -0
- package/publish/lib/cjs/Utils/time.d.ts +40 -0
- package/publish/lib/cjs/Utils/time.js +177 -0
- package/publish/lib/cjs/Utils/tree.d.ts +40 -0
- package/publish/lib/cjs/Utils/tree.js +195 -0
- package/publish/lib/cjs/Utils/useAutosizeTextArea.d.ts +10 -0
- package/publish/lib/cjs/Utils/useAutosizeTextArea.js +231 -0
- package/publish/lib/cjs/Utils/useBoundedDrag.d.ts +125 -0
- package/publish/lib/cjs/Utils/useBoundedDrag.js +380 -0
- package/publish/lib/cjs/Utils/useClickOutside.d.ts +33 -0
- package/publish/lib/cjs/Utils/useClickOutside.js +166 -0
- package/publish/lib/cjs/Utils/useComId.d.ts +6 -0
- package/publish/lib/cjs/Utils/useComId.js +114 -0
- package/publish/lib/cjs/Utils/useDebounce.d.ts +20 -0
- package/publish/lib/cjs/Utils/useDebounce.js +138 -0
- package/publish/lib/cjs/Utils/useDragDropPosition.d.ts +166 -0
- package/publish/lib/cjs/Utils/useDragDropPosition.js +453 -0
- package/publish/lib/cjs/Utils/useDraggable.d.ts +62 -0
- package/publish/lib/cjs/Utils/useDraggable.js +348 -0
- package/publish/lib/cjs/Utils/useHistoryTracker.d.ts +166 -0
- package/publish/lib/cjs/Utils/useHistoryTracker.js +649 -0
- package/publish/lib/cjs/Utils/useInterval.d.ts +5 -0
- package/publish/lib/cjs/Utils/useInterval.js +168 -0
- package/publish/lib/cjs/Utils/useIsMobile.d.ts +2 -0
- package/publish/lib/cjs/Utils/useIsMobile.js +232 -0
- package/publish/lib/cjs/Utils/useKeyPress.d.ts +44 -0
- package/publish/lib/cjs/Utils/useKeyPress.js +200 -0
- package/publish/lib/cjs/Utils/useSessionStorageListener.d.ts +2 -0
- package/publish/lib/cjs/Utils/useSessionStorageListener.js +157 -0
- package/publish/lib/cjs/Utils/useStreamController.d.ts +71 -0
- package/publish/lib/cjs/Utils/useStreamController.js +494 -0
- package/publish/lib/cjs/Utils/useThrottle.d.ts +2 -0
- package/publish/lib/cjs/Utils/useThrottle.js +136 -0
- package/publish/lib/cjs/Utils/useWindowScroll.d.ts +12 -0
- package/publish/lib/cjs/Utils/useWindowScroll.js +217 -0
- package/publish/lib/cjs/Utils/validate.d.ts +53 -0
- package/publish/lib/cjs/Utils/validate.js +536 -0
- package/publish/lib/cjs/Utils/viewport.d.ts +7 -0
- package/publish/lib/cjs/Utils/viewport.js +64 -0
- package/publish/lib/cjs/index.d.ts +49 -0
- package/publish/lib/cjs/index.js +50 -0
- package/publish/lib/css/BackToTop/index.css +34 -0
- package/publish/lib/css/CascadingSelect/index.css +245 -0
- package/publish/lib/css/CascadingSelectE2E/index.css +245 -0
- package/publish/lib/css/Chatbox/index.css +774 -0
- package/publish/lib/css/ColorPicker/index.css +58 -0
- package/publish/lib/css/Date/index.css +434 -0
- package/publish/lib/css/DragDropList/index.css +188 -0
- package/publish/lib/css/DropdownMenu/index.css +151 -0
- package/publish/lib/css/EventCalendar/index.css +300 -0
- package/publish/lib/css/EventCalendarTimeline/index.css +694 -0
- package/publish/lib/css/HorizontalScrollContent/index.css +70 -0
- package/publish/lib/css/LiveSearch/index.css +88 -0
- package/publish/lib/css/MultilevelDropdownMenu/index.css +38 -0
- package/publish/lib/css/MultipleSelect/index.css +313 -0
- package/publish/lib/css/RangeSlider/index.css +150 -0
- package/publish/lib/css/Scrollbar/index.css +176 -0
- package/publish/lib/css/Select/index.css +434 -0
- package/publish/lib/css/ShowMoreLess/index.css +23 -0
- package/publish/lib/css/SplitterPanel/index.css +63 -0
- package/publish/lib/css/Stepper/index.css +250 -0
- package/publish/lib/css/Table/index.css +584 -0
- package/publish/lib/css/TagInput/index.css +91 -0
- package/publish/lib/css/Toast/index.css +149 -0
- package/publish/lib/css/Tooltip/index.css +198 -0
- package/publish/lib/css/Tree/index.css +237 -0
- package/publish/lib/esm/Accordion/Accordion.tsx +185 -0
- package/publish/lib/esm/Accordion/AccordionItem.tsx +248 -0
- package/publish/lib/esm/Accordion/index.tsx +2 -0
- package/publish/lib/esm/BackToTop/index.scss +47 -0
- package/publish/lib/esm/BackToTop/index.tsx +177 -0
- package/publish/lib/esm/CascadingSelect/Group.tsx +83 -0
- package/publish/lib/esm/CascadingSelect/index.scss +330 -0
- package/publish/lib/esm/CascadingSelect/index.tsx +1397 -0
- package/publish/lib/esm/CascadingSelectE2E/Group.tsx +87 -0
- package/publish/lib/esm/CascadingSelectE2E/index.scss +333 -0
- package/publish/lib/esm/CascadingSelectE2E/index.tsx +1684 -0
- package/publish/lib/esm/Chatbox/PureLoader.tsx +47 -0
- package/publish/lib/esm/Chatbox/TypingEffect.tsx +56 -0
- package/publish/lib/esm/Chatbox/index.scss +966 -0
- package/publish/lib/esm/Chatbox/index.tsx +1742 -0
- package/publish/lib/esm/Chatbox/utils/func.ts +180 -0
- package/publish/lib/esm/Checkbox/index.tsx +206 -0
- package/publish/lib/esm/ColorPicker/index.scss +91 -0
- package/publish/lib/esm/ColorPicker/index.tsx +204 -0
- package/publish/lib/esm/Date/Calendar.tsx +723 -0
- package/publish/lib/esm/Date/index.scss +567 -0
- package/publish/lib/esm/Date/index.tsx +1797 -0
- package/publish/lib/esm/Date/localization/en_US.js +13 -0
- package/publish/lib/esm/Date/localization/zh_CN.js +12 -0
- package/publish/lib/esm/DigitalClock/index.tsx +74 -0
- package/publish/lib/esm/DragDropList/index.scss +245 -0
- package/publish/lib/esm/DragDropList/index.tsx +504 -0
- package/publish/lib/esm/DropdownMenu/Option.tsx +55 -0
- package/publish/lib/esm/DropdownMenu/index.scss +205 -0
- package/publish/lib/esm/DropdownMenu/index.tsx +378 -0
- package/publish/lib/esm/DynamicFields/index.tsx +409 -0
- package/publish/lib/esm/EventCalendar/index.scss +407 -0
- package/publish/lib/esm/EventCalendar/index.tsx +1005 -0
- package/publish/lib/esm/EventCalendarTimeline/index.scss +926 -0
- package/publish/lib/esm/EventCalendarTimeline/index.tsx +2686 -0
- package/publish/lib/esm/File/index.tsx +477 -0
- package/publish/lib/esm/HorizontalScrollContent/index.scss +87 -0
- package/publish/lib/esm/HorizontalScrollContent/index.tsx +171 -0
- package/publish/lib/esm/Input/index.tsx +641 -0
- package/publish/lib/esm/LiveSearch/index.scss +129 -0
- package/publish/lib/esm/LiveSearch/index.tsx +1058 -0
- package/publish/lib/esm/MasonryLayout/index.tsx +326 -0
- package/publish/lib/esm/ModalDialog/index.tsx +572 -0
- package/publish/lib/esm/ModeSwitch/index.tsx +82 -0
- package/publish/lib/esm/MultilevelDropdownMenu/ItemList.tsx +265 -0
- package/publish/lib/esm/MultilevelDropdownMenu/index.scss +79 -0
- package/publish/lib/esm/MultilevelDropdownMenu/index.tsx +77 -0
- package/publish/lib/esm/MultipleCheckboxes/index.tsx +849 -0
- package/publish/lib/esm/MultipleSelect/index.scss +398 -0
- package/publish/lib/esm/MultipleSelect/index.tsx +769 -0
- package/publish/lib/esm/MultipleSelect/utils/func.ts +63 -0
- package/publish/lib/esm/NativeSelect/index.tsx +396 -0
- package/publish/lib/esm/NativeSelect/utils/func.ts +51 -0
- package/publish/lib/esm/NumberInput/index.tsx +425 -0
- package/publish/lib/esm/Pagination/index.tsx +286 -0
- package/publish/lib/esm/Pagination/pagination-navigators.tsx +60 -0
- package/publish/lib/esm/Radio/index.tsx +694 -0
- package/publish/lib/esm/RangeSlider/index.scss +186 -0
- package/publish/lib/esm/RangeSlider/index.tsx +241 -0
- package/publish/lib/esm/Refresher/index.tsx +121 -0
- package/publish/lib/esm/RootPortal/index.tsx +59 -0
- package/publish/lib/esm/ScrollReveal/index.tsx +148 -0
- package/publish/lib/esm/Scrollbar/index.scss +221 -0
- package/publish/lib/esm/Scrollbar/index.tsx +561 -0
- package/publish/lib/esm/SearchBar/index.tsx +252 -0
- package/publish/lib/esm/Select/index.scss +639 -0
- package/publish/lib/esm/Select/index.tsx +3104 -0
- package/publish/lib/esm/Select/utils/func.ts +98 -0
- package/publish/lib/esm/ShowMoreLess/index.scss +27 -0
- package/publish/lib/esm/ShowMoreLess/index.tsx +145 -0
- package/publish/lib/esm/SplitterPanel/index.scss +82 -0
- package/publish/lib/esm/SplitterPanel/index.tsx +174 -0
- package/publish/lib/esm/Stepper/index.scss +315 -0
- package/publish/lib/esm/Stepper/index.tsx +325 -0
- package/publish/lib/esm/Switch/index.tsx +149 -0
- package/publish/lib/esm/Table/Table.tsx +351 -0
- package/publish/lib/esm/Table/TableBody.tsx +41 -0
- package/publish/lib/esm/Table/TableCaption.tsx +34 -0
- package/publish/lib/esm/Table/TableCell.tsx +126 -0
- package/publish/lib/esm/Table/TableColgroup.tsx +38 -0
- package/publish/lib/esm/Table/TableContext.tsx +26 -0
- package/publish/lib/esm/Table/TableFoot.tsx +28 -0
- package/publish/lib/esm/Table/TableHead.tsx +28 -0
- package/publish/lib/esm/Table/TableRow.tsx +76 -0
- package/publish/lib/esm/Table/index.scss +418 -0
- package/publish/lib/esm/Table/index.tsx +14 -0
- package/publish/lib/esm/Table/utils/DragHandleSprite.tsx +46 -0
- package/publish/lib/esm/Table/utils/SortSprite.tsx +63 -0
- package/publish/lib/esm/Table/utils/TableFilter.tsx +56 -0
- package/publish/lib/esm/Table/utils/ToggleSelection.tsx +255 -0
- package/publish/lib/esm/Table/utils/func.ts +182 -0
- package/publish/lib/esm/Table/utils/hooks/useTableDraggable.tsx +342 -0
- package/publish/lib/esm/Table/utils/hooks/useTableKeyPress.tsx +255 -0
- package/publish/lib/esm/Table/utils/hooks/useTableResponsive.tsx +92 -0
- package/publish/lib/esm/Table/utils/hooks/useTableSort.tsx +187 -0
- package/publish/lib/esm/Tabs/TabList.tsx +50 -0
- package/publish/lib/esm/Tabs/TabPanel.tsx +44 -0
- package/publish/lib/esm/Tabs/Tabs.tsx +282 -0
- package/publish/lib/esm/Tabs/index.tsx +3 -0
- package/publish/lib/esm/TagInput/index.scss +126 -0
- package/publish/lib/esm/TagInput/index.tsx +379 -0
- package/publish/lib/esm/Textarea/index.tsx +621 -0
- package/publish/lib/esm/Toast/Item.tsx +165 -0
- package/publish/lib/esm/Toast/Toast.tsx +391 -0
- package/publish/lib/esm/Toast/ToastContext.tsx +104 -0
- package/publish/lib/esm/Toast/__toast.vanilla.js +422 -0
- package/publish/lib/esm/Toast/index.scss +197 -0
- package/publish/lib/esm/Toast/index.tsx +3 -0
- package/publish/lib/esm/Toast/types.ts +60 -0
- package/publish/lib/esm/Toast/useToast.tsx +72 -0
- package/publish/lib/esm/Tooltip/index.scss +272 -0
- package/publish/lib/esm/Tooltip/index.tsx +416 -0
- package/publish/lib/esm/Tree/TreeList.tsx +600 -0
- package/publish/lib/esm/Tree/index.scss +384 -0
- package/publish/lib/esm/Tree/index.tsx +661 -0
- package/publish/lib/esm/Tree/init-height.tsx +40 -0
- package/publish/lib/esm/Tree/utils/func.ts +15 -0
- package/publish/lib/esm/Utils/hooks/useAutosizeTextArea.tsx +131 -0
- package/publish/lib/esm/Utils/hooks/useBoundedDrag.tsx +301 -0
- package/publish/lib/esm/Utils/hooks/useClickOutside.tsx +69 -0
- package/publish/lib/esm/Utils/hooks/useComId.tsx +13 -0
- package/publish/lib/esm/Utils/hooks/useDebounce.tsx +40 -0
- package/publish/lib/esm/Utils/hooks/useDragDropPosition.tsx +417 -0
- package/publish/lib/esm/Utils/hooks/useDraggable.tsx +265 -0
- package/publish/lib/esm/Utils/hooks/useHistoryTracker.tsx +554 -0
- package/publish/lib/esm/Utils/hooks/useInterval.tsx +74 -0
- package/publish/lib/esm/Utils/hooks/useIsMobile.tsx +139 -0
- package/publish/lib/esm/Utils/hooks/useKeyPress.tsx +104 -0
- package/publish/lib/esm/Utils/hooks/useSessionStorageListener.tsx +45 -0
- package/publish/lib/esm/Utils/hooks/useStreamController.tsx +277 -0
- package/publish/lib/esm/Utils/hooks/useThrottle.tsx +39 -0
- package/publish/lib/esm/Utils/hooks/useWindowScroll.tsx +83 -0
- package/publish/lib/esm/Utils/libs/anim.ts +96 -0
- package/publish/lib/esm/Utils/libs/buffer.ts +262 -0
- package/publish/lib/esm/Utils/libs/cls.ts +64 -0
- package/publish/lib/esm/Utils/libs/convert.ts +59 -0
- package/publish/lib/esm/Utils/libs/date.ts +598 -0
- package/publish/lib/esm/Utils/libs/dom.ts +150 -0
- package/publish/lib/esm/Utils/libs/easing.ts +201 -0
- package/publish/lib/esm/Utils/libs/extract.ts +160 -0
- package/publish/lib/esm/Utils/libs/format-string.ts +116 -0
- package/publish/lib/esm/Utils/libs/formdata.ts +93 -0
- package/publish/lib/esm/Utils/libs/getElementProperty.ts +150 -0
- package/publish/lib/esm/Utils/libs/guid.ts +16 -0
- package/publish/lib/esm/Utils/libs/initDefaultOptions.ts +43 -0
- package/publish/lib/esm/Utils/libs/inputsCalculation.ts +160 -0
- package/publish/lib/esm/Utils/libs/math.ts +276 -0
- package/publish/lib/esm/Utils/libs/object.ts +68 -0
- package/publish/lib/esm/Utils/libs/os.ts +63 -0
- package/publish/lib/esm/Utils/libs/performance.ts +47 -0
- package/publish/lib/esm/Utils/libs/sanitize.ts +55 -0
- package/publish/lib/esm/Utils/libs/time.ts +139 -0
- package/publish/lib/esm/Utils/libs/tree.ts +119 -0
- package/publish/lib/esm/Utils/libs/validate.ts +434 -0
- package/publish/lib/esm/Utils/libs/viewport.ts +20 -0
- package/publish/lib/esm/Utils/plugins/bodyScrollLock.ts +286 -0
- package/publish/lib/esm/index.js +47 -0
- package/publish/package.json +1 -0
- /package/{Accordion → publish/Accordion}/index.d.ts +0 -0
- /package/{Accordion → publish/Accordion}/index.js +0 -0
- /package/{BackToTop → publish/BackToTop}/index.css +0 -0
- /package/{BackToTop → publish/BackToTop}/index.d.ts +0 -0
- /package/{BackToTop → publish/BackToTop}/index.js +0 -0
- /package/{CascadingSelect → publish/CascadingSelect}/index.css +0 -0
- /package/{CascadingSelect → publish/CascadingSelect}/index.d.ts +0 -0
- /package/{CascadingSelect → publish/CascadingSelect}/index.js +0 -0
- /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.css +0 -0
- /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.d.ts +0 -0
- /package/{CascadingSelectE2E → publish/CascadingSelectE2E}/index.js +0 -0
- /package/{Chatbox → publish/Chatbox}/index.css +0 -0
- /package/{Chatbox → publish/Chatbox}/index.d.ts +0 -0
- /package/{Chatbox → publish/Chatbox}/index.js +0 -0
- /package/{Checkbox → publish/Checkbox}/index.d.ts +0 -0
- /package/{Checkbox → publish/Checkbox}/index.js +0 -0
- /package/{ColorPicker → publish/ColorPicker}/index.css +0 -0
- /package/{ColorPicker → publish/ColorPicker}/index.d.ts +0 -0
- /package/{ColorPicker → publish/ColorPicker}/index.js +0 -0
- /package/{Date → publish/Date}/index.css +0 -0
- /package/{Date → publish/Date}/index.d.ts +0 -0
- /package/{DigitalClock → publish/DigitalClock}/index.d.ts +0 -0
- /package/{DigitalClock → publish/DigitalClock}/index.js +0 -0
- /package/{DragDropList → publish/DragDropList}/index.css +0 -0
- /package/{DragDropList → publish/DragDropList}/index.d.ts +0 -0
- /package/{DragDropList → publish/DragDropList}/index.js +0 -0
- /package/{DropdownMenu → publish/DropdownMenu}/index.css +0 -0
- /package/{DropdownMenu → publish/DropdownMenu}/index.d.ts +0 -0
- /package/{DropdownMenu → publish/DropdownMenu}/index.js +0 -0
- /package/{DynamicFields → publish/DynamicFields}/index.d.ts +0 -0
- /package/{EventCalendar → publish/EventCalendar}/index.css +0 -0
- /package/{EventCalendar → publish/EventCalendar}/index.d.ts +0 -0
- /package/{EventCalendar → publish/EventCalendar}/index.js +0 -0
- /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.css +0 -0
- /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.d.ts +0 -0
- /package/{EventCalendarTimeline → publish/EventCalendarTimeline}/index.js +0 -0
- /package/{File → publish/File}/index.d.ts +0 -0
- /package/{File → publish/File}/index.js +0 -0
- /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.css +0 -0
- /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.d.ts +0 -0
- /package/{HorizontalScrollContent → publish/HorizontalScrollContent}/index.js +0 -0
- /package/{Input → publish/Input}/index.d.ts +0 -0
- /package/{Input → publish/Input}/index.js +0 -0
- /package/{LiveSearch → publish/LiveSearch}/index.css +0 -0
- /package/{LiveSearch → publish/LiveSearch}/index.d.ts +0 -0
- /package/{LiveSearch → publish/LiveSearch}/index.js +0 -0
- /package/{MasonryLayout → publish/MasonryLayout}/index.d.ts +0 -0
- /package/{MasonryLayout → publish/MasonryLayout}/index.js +0 -0
- /package/{ModalDialog → publish/ModalDialog}/index.d.ts +0 -0
- /package/{ModalDialog → publish/ModalDialog}/index.js +0 -0
- /package/{ModeSwitch → publish/ModeSwitch}/index.d.ts +0 -0
- /package/{ModeSwitch → publish/ModeSwitch}/index.js +0 -0
- /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.css +0 -0
- /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.d.ts +0 -0
- /package/{MultilevelDropdownMenu → publish/MultilevelDropdownMenu}/index.js +0 -0
- /package/{MultipleCheckboxes → publish/MultipleCheckboxes}/index.d.ts +0 -0
- /package/{MultipleCheckboxes → publish/MultipleCheckboxes}/index.js +0 -0
- /package/{MultipleSelect → publish/MultipleSelect}/index.css +0 -0
- /package/{MultipleSelect → publish/MultipleSelect}/index.d.ts +0 -0
- /package/{MultipleSelect → publish/MultipleSelect}/index.js +0 -0
- /package/{NativeSelect → publish/NativeSelect}/index.d.ts +0 -0
- /package/{NativeSelect → publish/NativeSelect}/index.js +0 -0
- /package/{NumberInput → publish/NumberInput}/index.d.ts +0 -0
- /package/{NumberInput → publish/NumberInput}/index.js +0 -0
- /package/{Pagination → publish/Pagination}/index.d.ts +0 -0
- /package/{Pagination → publish/Pagination}/index.js +0 -0
- /package/{Radio → publish/Radio}/index.d.ts +0 -0
- /package/{Radio → publish/Radio}/index.js +0 -0
- /package/{RangeSlider → publish/RangeSlider}/index.css +0 -0
- /package/{RangeSlider → publish/RangeSlider}/index.d.ts +0 -0
- /package/{RangeSlider → publish/RangeSlider}/index.js +0 -0
- /package/{Refresher → publish/Refresher}/index.d.ts +0 -0
- /package/{Refresher → publish/Refresher}/index.js +0 -0
- /package/{RootPortal → publish/RootPortal}/index.d.ts +0 -0
- /package/{RootPortal → publish/RootPortal}/index.js +0 -0
- /package/{ScrollReveal → publish/ScrollReveal}/index.d.ts +0 -0
- /package/{ScrollReveal → publish/ScrollReveal}/index.js +0 -0
- /package/{Scrollbar → publish/Scrollbar}/index.css +0 -0
- /package/{Scrollbar → publish/Scrollbar}/index.d.ts +0 -0
- /package/{Scrollbar → publish/Scrollbar}/index.js +0 -0
- /package/{SearchBar → publish/SearchBar}/index.d.ts +0 -0
- /package/{SearchBar → publish/SearchBar}/index.js +0 -0
- /package/{Select → publish/Select}/index.css +0 -0
- /package/{Select → publish/Select}/index.d.ts +0 -0
- /package/{Select → publish/Select}/index.js +0 -0
- /package/{ShowMoreLess → publish/ShowMoreLess}/index.css +0 -0
- /package/{ShowMoreLess → publish/ShowMoreLess}/index.d.ts +0 -0
- /package/{ShowMoreLess → publish/ShowMoreLess}/index.js +0 -0
- /package/{SplitterPanel → publish/SplitterPanel}/index.css +0 -0
- /package/{SplitterPanel → publish/SplitterPanel}/index.d.ts +0 -0
- /package/{SplitterPanel → publish/SplitterPanel}/index.js +0 -0
- /package/{Stepper → publish/Stepper}/index.css +0 -0
- /package/{Stepper → publish/Stepper}/index.d.ts +0 -0
- /package/{Stepper → publish/Stepper}/index.js +0 -0
- /package/{Switch → publish/Switch}/index.d.ts +0 -0
- /package/{Switch → publish/Switch}/index.js +0 -0
- /package/{Table → publish/Table}/index.css +0 -0
- /package/{Table → publish/Table}/index.d.ts +0 -0
- /package/{Table → publish/Table}/index.js +0 -0
- /package/{Tabs → publish/Tabs}/index.d.ts +0 -0
- /package/{Tabs → publish/Tabs}/index.js +0 -0
- /package/{TagInput → publish/TagInput}/index.css +0 -0
- /package/{TagInput → publish/TagInput}/index.d.ts +0 -0
- /package/{TagInput → publish/TagInput}/index.js +0 -0
- /package/{Textarea → publish/Textarea}/index.d.ts +0 -0
- /package/{Textarea → publish/Textarea}/index.js +0 -0
- /package/{Toast → publish/Toast}/index.css +0 -0
- /package/{Toast → publish/Toast}/index.d.ts +0 -0
- /package/{Toast → publish/Toast}/index.js +0 -0
- /package/{Tooltip → publish/Tooltip}/index.css +0 -0
- /package/{Tooltip → publish/Tooltip}/index.d.ts +0 -0
- /package/{Tooltip → publish/Tooltip}/index.js +0 -0
- /package/{Tree → publish/Tree}/index.css +0 -0
- /package/{Tree → publish/Tree}/index.d.ts +0 -0
- /package/{Tree → publish/Tree}/index.js +0 -0
- /package/{Utils → publish/Utils}/anim.d.ts +0 -0
- /package/{Utils → publish/Utils}/anim.js +0 -0
- /package/{Utils → publish/Utils}/bodyScrollLock.d.ts +0 -0
- /package/{Utils → publish/Utils}/bodyScrollLock.js +0 -0
- /package/{Utils → publish/Utils}/buffer.d.ts +0 -0
- /package/{Utils → publish/Utils}/buffer.js +0 -0
- /package/{Utils → publish/Utils}/cls.d.ts +0 -0
- /package/{Utils → publish/Utils}/cls.js +0 -0
- /package/{Utils → publish/Utils}/convert.d.ts +0 -0
- /package/{Utils → publish/Utils}/convert.js +0 -0
- /package/{Utils → publish/Utils}/date.d.ts +0 -0
- /package/{Utils → publish/Utils}/date.js +0 -0
- /package/{Utils → publish/Utils}/dom.d.ts +0 -0
- /package/{Utils → publish/Utils}/dom.js +0 -0
- /package/{Utils → publish/Utils}/easing.d.ts +0 -0
- /package/{Utils → publish/Utils}/easing.js +0 -0
- /package/{Utils → publish/Utils}/extract.d.ts +0 -0
- /package/{Utils → publish/Utils}/extract.js +0 -0
- /package/{Utils → publish/Utils}/format-string.d.ts +0 -0
- /package/{Utils → publish/Utils}/format-string.js +0 -0
- /package/{Utils → publish/Utils}/formdata.d.ts +0 -0
- /package/{Utils → publish/Utils}/formdata.js +0 -0
- /package/{Utils → publish/Utils}/getElementProperty.d.ts +0 -0
- /package/{Utils → publish/Utils}/getElementProperty.js +0 -0
- /package/{Utils → publish/Utils}/guid.d.ts +0 -0
- /package/{Utils → publish/Utils}/guid.js +0 -0
- /package/{Utils → publish/Utils}/initDefaultOptions.d.ts +0 -0
- /package/{Utils → publish/Utils}/initDefaultOptions.js +0 -0
- /package/{Utils → publish/Utils}/inputsCalculation.d.ts +0 -0
- /package/{Utils → publish/Utils}/inputsCalculation.js +0 -0
- /package/{Utils → publish/Utils}/math.d.ts +0 -0
- /package/{Utils → publish/Utils}/math.js +0 -0
- /package/{Utils → publish/Utils}/object.d.ts +0 -0
- /package/{Utils → publish/Utils}/object.js +0 -0
- /package/{Utils → publish/Utils}/os.d.ts +0 -0
- /package/{Utils → publish/Utils}/os.js +0 -0
- /package/{Utils → publish/Utils}/performance.d.ts +0 -0
- /package/{Utils → publish/Utils}/performance.js +0 -0
- /package/{Utils → publish/Utils}/sanitize.d.ts +0 -0
- /package/{Utils → publish/Utils}/sanitize.js +0 -0
- /package/{Utils → publish/Utils}/time.d.ts +0 -0
- /package/{Utils → publish/Utils}/time.js +0 -0
- /package/{Utils → publish/Utils}/tree.d.ts +0 -0
- /package/{Utils → publish/Utils}/tree.js +0 -0
- /package/{Utils → publish/Utils}/useAutosizeTextArea.d.ts +0 -0
- /package/{Utils → publish/Utils}/useAutosizeTextArea.js +0 -0
- /package/{Utils → publish/Utils}/useBoundedDrag.d.ts +0 -0
- /package/{Utils → publish/Utils}/useBoundedDrag.js +0 -0
- /package/{Utils → publish/Utils}/useClickOutside.d.ts +0 -0
- /package/{Utils → publish/Utils}/useClickOutside.js +0 -0
- /package/{Utils → publish/Utils}/useComId.d.ts +0 -0
- /package/{Utils → publish/Utils}/useComId.js +0 -0
- /package/{Utils → publish/Utils}/useDebounce.d.ts +0 -0
- /package/{Utils → publish/Utils}/useDebounce.js +0 -0
- /package/{Utils → publish/Utils}/useDragDropPosition.d.ts +0 -0
- /package/{Utils → publish/Utils}/useDragDropPosition.js +0 -0
- /package/{Utils → publish/Utils}/useDraggable.d.ts +0 -0
- /package/{Utils → publish/Utils}/useDraggable.js +0 -0
- /package/{Utils → publish/Utils}/useHistoryTracker.d.ts +0 -0
- /package/{Utils → publish/Utils}/useHistoryTracker.js +0 -0
- /package/{Utils → publish/Utils}/useInterval.d.ts +0 -0
- /package/{Utils → publish/Utils}/useInterval.js +0 -0
- /package/{Utils → publish/Utils}/useIsMobile.d.ts +0 -0
- /package/{Utils → publish/Utils}/useIsMobile.js +0 -0
- /package/{Utils → publish/Utils}/useKeyPress.d.ts +0 -0
- /package/{Utils → publish/Utils}/useKeyPress.js +0 -0
- /package/{Utils → publish/Utils}/useSessionStorageListener.d.ts +0 -0
- /package/{Utils → publish/Utils}/useSessionStorageListener.js +0 -0
- /package/{Utils → publish/Utils}/useStreamController.d.ts +0 -0
- /package/{Utils → publish/Utils}/useStreamController.js +0 -0
- /package/{Utils → publish/Utils}/useThrottle.d.ts +0 -0
- /package/{Utils → publish/Utils}/useThrottle.js +0 -0
- /package/{Utils → publish/Utils}/useWindowScroll.d.ts +0 -0
- /package/{Utils → publish/Utils}/useWindowScroll.js +0 -0
- /package/{Utils → publish/Utils}/validate.d.ts +0 -0
- /package/{Utils → publish/Utils}/validate.js +0 -0
- /package/{Utils → publish/Utils}/viewport.d.ts +0 -0
- /package/{Utils → publish/Utils}/viewport.js +0 -0
- /package/{all.d.ts → publish/all.d.ts} +0 -0
- /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 ? ` ` : ` `;
|
|
256
|
+
const INDENT_LAST_PLACEHOLDER = `${typeof indentation !== 'undefined' && indentation !== '' ? `${indentation} ` : ''}`;
|
|
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;
|