@mindlogic-ai/logician-ui 2.0.0-alpha.0
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/LICENSE +21 -0
- package/README.md +234 -0
- package/USAGE.md +299 -0
- package/dist/Markdown-2D5K42BY.js +16 -0
- package/dist/Markdown-2D5K42BY.js.map +1 -0
- package/dist/Markdown-AZBXO5ZP.css +29 -0
- package/dist/Markdown-AZBXO5ZP.css.map +1 -0
- package/dist/Markdown-RJJEQN4R.mjs +3 -0
- package/dist/Markdown-RJJEQN4R.mjs.map +1 -0
- package/dist/analytics-GNSHP7X3.svg +1 -0
- package/dist/bulb-24SQINQB.svg +1 -0
- package/dist/chat-TLRFEUAS.svg +1 -0
- package/dist/chunk-5FHXD7KR.js +1735 -0
- package/dist/chunk-5FHXD7KR.js.map +1 -0
- package/dist/chunk-WSOHBA2C.mjs +1693 -0
- package/dist/chunk-WSOHBA2C.mjs.map +1 -0
- package/dist/edit-RWL72JNM.svg +1 -0
- package/dist/face-55KPDCH4.svg +1 -0
- package/dist/filled-analytics-RBC7KWND.svg +1 -0
- package/dist/filled-bulb-RC7E2WSM.svg +1 -0
- package/dist/filled-chat-A6J44Q7A.svg +1 -0
- package/dist/filled-edit-NKKWFSTW.svg +1 -0
- package/dist/filled-face-UML5C3LB.svg +1 -0
- package/dist/filled-layout-HBVCSDFO.svg +1 -0
- package/dist/index.css +51 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +964 -0
- package/dist/index.d.ts +964 -0
- package/dist/index.js +5600 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5401 -0
- package/dist/index.mjs.map +1 -0
- package/dist/language-VBJ24OPV.svg +1 -0
- package/dist/layout-NDDSWNNV.svg +1 -0
- package/dist/pending-NF7NSBYO.svg +1 -0
- package/dist/receipt-MNLQIFCO.svg +1 -0
- package/dist/sparkles-EOEGVL6G.svg +1 -0
- package/dist/store-3RQPBJWG.svg +1 -0
- package/dist/store_active-SAOAGVKC.svg +1 -0
- package/dist/studio-LYPUIEFA.svg +1 -0
- package/dist/studio_active-BC6O66OI.svg +1 -0
- package/dist/vertical-ellipsis-3G4WEOCW.svg +1 -0
- package/package.json +138 -0
- package/src/components/Accordion/Accordion.stories.tsx +41 -0
- package/src/components/Accordion/Accordion.tsx +14 -0
- package/src/components/Accordion/AccordionButton.tsx +40 -0
- package/src/components/Accordion/AccordionItem.tsx +17 -0
- package/src/components/Accordion/index.ts +4 -0
- package/src/components/Alert/Alert.stories.tsx +38 -0
- package/src/components/Alert/Alert.styles.ts +19 -0
- package/src/components/Alert/Alert.tsx +41 -0
- package/src/components/Alert/Alert.types.ts +5 -0
- package/src/components/Alert/index.ts +1 -0
- package/src/components/AutowidthInput/AutowidthInput.stories.tsx +23 -0
- package/src/components/AutowidthInput/AutowidthInput.tsx +47 -0
- package/src/components/AutowidthInput/index.ts +1 -0
- package/src/components/Avatar/Avatar.stories.tsx +23 -0
- package/src/components/Avatar/Avatar.tsx +19 -0
- package/src/components/Avatar/index.tsx +1 -0
- package/src/components/Badge/Badge.stories.tsx +23 -0
- package/src/components/Badge/Badge.styles.ts +11 -0
- package/src/components/Badge/Badge.tsx +26 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Banner/Banner.stories.tsx +37 -0
- package/src/components/Banner/Banner.styles.ts +79 -0
- package/src/components/Banner/Banner.tsx +68 -0
- package/src/components/Banner/Banner.types.ts +6 -0
- package/src/components/Banner/index.ts +2 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +14 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +19 -0
- package/src/components/Breadcrumb/Breadcrumb.types.ts +3 -0
- package/src/components/Breadcrumb/BreadcrumbItem/BreadcrumbItem.tsx +12 -0
- package/src/components/Breadcrumb/BreadcrumbItem/BreadcrumbItem.types.ts +3 -0
- package/src/components/Breadcrumb/BreadcrumbItem/index.ts +2 -0
- package/src/components/Breadcrumb/BreadcrumbLink/BreadcrumbLink.tsx +30 -0
- package/src/components/Breadcrumb/BreadcrumbLink/BreadcrumbLink.types.ts +3 -0
- package/src/components/Breadcrumb/BreadcrumbLink/index.ts +2 -0
- package/src/components/Breadcrumb/index.ts +3 -0
- package/src/components/Button/Button.stories.tsx +52 -0
- package/src/components/Button/Button.styles.ts +59 -0
- package/src/components/Button/Button.tsx +43 -0
- package/src/components/Button/Button.types.ts +13 -0
- package/src/components/Button/index.tsx +3 -0
- package/src/components/Card/Card.stories.tsx +24 -0
- package/src/components/Card/Card.styles.ts +30 -0
- package/src/components/Card/Card.tsx +29 -0
- package/src/components/Card/Card.types.ts +8 -0
- package/src/components/Card/index.ts +2 -0
- package/src/components/Carousel/Carousel.stories.tsx +159 -0
- package/src/components/Carousel/Carousel.tsx +160 -0
- package/src/components/Carousel/Carousel.types.ts +22 -0
- package/src/components/Carousel/index.ts +1 -0
- package/src/components/CarouselModal/CarouselModal.stories.tsx +53 -0
- package/src/components/CarouselModal/CarouselModal.tsx +106 -0
- package/src/components/CarouselModal/CarouselModal.types.ts +16 -0
- package/src/components/CarouselModal/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +16 -0
- package/src/components/Checkbox/Checkbox.tsx +29 -0
- package/src/components/Checkbox/Checkbox.types.ts +3 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/Chip/Chip.stories.tsx +44 -0
- package/src/components/Chip/Chip.styles.ts +114 -0
- package/src/components/Chip/Chip.tsx +23 -0
- package/src/components/Chip/Chip.types.ts +14 -0
- package/src/components/Chip/index.ts +2 -0
- package/src/components/ChipButton/Chip.types.ts +4 -0
- package/src/components/ChipButton/ChipButton.tsx +25 -0
- package/src/components/ChipButton/index.ts +1 -0
- package/src/components/Code/Code.stories.tsx +28 -0
- package/src/components/Code/Code.tsx +160 -0
- package/src/components/Code/Code.types.ts +40 -0
- package/src/components/Code/_components/CopyButton.tsx +48 -0
- package/src/components/Code/index.ts +1 -0
- package/src/components/CodeTabs/CodeTabs.stories.tsx +51 -0
- package/src/components/CodeTabs/CodeTabs.tsx +98 -0
- package/src/components/CodeTabs/CodeTabs.types.ts +17 -0
- package/src/components/CodeTabs/index.ts +1 -0
- package/src/components/Container/Container.stories.tsx +28 -0
- package/src/components/Container/Container.tsx +21 -0
- package/src/components/Container/index.ts +1 -0
- package/src/components/Container/useContainerSize.ts +47 -0
- package/src/components/CopyableCode/CopyableCode.stories.tsx +26 -0
- package/src/components/CopyableCode/CopyableCode.tsx +58 -0
- package/src/components/CopyableCode/CopyableCode.types.ts +7 -0
- package/src/components/CopyableCode/index.ts +2 -0
- package/src/components/CrossPageToasts/CrossPageToasts.tsx +33 -0
- package/src/components/CrossPageToasts/index.ts +1 -0
- package/src/components/DataField/DataField.stories.tsx +61 -0
- package/src/components/DataField/DataField.styles.ts +33 -0
- package/src/components/DataField/DataField.tsx +141 -0
- package/src/components/DataField/DataField.types.ts +18 -0
- package/src/components/DataField/index.ts +1 -0
- package/src/components/DatePicker/RangeDatePicker.stories.tsx +45 -0
- package/src/components/DatePicker/RangeDatePicker.tsx +74 -0
- package/src/components/DatePicker/SingleDatePicker.stories.tsx +31 -0
- package/src/components/DatePicker/SingleDatePicker.tsx +72 -0
- package/src/components/DatePicker/index.ts +2 -0
- package/src/components/FileInput/FileInput.stories.tsx +28 -0
- package/src/components/FileInput/FileInput.tsx +117 -0
- package/src/components/FileInput/FileInput.types.ts +14 -0
- package/src/components/FileInput/index.ts +2 -0
- package/src/components/FileItem/FileItem.stories.tsx +27 -0
- package/src/components/FileItem/FileItem.tsx +134 -0
- package/src/components/FileItem/FileItem.types.ts +11 -0
- package/src/components/FileItem/index.ts +1 -0
- package/src/components/FileList/FileList.stories.tsx +65 -0
- package/src/components/FileList/FileList.tsx +97 -0
- package/src/components/FileList/FileList.types.ts +18 -0
- package/src/components/FileList/index.tsx +1 -0
- package/src/components/FormControl/FormControl.stories.tsx +16 -0
- package/src/components/FormControl/FormControl.tsx +12 -0
- package/src/components/FormControl/FormControl.types.ts +3 -0
- package/src/components/FormControl/index.ts +2 -0
- package/src/components/FormLabel/FormLabel.tsx +5 -0
- package/src/components/FormLabel/index.ts +1 -0
- package/src/components/GuideCue/GuideCue.stories.tsx +57 -0
- package/src/components/GuideCue/GuideCue.tsx +231 -0
- package/src/components/GuideCue/GuideCueContext.tsx +70 -0
- package/src/components/GuideCue/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +77 -0
- package/src/components/Icon/Icon.styles.ts +6 -0
- package/src/components/Icon/Icon.tsx +73 -0
- package/src/components/Icon/Icon.types.ts +10 -0
- package/src/components/Icon/IconMap.ts +290 -0
- package/src/components/Icon/icons/analytics.svg +1 -0
- package/src/components/Icon/icons/bulb.svg +1 -0
- package/src/components/Icon/icons/chat.svg +1 -0
- package/src/components/Icon/icons/edit.svg +1 -0
- package/src/components/Icon/icons/face.svg +1 -0
- package/src/components/Icon/icons/filled-analytics.svg +1 -0
- package/src/components/Icon/icons/filled-bulb.svg +1 -0
- package/src/components/Icon/icons/filled-chat.svg +1 -0
- package/src/components/Icon/icons/filled-edit.svg +1 -0
- package/src/components/Icon/icons/filled-face.svg +1 -0
- package/src/components/Icon/icons/filled-layout.svg +1 -0
- package/src/components/Icon/icons/language.svg +1 -0
- package/src/components/Icon/icons/layout.svg +1 -0
- package/src/components/Icon/icons/pending.svg +1 -0
- package/src/components/Icon/icons/receipt.svg +1 -0
- package/src/components/Icon/icons/sparkles.svg +1 -0
- package/src/components/Icon/icons/store.svg +1 -0
- package/src/components/Icon/icons/store_active.svg +1 -0
- package/src/components/Icon/icons/studio.svg +1 -0
- package/src/components/Icon/icons/studio_active.svg +1 -0
- package/src/components/Icon/icons/vertical-ellipsis.svg +1 -0
- package/src/components/Icon/index.tsx +3 -0
- package/src/components/IconButton/IconButton.stories.tsx +51 -0
- package/src/components/IconButton/IconButton.styles.ts +52 -0
- package/src/components/IconButton/IconButton.tsx +36 -0
- package/src/components/IconButton/IconButton.types.ts +12 -0
- package/src/components/IconButton/index.tsx +1 -0
- package/src/components/InfoSprinkle/InfoSprinkle.stories.tsx +25 -0
- package/src/components/InfoSprinkle/InfoSprinkle.tsx +48 -0
- package/src/components/InfoSprinkle/index.ts +1 -0
- package/src/components/InlineCode/InlineCode.tsx +18 -0
- package/src/components/InlineCode/index.ts +1 -0
- package/src/components/Input/Input.stories.tsx +55 -0
- package/src/components/Input/Input.tsx +358 -0
- package/src/components/Input/Input.types.ts +19 -0
- package/src/components/Input/index.tsx +2 -0
- package/src/components/LineGraph/LineGraph.stories.tsx +98 -0
- package/src/components/LineGraph/LineGraph.tsx +88 -0
- package/src/components/LineGraph/LineGraph.types.ts +41 -0
- package/src/components/LineGraph/index.ts +1 -0
- package/src/components/Link/Link.styles.ts +13 -0
- package/src/components/Link/Link.tsx +93 -0
- package/src/components/Link/index.ts +1 -0
- package/src/components/Loaders/PageLoader.stories.tsx +29 -0
- package/src/components/Loaders/PageLoader.tsx +30 -0
- package/src/components/Loaders/SectionLoader.stories.tsx +26 -0
- package/src/components/Loaders/SectionLoader.tsx +30 -0
- package/src/components/Loaders/index.ts +1 -0
- package/src/components/MDXEditor/MDXEditor.css +21 -0
- package/src/components/MDXEditor/MDXEditor.stories.tsx +45 -0
- package/src/components/MDXEditor/MDXEditor.tsx +189 -0
- package/src/components/MDXEditor/MDXEditor.types.ts +6 -0
- package/src/components/MDXEditor/index.ts +1 -0
- package/src/components/Markdown/Markdown.module.css +30 -0
- package/src/components/Markdown/Markdown.tsx +133 -0
- package/src/components/Markdown/Markdown.types.ts +5 -0
- package/src/components/Markdown/index.ts +2 -0
- package/src/components/Masonry/Masonry.stories.tsx +288 -0
- package/src/components/Masonry/Masonry.tsx +187 -0
- package/src/components/Masonry/Masonry.types.ts +18 -0
- package/src/components/Masonry/index.ts +2 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.stories.tsx +26 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.tsx +25 -0
- package/src/components/MaxLengthIndicator/index.tsx +1 -0
- package/src/components/Menu/Menu.stories.tsx +186 -0
- package/src/components/Menu/MenuButton.tsx +8 -0
- package/src/components/Menu/MenuButton.types.ts +23 -0
- package/src/components/Menu/MenuItem.tsx +35 -0
- package/src/components/Menu/MenuItem.types.ts +13 -0
- package/src/components/Menu/MenuList.tsx +19 -0
- package/src/components/Menu/index.ts +7 -0
- package/src/components/Modal/Modal.stories.tsx +83 -0
- package/src/components/Modal/Modal.styles.ts +14 -0
- package/src/components/Modal/Modal.tsx +14 -0
- package/src/components/Modal/Modal.types.ts +3 -0
- package/src/components/Modal/ModalBody.tsx +9 -0
- package/src/components/Modal/ModalCloseButton.tsx +18 -0
- package/src/components/Modal/ModalContent/ModalContent.tsx +8 -0
- package/src/components/Modal/ModalContent/ModalContent.types.ts +3 -0
- package/src/components/Modal/ModalContent/index.ts +1 -0
- package/src/components/Modal/ModalFooter/ModalFooter.module.css +3 -0
- package/src/components/Modal/ModalFooter/ModalFooter.tsx +20 -0
- package/src/components/Modal/ModalFooter/index.ts +1 -0
- package/src/components/Modal/ModalHeader.tsx +9 -0
- package/src/components/Modal/ModalOverlay.tsx +9 -0
- package/src/components/Modal/index.tsx +8 -0
- package/src/components/MonthRangePicker/MonthButton/MonthButton.tsx +105 -0
- package/src/components/MonthRangePicker/MonthButton/MonthButton.types.ts +42 -0
- package/src/components/MonthRangePicker/MonthButton/index.ts +2 -0
- package/src/components/MonthRangePicker/MonthRangePicker.stories.tsx +164 -0
- package/src/components/MonthRangePicker/MonthRangePicker.tsx +274 -0
- package/src/components/MonthRangePicker/MonthRangePicker.types.ts +38 -0
- package/src/components/MonthRangePicker/_utils/hasEnabledMonthsInYear.ts +15 -0
- package/src/components/MonthRangePicker/_utils/index.ts +6 -0
- package/src/components/MonthRangePicker/_utils/isMonthDisabled.ts +20 -0
- package/src/components/MonthRangePicker/_utils/isMonthInPreviewRange.ts +32 -0
- package/src/components/MonthRangePicker/_utils/isMonthInRange.ts +17 -0
- package/src/components/MonthRangePicker/_utils/isMonthSelected.ts +19 -0
- package/src/components/MonthRangePicker/_utils/isSelectionStart.ts +12 -0
- package/src/components/MonthRangePicker/constants.ts +63 -0
- package/src/components/MonthRangePicker/index.ts +2 -0
- package/src/components/Pagination/Pagination.stories.tsx +51 -0
- package/src/components/Pagination/Pagination.tsx +150 -0
- package/src/components/Pagination/Pagination.types.ts +12 -0
- package/src/components/Pagination/index.tsx +1 -0
- package/src/components/PasswordInput/PasswordInput.stories.tsx +16 -0
- package/src/components/PasswordInput/PasswordInput.tsx +42 -0
- package/src/components/PasswordInput/PasswordInput.types.ts +11 -0
- package/src/components/PasswordInput/index.ts +1 -0
- package/src/components/PinInput/PinInput.stories.tsx +26 -0
- package/src/components/PinInput/PinInput.tsx +53 -0
- package/src/components/PinInput/PinInput.types.ts +27 -0
- package/src/components/PinInput/index.tsx +2 -0
- package/src/components/ProgressBar/ProgressBar.stories.tsx +18 -0
- package/src/components/ProgressBar/ProgressBar.styles.ts +4 -0
- package/src/components/ProgressBar/ProgressBar.tsx +27 -0
- package/src/components/ProgressBar/ProgressBar.types.ts +4 -0
- package/src/components/ProgressBar/index.ts +1 -0
- package/src/components/RadialProgress/RadialProgress.stories.tsx +272 -0
- package/src/components/RadialProgress/RadialProgress.tsx +232 -0
- package/src/components/RadialProgress/RadialProgress.types.ts +27 -0
- package/src/components/RadialProgress/index.ts +2 -0
- package/src/components/Radio/Radio.stories.tsx +226 -0
- package/src/components/Radio/Radio.tsx +35 -0
- package/src/components/Radio/Radio.types.ts +21 -0
- package/src/components/Radio/RadioGroup.tsx +26 -0
- package/src/components/Radio/index.ts +3 -0
- package/src/components/SeeMoreButton/SeeMoreButton.stories.tsx +48 -0
- package/src/components/SeeMoreButton/SeeMoreButton.styles.ts +11 -0
- package/src/components/SeeMoreButton/SeeMoreButton.tsx +34 -0
- package/src/components/SeeMoreButton/SeeMoreButton.types.ts +6 -0
- package/src/components/SeeMoreButton/index.tsx +1 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +96 -0
- package/src/components/SegmentedControl/SegmentedControl.styles.ts +28 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +89 -0
- package/src/components/SegmentedControl/SegmentedControl.types.ts +15 -0
- package/src/components/SegmentedControl/index.ts +2 -0
- package/src/components/SegmentedProgressBar/ProgressSegment.tsx +18 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.stories.tsx +228 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.tsx +25 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.types.ts +11 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBarContext.tsx +24 -0
- package/src/components/SegmentedProgressBar/index.ts +3 -0
- package/src/components/Select/MenuList/MenuList.tsx +87 -0
- package/src/components/Select/MenuList/MenuList.types.ts +21 -0
- package/src/components/Select/MenuList/VirtualizedMenuList.tsx +140 -0
- package/src/components/Select/MenuList/VirtualizedMenuListContext.tsx +35 -0
- package/src/components/Select/MenuList/index.ts +3 -0
- package/src/components/Select/Select.stories.tsx +70 -0
- package/src/components/Select/Select.styles.ts +102 -0
- package/src/components/Select/Select.tsx +204 -0
- package/src/components/Select/Select.types.ts +18 -0
- package/src/components/Select/_utils/resolveStyle.ts +21 -0
- package/src/components/Select/index.ts +1 -0
- package/src/components/Slider/Slider.stories.tsx +75 -0
- package/src/components/Slider/Slider.tsx +12 -0
- package/src/components/Slider/Slider.types.ts +3 -0
- package/src/components/Slider/SliderFilledTrack/SliderFilledTrack.tsx +14 -0
- package/src/components/Slider/SliderFilledTrack/SliderFilledTrack.types.ts +3 -0
- package/src/components/Slider/SliderFilledTrack/index.ts +2 -0
- package/src/components/Slider/SliderMark/SliderMark.tsx +12 -0
- package/src/components/Slider/SliderMark/SliderMark.types.ts +3 -0
- package/src/components/Slider/SliderMark/index.ts +2 -0
- package/src/components/Slider/SliderThumb/SliderThumb.tsx +22 -0
- package/src/components/Slider/SliderThumb/SliderThumb.types.ts +3 -0
- package/src/components/Slider/SliderThumb/index.ts +2 -0
- package/src/components/Slider/SliderTrack/SliderTrack.tsx +12 -0
- package/src/components/Slider/SliderTrack/SliderTrack.types.ts +3 -0
- package/src/components/Slider/SliderTrack/index.ts +2 -0
- package/src/components/Slider/index.ts +5 -0
- package/src/components/Spinner/Spinner.stories.tsx +16 -0
- package/src/components/Spinner/Spinner.tsx +20 -0
- package/src/components/Spinner/Spinner.types.ts +3 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/Switch/Switch.stories.tsx +63 -0
- package/src/components/Switch/Switch.tsx +8 -0
- package/src/components/Switch/index.ts +1 -0
- package/src/components/Table/ExpandingTr/ExpandingTr.tsx +31 -0
- package/src/components/Table/ExpandingTr/ExpandingTr.types.ts +9 -0
- package/src/components/Table/ExpandingTr/index.ts +2 -0
- package/src/components/Table/Table.stories.tsx +326 -0
- package/src/components/Table/Table.styles.ts +48 -0
- package/src/components/Table/Table.tsx +9 -0
- package/src/components/Table/Table.types.ts +16 -0
- package/src/components/Table/TableContainer.tsx +55 -0
- package/src/components/Table/TableContext.tsx +187 -0
- package/src/components/Table/Tbody.tsx +12 -0
- package/src/components/Table/Td.tsx +138 -0
- package/src/components/Table/Th.tsx +154 -0
- package/src/components/Table/Thead.tsx +5 -0
- package/src/components/Table/Tr.tsx +5 -0
- package/src/components/Table/index.tsx +8 -0
- package/src/components/Tabs/Tab/Tab.styles.ts +35 -0
- package/src/components/Tabs/Tab/Tab.tsx +67 -0
- package/src/components/Tabs/Tab/index.ts +1 -0
- package/src/components/Tabs/TabList/TabList.styles.ts +11 -0
- package/src/components/Tabs/TabList/TabList.tsx +19 -0
- package/src/components/Tabs/TabList/index.ts +1 -0
- package/src/components/Tabs/TabPanel.tsx +5 -0
- package/src/components/Tabs/TabPanels.tsx +5 -0
- package/src/components/Tabs/Tabs.stories.tsx +45 -0
- package/src/components/Tabs/Tabs.tsx +65 -0
- package/src/components/Tabs/Tabs.types.ts +19 -0
- package/src/components/Tabs/TabsContext.tsx +162 -0
- package/src/components/Tabs/index.tsx +5 -0
- package/src/components/Tag/Tag.stories.tsx +28 -0
- package/src/components/Tag/Tag.styles.ts +12 -0
- package/src/components/Tag/Tag.tsx +23 -0
- package/src/components/Tag/Tag.types.ts +5 -0
- package/src/components/Tag/TagCloseButton/TagCloseButton.tsx +12 -0
- package/src/components/Tag/TagCloseButton/TagCloseButton.types.ts +3 -0
- package/src/components/Tag/TagCloseButton/index.ts +2 -0
- package/src/components/Tag/TagLabel/TagLabel.tsx +12 -0
- package/src/components/Tag/TagLabel/TagLabel.types.ts +3 -0
- package/src/components/Tag/TagLabel/index.ts +2 -0
- package/src/components/Tag/TagLeftIcon/TagLeftIcon.tsx +12 -0
- package/src/components/Tag/TagLeftIcon/TagLeftIcon.types.ts +3 -0
- package/src/components/Tag/TagLeftIcon/index.ts +2 -0
- package/src/components/Tag/TagRightIcon/TagRightIcon.tsx +12 -0
- package/src/components/Tag/TagRightIcon/TagRightIcon.types.ts +3 -0
- package/src/components/Tag/TagRightIcon/index.ts +2 -0
- package/src/components/Tag/index.ts +5 -0
- package/src/components/Textarea/Textarea.tsx +56 -0
- package/src/components/Textarea/adjustHeight.tsx +9 -0
- package/src/components/Textarea/index.ts +1 -0
- package/src/components/Toast/Toast.stories.tsx +49 -0
- package/src/components/Toast/Toast.styles.ts +19 -0
- package/src/components/Toast/Toast.tsx +38 -0
- package/src/components/Toast/Toast.types.ts +22 -0
- package/src/components/Toast/ToastIcon/ToastIcon.tsx +26 -0
- package/src/components/Toast/ToastIcon/index.ts +0 -0
- package/src/components/Toast/index.ts +2 -0
- package/src/components/Toast/useToast.tsx +65 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +97 -0
- package/src/components/Tooltip/Tooltip.tsx +22 -0
- package/src/components/Tooltip/Tooltip.types.ts +3 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/Typography/H1.tsx +17 -0
- package/src/components/Typography/H2.tsx +17 -0
- package/src/components/Typography/H3.tsx +17 -0
- package/src/components/Typography/H4.tsx +17 -0
- package/src/components/Typography/H5.tsx +17 -0
- package/src/components/Typography/Link.tsx +49 -0
- package/src/components/Typography/Subtext.tsx +17 -0
- package/src/components/Typography/Subtitle.tsx +18 -0
- package/src/components/Typography/Text.tsx +22 -0
- package/src/components/Typography/Typography.stories.tsx +54 -0
- package/src/components/Typography/Typography.types.ts +3 -0
- package/src/components/Typography/index.ts +26 -0
- package/src/components/UrlInput/UrlInput.stories.tsx +66 -0
- package/src/components/UrlInput/UrlInput.tsx +47 -0
- package/src/components/UrlInput/index.tsx +1 -0
- package/src/hooks/useLocale.ts +11 -0
- package/src/hooks/useTranslate.ts +57 -0
- package/src/index.ts +96 -0
- package/src/theme/Palette.stories.tsx +171 -0
- package/src/theme/colors.ts +64 -0
- package/src/theme/font.ts +23 -0
- package/src/theme/global.ts +30 -0
- package/src/theme/index.ts +49 -0
- package/src/translations/Defaults.translations.json +100 -0
- package/src/types/css-modules.d.ts +0 -0
- package/src/types/svg.d.ts +15 -0
- package/src/utils/findKeyByValue.ts +17 -0
- package/src/utils/formatDateByLocale.ts +36 -0
- package/src/utils/formatFileSize.ts +14 -0
- package/src/utils/formatNumber.ts +29 -0
- package/src/utils/formatTextForMarkdown.ts +3 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Flex, Text, VStack } from '@chakra-ui/react';
|
|
3
|
+
import { Meta, StoryFn } from '@storybook/react';
|
|
4
|
+
|
|
5
|
+
import { ProgressSegment, SegmentedProgressBar } from './';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof SegmentedProgressBar> = {
|
|
8
|
+
title: 'Components/SegmentedProgressBar',
|
|
9
|
+
component: SegmentedProgressBar,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'A segmented progress bar that displays multiple progress segments within a single container. Useful for showing different categories of progress like success/error counts.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
args: {
|
|
19
|
+
max: 100,
|
|
20
|
+
height: '12px',
|
|
21
|
+
},
|
|
22
|
+
argTypes: {
|
|
23
|
+
max: {
|
|
24
|
+
control: 'number',
|
|
25
|
+
description: 'Maximum value for the progress bar',
|
|
26
|
+
},
|
|
27
|
+
height: {
|
|
28
|
+
control: 'text',
|
|
29
|
+
description: 'Height of the progress bar',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
|
|
36
|
+
type Story = StoryFn<typeof SegmentedProgressBar>;
|
|
37
|
+
|
|
38
|
+
const Template: Story = (args) => (
|
|
39
|
+
<Box width="400px">
|
|
40
|
+
<SegmentedProgressBar {...args}>
|
|
41
|
+
<ProgressSegment value={30} filledTrackColor="primary.main" />
|
|
42
|
+
<ProgressSegment value={20} filledTrackColor="success.main" />
|
|
43
|
+
</SegmentedProgressBar>
|
|
44
|
+
</Box>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const Default = Template.bind({});
|
|
48
|
+
Default.args = {
|
|
49
|
+
max: 100,
|
|
50
|
+
height: '12px',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const BasicUsage: Story = () => (
|
|
54
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
55
|
+
<Box>
|
|
56
|
+
<Text mb={2} fontWeight="semibold">
|
|
57
|
+
Basic Two-Segment Progress
|
|
58
|
+
</Text>
|
|
59
|
+
<SegmentedProgressBar max={100} height="12px">
|
|
60
|
+
<ProgressSegment value={60} filledTrackColor="primary.main" />
|
|
61
|
+
<ProgressSegment value={25} filledTrackColor="success.main" />
|
|
62
|
+
</SegmentedProgressBar>
|
|
63
|
+
<Flex justify="space-between" mt={1} fontSize="sm" color="gray.600">
|
|
64
|
+
<Text>Primary: 60</Text>
|
|
65
|
+
<Text>Success: 25</Text>
|
|
66
|
+
<Text>Remaining: 15</Text>
|
|
67
|
+
</Flex>
|
|
68
|
+
</Box>
|
|
69
|
+
</VStack>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export const MultipleSegments: Story = () => (
|
|
73
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
74
|
+
<Box>
|
|
75
|
+
<Text mb={2} fontWeight="semibold">
|
|
76
|
+
Multiple Segments with Different Colors
|
|
77
|
+
</Text>
|
|
78
|
+
<SegmentedProgressBar max={200} height="16px">
|
|
79
|
+
<ProgressSegment value={80} filledTrackColor="primary.main" />
|
|
80
|
+
<ProgressSegment value={45} filledTrackColor="success.main" />
|
|
81
|
+
<ProgressSegment value={30} filledTrackColor="warning.main" />
|
|
82
|
+
<ProgressSegment value={25} filledTrackColor="danger.main" />
|
|
83
|
+
</SegmentedProgressBar>
|
|
84
|
+
<Flex justify="space-between" mt={2} fontSize="sm" color="gray.600">
|
|
85
|
+
<Text>Primary: 80</Text>
|
|
86
|
+
<Text>Success: 45</Text>
|
|
87
|
+
<Text>Warning: 30</Text>
|
|
88
|
+
<Text>Error: 25</Text>
|
|
89
|
+
</Flex>
|
|
90
|
+
</Box>
|
|
91
|
+
</VStack>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export const WithStripes: Story = () => (
|
|
95
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
96
|
+
<Box>
|
|
97
|
+
<Text mb={2} fontWeight="semibold">
|
|
98
|
+
Progress Segments with Stripes
|
|
99
|
+
</Text>
|
|
100
|
+
<SegmentedProgressBar max={100} height="16px">
|
|
101
|
+
<ProgressSegment value={45} filledTrackColor="primary.main" hasStripe />
|
|
102
|
+
<ProgressSegment value={30} filledTrackColor="success.main" hasStripe />
|
|
103
|
+
<ProgressSegment value={15} filledTrackColor="danger.main" hasStripe />
|
|
104
|
+
</SegmentedProgressBar>
|
|
105
|
+
<Flex justify="space-between" mt={2} fontSize="sm" color="gray.600">
|
|
106
|
+
<Text>Completed: 45</Text>
|
|
107
|
+
<Text>In Progress: 30</Text>
|
|
108
|
+
<Text>Failed: 15</Text>
|
|
109
|
+
</Flex>
|
|
110
|
+
</Box>
|
|
111
|
+
</VStack>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
export const DifferentSizes: Story = () => (
|
|
115
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
116
|
+
<Box>
|
|
117
|
+
<Text mb={2} fontWeight="semibold">
|
|
118
|
+
Small Progress Bar (8px)
|
|
119
|
+
</Text>
|
|
120
|
+
<SegmentedProgressBar max={100} height="8px">
|
|
121
|
+
<ProgressSegment value={70} filledTrackColor="primary.main" />
|
|
122
|
+
<ProgressSegment value={20} filledTrackColor="success.main" />
|
|
123
|
+
</SegmentedProgressBar>
|
|
124
|
+
</Box>
|
|
125
|
+
|
|
126
|
+
<Box>
|
|
127
|
+
<Text mb={2} fontWeight="semibold">
|
|
128
|
+
Medium Progress Bar (12px)
|
|
129
|
+
</Text>
|
|
130
|
+
<SegmentedProgressBar max={100} height="12px">
|
|
131
|
+
<ProgressSegment value={70} filledTrackColor="primary.main" />
|
|
132
|
+
<ProgressSegment value={20} filledTrackColor="success.main" />
|
|
133
|
+
</SegmentedProgressBar>
|
|
134
|
+
</Box>
|
|
135
|
+
|
|
136
|
+
<Box>
|
|
137
|
+
<Text mb={2} fontWeight="semibold">
|
|
138
|
+
Large Progress Bar (20px)
|
|
139
|
+
</Text>
|
|
140
|
+
<SegmentedProgressBar max={100} height="20px">
|
|
141
|
+
<ProgressSegment value={70} filledTrackColor="primary.main" />
|
|
142
|
+
<ProgressSegment value={20} filledTrackColor="success.main" />
|
|
143
|
+
</SegmentedProgressBar>
|
|
144
|
+
</Box>
|
|
145
|
+
</VStack>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
export const RealWorldExample: Story = () => (
|
|
149
|
+
<VStack spacing={6} align="stretch" width="500px">
|
|
150
|
+
<Box>
|
|
151
|
+
<Text mb={2} fontWeight="semibold">
|
|
152
|
+
Member Invitation Progress
|
|
153
|
+
</Text>
|
|
154
|
+
<Text mb={4} fontSize="sm" color="gray.600">
|
|
155
|
+
Inviting 1,500 members in batches of 100
|
|
156
|
+
</Text>
|
|
157
|
+
|
|
158
|
+
<SegmentedProgressBar max={1500} height="14px">
|
|
159
|
+
<ProgressSegment
|
|
160
|
+
value={1200}
|
|
161
|
+
filledTrackColor="success.main"
|
|
162
|
+
hasStripe
|
|
163
|
+
/>
|
|
164
|
+
<ProgressSegment value={150} filledTrackColor="danger.main" hasStripe />
|
|
165
|
+
</SegmentedProgressBar>
|
|
166
|
+
|
|
167
|
+
<Flex justify="space-between" mt={2} fontSize="sm" color="gray.600">
|
|
168
|
+
<Text color="success.600">✓ 1,200 successful</Text>
|
|
169
|
+
<Text color="danger.600">✗ 150 failed</Text>
|
|
170
|
+
<Text>90% complete</Text>
|
|
171
|
+
</Flex>
|
|
172
|
+
</Box>
|
|
173
|
+
</VStack>
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
export const EmptyState: Story = () => (
|
|
177
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
178
|
+
<Box>
|
|
179
|
+
<Text mb={2} fontWeight="semibold">
|
|
180
|
+
Empty Progress Bar
|
|
181
|
+
</Text>
|
|
182
|
+
<SegmentedProgressBar max={100} height="12px">
|
|
183
|
+
{/* No segments - shows empty state */}
|
|
184
|
+
</SegmentedProgressBar>
|
|
185
|
+
<Text mt={2} fontSize="sm" color="gray.600">
|
|
186
|
+
No progress yet
|
|
187
|
+
</Text>
|
|
188
|
+
</Box>
|
|
189
|
+
</VStack>
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
export const SingleSegment: Story = () => (
|
|
193
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
194
|
+
<Box>
|
|
195
|
+
<Text mb={2} fontWeight="semibold">
|
|
196
|
+
Single Segment Progress
|
|
197
|
+
</Text>
|
|
198
|
+
<SegmentedProgressBar max={100} height="12px">
|
|
199
|
+
<ProgressSegment value={75} filledTrackColor="primary.main" />
|
|
200
|
+
</SegmentedProgressBar>
|
|
201
|
+
<Text mt={2} fontSize="sm" color="gray.600">
|
|
202
|
+
75% complete
|
|
203
|
+
</Text>
|
|
204
|
+
</Box>
|
|
205
|
+
</VStack>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
export const CustomColors: Story = () => (
|
|
209
|
+
<VStack spacing={6} align="stretch" width="400px">
|
|
210
|
+
<Box>
|
|
211
|
+
<Text mb={2} fontWeight="semibold">
|
|
212
|
+
Custom Color Segments
|
|
213
|
+
</Text>
|
|
214
|
+
<SegmentedProgressBar max={100} height="16px">
|
|
215
|
+
<ProgressSegment value={25} filledTrackColor="#FF6B6B" />
|
|
216
|
+
<ProgressSegment value={25} filledTrackColor="#4ECDC4" />
|
|
217
|
+
<ProgressSegment value={25} filledTrackColor="#45B7D1" />
|
|
218
|
+
<ProgressSegment value={20} filledTrackColor="#96CEB4" />
|
|
219
|
+
</SegmentedProgressBar>
|
|
220
|
+
<Flex justify="space-between" mt={2} fontSize="sm" color="gray.600">
|
|
221
|
+
<Text>Red: 25</Text>
|
|
222
|
+
<Text>Teal: 25</Text>
|
|
223
|
+
<Text>Blue: 25</Text>
|
|
224
|
+
<Text>Green: 20</Text>
|
|
225
|
+
</Flex>
|
|
226
|
+
</Box>
|
|
227
|
+
</VStack>
|
|
228
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Box } from '@chakra-ui/react';
|
|
2
|
+
|
|
3
|
+
import { SegmentedProgressBarProps } from './SegmentedProgressBar.types';
|
|
4
|
+
import { SegmentedProgressBarProvider } from './SegmentedProgressBarContext';
|
|
5
|
+
|
|
6
|
+
export const SegmentedProgressBar = ({
|
|
7
|
+
max,
|
|
8
|
+
...rest
|
|
9
|
+
}: SegmentedProgressBarProps) => {
|
|
10
|
+
return (
|
|
11
|
+
<SegmentedProgressBarProvider max={max}>
|
|
12
|
+
<Box
|
|
13
|
+
position="relative"
|
|
14
|
+
flex={1}
|
|
15
|
+
display="flex"
|
|
16
|
+
bgColor="gray.200"
|
|
17
|
+
borderRadius="full"
|
|
18
|
+
w="100%"
|
|
19
|
+
h="16px"
|
|
20
|
+
overflow="hidden"
|
|
21
|
+
{...rest}
|
|
22
|
+
/>
|
|
23
|
+
</SegmentedProgressBarProvider>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BoxProps } from '@chakra-ui/react';
|
|
2
|
+
|
|
3
|
+
import { ProgressBarProps } from '../ProgressBar/ProgressBar.types';
|
|
4
|
+
|
|
5
|
+
export type SegmentedProgressBarProps = BoxProps & {
|
|
6
|
+
max: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type ProgressSegmentProps = ProgressBarProps & {
|
|
10
|
+
value: number;
|
|
11
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
// TODO: typescript
|
|
4
|
+
const SegmentedProgressBarContext = createContext<any>({});
|
|
5
|
+
export const useSegmentedProgressBarContext = () =>
|
|
6
|
+
useContext(SegmentedProgressBarContext);
|
|
7
|
+
|
|
8
|
+
interface SegmentedProgressBarProviderProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
max: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function SegmentedProgressBarProvider({
|
|
14
|
+
children,
|
|
15
|
+
max,
|
|
16
|
+
}: SegmentedProgressBarProviderProps) {
|
|
17
|
+
return (
|
|
18
|
+
<SegmentedProgressBarContext.Provider value={{ max }}>
|
|
19
|
+
{children}
|
|
20
|
+
</SegmentedProgressBarContext.Provider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default SegmentedProgressBarContext;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { components, GroupBase } from 'react-select';
|
|
3
|
+
|
|
4
|
+
import { MenuListProps } from './MenuList.types';
|
|
5
|
+
|
|
6
|
+
const { MenuList: DefaultMenuList } = components;
|
|
7
|
+
|
|
8
|
+
// Utility to merge refs
|
|
9
|
+
const mergeRefs = <T extends HTMLElement>(
|
|
10
|
+
refs: Array<React.Ref<T> | null | undefined>
|
|
11
|
+
) => {
|
|
12
|
+
return (value: T) => {
|
|
13
|
+
refs.forEach((ref) => {
|
|
14
|
+
if (!ref) return;
|
|
15
|
+
|
|
16
|
+
if (typeof ref === 'function') {
|
|
17
|
+
ref(value);
|
|
18
|
+
} else if (ref && typeof ref === 'object') {
|
|
19
|
+
(ref as React.MutableRefObject<T | null>).current = value;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Regular MenuList with explicit scroll handling
|
|
26
|
+
export const MenuList = <
|
|
27
|
+
Option,
|
|
28
|
+
IsMulti extends boolean = false,
|
|
29
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
30
|
+
>({
|
|
31
|
+
onMenuScrollToBottom,
|
|
32
|
+
innerRef,
|
|
33
|
+
...props
|
|
34
|
+
}: MenuListProps<Option, IsMulti, Group>) => {
|
|
35
|
+
const menuListRef = useRef<HTMLDivElement>(null);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!menuListRef.current || !onMenuScrollToBottom) return;
|
|
39
|
+
|
|
40
|
+
let lastScrollTop = 0;
|
|
41
|
+
|
|
42
|
+
const handleScroll = (event: WheelEvent | TouchEvent) => {
|
|
43
|
+
const element = menuListRef.current;
|
|
44
|
+
if (!element) return;
|
|
45
|
+
|
|
46
|
+
// Check if scrolled downward
|
|
47
|
+
const scrollingDown = element.scrollTop > lastScrollTop;
|
|
48
|
+
|
|
49
|
+
// Check if scrolled to bottom (with small buffer for browser precision)
|
|
50
|
+
const scrolledToBottom =
|
|
51
|
+
Math.abs(
|
|
52
|
+
element.scrollHeight - element.scrollTop - element.clientHeight
|
|
53
|
+
) < 2;
|
|
54
|
+
|
|
55
|
+
// Only trigger if scrolling down AND reached the bottom
|
|
56
|
+
if (scrollingDown && scrolledToBottom) {
|
|
57
|
+
onMenuScrollToBottom(event);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Update last scroll position
|
|
61
|
+
lastScrollTop = element.scrollTop;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const menuListElement = menuListRef.current;
|
|
65
|
+
menuListElement.addEventListener('scroll', handleScroll as EventListener);
|
|
66
|
+
menuListElement.addEventListener(
|
|
67
|
+
'touchmove',
|
|
68
|
+
handleScroll as EventListener
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return () => {
|
|
72
|
+
menuListElement.removeEventListener(
|
|
73
|
+
'scroll',
|
|
74
|
+
handleScroll as EventListener
|
|
75
|
+
);
|
|
76
|
+
menuListElement.removeEventListener(
|
|
77
|
+
'touchmove',
|
|
78
|
+
handleScroll as EventListener
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
}, [onMenuScrollToBottom]);
|
|
82
|
+
|
|
83
|
+
// Apply both refs instead of using OR logic
|
|
84
|
+
return (
|
|
85
|
+
<DefaultMenuList {...props} innerRef={mergeRefs([innerRef, menuListRef])} />
|
|
86
|
+
);
|
|
87
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GroupBase,
|
|
3
|
+
MenuListProps as ReactSelectMenuListProps,
|
|
4
|
+
} from 'react-select';
|
|
5
|
+
|
|
6
|
+
export interface MenuListProps<
|
|
7
|
+
Option,
|
|
8
|
+
IsMulti extends boolean,
|
|
9
|
+
Group extends GroupBase<Option>,
|
|
10
|
+
> extends ReactSelectMenuListProps<Option, IsMulti, Group> {
|
|
11
|
+
onMenuScrollToBottom?: (event: WheelEvent | TouchEvent) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface VirtualizedMenuListProps<
|
|
15
|
+
Option,
|
|
16
|
+
IsMulti extends boolean,
|
|
17
|
+
Group extends GroupBase<Option>,
|
|
18
|
+
> extends Omit<MenuListProps<Option, IsMulti, Group>, 'maxHeight'> {
|
|
19
|
+
optionHeight?: number;
|
|
20
|
+
maxHeight?: number;
|
|
21
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { GroupBase } from 'react-select';
|
|
3
|
+
import { useTheme } from '@chakra-ui/react';
|
|
4
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
5
|
+
|
|
6
|
+
import { optionStyles } from '../Select.styles';
|
|
7
|
+
import { MenuList } from './MenuList';
|
|
8
|
+
import { VirtualizedMenuListProps } from './MenuList.types';
|
|
9
|
+
import { useVirtualizedMenuListState } from './VirtualizedMenuListContext';
|
|
10
|
+
// Custom MenuList component that uses @tanstack/react-virtual when virtualization is enabled
|
|
11
|
+
export const VirtualizedMenuList = <
|
|
12
|
+
Option,
|
|
13
|
+
IsMulti extends boolean,
|
|
14
|
+
Group extends GroupBase<Option>,
|
|
15
|
+
>({
|
|
16
|
+
children,
|
|
17
|
+
maxHeight = 35 * 4,
|
|
18
|
+
optionHeight = 35,
|
|
19
|
+
...props
|
|
20
|
+
}: VirtualizedMenuListProps<Option, IsMulti, Group>) => {
|
|
21
|
+
// Get the number of children (options) to render
|
|
22
|
+
const childrenArray = React.Children.toArray(children ?? []);
|
|
23
|
+
const childrenCount = childrenArray.length;
|
|
24
|
+
const menuListRef = useRef(null);
|
|
25
|
+
const theme = useTheme();
|
|
26
|
+
const { isInitialRender, previousChildrenCount } =
|
|
27
|
+
useVirtualizedMenuListState();
|
|
28
|
+
|
|
29
|
+
// Set up virtualizer
|
|
30
|
+
const virtualizer = useVirtualizer({
|
|
31
|
+
count: childrenCount,
|
|
32
|
+
getScrollElement: () => menuListRef.current,
|
|
33
|
+
estimateSize: () => optionHeight,
|
|
34
|
+
overscan: 5,
|
|
35
|
+
getItemKey: (index) => {
|
|
36
|
+
const child = childrenArray[index];
|
|
37
|
+
// @ts-expect-error - Not all ReactNode types have key property
|
|
38
|
+
return child?.key || `item-${index}`;
|
|
39
|
+
}, // Use stable keys
|
|
40
|
+
measureElement: (_, entry, instance) => {
|
|
41
|
+
if (entry) {
|
|
42
|
+
instance.measure();
|
|
43
|
+
}
|
|
44
|
+
return 0;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Make sure the menuList takes the full height available to it
|
|
49
|
+
// We need to ensure react-select's menuList is scrollable
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (menuListRef.current) {
|
|
52
|
+
// Important: react-select MenuList needs overflow:auto to scroll
|
|
53
|
+
(menuListRef.current as HTMLElement).style.overflowY = 'auto';
|
|
54
|
+
}
|
|
55
|
+
}, [menuListRef.current]);
|
|
56
|
+
|
|
57
|
+
// When items change, tell the virtualizer to recalculate
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (isInitialRender.current) {
|
|
60
|
+
isInitialRender.current = false;
|
|
61
|
+
previousChildrenCount.current = childrenCount;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const itemsWereAdded = childrenCount > previousChildrenCount.current;
|
|
65
|
+
if (itemsWereAdded) {
|
|
66
|
+
// This triggers recalculation while preserving scroll position
|
|
67
|
+
virtualizer.measure();
|
|
68
|
+
virtualizer.scrollToIndex(previousChildrenCount.current - 1, {
|
|
69
|
+
align: 'end',
|
|
70
|
+
behavior: 'auto',
|
|
71
|
+
});
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
previousChildrenCount.current = childrenCount;
|
|
74
|
+
}, 100);
|
|
75
|
+
}
|
|
76
|
+
}, [childrenArray.length, virtualizer]);
|
|
77
|
+
|
|
78
|
+
// Default option styles with fallback values
|
|
79
|
+
const baseOptionStyle = optionStyles({
|
|
80
|
+
isDisabled: false,
|
|
81
|
+
isFocused: false,
|
|
82
|
+
isSelected: false,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<MenuList
|
|
87
|
+
{...props}
|
|
88
|
+
innerRef={menuListRef}
|
|
89
|
+
maxHeight={maxHeight}
|
|
90
|
+
// Override the style here to ensure scrolling works
|
|
91
|
+
innerProps={{
|
|
92
|
+
...props.innerProps,
|
|
93
|
+
style: {
|
|
94
|
+
...props.innerProps?.style,
|
|
95
|
+
padding: 0,
|
|
96
|
+
height: Math.min(childrenCount * optionHeight, maxHeight),
|
|
97
|
+
maxHeight: Math.min(childrenCount * optionHeight, maxHeight),
|
|
98
|
+
overflow: 'auto',
|
|
99
|
+
},
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<div
|
|
103
|
+
style={{
|
|
104
|
+
height: `${virtualizer.getTotalSize()}px`,
|
|
105
|
+
width: '100%',
|
|
106
|
+
position: 'relative',
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
{virtualizer.getVirtualItems().map((virtualRow) => (
|
|
110
|
+
<div
|
|
111
|
+
key={virtualRow.index}
|
|
112
|
+
data-index={virtualRow.index}
|
|
113
|
+
style={{
|
|
114
|
+
position: 'absolute',
|
|
115
|
+
top: 0,
|
|
116
|
+
left: 0,
|
|
117
|
+
width: '100%',
|
|
118
|
+
height: `${virtualRow.size}px`,
|
|
119
|
+
transform: `translateY(${virtualRow.start}px)`,
|
|
120
|
+
boxSizing: 'border-box',
|
|
121
|
+
// Apply the base styles from optionStyles
|
|
122
|
+
cursor: baseOptionStyle.cursor,
|
|
123
|
+
borderRadius: baseOptionStyle.borderRadius,
|
|
124
|
+
// Add some necessary styles for proper display
|
|
125
|
+
padding: `${theme.spacing[2]} ${theme.spacing[4]}`,
|
|
126
|
+
userSelect: 'none',
|
|
127
|
+
WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',
|
|
128
|
+
display: 'block',
|
|
129
|
+
lineHeight: 2,
|
|
130
|
+
// Don't apply background or text colors here as they're handled by react-select
|
|
131
|
+
// based on interaction state (focus, hover, selected)
|
|
132
|
+
}}
|
|
133
|
+
>
|
|
134
|
+
{childrenArray[virtualRow.index]}
|
|
135
|
+
</div>
|
|
136
|
+
))}
|
|
137
|
+
</div>
|
|
138
|
+
</MenuList>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createContext, MutableRefObject, useContext, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
// Create a context for each VirtualizedMenuList instance
|
|
4
|
+
const VirtualizedMenuListStateContext = createContext<{
|
|
5
|
+
isInitialRender: MutableRefObject<boolean>;
|
|
6
|
+
previousChildrenCount: MutableRefObject<number>;
|
|
7
|
+
} | null>(null);
|
|
8
|
+
|
|
9
|
+
export const useVirtualizedMenuListState = () => {
|
|
10
|
+
const context = useContext(VirtualizedMenuListStateContext);
|
|
11
|
+
if (!context) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'useVirtualizedMenuListState must be used within a VirtualizedMenuListProvider'
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return context;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Provider component that creates isolated state for each instance
|
|
20
|
+
export const VirtualizedMenuListProvider = ({
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}) => {
|
|
25
|
+
const isInitialRender = useRef(true);
|
|
26
|
+
const previousChildrenCount = useRef(0);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<VirtualizedMenuListStateContext.Provider
|
|
30
|
+
value={{ isInitialRender, previousChildrenCount }}
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</VirtualizedMenuListStateContext.Provider>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Meta, StoryFn } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import { Select } from '.';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Select> = {
|
|
7
|
+
title: 'Components/Select',
|
|
8
|
+
component: Select,
|
|
9
|
+
args: {
|
|
10
|
+
options: [
|
|
11
|
+
{ label: 'Option 1', value: 'option1' },
|
|
12
|
+
{ label: 'Option 2', value: 'option2' },
|
|
13
|
+
{ label: 'Option 3', value: 'option3' },
|
|
14
|
+
{ label: 'Disabled', value: 'option4', isDisabled: true },
|
|
15
|
+
],
|
|
16
|
+
defaultValue: { label: 'Option 1', value: 'option1' },
|
|
17
|
+
},
|
|
18
|
+
argTypes: {
|
|
19
|
+
isMulti: { control: 'boolean' },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
type Story = StoryFn<typeof Select>;
|
|
25
|
+
|
|
26
|
+
export const Basic: Story = (args) => <Select {...args} />;
|
|
27
|
+
|
|
28
|
+
export const Multiselect: Story = (args) => <Select {...args} isMulti={true} />;
|
|
29
|
+
export const Combobox: Story = (args) => (
|
|
30
|
+
<Select {...args} isMulti={true} isSearchable={true} />
|
|
31
|
+
);
|
|
32
|
+
export const OnScrollToBottom: Story = (args) => (
|
|
33
|
+
<Select
|
|
34
|
+
{...args}
|
|
35
|
+
options={Array.from({ length: 50 }, (_, i) => ({
|
|
36
|
+
label: `Option ${i + 1}`,
|
|
37
|
+
value: `option${i + 1}`,
|
|
38
|
+
}))}
|
|
39
|
+
onMenuScrollToBottom={() => {
|
|
40
|
+
console.log('scrolled to bottom');
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const OnScrollToBottomNewItems: Story = (args) => {
|
|
46
|
+
const [options, setOptions] = React.useState(
|
|
47
|
+
Array.from({ length: 500 }, (_, i) => ({
|
|
48
|
+
label: `Option ${i + 1}`,
|
|
49
|
+
value: `option${i + 1}`,
|
|
50
|
+
}))
|
|
51
|
+
);
|
|
52
|
+
return (
|
|
53
|
+
<Select
|
|
54
|
+
{...args}
|
|
55
|
+
options={options}
|
|
56
|
+
isMulti={true}
|
|
57
|
+
isSearchable={true}
|
|
58
|
+
onMenuScrollToBottom={() => {
|
|
59
|
+
console.log('scrolled to bottom');
|
|
60
|
+
setOptions((prev) => [
|
|
61
|
+
...prev,
|
|
62
|
+
...Array.from({ length: 500 }, (_, i) => ({
|
|
63
|
+
label: `Option ${prev.length + i + 1}`,
|
|
64
|
+
value: `option${prev.length + i + 1}`,
|
|
65
|
+
})),
|
|
66
|
+
]);
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
};
|