@vkontakte/vkui 7.5.4 → 7.6.1
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/dist/components/Calendar/Calendar.js +6 -6
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/CalendarDays/CalendarDays.js +3 -3
- package/dist/components/CalendarDays/CalendarDays.js.map +1 -1
- package/dist/components/CalendarRange/CalendarRange.d.ts.map +1 -1
- package/dist/components/CalendarRange/CalendarRange.js +16 -14
- package/dist/components/CalendarRange/CalendarRange.js.map +1 -1
- package/dist/components/CalendarRange/utils.d.ts.map +1 -1
- package/dist/components/CalendarRange/utils.js +6 -5
- package/dist/components/CalendarRange/utils.js.map +1 -1
- package/dist/components/Cell/Cell.d.ts.map +1 -1
- package/dist/components/Cell/Cell.js +6 -3
- package/dist/components/Cell/Cell.js.map +1 -1
- package/dist/components/CellButtonGroup/CellButtonGroup.d.ts +5 -3
- package/dist/components/CellButtonGroup/CellButtonGroup.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +4 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.js +4 -2
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.d.ts +1 -1
- package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.d.ts.map +1 -1
- package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.js +6 -3
- package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.js.map +1 -1
- package/dist/components/ChipsInputBase/Chip/Chip.d.ts +41 -2
- package/dist/components/ChipsInputBase/Chip/Chip.d.ts.map +1 -1
- package/dist/components/ChipsInputBase/Chip/Chip.js +7 -2
- package/dist/components/ChipsInputBase/Chip/Chip.js.map +1 -1
- package/dist/components/ChipsInputBase/types.d.ts +2 -35
- package/dist/components/ChipsInputBase/types.d.ts.map +1 -1
- package/dist/components/ChipsInputBase/types.js.map +1 -1
- package/dist/components/ContentBadge/ContentBadge.d.ts +1 -1
- package/dist/components/ContentBadge/ContentBadge.d.ts.map +1 -1
- package/dist/components/ContentBadge/ContentBadge.js +15 -9
- package/dist/components/ContentBadge/ContentBadge.js.map +1 -1
- package/dist/components/ContentCard/ContentCard.d.ts +1 -1
- package/dist/components/ContentCard/ContentCard.d.ts.map +1 -1
- package/dist/components/ContentCard/ContentCard.js.map +1 -1
- package/dist/components/CustomSelect/CustomSelect.d.ts +16 -27
- package/dist/components/CustomSelect/CustomSelect.d.ts.map +1 -1
- package/dist/components/CustomSelect/CustomSelect.js +161 -428
- package/dist/components/CustomSelect/CustomSelect.js.map +1 -1
- package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.d.ts +3 -1
- package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.d.ts.map +1 -1
- package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.js +25 -5
- package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.js.map +1 -1
- package/dist/components/CustomSelect/helpers.d.ts +12 -0
- package/dist/components/CustomSelect/helpers.d.ts.map +1 -0
- package/dist/components/CustomSelect/helpers.js +63 -0
- package/dist/components/CustomSelect/helpers.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useAfterItems.d.ts +11 -0
- package/dist/components/CustomSelect/hooks/useAfterItems.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useAfterItems.js +57 -0
- package/dist/components/CustomSelect/hooks/useAfterItems.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useDropdownOpenedController.d.ts +13 -0
- package/dist/components/CustomSelect/hooks/useDropdownOpenedController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useDropdownOpenedController.js +60 -0
- package/dist/components/CustomSelect/hooks/useDropdownOpenedController.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useFocusedOptionController.d.ts +20 -0
- package/dist/components/CustomSelect/hooks/useFocusedOptionController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useFocusedOptionController.js +52 -0
- package/dist/components/CustomSelect/hooks/useFocusedOptionController.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useInputKeyboardController.d.ts +13 -0
- package/dist/components/CustomSelect/hooks/useInputKeyboardController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useInputKeyboardController.js +78 -0
- package/dist/components/CustomSelect/hooks/useInputKeyboardController.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useInputValueController.d.ts +15 -0
- package/dist/components/CustomSelect/hooks/useInputValueController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useInputValueController.js +43 -0
- package/dist/components/CustomSelect/hooks/useInputValueController.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useScrollListController.d.ts +9 -0
- package/dist/components/CustomSelect/hooks/useScrollListController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useScrollListController.js +37 -0
- package/dist/components/CustomSelect/hooks/useScrollListController.js.map +1 -0
- package/dist/components/CustomSelect/hooks/useSelectedOptionController.d.ts +18 -0
- package/dist/components/CustomSelect/hooks/useSelectedOptionController.d.ts.map +1 -0
- package/dist/components/CustomSelect/hooks/useSelectedOptionController.js +81 -0
- package/dist/components/CustomSelect/hooks/useSelectedOptionController.js.map +1 -0
- package/dist/components/CustomSelect/types.d.ts +33 -0
- package/dist/components/CustomSelect/types.d.ts.map +1 -0
- package/dist/components/CustomSelect/types.js +3 -0
- package/dist/components/CustomSelect/types.js.map +1 -0
- package/dist/components/CustomSelectDropdown/CustomSelectDropdown.d.ts.map +1 -1
- package/dist/components/CustomSelectDropdown/CustomSelectDropdown.js +1 -0
- package/dist/components/CustomSelectDropdown/CustomSelectDropdown.js.map +1 -1
- package/dist/components/DateInput/DateInput.d.ts.map +1 -1
- package/dist/components/DateInput/DateInput.js +3 -2
- package/dist/components/DateInput/DateInput.js.map +1 -1
- package/dist/components/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/components/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/components/DateRangeInput/DateRangeInput.js.map +1 -1
- package/dist/components/ImageBase/ImageBaseBadge/ImageBaseBadge.d.ts +1 -1
- package/dist/components/ImageBase/ImageBaseBadge/ImageBaseBadge.js.map +1 -1
- package/dist/components/MiniInfoCell/MiniInfoCell.d.ts +3 -2
- package/dist/components/MiniInfoCell/MiniInfoCell.d.ts.map +1 -1
- package/dist/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
- package/dist/components/ModalCard/ModalCard.d.ts +1 -1
- package/dist/components/ModalCard/ModalCard.d.ts.map +1 -1
- package/dist/components/ModalCard/ModalCard.js +4 -2
- package/dist/components/ModalCard/ModalCard.js.map +1 -1
- package/dist/components/ModalCard/ModalCardInternal.d.ts +1 -1
- package/dist/components/ModalCard/ModalCardInternal.d.ts.map +1 -1
- package/dist/components/ModalCard/ModalCardInternal.js +5 -3
- package/dist/components/ModalCard/ModalCardInternal.js.map +1 -1
- package/dist/components/ModalCard/types.d.ts +8 -0
- package/dist/components/ModalCard/types.d.ts.map +1 -1
- package/dist/components/ModalCard/types.js.map +1 -1
- package/dist/components/ModalOutlet/ModalOutlet.d.ts +2 -1
- package/dist/components/ModalOutlet/ModalOutlet.d.ts.map +1 -1
- package/dist/components/ModalOutlet/ModalOutlet.js +4 -3
- package/dist/components/ModalOutlet/ModalOutlet.js.map +1 -1
- package/dist/components/ModalPage/ModalPage.d.ts +1 -1
- package/dist/components/ModalPage/ModalPage.d.ts.map +1 -1
- package/dist/components/ModalPage/ModalPage.js +3 -1
- package/dist/components/ModalPage/ModalPage.js.map +1 -1
- package/dist/components/ModalPage/ModalPageInternal.d.ts +1 -1
- package/dist/components/ModalPage/ModalPageInternal.d.ts.map +1 -1
- package/dist/components/ModalPage/ModalPageInternal.js +5 -3
- package/dist/components/ModalPage/ModalPageInternal.js.map +1 -1
- package/dist/components/ModalPage/types.d.ts +8 -0
- package/dist/components/ModalPage/types.d.ts.map +1 -1
- package/dist/components/ModalPage/types.js.map +1 -1
- package/dist/components/ModalRoot/ModalRoot.d.ts +1 -1
- package/dist/components/ModalRoot/ModalRoot.d.ts.map +1 -1
- package/dist/components/ModalRoot/ModalRoot.js +4 -2
- package/dist/components/ModalRoot/ModalRoot.js.map +1 -1
- package/dist/components/ModalRoot/types.d.ts +6 -0
- package/dist/components/ModalRoot/types.d.ts.map +1 -1
- package/dist/components/ModalRoot/types.js.map +1 -1
- package/dist/components/ModalRoot/useModalManager.d.ts +3 -1
- package/dist/components/ModalRoot/useModalManager.d.ts.map +1 -1
- package/dist/components/ModalRoot/useModalManager.js +2 -1
- package/dist/components/ModalRoot/useModalManager.js.map +1 -1
- package/dist/components/OnboardingTooltip/OnboardingTooltip.d.ts +2 -2
- package/dist/components/OnboardingTooltip/OnboardingTooltip.d.ts.map +1 -1
- package/dist/components/OnboardingTooltip/OnboardingTooltip.js +4 -2
- package/dist/components/OnboardingTooltip/OnboardingTooltip.js.map +1 -1
- package/dist/components/Popover/Popover.d.ts +1 -1
- package/dist/components/Popover/Popover.d.ts.map +1 -1
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Popover/usePopover.d.ts +1 -1
- package/dist/components/Popover/usePopover.d.ts.map +1 -1
- package/dist/components/Popover/usePopover.js +3 -1
- package/dist/components/Popover/usePopover.js.map +1 -1
- package/dist/components/Popper/Popper.d.ts +2 -2
- package/dist/components/Popper/Popper.d.ts.map +1 -1
- package/dist/components/Popper/Popper.js +3 -1
- package/dist/components/Popper/Popper.js.map +1 -1
- package/dist/components/Select/Select.d.ts +2 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +5 -2
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/SelectionControl/SelectionControl.d.ts +5 -1
- package/dist/components/SelectionControl/SelectionControl.d.ts.map +1 -1
- package/dist/components/SelectionControl/SelectionControl.js +22 -6
- package/dist/components/SelectionControl/SelectionControl.js.map +1 -1
- package/dist/components/SelectionControl/SelectionControlContext.d.ts +7 -0
- package/dist/components/SelectionControl/SelectionControlContext.d.ts.map +1 -0
- package/dist/components/SelectionControl/SelectionControlContext.js +7 -0
- package/dist/components/SelectionControl/SelectionControlContext.js.map +1 -0
- package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.d.ts.map +1 -1
- package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js +3 -1
- package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js.map +1 -1
- package/dist/components/SimpleCell/SimpleCell.d.ts.map +1 -1
- package/dist/components/SimpleCell/SimpleCell.js +29 -8
- package/dist/components/SimpleCell/SimpleCell.js.map +1 -1
- package/dist/components/Skeleton/Skeleton.js +1 -1
- package/dist/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +19 -9
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/TabsController.d.ts +2 -2
- package/dist/components/Tabs/TabsController.d.ts.map +1 -1
- package/dist/components/Tabs/TabsController.js.map +1 -1
- package/dist/components/Tabs/TabsControllerContext.d.ts +5 -0
- package/dist/components/Tabs/TabsControllerContext.d.ts.map +1 -0
- package/dist/components/Tabs/TabsControllerContext.js +4 -0
- package/dist/components/Tabs/TabsControllerContext.js.map +1 -0
- package/dist/components/Tabs/TabsModeContext.d.ts +0 -2
- package/dist/components/Tabs/TabsModeContext.d.ts.map +1 -1
- package/dist/components/Tabs/TabsModeContext.js +1 -2
- package/dist/components/Tabs/TabsModeContext.js.map +1 -1
- package/dist/components/TabsItem/TabsItem.d.ts.map +1 -1
- package/dist/components/TabsItem/TabsItem.js +3 -1
- package/dist/components/TabsItem/TabsItem.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tooltip/useTooltip.d.ts +1 -1
- package/dist/components/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/useTooltip.js +3 -1
- package/dist/components/Tooltip/useTooltip.js.map +1 -1
- package/dist/components/Typography/Caption/Caption.d.ts +2 -0
- package/dist/components/Typography/Caption/Caption.d.ts.map +1 -1
- package/dist/components/Typography/Caption/Caption.js +4 -1
- package/dist/components/Typography/Caption/Caption.js.map +1 -1
- package/dist/components/Typography/Footnote/Footnote.d.ts +2 -0
- package/dist/components/Typography/Footnote/Footnote.d.ts.map +1 -1
- package/dist/components/Typography/Footnote/Footnote.js +4 -1
- package/dist/components/Typography/Footnote/Footnote.js.map +1 -1
- package/dist/components/Typography/Typography.d.ts +1 -0
- package/dist/components/Typography/Typography.d.ts.map +1 -1
- package/dist/components/Typography/Typography.js +7 -1
- package/dist/components/Typography/Typography.js.map +1 -1
- package/dist/components/View/View.d.ts.map +1 -1
- package/dist/components/View/View.js +2 -1
- package/dist/components/View/View.js.map +1 -1
- package/dist/components/View/ViewInfinite.d.ts.map +1 -1
- package/dist/components/View/ViewInfinite.js +2 -1
- package/dist/components/View/ViewInfinite.js.map +1 -1
- package/dist/components.css +1 -1
- package/dist/components.css.map +1 -1
- package/dist/cssm/components/Banner/Banner.module.css +1 -6
- package/dist/cssm/components/Calendar/Calendar.js +6 -6
- package/dist/cssm/components/Calendar/Calendar.js.map +1 -1
- package/dist/cssm/components/CalendarDays/CalendarDays.js +3 -3
- package/dist/cssm/components/CalendarDays/CalendarDays.js.map +1 -1
- package/dist/cssm/components/CalendarRange/CalendarRange.js +16 -14
- package/dist/cssm/components/CalendarRange/CalendarRange.js.map +1 -1
- package/dist/cssm/components/CalendarRange/utils.js +6 -5
- package/dist/cssm/components/CalendarRange/utils.js.map +1 -1
- package/dist/cssm/components/Cell/Cell.js +3 -1
- package/dist/cssm/components/Cell/Cell.js.map +1 -1
- package/dist/cssm/components/Checkbox/Checkbox.js +2 -1
- package/dist/cssm/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.js +4 -2
- package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.js.map +1 -1
- package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css +11 -2
- package/dist/cssm/components/ChipsInputBase/Chip/Chip.js +6 -2
- package/dist/cssm/components/ChipsInputBase/Chip/Chip.js.map +1 -1
- package/dist/cssm/components/ChipsInputBase/Chip/Chip.module.css +8 -1
- package/dist/cssm/components/ChipsInputBase/types.js.map +1 -1
- package/dist/cssm/components/ContentBadge/ContentBadge.js +14 -8
- package/dist/cssm/components/ContentBadge/ContentBadge.js.map +1 -1
- package/dist/cssm/components/ContentCard/ContentCard.js.map +1 -1
- package/dist/cssm/components/CustomSelect/CustomSelect.js +154 -421
- package/dist/cssm/components/CustomSelect/CustomSelect.js.map +1 -1
- package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.js +22 -4
- package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.js.map +1 -1
- package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css +12 -0
- package/dist/cssm/components/CustomSelect/helpers.js +62 -0
- package/dist/cssm/components/CustomSelect/helpers.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useAfterItems.js +58 -0
- package/dist/cssm/components/CustomSelect/hooks/useAfterItems.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useDropdownOpenedController.js +60 -0
- package/dist/cssm/components/CustomSelect/hooks/useDropdownOpenedController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useFocusedOptionController.js +52 -0
- package/dist/cssm/components/CustomSelect/hooks/useFocusedOptionController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useInputKeyboardController.js +78 -0
- package/dist/cssm/components/CustomSelect/hooks/useInputKeyboardController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useInputValueController.js +43 -0
- package/dist/cssm/components/CustomSelect/hooks/useInputValueController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useScrollListController.js +37 -0
- package/dist/cssm/components/CustomSelect/hooks/useScrollListController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/hooks/useSelectedOptionController.js +81 -0
- package/dist/cssm/components/CustomSelect/hooks/useSelectedOptionController.js.map +1 -0
- package/dist/cssm/components/CustomSelect/types.js +3 -0
- package/dist/cssm/components/CustomSelect/types.js.map +1 -0
- package/dist/cssm/components/CustomSelectDropdown/CustomSelectDropdown.js +1 -0
- package/dist/cssm/components/CustomSelectDropdown/CustomSelectDropdown.js.map +1 -1
- package/dist/cssm/components/DateInput/DateInput.js +3 -2
- package/dist/cssm/components/DateInput/DateInput.js.map +1 -1
- package/dist/cssm/components/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/cssm/components/DateRangeInput/DateRangeInput.js.map +1 -1
- package/dist/cssm/components/ImageBase/ImageBaseBadge/ImageBaseBadge.js.map +1 -1
- package/dist/cssm/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
- package/dist/cssm/components/ModalCard/ModalCard.js +2 -1
- package/dist/cssm/components/ModalCard/ModalCard.js.map +1 -1
- package/dist/cssm/components/ModalCard/ModalCardInternal.js +3 -2
- package/dist/cssm/components/ModalCard/ModalCardInternal.js.map +1 -1
- package/dist/cssm/components/ModalCard/types.js.map +1 -1
- package/dist/cssm/components/ModalOutlet/ModalOutlet.js +2 -2
- package/dist/cssm/components/ModalOutlet/ModalOutlet.js.map +1 -1
- package/dist/cssm/components/ModalOutlet/ModalOutlet.module.css +4 -0
- package/dist/cssm/components/ModalOverlay/ModalOverlay.module.css +1 -1
- package/dist/cssm/components/ModalPage/ModalPage.js +2 -1
- package/dist/cssm/components/ModalPage/ModalPage.js.map +1 -1
- package/dist/cssm/components/ModalPage/ModalPage.module.css +1 -0
- package/dist/cssm/components/ModalPage/ModalPageInternal.js +3 -2
- package/dist/cssm/components/ModalPage/ModalPageInternal.js.map +1 -1
- package/dist/cssm/components/ModalPage/types.js.map +1 -1
- package/dist/cssm/components/ModalRoot/ModalRoot.js +4 -2
- package/dist/cssm/components/ModalRoot/ModalRoot.js.map +1 -1
- package/dist/cssm/components/ModalRoot/types.js.map +1 -1
- package/dist/cssm/components/ModalRoot/useModalManager.js +2 -1
- package/dist/cssm/components/ModalRoot/useModalManager.js.map +1 -1
- package/dist/cssm/components/OnboardingTooltip/OnboardingTooltip.js +3 -2
- package/dist/cssm/components/OnboardingTooltip/OnboardingTooltip.js.map +1 -1
- package/dist/cssm/components/Popover/Popover.js.map +1 -1
- package/dist/cssm/components/Popover/usePopover.js +2 -1
- package/dist/cssm/components/Popover/usePopover.js.map +1 -1
- package/dist/cssm/components/Popper/Popper.js +2 -1
- package/dist/cssm/components/Popper/Popper.js.map +1 -1
- package/dist/cssm/components/RichCell/RichCell.module.css +4 -2
- package/dist/cssm/components/Select/Select.js +1 -1
- package/dist/cssm/components/Select/Select.js.map +1 -1
- package/dist/cssm/components/SelectionControl/SelectionControl.js +16 -6
- package/dist/cssm/components/SelectionControl/SelectionControl.js.map +1 -1
- package/dist/cssm/components/SelectionControl/SelectionControl.module.css +6 -3
- package/dist/cssm/components/SelectionControl/SelectionControlContext.js +7 -0
- package/dist/cssm/components/SelectionControl/SelectionControlContext.js.map +1 -0
- package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js +3 -1
- package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js.map +1 -1
- package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css +6 -3
- package/dist/cssm/components/SimpleCell/SimpleCell.js +29 -8
- package/dist/cssm/components/SimpleCell/SimpleCell.js.map +1 -1
- package/dist/cssm/components/Skeleton/Skeleton.js +1 -1
- package/dist/cssm/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/cssm/components/Slider/SliderThumb/SliderThumb.module.css +2 -1
- package/dist/cssm/components/Tabs/Tabs.js +19 -9
- package/dist/cssm/components/Tabs/Tabs.js.map +1 -1
- package/dist/cssm/components/Tabs/TabsController.js.map +1 -1
- package/dist/cssm/components/Tabs/TabsControllerContext.js +4 -0
- package/dist/cssm/components/Tabs/TabsControllerContext.js.map +1 -0
- package/dist/cssm/components/Tabs/TabsModeContext.js +1 -2
- package/dist/cssm/components/Tabs/TabsModeContext.js.map +1 -1
- package/dist/cssm/components/TabsItem/TabsItem.js +3 -1
- package/dist/cssm/components/TabsItem/TabsItem.js.map +1 -1
- package/dist/cssm/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/cssm/components/Tooltip/useTooltip.js +2 -1
- package/dist/cssm/components/Tooltip/useTooltip.js.map +1 -1
- package/dist/cssm/components/Typography/Caption/Caption.js +4 -1
- package/dist/cssm/components/Typography/Caption/Caption.js.map +1 -1
- package/dist/cssm/components/Typography/Footnote/Footnote.js +4 -1
- package/dist/cssm/components/Typography/Footnote/Footnote.js.map +1 -1
- package/dist/cssm/components/Typography/Typography.js +7 -1
- package/dist/cssm/components/Typography/Typography.js.map +1 -1
- package/dist/cssm/components/View/View.js +2 -1
- package/dist/cssm/components/View/View.js.map +1 -1
- package/dist/cssm/components/View/View.module.css +1 -1
- package/dist/cssm/components/View/ViewInfinite.js +2 -1
- package/dist/cssm/components/View/ViewInfinite.js.map +1 -1
- package/dist/cssm/components/VisuallyHidden/VisuallyHidden.module.css +0 -2
- package/dist/cssm/hooks/useCalendar.js +6 -4
- package/dist/cssm/hooks/useCalendar.js.map +1 -1
- package/dist/cssm/hooks/useFloatingElement.js +3 -2
- package/dist/cssm/hooks/useFloatingElement.js.map +1 -1
- package/dist/cssm/hooks/useTodayDate.js +3 -2
- package/dist/cssm/hooks/useTodayDate.js.map +1 -1
- package/dist/cssm/index.js.map +1 -1
- package/dist/cssm/lib/accessibility.js +8 -0
- package/dist/cssm/lib/accessibility.js.map +1 -1
- package/dist/cssm/lib/calendar.js +9 -7
- package/dist/cssm/lib/calendar.js.map +1 -1
- package/dist/cssm/lib/date.js +66 -3
- package/dist/cssm/lib/date.js.map +1 -1
- package/dist/cssm/lib/floating/useFloatingMiddlewaresBootstrap/index.js +18 -8
- package/dist/cssm/lib/floating/useFloatingMiddlewaresBootstrap/index.js.map +1 -1
- package/dist/cssm/lib/floating/useFloatingWithInteractions/types.js.map +1 -1
- package/dist/cssm/lib/touch/UIPanGestureRecognizer.js +2 -2
- package/dist/cssm/lib/touch/UIPanGestureRecognizer.js.map +1 -1
- package/dist/cssm/lib/utils.js +1 -0
- package/dist/cssm/lib/utils.js.map +1 -1
- package/dist/cssm/styles/dynamicTokens.css +14 -2
- package/dist/cssm/styles/themes.css +1 -1
- package/dist/hooks/useCalendar.d.ts.map +1 -1
- package/dist/hooks/useCalendar.js +6 -4
- package/dist/hooks/useCalendar.js.map +1 -1
- package/dist/hooks/useFloatingElement.d.ts +1 -1
- package/dist/hooks/useFloatingElement.d.ts.map +1 -1
- package/dist/hooks/useFloatingElement.js +3 -2
- package/dist/hooks/useFloatingElement.js.map +1 -1
- package/dist/hooks/useTodayDate.d.ts.map +1 -1
- package/dist/hooks/useTodayDate.js +3 -2
- package/dist/hooks/useTodayDate.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/accessibility.d.ts +1 -1
- package/dist/lib/accessibility.d.ts.map +1 -1
- package/dist/lib/accessibility.js +8 -0
- package/dist/lib/accessibility.js.map +1 -1
- package/dist/lib/calendar.d.ts.map +1 -1
- package/dist/lib/calendar.js +9 -7
- package/dist/lib/calendar.js.map +1 -1
- package/dist/lib/date.d.ts +31 -1
- package/dist/lib/date.d.ts.map +1 -1
- package/dist/lib/date.js +67 -3
- package/dist/lib/date.js.map +1 -1
- package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.d.ts +6 -1
- package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.d.ts.map +1 -1
- package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.js +18 -8
- package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.js.map +1 -1
- package/dist/lib/floating/useFloatingWithInteractions/types.d.ts +2 -0
- package/dist/lib/floating/useFloatingWithInteractions/types.d.ts.map +1 -1
- package/dist/lib/floating/useFloatingWithInteractions/types.js.map +1 -1
- package/dist/lib/touch/UIPanGestureRecognizer.d.ts.map +1 -1
- package/dist/lib/touch/UIPanGestureRecognizer.js +2 -2
- package/dist/lib/touch/UIPanGestureRecognizer.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +1 -0
- package/dist/lib/utils.js.map +1 -1
- package/dist/vkui.css +1 -1
- package/dist/vkui.css.map +1 -1
- package/package.json +6 -7
- package/src/components/Banner/Banner.module.css +1 -6
- package/src/components/Banner/Banner.module.css.d.ts.map +1 -1
- package/src/components/Calendar/Calendar.tsx +6 -6
- package/src/components/CalendarDays/CalendarDays.tsx +3 -3
- package/src/components/CalendarRange/CalendarRange.tsx +15 -20
- package/src/components/CalendarRange/utils.ts +7 -6
- package/src/components/Cell/Cell.tsx +3 -0
- package/src/components/Checkbox/Checkbox.tsx +6 -0
- package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css +7 -2
- package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css.d.ts.map +1 -1
- package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.tsx +12 -3
- package/src/components/ChipsInputBase/Chip/Chip.module.css +8 -1
- package/src/components/ChipsInputBase/Chip/Chip.module.css.d.ts.map +1 -1
- package/src/components/ChipsInputBase/Chip/Chip.tsx +55 -1
- package/src/components/ChipsInputBase/types.ts +2 -45
- package/src/components/ContentBadge/ContentBadge.tsx +18 -12
- package/src/components/ContentCard/ContentCard.tsx +1 -1
- package/src/components/CustomSelect/CustomSelect.tsx +216 -562
- package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css +12 -0
- package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css.d.ts.map +1 -1
- package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.tsx +25 -2
- package/src/components/CustomSelect/helpers.ts +103 -0
- package/src/components/CustomSelect/hooks/useAfterItems.tsx +89 -0
- package/src/components/CustomSelect/hooks/useDropdownOpenedController.ts +61 -0
- package/src/components/CustomSelect/hooks/useFocusedOptionController.ts +86 -0
- package/src/components/CustomSelect/hooks/useInputKeyboardController.ts +96 -0
- package/src/components/CustomSelect/hooks/useInputValueController.ts +58 -0
- package/src/components/CustomSelect/hooks/useScrollListController.ts +46 -0
- package/src/components/CustomSelect/hooks/useSelectedOptionController.ts +132 -0
- package/src/components/CustomSelect/types.ts +38 -0
- package/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx +1 -0
- package/src/components/DateInput/DateInput.tsx +9 -3
- package/src/components/DateRangeInput/DateRangeInput.tsx +9 -6
- package/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx +1 -1
- package/src/components/MiniInfoCell/MiniInfoCell.tsx +8 -3
- package/src/components/ModalCard/ModalCard.tsx +2 -0
- package/src/components/ModalCard/ModalCardInternal.tsx +8 -2
- package/src/components/ModalCard/types.ts +8 -0
- package/src/components/ModalOutlet/ModalOutlet.module.css +4 -0
- package/src/components/ModalOutlet/ModalOutlet.module.css.d.ts.map +1 -1
- package/src/components/ModalOutlet/ModalOutlet.tsx +8 -1
- package/src/components/ModalOverlay/ModalOverlay.module.css +1 -1
- package/src/components/ModalPage/ModalPage.module.css +1 -0
- package/src/components/ModalPage/ModalPage.module.css.d.ts.map +1 -1
- package/src/components/ModalPage/ModalPage.tsx +2 -0
- package/src/components/ModalPage/ModalPageInternal.tsx +8 -2
- package/src/components/ModalPage/types.ts +8 -0
- package/src/components/ModalRoot/ModalRoot.tsx +19 -6
- package/src/components/ModalRoot/types.ts +7 -0
- package/src/components/ModalRoot/useModalManager.tsx +4 -0
- package/src/components/OnboardingTooltip/OnboardingTooltip.tsx +3 -0
- package/src/components/Popover/Popover.tsx +1 -0
- package/src/components/Popover/usePopover.tsx +2 -0
- package/src/components/Popper/Popper.tsx +3 -0
- package/src/components/RichCell/RichCell.module.css +4 -2
- package/src/components/RichCell/RichCell.module.css.d.ts.map +1 -1
- package/src/components/Select/Select.tsx +5 -5
- package/src/components/SelectionControl/SelectionControl.module.css +6 -3
- package/src/components/SelectionControl/SelectionControl.module.css.d.ts.map +1 -1
- package/src/components/SelectionControl/SelectionControl.tsx +30 -8
- package/src/components/SelectionControl/SelectionControlContext.ts +7 -0
- package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css +6 -3
- package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css.d.ts.map +1 -1
- package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.tsx +7 -1
- package/src/components/SimpleCell/SimpleCell.tsx +5 -0
- package/src/components/Skeleton/Skeleton.tsx +1 -1
- package/src/components/Slider/SliderThumb/SliderThumb.module.css +1 -1
- package/src/components/Tabs/Tabs.tsx +16 -12
- package/src/components/Tabs/TabsController.ts +2 -2
- package/src/components/Tabs/TabsControllerContext.ts +7 -0
- package/src/components/Tabs/TabsModeContext.ts +0 -3
- package/src/components/TabsItem/TabsItem.tsx +5 -9
- package/src/components/Tooltip/Tooltip.tsx +1 -0
- package/src/components/Tooltip/useTooltip.tsx +2 -0
- package/src/components/Typography/Caption/Caption.tsx +14 -6
- package/src/components/Typography/Footnote/Footnote.tsx +10 -6
- package/src/components/Typography/Typography.tsx +9 -2
- package/src/components/View/View.module.css +1 -1
- package/src/components/View/View.tsx +2 -1
- package/src/components/View/ViewInfinite.tsx +2 -1
- package/src/components/VisuallyHidden/VisuallyHidden.module.css +0 -2
- package/src/components/VisuallyHidden/VisuallyHidden.module.css.d.ts.map +1 -1
- package/src/hooks/useCalendar.ts +6 -4
- package/src/hooks/useFloatingElement.tsx +2 -0
- package/src/hooks/useTodayDate.ts +3 -2
- package/src/index.ts +5 -3
- package/src/lib/accessibility.ts +4 -0
- package/src/lib/calendar.ts +8 -12
- package/src/lib/date.ts +82 -3
- package/src/lib/floating/useFloatingMiddlewaresBootstrap/index.ts +23 -10
- package/src/lib/floating/useFloatingWithInteractions/types.ts +2 -0
- package/src/lib/touch/UIPanGestureRecognizer.ts +2 -2
- package/src/lib/utils.ts +3 -0
- package/src/styles/dynamicTokens.css +13 -2
|
@@ -1,48 +1,52 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { classNames
|
|
4
|
+
import { classNames } from '@vkontakte/vkjs';
|
|
5
|
+
import { getRequiredValueByKey } from '../../helpers/getValueByKey';
|
|
5
6
|
import { useAdaptivity } from '../../hooks/useAdaptivity';
|
|
6
7
|
import { useExternRef } from '../../hooks/useExternRef';
|
|
7
|
-
import { useFocusWithin } from '../../hooks/useFocusWithin';
|
|
8
|
-
import { useStateWithPrev } from '../../hooks/useStateWithPrev';
|
|
9
8
|
import { callMultiple } from '../../lib/callMultiple';
|
|
10
9
|
import { useDOM } from '../../lib/dom';
|
|
11
|
-
import type {
|
|
10
|
+
import type { Placement } from '../../lib/floating';
|
|
12
11
|
import { defaultFilterFn, type FilterFn } from '../../lib/select';
|
|
13
12
|
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
|
|
14
|
-
import {
|
|
13
|
+
import { preventDefault } from '../../lib/utils';
|
|
15
14
|
import {
|
|
16
15
|
CustomSelectDropdown,
|
|
17
16
|
type CustomSelectDropdownProps,
|
|
18
17
|
} from '../CustomSelectDropdown/CustomSelectDropdown';
|
|
19
|
-
import {
|
|
20
|
-
CustomSelectOption,
|
|
21
|
-
type CustomSelectOptionProps,
|
|
22
|
-
} from '../CustomSelectOption/CustomSelectOption';
|
|
23
|
-
import { DropdownIcon } from '../DropdownIcon/DropdownIcon';
|
|
18
|
+
import { CustomSelectOption } from '../CustomSelectOption/CustomSelectOption';
|
|
24
19
|
import type { FormFieldProps } from '../FormField/FormField';
|
|
25
|
-
import type {
|
|
26
|
-
|
|
27
|
-
NativeSelectValue,
|
|
28
|
-
SelectValue,
|
|
29
|
-
} from '../NativeSelect/NativeSelect';
|
|
30
|
-
import {
|
|
31
|
-
NOT_SELECTED,
|
|
32
|
-
remapFromNativeValueToSelectValue,
|
|
33
|
-
remapFromSelectValueToNativeValue,
|
|
34
|
-
} from '../NativeSelect/NativeSelect';
|
|
20
|
+
import type { NativeSelectProps, SelectValue } from '../NativeSelect/NativeSelect';
|
|
21
|
+
import { NOT_SELECTED, remapFromNativeValueToSelectValue } from '../NativeSelect/NativeSelect';
|
|
35
22
|
import type { SelectType } from '../Select/Select';
|
|
36
23
|
import { Footnote } from '../Typography/Footnote/Footnote';
|
|
37
24
|
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden';
|
|
38
|
-
import {
|
|
39
|
-
CustomSelectClearButton,
|
|
40
|
-
type CustomSelectClearButtonProps,
|
|
41
|
-
} from './CustomSelectClearButton';
|
|
25
|
+
import { type CustomSelectClearButtonProps } from './CustomSelectClearButton';
|
|
42
26
|
import {
|
|
43
27
|
CustomSelectInput,
|
|
44
28
|
type CustomSelectInputProps,
|
|
45
29
|
} from './CustomSelectInput/CustomSelectInput';
|
|
30
|
+
import {
|
|
31
|
+
checkMixControlledAndUncontrolledState,
|
|
32
|
+
checkOptionsValueType,
|
|
33
|
+
filter,
|
|
34
|
+
findSelectedIndex,
|
|
35
|
+
getOptionByValue,
|
|
36
|
+
} from './helpers';
|
|
37
|
+
import { useAfterItems } from './hooks/useAfterItems';
|
|
38
|
+
import { useDropdownOpenedController } from './hooks/useDropdownOpenedController';
|
|
39
|
+
import { useFocusedOptionController } from './hooks/useFocusedOptionController';
|
|
40
|
+
import { useInputKeyboardController } from './hooks/useInputKeyboardController';
|
|
41
|
+
import { useInputValueController } from './hooks/useInputValueController';
|
|
42
|
+
import { useScrollListController } from './hooks/useScrollListController';
|
|
43
|
+
import { useSelectedOptionController } from './hooks/useSelectedOptionController';
|
|
44
|
+
import type {
|
|
45
|
+
CustomSelectOptionInterface,
|
|
46
|
+
CustomSelectRenderOption,
|
|
47
|
+
MousePosition,
|
|
48
|
+
PopupDirection,
|
|
49
|
+
} from './types';
|
|
46
50
|
import styles from './CustomSelect.module.css';
|
|
47
51
|
|
|
48
52
|
const sizeYClassNames = {
|
|
@@ -50,61 +54,6 @@ const sizeYClassNames = {
|
|
|
50
54
|
compact: styles.sizeYCompact,
|
|
51
55
|
};
|
|
52
56
|
|
|
53
|
-
const findIndexAfter = (options: CustomSelectOptionInterface[] = [], startIndex = -1) => {
|
|
54
|
-
if (startIndex >= options.length - 1) {
|
|
55
|
-
return -1;
|
|
56
|
-
}
|
|
57
|
-
return options.findIndex((option, i) => i > startIndex && !option.disabled);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const findIndexBefore = (
|
|
61
|
-
options: CustomSelectOptionInterface[] = [],
|
|
62
|
-
endIndex: number = options.length,
|
|
63
|
-
) => {
|
|
64
|
-
let result = -1;
|
|
65
|
-
if (endIndex <= 0) {
|
|
66
|
-
return result;
|
|
67
|
-
}
|
|
68
|
-
for (let i = endIndex - 1; i >= 0; i--) {
|
|
69
|
-
let option = options[i];
|
|
70
|
-
|
|
71
|
-
if (!option.disabled) {
|
|
72
|
-
result = i;
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return result;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const warn = warnOnce('CustomSelect');
|
|
80
|
-
|
|
81
|
-
const checkOptionsValueType = <T extends CustomSelectOptionInterface>(options: T[]) => {
|
|
82
|
-
if (new Set(options.map((item) => typeof item.value)).size > 1) {
|
|
83
|
-
warn(
|
|
84
|
-
'Некоторые значения ваших опций имеют разные типы. onChange всегда возвращает строковый тип.',
|
|
85
|
-
'error',
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const checkMixControlledAndUncontrolledState = (
|
|
91
|
-
oldIsControlled: boolean,
|
|
92
|
-
newIsControlled: boolean,
|
|
93
|
-
) => {
|
|
94
|
-
if (!oldIsControlled && newIsControlled) {
|
|
95
|
-
warn(
|
|
96
|
-
`Похоже, что компонент был переведен из состояния Uncontrolled в Controlled. Пожалуйста, не делайте так. Если вам нужно отобразить невыбранное состояние компонента, используйте value=null вместо undefined`,
|
|
97
|
-
'error',
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
if (oldIsControlled && !newIsControlled) {
|
|
101
|
-
warn(
|
|
102
|
-
`Похоже, что компонент был переведен из состояния Controlled в Uncontrolled. Пожалуйста, не делайте так. Если вам нужно отобразить невыбранное состояние компонента, используйте value=null вместо undefined`,
|
|
103
|
-
'error',
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
57
|
function defaultRenderOptionFn<T extends CustomSelectOptionInterface>({
|
|
109
58
|
option,
|
|
110
59
|
...props
|
|
@@ -112,75 +61,48 @@ function defaultRenderOptionFn<T extends CustomSelectOptionInterface>({
|
|
|
112
61
|
return <CustomSelectOption {...props} />;
|
|
113
62
|
}
|
|
114
63
|
|
|
115
|
-
const handleOptionDown: MouseEventHandler = (e: React.MouseEvent<HTMLElement>) => {
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
function findSelectedIndex<T extends CustomSelectOptionInterface>(
|
|
120
|
-
options: T[] = [],
|
|
121
|
-
value: SelectValue,
|
|
122
|
-
) {
|
|
123
|
-
if (value === NOT_SELECTED.CUSTOM) {
|
|
124
|
-
return -1;
|
|
125
|
-
}
|
|
126
|
-
return (
|
|
127
|
-
options.findIndex((item) => {
|
|
128
|
-
value = typeof item.value === 'number' ? Number(value) : value;
|
|
129
|
-
return item.value === value;
|
|
130
|
-
}) ?? -1
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const filter = <T extends CustomSelectOptionInterface>(
|
|
135
|
-
options: SelectProps<T>['options'],
|
|
136
|
-
inputValue: string,
|
|
137
|
-
filterFn: SelectProps<T>['filterFn'],
|
|
138
|
-
) => {
|
|
139
|
-
return typeof filterFn === 'function'
|
|
140
|
-
? options.filter((option) => filterFn(inputValue, option))
|
|
141
|
-
: options;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
/* eslint-disable jsdoc/require-jsdoc */
|
|
145
|
-
type MousePosition = {
|
|
146
|
-
x: React.MouseEvent['clientX'];
|
|
147
|
-
y: React.MouseEvent['clientY'];
|
|
148
|
-
};
|
|
149
|
-
/* eslint-enable jsdoc/require-jsdoc */
|
|
150
|
-
|
|
151
64
|
function isMousePositionChanged(event: React.MouseEvent, prevPosition: MousePosition) {
|
|
152
65
|
return (
|
|
153
66
|
Math.abs(prevPosition.x - event.clientX) >= 1 || Math.abs(prevPosition.y - event.clientY) >= 1
|
|
154
67
|
);
|
|
155
68
|
}
|
|
156
69
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
70
|
+
const FETCH_STATUS_RESET_DELAY = 2000;
|
|
71
|
+
|
|
72
|
+
const FetchingStatus = ({
|
|
73
|
+
fetching = false,
|
|
74
|
+
options,
|
|
75
|
+
fetchingInProgressLabel = 'Список опций загружается...',
|
|
76
|
+
fetchingCompletedLabel = `Загружено опций: ${options.length}`,
|
|
77
|
+
}: Pick<
|
|
78
|
+
SelectProps,
|
|
79
|
+
'fetching' | 'fetchingInProgressLabel' | 'fetchingCompletedLabel' | 'options'
|
|
80
|
+
>) => {
|
|
81
|
+
const [status, setStatus] = React.useState<'fetching' | 'loaded' | 'none'>('none');
|
|
82
|
+
|
|
83
|
+
const content = getRequiredValueByKey(status, {
|
|
84
|
+
fetching: fetchingInProgressLabel,
|
|
85
|
+
loaded:
|
|
86
|
+
typeof fetchingCompletedLabel === 'function'
|
|
87
|
+
? fetchingCompletedLabel(options.length)
|
|
88
|
+
: fetchingCompletedLabel,
|
|
89
|
+
none: '',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
useIsomorphicLayoutEffect(
|
|
93
|
+
function updateStatus() {
|
|
94
|
+
if (fetching) {
|
|
95
|
+
setStatus('fetching');
|
|
96
|
+
} else {
|
|
97
|
+
setStatus('loaded');
|
|
98
|
+
setTimeout(() => setStatus('none'), FETCH_STATUS_RESET_DELAY);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
[fetching],
|
|
102
|
+
);
|
|
182
103
|
|
|
183
|
-
|
|
104
|
+
return <VisuallyHidden aria-live="polite">{content}</VisuallyHidden>;
|
|
105
|
+
};
|
|
184
106
|
|
|
185
107
|
export type { CustomSelectClearButtonProps };
|
|
186
108
|
|
|
@@ -223,7 +145,7 @@ export interface SelectProps<
|
|
|
223
145
|
* Рендер-проп для кастомного рендера опции.
|
|
224
146
|
* В объекте аргумента приходят [свойства опции](https://vkui.io/components/custom-select#custom-select-option-api).
|
|
225
147
|
*
|
|
226
|
-
* > ⚠️ Важно:
|
|
148
|
+
* > ⚠️ Важно: свойство опции `disabled` должно выставляться только через проп `options`.
|
|
227
149
|
* > Запрещается выставлять `disabled` проп опциям в обход `options`, иначе `CustomSelect` не будет знать об актуальном состоянии
|
|
228
150
|
* опции.
|
|
229
151
|
*/
|
|
@@ -299,17 +221,27 @@ export interface SelectProps<
|
|
|
299
221
|
* Обработчик события `keyDown` в поле ввода.
|
|
300
222
|
*/
|
|
301
223
|
onInputKeyDown?: (e: React.KeyboardEvent, isOpen: boolean) => void;
|
|
224
|
+
/**
|
|
225
|
+
* Включает режим в котором выбранное значение `CustomSelect` читается скринридерами корректно.
|
|
226
|
+
* В данном режиме введенное в поле ввода значение не сбрасывается при потере фокуса.
|
|
227
|
+
*/
|
|
228
|
+
accessible?: boolean /* TODO [>=v8] включить по умолчанию */;
|
|
229
|
+
/**
|
|
230
|
+
* Текстовая метка для индикации процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Список опций загружается..."`.
|
|
231
|
+
*/
|
|
232
|
+
fetchingInProgressLabel?: string;
|
|
233
|
+
/**
|
|
234
|
+
* Текстовая метка для индикации завершения процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Загружено опций: ${options.length}"`.
|
|
235
|
+
*/
|
|
236
|
+
fetchingCompletedLabel?: string | ((optionsCount: number) => string);
|
|
302
237
|
}
|
|
303
238
|
|
|
304
|
-
type MouseEventHandler = (event: React.MouseEvent<HTMLElement>) => void;
|
|
305
|
-
|
|
306
239
|
/**
|
|
307
240
|
* @see https://vkui.io/components/custom-select
|
|
308
241
|
*/
|
|
309
242
|
export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterface>(
|
|
310
243
|
props: SelectProps<OptionInterfaceT>,
|
|
311
244
|
): React.ReactNode {
|
|
312
|
-
const [opened, setOpened] = React.useState(false);
|
|
313
245
|
const {
|
|
314
246
|
before,
|
|
315
247
|
name,
|
|
@@ -329,11 +261,11 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
329
261
|
selectType = 'default',
|
|
330
262
|
searchable = false,
|
|
331
263
|
'renderOption': renderOptionProp = defaultRenderOptionFn,
|
|
332
|
-
'options':
|
|
264
|
+
'options': options,
|
|
333
265
|
emptyText = 'Ничего не найдено',
|
|
334
266
|
filterFn = defaultFilterFn,
|
|
335
267
|
'icon': iconProp,
|
|
336
|
-
ClearButton
|
|
268
|
+
ClearButton,
|
|
337
269
|
allowClearButton = false,
|
|
338
270
|
dropdownOffsetDistance = 0,
|
|
339
271
|
dropdownAutoWidth = false,
|
|
@@ -345,85 +277,119 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
345
277
|
required,
|
|
346
278
|
getSelectInputRef,
|
|
347
279
|
overscrollBehavior,
|
|
348
|
-
onInputKeyDown,
|
|
280
|
+
'onInputKeyDown': onInputKeyDownProp,
|
|
349
281
|
readOnly,
|
|
282
|
+
accessible = false,
|
|
283
|
+
fetchingInProgressLabel,
|
|
284
|
+
fetchingCompletedLabel,
|
|
350
285
|
...restProps
|
|
351
286
|
} = props;
|
|
352
287
|
|
|
353
288
|
if (process.env.NODE_ENV === 'development') {
|
|
354
|
-
checkOptionsValueType(
|
|
289
|
+
checkOptionsValueType(options);
|
|
355
290
|
}
|
|
356
291
|
|
|
357
292
|
const { sizeY = 'none' } = useAdaptivity();
|
|
358
293
|
|
|
359
294
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
360
295
|
const handleRootRef = useExternRef(containerRef, getRootRef);
|
|
361
|
-
const scrollBoxRef = React.useRef<HTMLDivElement | null>(null);
|
|
362
296
|
const selectElRef = useExternRef(getRef);
|
|
363
|
-
const
|
|
364
|
-
const scrollPerformedRef = React.useRef(false);
|
|
297
|
+
const selectInputRef = useExternRef(getSelectInputRef);
|
|
365
298
|
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
return remapFromSelectValueToNativeValue(props.value);
|
|
373
|
-
}
|
|
374
|
-
if (defaultValue !== undefined) {
|
|
375
|
-
return remapFromSelectValueToNativeValue(defaultValue);
|
|
376
|
-
}
|
|
377
|
-
return NOT_SELECTED.NATIVE;
|
|
378
|
-
});
|
|
299
|
+
const propsValue = React.useMemo<SelectValue | undefined>(() => {
|
|
300
|
+
if (props.value === undefined) {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
return getOptionByValue(options, props.value)?.value ?? null;
|
|
304
|
+
}, [options, props.value]);
|
|
379
305
|
|
|
306
|
+
const [isControlledOutside, setIsControlledOutside] = React.useState(props.value !== undefined);
|
|
380
307
|
const [popperPlacement, setPopperPlacement] = React.useState<Placement>(popupDirection);
|
|
381
308
|
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
309
|
+
const {
|
|
310
|
+
nativeSelectValue,
|
|
311
|
+
setNativeSelectValue,
|
|
312
|
+
selectedOptionValue,
|
|
313
|
+
setSelectedOptionValue,
|
|
314
|
+
onNativeSelectChange,
|
|
315
|
+
} = useSelectedOptionController({
|
|
316
|
+
value: propsValue,
|
|
317
|
+
defaultValue,
|
|
318
|
+
isControlledOutside,
|
|
319
|
+
allowClearButton,
|
|
320
|
+
onChange,
|
|
321
|
+
});
|
|
385
322
|
|
|
386
|
-
const
|
|
387
|
-
|
|
323
|
+
const selected = React.useMemo(
|
|
324
|
+
() => options.find((option) => option.value === selectedOptionValue),
|
|
325
|
+
[options, selectedOptionValue],
|
|
388
326
|
);
|
|
389
327
|
|
|
328
|
+
const { inputValue, onInputChange, resetInputValue, resetInputValueBySelectedOption } =
|
|
329
|
+
useInputValueController({
|
|
330
|
+
options,
|
|
331
|
+
accessible,
|
|
332
|
+
selectedValue: selectedOptionValue,
|
|
333
|
+
onInputChange: onInputChangeProp,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const filteredOptions = React.useMemo(
|
|
337
|
+
() => filter(options, searchable ? inputValue : '', filterFn),
|
|
338
|
+
[filterFn, inputValue, options, searchable],
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const { scrollToElement, optionsWrapperRef, scrollBoxRef } = useScrollListController();
|
|
342
|
+
|
|
343
|
+
const {
|
|
344
|
+
focusedOptionValue,
|
|
345
|
+
setFocusedOptionValue,
|
|
346
|
+
resetFocusedOption,
|
|
347
|
+
focusOptionByIndex,
|
|
348
|
+
focusOption,
|
|
349
|
+
selectFocusedValue,
|
|
350
|
+
} = useFocusedOptionController({
|
|
351
|
+
selectedOptionValue,
|
|
352
|
+
filteredOptions,
|
|
353
|
+
scrollToElement,
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const scrollToSelectedOption = () => {
|
|
357
|
+
scrollToElement(findSelectedIndex(filteredOptions, selectedOptionValue), true);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const { opened, open, close, toggleOpened } = useDropdownOpenedController({
|
|
361
|
+
onOpen: callMultiple(selectFocusedValue, onOpen),
|
|
362
|
+
onOpened: scrollToSelectedOption,
|
|
363
|
+
onClose,
|
|
364
|
+
onClosed: accessible ? resetInputValueBySelectedOption : resetInputValue,
|
|
365
|
+
});
|
|
366
|
+
|
|
390
367
|
React.useEffect(
|
|
391
|
-
function
|
|
368
|
+
function updateOptionsValue() {
|
|
392
369
|
const value =
|
|
393
|
-
|
|
394
|
-
?
|
|
370
|
+
propsValue !== undefined
|
|
371
|
+
? propsValue
|
|
395
372
|
: remapFromNativeValueToSelectValue(nativeSelectValue);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
setSelectedOptionIndex(selectedIndex);
|
|
399
|
-
setFocusedOptionIndex(selectedIndex);
|
|
373
|
+
setSelectedOptionValue(value);
|
|
374
|
+
setFocusedOptionValue(value);
|
|
400
375
|
},
|
|
401
|
-
[
|
|
376
|
+
[propsValue, nativeSelectValue, setFocusedOptionValue, setSelectedOptionValue],
|
|
402
377
|
);
|
|
403
378
|
|
|
404
379
|
React.useEffect(
|
|
405
380
|
function syncIsControlledState() {
|
|
406
381
|
setIsControlledOutside((oldIsControlled) => {
|
|
407
|
-
const newIsControlled =
|
|
382
|
+
const newIsControlled = propsValue !== undefined;
|
|
408
383
|
checkMixControlledAndUncontrolledState(oldIsControlled, newIsControlled);
|
|
409
384
|
return newIsControlled;
|
|
410
385
|
});
|
|
411
386
|
},
|
|
412
|
-
[
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
React.useEffect(
|
|
416
|
-
function syncNativeSelectValueWithPropValue() {
|
|
417
|
-
if (props.value !== undefined) {
|
|
418
|
-
setNativeSelectValue(remapFromSelectValueToNativeValue(props.value));
|
|
419
|
-
}
|
|
420
|
-
},
|
|
421
|
-
[props.value, setNativeSelectValue],
|
|
387
|
+
[propsValue],
|
|
422
388
|
);
|
|
423
389
|
|
|
424
390
|
useIsomorphicLayoutEffect(() => {
|
|
425
391
|
if (
|
|
426
|
-
|
|
392
|
+
filteredOptions.some(({ value }) => nativeSelectValue === value) ||
|
|
427
393
|
(allowClearButton && nativeSelectValue === NOT_SELECTED.NATIVE)
|
|
428
394
|
) {
|
|
429
395
|
const event = new Event('change', { bubbles: true });
|
|
@@ -432,14 +398,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
432
398
|
}
|
|
433
399
|
}, [nativeSelectValue]);
|
|
434
400
|
|
|
435
|
-
const selected = React.useMemo(() => {
|
|
436
|
-
if (!options.length) {
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return selectedOptionIndex !== undefined ? options[selectedOptionIndex] : undefined;
|
|
441
|
-
}, [options, selectedOptionIndex]);
|
|
442
|
-
|
|
443
401
|
const openedClassNames = React.useMemo(
|
|
444
402
|
() =>
|
|
445
403
|
(opened &&
|
|
@@ -449,150 +407,40 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
449
407
|
[dropdownOffsetDistance, opened, popperPlacement],
|
|
450
408
|
);
|
|
451
409
|
|
|
452
|
-
const scrollToElement = React.useCallback((index: number, center = false) => {
|
|
453
|
-
const dropdown = scrollBoxRef.current;
|
|
454
|
-
const optionsWrapper = optionsWrapperRef.current;
|
|
455
|
-
const item =
|
|
456
|
-
dropdown && optionsWrapper ? (optionsWrapper.children[index] as HTMLElement) : null;
|
|
457
|
-
|
|
458
|
-
if (!item || !dropdown) {
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
const dropdownHeight = dropdown.offsetHeight;
|
|
463
|
-
const scrollTop = dropdown.scrollTop;
|
|
464
|
-
const itemTop = item.offsetTop;
|
|
465
|
-
const itemHeight = item.offsetHeight;
|
|
466
|
-
|
|
467
|
-
if (center) {
|
|
468
|
-
dropdown.scrollTop = itemTop - dropdownHeight / 2 + itemHeight / 2;
|
|
469
|
-
} else if (itemTop + itemHeight > dropdownHeight + scrollTop) {
|
|
470
|
-
dropdown.scrollTop = itemTop - dropdownHeight + itemHeight;
|
|
471
|
-
} else if (itemTop < scrollTop) {
|
|
472
|
-
dropdown.scrollTop = itemTop;
|
|
473
|
-
}
|
|
474
|
-
}, []);
|
|
475
|
-
|
|
476
|
-
const focusOptionByIndex = React.useCallback(
|
|
477
|
-
(index: number | undefined, scrollTo = true) => {
|
|
478
|
-
if (index === undefined || index < 0 || index > (options.length ?? 0) - 1) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const option = options[index];
|
|
483
|
-
|
|
484
|
-
if (option?.disabled) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if (scrollTo) {
|
|
489
|
-
scrollToElement(index);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
setFocusedOptionIndex(index);
|
|
493
|
-
},
|
|
494
|
-
[options, scrollToElement],
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
const isValidIndex = React.useCallback(
|
|
498
|
-
(index: number) => {
|
|
499
|
-
return index >= 0 && index < (options.length ?? 0);
|
|
500
|
-
},
|
|
501
|
-
[options.length],
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
useIsomorphicLayoutEffect(() => {
|
|
505
|
-
if (!opened) {
|
|
506
|
-
scrollPerformedRef.current = false;
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (scrollPerformedRef.current) {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const isIndexValid = selectedOptionIndex !== undefined && isValidIndex(selectedOptionIndex);
|
|
515
|
-
|
|
516
|
-
if (scrollBoxRef.current && isIndexValid) {
|
|
517
|
-
scrollPerformedRef.current = true;
|
|
518
|
-
scrollToElement(selectedOptionIndex, true);
|
|
519
|
-
}
|
|
520
|
-
}, [opened, selectedOptionIndex, scrollToElement, isValidIndex]);
|
|
521
|
-
|
|
522
|
-
const [keyboardInput, setKeyboardInput] = React.useState('');
|
|
523
|
-
const resetKeyboardInput = React.useCallback(() => {
|
|
524
|
-
setKeyboardInput('');
|
|
525
|
-
}, []);
|
|
526
|
-
|
|
527
|
-
const resetFocusedOption = React.useCallback(() => {
|
|
528
|
-
setFocusedOptionIndex(-1);
|
|
529
|
-
}, []);
|
|
530
|
-
|
|
531
|
-
const onKeyboardInput = React.useCallback(
|
|
532
|
-
(key: string) => {
|
|
533
|
-
if (!opened) {
|
|
534
|
-
setOpened(true);
|
|
535
|
-
}
|
|
536
|
-
resetFocusedOption();
|
|
537
|
-
const fullInput = keyboardInput + key;
|
|
538
|
-
|
|
539
|
-
setKeyboardInput(fullInput);
|
|
540
|
-
},
|
|
541
|
-
[keyboardInput, opened, resetFocusedOption],
|
|
542
|
-
);
|
|
543
|
-
|
|
544
|
-
const close = React.useCallback(() => {
|
|
545
|
-
resetKeyboardInput();
|
|
546
|
-
|
|
547
|
-
setInputValue('');
|
|
548
|
-
setOpened(false);
|
|
549
|
-
resetFocusedOption();
|
|
550
|
-
onClose?.();
|
|
551
|
-
}, [onClose, resetKeyboardInput, resetFocusedOption]);
|
|
552
|
-
|
|
553
410
|
const selectOption = React.useCallback(
|
|
554
|
-
(
|
|
555
|
-
|
|
556
|
-
setNativeSelectValue(item?.value ?? NOT_SELECTED.NATIVE);
|
|
411
|
+
(value: Exclude<SelectValue, null>) => {
|
|
412
|
+
setNativeSelectValue(value ?? NOT_SELECTED.NATIVE);
|
|
557
413
|
close();
|
|
558
414
|
|
|
559
415
|
const shouldTriggerOnChangeWhenControlledAndInnerValueIsOutOfSync =
|
|
560
|
-
isControlledOutside &&
|
|
561
|
-
props.value !== nativeSelectValue &&
|
|
562
|
-
nativeSelectValue === item?.value;
|
|
416
|
+
isControlledOutside && propsValue !== nativeSelectValue && nativeSelectValue === value;
|
|
563
417
|
|
|
564
418
|
if (shouldTriggerOnChangeWhenControlledAndInnerValueIsOutOfSync) {
|
|
565
419
|
const event = new Event('change', { bubbles: true });
|
|
566
420
|
selectElRef.current?.dispatchEvent(event);
|
|
567
421
|
}
|
|
568
422
|
},
|
|
569
|
-
[
|
|
570
|
-
close,
|
|
571
|
-
options,
|
|
572
|
-
selectElRef,
|
|
573
|
-
isControlledOutside,
|
|
574
|
-
props.value,
|
|
575
|
-
nativeSelectValue,
|
|
576
|
-
setNativeSelectValue,
|
|
577
|
-
],
|
|
423
|
+
[close, setNativeSelectValue, isControlledOutside, propsValue, nativeSelectValue, selectElRef],
|
|
578
424
|
);
|
|
579
425
|
|
|
580
426
|
const selectFocused = React.useCallback(() => {
|
|
581
|
-
if (
|
|
427
|
+
if (focusedOptionValue === null) {
|
|
582
428
|
return;
|
|
583
429
|
}
|
|
584
430
|
|
|
585
|
-
selectOption(
|
|
586
|
-
}, [
|
|
587
|
-
|
|
588
|
-
const open = React.useCallback(() => {
|
|
589
|
-
setOpened(true);
|
|
590
|
-
setFocusedOptionIndex(selectedOptionIndex);
|
|
431
|
+
selectOption(focusedOptionValue);
|
|
432
|
+
}, [focusedOptionValue, selectOption]);
|
|
591
433
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
434
|
+
const onInputKeyDown = useInputKeyboardController({
|
|
435
|
+
opened,
|
|
436
|
+
open,
|
|
437
|
+
close,
|
|
438
|
+
resetFocusedOption,
|
|
439
|
+
selectFocused,
|
|
440
|
+
focusOption,
|
|
441
|
+
scrollBoxRef,
|
|
442
|
+
onInputKeyDown: onInputKeyDownProp,
|
|
443
|
+
});
|
|
596
444
|
|
|
597
445
|
const onBlur = React.useCallback(() => {
|
|
598
446
|
close();
|
|
@@ -605,174 +453,19 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
605
453
|
selectElRef.current?.dispatchEvent(event);
|
|
606
454
|
}, [selectElRef]);
|
|
607
455
|
|
|
608
|
-
const onClick = React.useCallback(() => {
|
|
609
|
-
if (opened) {
|
|
610
|
-
close();
|
|
611
|
-
} else {
|
|
612
|
-
open();
|
|
613
|
-
}
|
|
614
|
-
}, [close, open, opened]);
|
|
615
|
-
|
|
616
|
-
const handleKeyUp = React.useMemo(() => debounce(resetKeyboardInput, 1000), [resetKeyboardInput]);
|
|
617
|
-
|
|
618
|
-
const focusOption = React.useCallback(
|
|
619
|
-
(type: 'next' | 'prev') => {
|
|
620
|
-
let index = focusedOptionIndex;
|
|
621
|
-
|
|
622
|
-
if (type === 'next') {
|
|
623
|
-
const nextIndex = findIndexAfter(options, index);
|
|
624
|
-
index = nextIndex === -1 ? findIndexAfter(options) : nextIndex; // Следующий за index или первый валидный до index
|
|
625
|
-
} else if (type === 'prev') {
|
|
626
|
-
const beforeIndex = findIndexBefore(options, index);
|
|
627
|
-
index = beforeIndex === -1 ? findIndexBefore(options) : beforeIndex; // Предшествующий index или последний валидный после index
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
focusOptionByIndex(index);
|
|
631
|
-
},
|
|
632
|
-
[focusOptionByIndex, focusedOptionIndex, options],
|
|
633
|
-
);
|
|
634
|
-
|
|
635
|
-
const onNativeSelectChange: React.ChangeEventHandler<HTMLSelectElement> = (e) => {
|
|
636
|
-
// для ситуаций, когда в опциях value это string а value/defaultValue это number
|
|
637
|
-
// и наоборот, приводим значение nativeSelectValue из стейта к строке.
|
|
638
|
-
// ведь nativeSelect всегда возвращает string в onChange, а пользователь
|
|
639
|
-
// может использовать number для опций
|
|
640
|
-
//
|
|
641
|
-
// native select всегда возвращает string в качестве value в onChange
|
|
642
|
-
// Когда селект контролируемый, то пользователь, в onChange может сохранить в свой стейт строку (например '3'), хотя
|
|
643
|
-
// в качестве value опции может использовать число (3),
|
|
644
|
-
// тогда строчное значение value ('3') из стейта пользователя
|
|
645
|
-
// будет передано в CustomSelect, и после синхронизации nativeSelectValue (3) и props.value ('3') и после клика на уже выбранную опцию (3),
|
|
646
|
-
// когда nativeSelectValue обновится на значение опции (число 3),
|
|
647
|
-
// сравнение nativeSelectValue (3) и prevNativeSelectValue ('3') может не сработать лишь из-за того, что они в разных типах.
|
|
648
|
-
const convertedNativeSelectValue =
|
|
649
|
-
typeof nativeSelectValue === 'number' &&
|
|
650
|
-
(typeof props.value === 'string' || typeof prevNativeSelectValue === 'string')
|
|
651
|
-
? String(nativeSelectValue)
|
|
652
|
-
: nativeSelectValue;
|
|
653
|
-
|
|
654
|
-
const isCalledWithSameControlledOptionValue =
|
|
655
|
-
isControlledOutside &&
|
|
656
|
-
props.value === remapFromNativeValueToSelectValue(convertedNativeSelectValue);
|
|
657
|
-
|
|
658
|
-
const isNativeValueChanged =
|
|
659
|
-
convertedNativeSelectValue !== prevNativeSelectValue && prevNativeSelectValue !== undefined;
|
|
660
|
-
|
|
661
|
-
const isTriggeredByClearButton = allowClearButton && nativeSelectValue === NOT_SELECTED.NATIVE;
|
|
662
|
-
|
|
663
|
-
const shouldCallOnChange =
|
|
664
|
-
!isCalledWithSameControlledOptionValue && (isNativeValueChanged || isTriggeredByClearButton);
|
|
665
|
-
|
|
666
|
-
if (!shouldCallOnChange) {
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
const remappedNativeValue = remapFromNativeValueToSelectValue(e.currentTarget.value);
|
|
671
|
-
|
|
672
|
-
if (e.target.value === NOT_SELECTED.NATIVE) {
|
|
673
|
-
e.target.value = '';
|
|
674
|
-
}
|
|
675
|
-
if (e.currentTarget.value === NOT_SELECTED.NATIVE) {
|
|
676
|
-
e.currentTarget.value = '';
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
onChange?.(e, remappedNativeValue);
|
|
680
|
-
};
|
|
681
|
-
|
|
682
|
-
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = React.useCallback(
|
|
683
|
-
(e) => {
|
|
684
|
-
onInputChangeProp && onInputChangeProp(e);
|
|
685
|
-
setInputValue(e.target.value);
|
|
686
|
-
},
|
|
687
|
-
[onInputChangeProp],
|
|
688
|
-
);
|
|
689
|
-
|
|
690
|
-
const areOptionsShown = React.useCallback(() => {
|
|
691
|
-
return scrollBoxRef.current !== null;
|
|
692
|
-
}, []);
|
|
693
|
-
|
|
694
|
-
const handleKeyDownSelect = React.useCallback(
|
|
695
|
-
(event: React.KeyboardEvent) => {
|
|
696
|
-
if (event.key.length === 1 && event.key !== ' ') {
|
|
697
|
-
onKeyboardInput(event.key);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
['ArrowUp', 'ArrowDown', 'Escape', 'Enter'].includes(event.key) &&
|
|
702
|
-
areOptionsShown() &&
|
|
703
|
-
event.preventDefault();
|
|
704
|
-
|
|
705
|
-
switch (event.key) {
|
|
706
|
-
case 'ArrowUp':
|
|
707
|
-
if (opened) {
|
|
708
|
-
areOptionsShown() && focusOption('prev');
|
|
709
|
-
} else {
|
|
710
|
-
open();
|
|
711
|
-
}
|
|
712
|
-
break;
|
|
713
|
-
case 'ArrowDown':
|
|
714
|
-
if (opened) {
|
|
715
|
-
areOptionsShown() && focusOption('next');
|
|
716
|
-
} else {
|
|
717
|
-
open();
|
|
718
|
-
}
|
|
719
|
-
break;
|
|
720
|
-
case 'Escape':
|
|
721
|
-
close();
|
|
722
|
-
break;
|
|
723
|
-
case 'Backspace':
|
|
724
|
-
case 'Delete': {
|
|
725
|
-
if (!opened) {
|
|
726
|
-
setOpened(true);
|
|
727
|
-
}
|
|
728
|
-
resetFocusedOption();
|
|
729
|
-
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
case 'Enter':
|
|
733
|
-
case 'Spacebar':
|
|
734
|
-
case ' ':
|
|
735
|
-
if (opened) {
|
|
736
|
-
areOptionsShown() && selectFocused();
|
|
737
|
-
} else {
|
|
738
|
-
open();
|
|
739
|
-
}
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
},
|
|
743
|
-
[
|
|
744
|
-
areOptionsShown,
|
|
745
|
-
close,
|
|
746
|
-
focusOption,
|
|
747
|
-
onKeyboardInput,
|
|
748
|
-
open,
|
|
749
|
-
opened,
|
|
750
|
-
selectFocused,
|
|
751
|
-
resetFocusedOption,
|
|
752
|
-
],
|
|
753
|
-
);
|
|
754
|
-
|
|
755
|
-
const handleInputKeydown = React.useCallback(
|
|
756
|
-
(event: React.KeyboardEvent) => {
|
|
757
|
-
onInputKeyDown?.(event, opened);
|
|
758
|
-
},
|
|
759
|
-
[opened, onInputKeyDown],
|
|
760
|
-
);
|
|
761
|
-
const _onInputKeyDown = callMultiple(handleKeyDownSelect, handleInputKeydown);
|
|
762
|
-
|
|
763
456
|
const handleOptionClick = React.useCallback(
|
|
764
457
|
(e: React.MouseEvent<HTMLElement>) => {
|
|
765
458
|
const index = Array.prototype.indexOf.call(
|
|
766
459
|
e.currentTarget.parentNode?.children,
|
|
767
460
|
e.currentTarget,
|
|
768
461
|
);
|
|
769
|
-
const option =
|
|
462
|
+
const option = filteredOptions[index];
|
|
770
463
|
|
|
771
464
|
if (option && !option.disabled) {
|
|
772
|
-
selectOption(
|
|
465
|
+
selectOption(option.value);
|
|
773
466
|
}
|
|
774
467
|
},
|
|
775
|
-
[
|
|
468
|
+
[filteredOptions, selectOption],
|
|
776
469
|
);
|
|
777
470
|
|
|
778
471
|
const lastMousePositionRef = React.useRef<MousePosition>({ x: 0, y: 0 });
|
|
@@ -788,8 +481,8 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
788
481
|
const popupAriaId = React.useId();
|
|
789
482
|
const renderOption = React.useCallback(
|
|
790
483
|
(option: OptionInterfaceT, index: number) => {
|
|
791
|
-
const hovered =
|
|
792
|
-
const selected =
|
|
484
|
+
const hovered = option.value === focusedOptionValue;
|
|
485
|
+
const selected = option.value === selectedOptionValue;
|
|
793
486
|
|
|
794
487
|
return (
|
|
795
488
|
<React.Fragment key={`${typeof option.value}-${option.value}`}>
|
|
@@ -800,7 +493,7 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
800
493
|
selected,
|
|
801
494
|
disabled: option.disabled,
|
|
802
495
|
onClick: handleOptionClick,
|
|
803
|
-
onMouseDown:
|
|
496
|
+
onMouseDown: preventDefault,
|
|
804
497
|
// Используем `onMouseMove` вместо `onMouseEnter/onMouseOver`.
|
|
805
498
|
// Потому что если при навигации с клавиатуры курсор наведён на
|
|
806
499
|
// список, то при первом автоматическом скролле списка вызывается событие MouseOver/MouseEnter
|
|
@@ -816,19 +509,19 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
816
509
|
);
|
|
817
510
|
},
|
|
818
511
|
[
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
focusOptionOnMouseMove,
|
|
512
|
+
focusedOptionValue,
|
|
513
|
+
selectedOptionValue,
|
|
822
514
|
renderOptionProp,
|
|
823
|
-
|
|
515
|
+
handleOptionClick,
|
|
824
516
|
popupAriaId,
|
|
517
|
+
focusOptionOnMouseMove,
|
|
825
518
|
],
|
|
826
519
|
);
|
|
827
520
|
|
|
828
521
|
const resolvedContent = React.useMemo(() => {
|
|
829
522
|
const defaultDropdownContent =
|
|
830
|
-
|
|
831
|
-
<div ref={optionsWrapperRef}>{
|
|
523
|
+
filteredOptions.length > 0 ? (
|
|
524
|
+
<div ref={optionsWrapperRef}>{filteredOptions.map(renderOption)}</div>
|
|
832
525
|
) : (
|
|
833
526
|
<Footnote className={styles.empty}>{emptyText}</Footnote>
|
|
834
527
|
);
|
|
@@ -838,61 +531,25 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
838
531
|
} else {
|
|
839
532
|
return defaultDropdownContent;
|
|
840
533
|
}
|
|
841
|
-
}, [emptyText,
|
|
842
|
-
|
|
843
|
-
const
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
allowClearButton
|
|
849
|
-
|
|
850
|
-
const clearButton = React.useMemo(() => {
|
|
851
|
-
if (!clearButtonShown) {
|
|
852
|
-
return null;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
return (
|
|
856
|
-
<ClearButton
|
|
857
|
-
className={iconProp === undefined ? styles.clearIcon : undefined}
|
|
858
|
-
onClick={function clearSelectState() {
|
|
859
|
-
setNativeSelectValue(NOT_SELECTED.NATIVE);
|
|
860
|
-
setInputValue('');
|
|
861
|
-
selectInputRef.current && selectInputRef.current.focus();
|
|
862
|
-
}}
|
|
863
|
-
disabled={restProps.disabled}
|
|
864
|
-
data-testid={clearButtonTestId}
|
|
865
|
-
/>
|
|
866
|
-
);
|
|
867
|
-
}, [
|
|
868
|
-
clearButtonShown,
|
|
534
|
+
}, [emptyText, filteredOptions, optionsWrapperRef, renderDropdown, renderOption]);
|
|
535
|
+
|
|
536
|
+
const afterItems = useAfterItems({
|
|
537
|
+
value: propsValue,
|
|
538
|
+
nativeSelectValue,
|
|
539
|
+
isControlledOutside,
|
|
540
|
+
opened,
|
|
541
|
+
allowClearButton,
|
|
869
542
|
ClearButton,
|
|
870
|
-
|
|
871
|
-
|
|
543
|
+
onClearButtonClick: () => {
|
|
544
|
+
setNativeSelectValue(NOT_SELECTED.NATIVE);
|
|
545
|
+
resetInputValue();
|
|
546
|
+
selectInputRef.current && selectInputRef.current.focus();
|
|
547
|
+
},
|
|
872
548
|
clearButtonTestId,
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const icon = React.useMemo(() => {
|
|
878
|
-
if (iconProp !== undefined) {
|
|
879
|
-
return iconProp;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
return (
|
|
883
|
-
<DropdownIcon
|
|
884
|
-
className={clearButtonShown ? styles.dropdownIcon : undefined}
|
|
885
|
-
opened={opened}
|
|
886
|
-
/>
|
|
887
|
-
);
|
|
888
|
-
}, [clearButtonShown, iconProp, opened]);
|
|
889
|
-
|
|
890
|
-
const afterIcons = !readOnly && (icon || clearButtonShown) && (
|
|
891
|
-
<React.Fragment>
|
|
892
|
-
{clearButton}
|
|
893
|
-
{icon}
|
|
894
|
-
</React.Fragment>
|
|
895
|
-
);
|
|
549
|
+
disabled: restProps.disabled,
|
|
550
|
+
readOnly,
|
|
551
|
+
icon: iconProp,
|
|
552
|
+
});
|
|
896
553
|
|
|
897
554
|
const { document } = useDOM();
|
|
898
555
|
const passClickAndFocusToInputOnClick = React.useCallback(
|
|
@@ -935,17 +592,11 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
935
592
|
}
|
|
936
593
|
};
|
|
937
594
|
|
|
938
|
-
const
|
|
939
|
-
focusedOptionIndex !== -1 ? focusedOptionIndex : undefined;
|
|
940
|
-
const ariaActiveDescendantId =
|
|
941
|
-
ariaActiveDescendantOptionIndex !== undefined
|
|
942
|
-
? options[ariaActiveDescendantOptionIndex] && options[ariaActiveDescendantOptionIndex].value
|
|
943
|
-
: null;
|
|
595
|
+
const ariaActiveDescendantId = focusedOptionValue !== null ? focusedOptionValue : undefined;
|
|
944
596
|
|
|
945
597
|
const selectInputAriaProps: React.HTMLAttributes<HTMLElement> = {
|
|
946
598
|
'role': 'combobox',
|
|
947
599
|
'aria-controls': popupAriaId,
|
|
948
|
-
'aria-owns': popupAriaId,
|
|
949
600
|
'aria-expanded': opened,
|
|
950
601
|
'aria-activedescendant':
|
|
951
602
|
ariaActiveDescendantId && opened ? `${popupAriaId}-${ariaActiveDescendantId}` : undefined,
|
|
@@ -954,8 +605,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
954
605
|
'aria-autocomplete': 'none',
|
|
955
606
|
};
|
|
956
607
|
|
|
957
|
-
const focusWithin = useFocusWithin(handleRootRef);
|
|
958
|
-
|
|
959
608
|
const resetOptionFocusOnMouseLeave = React.useCallback(
|
|
960
609
|
(event: React.MouseEvent) => {
|
|
961
610
|
// В Хроме eсли мышка пользователя находится над инпутом селекта,
|
|
@@ -983,9 +632,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
983
632
|
lastMousePositionRef.current = { x: e.clientX, y: e.clientY };
|
|
984
633
|
}}
|
|
985
634
|
>
|
|
986
|
-
{focusWithin && selected && !opened && (
|
|
987
|
-
<VisuallyHidden aria-live="polite">{selected.label}</VisuallyHidden>
|
|
988
|
-
)}
|
|
989
635
|
<CustomSelectInput
|
|
990
636
|
autoComplete="off"
|
|
991
637
|
autoCapitalize="none"
|
|
@@ -999,17 +645,25 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
999
645
|
className={openedClassNames}
|
|
1000
646
|
readOnly={readOnly || !searchable}
|
|
1001
647
|
fetching={fetching}
|
|
648
|
+
searchable={searchable}
|
|
649
|
+
accessible={accessible}
|
|
1002
650
|
value={inputValue}
|
|
1003
|
-
|
|
1004
|
-
onKeyDown={!readOnly ? _onInputKeyDown : undefined}
|
|
651
|
+
onKeyDown={!readOnly ? onInputKeyDown : undefined}
|
|
1005
652
|
onChange={onInputChange}
|
|
1006
|
-
onClick={!readOnly ?
|
|
653
|
+
onClick={!readOnly ? toggleOpened : undefined}
|
|
1007
654
|
before={before}
|
|
1008
|
-
after={
|
|
655
|
+
after={afterItems}
|
|
1009
656
|
selectType={selectType}
|
|
1010
657
|
>
|
|
1011
658
|
{selected?.label}
|
|
1012
659
|
</CustomSelectInput>
|
|
660
|
+
|
|
661
|
+
<FetchingStatus
|
|
662
|
+
fetching={fetching}
|
|
663
|
+
options={filteredOptions}
|
|
664
|
+
fetchingInProgressLabel={fetchingInProgressLabel}
|
|
665
|
+
fetchingCompletedLabel={fetchingCompletedLabel}
|
|
666
|
+
/>
|
|
1013
667
|
<select
|
|
1014
668
|
tabIndex={-1}
|
|
1015
669
|
ref={selectElRef}
|
|
@@ -1027,7 +681,7 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
|
|
|
1027
681
|
{(allowClearButton || nativeSelectValue === NOT_SELECTED.NATIVE) && (
|
|
1028
682
|
<option key={NOT_SELECTED.NATIVE} value={NOT_SELECTED.NATIVE} />
|
|
1029
683
|
)}
|
|
1030
|
-
{
|
|
684
|
+
{options.map((item) => (
|
|
1031
685
|
<option key={`${item.value}`} value={item.value} />
|
|
1032
686
|
))}
|
|
1033
687
|
</select>
|