@workday/canvas-kit-react 16.2.0-0622-next.0 → 16.2.0-0634-next.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/collection/lib/useOverflowListModel.tsx +9 -0
- package/dist/commonjs/action-bar/lib/ActionBarList.js +1 -1
- package/dist/commonjs/action-bar/lib/ActionBarOverflowButton.js +1 -1
- package/dist/commonjs/avatar/lib/Avatar.js +13 -13
- package/dist/commonjs/avatar/lib/AvatarImage.js +1 -1
- package/dist/commonjs/avatar/lib/AvatarName.js +1 -1
- package/dist/commonjs/avatar/lib/BaseAvatar.js +14 -14
- package/dist/commonjs/badge/lib/CountBadge.js +6 -6
- package/dist/commonjs/banner/lib/Banner.js +5 -5
- package/dist/commonjs/banner/lib/BannerActionText.js +2 -2
- package/dist/commonjs/banner/lib/BannerIcon.js +1 -1
- package/dist/commonjs/banner/lib/BannerLabel.js +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsCurrentItem.js +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsItem.js +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsLink.js +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsList.js +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsMenu.js +2 -2
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsOverflowButton.js +1 -1
- package/dist/commonjs/button/lib/BaseButton.js +21 -21
- package/dist/commonjs/button/lib/DeleteButton.js +2 -2
- package/dist/commonjs/button/lib/ExternalHyperlink.js +1 -1
- package/dist/commonjs/button/lib/Hyperlink.js +5 -5
- package/dist/commonjs/button/lib/PrimaryButton.js +2 -2
- package/dist/commonjs/button/lib/SecondaryButton.js +2 -2
- package/dist/commonjs/button/lib/TertiaryButton.js +14 -14
- package/dist/commonjs/button/lib/ToolbarDropdownButton.js +3 -3
- package/dist/commonjs/button/lib/ToolbarIconButton.js +1 -1
- package/dist/commonjs/button/lib/parts/ButtonLabel.js +1 -1
- package/dist/commonjs/button/lib/parts/ButtonLabelIcon.js +5 -5
- package/dist/commonjs/card/lib/Card.js +3 -3
- package/dist/commonjs/card/lib/CardBody.js +1 -1
- package/dist/commonjs/card/lib/CardHeading.js +1 -1
- package/dist/commonjs/checkbox/lib/CheckBackground.js +6 -6
- package/dist/commonjs/checkbox/lib/CheckboxCheck.js +6 -6
- package/dist/commonjs/checkbox/lib/CheckboxContainer.js +2 -2
- package/dist/commonjs/checkbox/lib/CheckboxInput.js +5 -5
- package/dist/commonjs/checkbox/lib/CheckboxRipple.js +1 -1
- package/dist/commonjs/collection/lib/ListBox.js +3 -3
- package/dist/commonjs/collection/lib/useOverflowListModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useOverflowListModel.js +2 -0
- package/dist/commonjs/color-picker/lib/ColorInput.js +3 -3
- package/dist/commonjs/color-picker/lib/ColorPreview.js +1 -1
- package/dist/commonjs/color-picker/lib/parts/ColorSwatch.js +2 -2
- package/dist/commonjs/combobox/lib/ComboboxMenuList.js +1 -1
- package/dist/commonjs/common/lib/AccessibleHide.js +1 -1
- package/dist/commonjs/common/lib/CanvasProvider.js +1 -1
- package/dist/commonjs/common/lib/EllipsisText.js +1 -1
- package/dist/commonjs/common/lib/styles/cornerShape.js +1 -1
- package/dist/commonjs/expandable/lib/Expandable.js +1 -1
- package/dist/commonjs/expandable/lib/ExpandableAvatar.js +1 -1
- package/dist/commonjs/expandable/lib/ExpandableContent.js +1 -1
- package/dist/commonjs/expandable/lib/ExpandableIcon.js +10 -10
- package/dist/commonjs/expandable/lib/ExpandableTarget.js +1 -1
- package/dist/commonjs/expandable/lib/ExpandableTitle.js +1 -1
- package/dist/commonjs/form-field/lib/FormFieldField.js +1 -1
- package/dist/commonjs/form-field/lib/FormFieldGroupLabel.js +5 -5
- package/dist/commonjs/form-field/lib/FormFieldGroupList.js +3 -3
- package/dist/commonjs/form-field/lib/FormFieldHint.js +3 -3
- package/dist/commonjs/form-field/lib/FormFieldLabel.js +6 -6
- package/dist/commonjs/form-field/lib/formFieldStencil.js +8 -8
- package/dist/commonjs/icon/lib/AccentIcon.js +2 -2
- package/dist/commonjs/icon/lib/AppletIcon.js +1 -1
- package/dist/commonjs/icon/lib/ExpressiveIcon.js +1 -1
- package/dist/commonjs/icon/lib/Graphic.js +4 -4
- package/dist/commonjs/icon/lib/Svg.js +3 -3
- package/dist/commonjs/icon/lib/SystemIcon.js +1 -1
- package/dist/commonjs/icon/lib/SystemIconCircle.js +2 -2
- package/dist/commonjs/information-highlight/lib/InformationHighlight.js +9 -9
- package/dist/commonjs/information-highlight/lib/parts/Body.js +3 -3
- package/dist/commonjs/information-highlight/lib/parts/Heading.js +3 -3
- package/dist/commonjs/information-highlight/lib/parts/Link.js +3 -3
- package/dist/commonjs/loading-dots/lib/LoadingDots.js +3 -3
- package/dist/commonjs/menu/lib/MenuCard.js +1 -1
- package/dist/commonjs/menu/lib/MenuDivider.js +1 -1
- package/dist/commonjs/menu/lib/MenuGroup.js +1 -1
- package/dist/commonjs/menu/lib/MenuItem.js +1 -1
- package/dist/commonjs/menu/lib/MenuList.js +3 -3
- package/dist/commonjs/modal/lib/ModalBody.js +1 -1
- package/dist/commonjs/modal/lib/ModalCard.js +1 -1
- package/dist/commonjs/modal/lib/ModalHeading.js +1 -1
- package/dist/commonjs/modal/lib/ModalOverflowOverlay.js +1 -1
- package/dist/commonjs/modal/lib/ModalOverlay.js +2 -2
- package/dist/commonjs/pagination/lib/Pagination/AdditionalDetails.js +2 -2
- package/dist/commonjs/pagination/lib/Pagination/Controls.js +2 -2
- package/dist/commonjs/pagination/lib/Pagination/GoTo/Form.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/GoTo/Label.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/GoTo/TextInput.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/Nav.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/PageButton.js +2 -2
- package/dist/commonjs/pagination/lib/Pagination/PageList.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/Pagination.js +1 -1
- package/dist/commonjs/pagination/lib/Pagination/common/List.js +2 -2
- package/dist/commonjs/pill/lib/Pill.js +3 -3
- package/dist/commonjs/pill/lib/PillAvatar.js +1 -1
- package/dist/commonjs/pill/lib/PillCount.js +1 -1
- package/dist/commonjs/pill/lib/PillIcon.js +1 -1
- package/dist/commonjs/pill/lib/PillIconButton.js +1 -1
- package/dist/commonjs/pill/lib/PillLabel.js +1 -1
- package/dist/commonjs/popup/lib/PopupBody.js +1 -1
- package/dist/commonjs/popup/lib/PopupButtonGroup.js +5 -5
- package/dist/commonjs/popup/lib/PopupCard.js +2 -2
- package/dist/commonjs/popup/lib/PopupCloseIcon.js +1 -1
- package/dist/commonjs/popup/lib/PopupHeading.js +1 -1
- package/dist/commonjs/popup/lib/hooks/useDisableBodyScroll.js +1 -1
- package/dist/commonjs/segmented-control/lib/SegmentedControlItem.js +16 -16
- package/dist/commonjs/segmented-control/lib/SegmentedControlList.js +6 -6
- package/dist/commonjs/select/lib/SelectCard.js +1 -1
- package/dist/commonjs/select/lib/SelectInput.js +3 -3
- package/dist/commonjs/side-panel/lib/SidePanel.js +8 -8
- package/dist/commonjs/side-panel/lib/SidePanelHeading.js +3 -3
- package/dist/commonjs/side-panel/lib/SidePanelToggleButton.js +7 -7
- package/dist/commonjs/skeleton/lib/Skeleton.js +2 -2
- package/dist/commonjs/skeleton/lib/parts/SkeletonHeader.js +1 -1
- package/dist/commonjs/skeleton/lib/parts/SkeletonShape.js +2 -2
- package/dist/commonjs/skeleton/lib/parts/SkeletonText.js +2 -2
- package/dist/commonjs/switch/lib/Switch.js +7 -7
- package/dist/commonjs/table/lib/BaseTable.js +1 -1
- package/dist/commonjs/table/lib/Table.js +7 -7
- package/dist/commonjs/table/lib/parts/BaseTableBody.js +1 -1
- package/dist/commonjs/table/lib/parts/BaseTableCaption.js +1 -1
- package/dist/commonjs/table/lib/parts/BaseTableCell.js +1 -1
- package/dist/commonjs/table/lib/parts/BaseTableHead.js +1 -1
- package/dist/commonjs/table/lib/parts/BaseTableHeader.js +1 -1
- package/dist/commonjs/table/lib/parts/css-grid-table/TableRow.js +1 -1
- package/dist/commonjs/tabs/lib/TabsItem.d.ts +3 -1
- package/dist/commonjs/tabs/lib/TabsItem.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsItem.js +58 -3
- package/dist/commonjs/tabs/lib/TabsList.d.ts +329 -2
- package/dist/commonjs/tabs/lib/TabsList.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsList.js +67 -12
- package/dist/commonjs/tabs/lib/TabsOverflowButton.d.ts +24 -214
- package/dist/commonjs/tabs/lib/TabsOverflowButton.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsOverflowButton.js +72 -7
- package/dist/commonjs/tabs/lib/TabsPanels.d.ts +14 -14
- package/dist/commonjs/tabs/lib/TabsPanels.js +2 -2
- package/dist/commonjs/tabs/lib/useTabsModel.d.ts +5 -0
- package/dist/commonjs/tabs/lib/useTabsModel.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/useTabsModel.js +146 -7
- package/dist/commonjs/testing/lib/ComponentStatesTable.js +1 -1
- package/dist/commonjs/text/lib/LabelText.js +6 -6
- package/dist/commonjs/text/lib/Text.js +16 -16
- package/dist/commonjs/text/lib/TypeLevelComponents.js +4 -4
- package/dist/commonjs/text-area/lib/TextArea.js +5 -5
- package/dist/commonjs/text-input/lib/InputGroup.js +7 -7
- package/dist/commonjs/text-input/lib/TextInput.js +5 -5
- package/dist/commonjs/toast/lib/Toast.js +1 -1
- package/dist/commonjs/toast/lib/ToastBody.js +1 -1
- package/dist/commonjs/toast/lib/ToastCloseIcon.js +1 -1
- package/dist/commonjs/toast/lib/ToastIcon.js +1 -1
- package/dist/commonjs/toast/lib/ToastMessage.js +1 -1
- package/dist/commonjs/tooltip/lib/TooltipContainer.js +4 -4
- package/dist/commonjs/version/lib/version.js +1 -1
- package/dist/es6/action-bar/lib/ActionBarList.js +1 -1
- package/dist/es6/action-bar/lib/ActionBarOverflowButton.js +1 -1
- package/dist/es6/avatar/lib/Avatar.js +13 -13
- package/dist/es6/avatar/lib/AvatarImage.js +1 -1
- package/dist/es6/avatar/lib/AvatarName.js +1 -1
- package/dist/es6/avatar/lib/BaseAvatar.js +14 -14
- package/dist/es6/badge/lib/CountBadge.js +6 -6
- package/dist/es6/banner/lib/Banner.js +5 -5
- package/dist/es6/banner/lib/BannerActionText.js +2 -2
- package/dist/es6/banner/lib/BannerIcon.js +1 -1
- package/dist/es6/banner/lib/BannerLabel.js +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsCurrentItem.js +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsItem.js +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsLink.js +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsList.js +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsMenu.js +2 -2
- package/dist/es6/breadcrumbs/lib/BreadcrumbsOverflowButton.js +1 -1
- package/dist/es6/button/lib/BaseButton.js +21 -21
- package/dist/es6/button/lib/DeleteButton.js +2 -2
- package/dist/es6/button/lib/ExternalHyperlink.js +1 -1
- package/dist/es6/button/lib/Hyperlink.js +5 -5
- package/dist/es6/button/lib/PrimaryButton.js +2 -2
- package/dist/es6/button/lib/SecondaryButton.js +2 -2
- package/dist/es6/button/lib/TertiaryButton.js +14 -14
- package/dist/es6/button/lib/ToolbarDropdownButton.js +3 -3
- package/dist/es6/button/lib/ToolbarIconButton.js +1 -1
- package/dist/es6/button/lib/parts/ButtonLabel.js +1 -1
- package/dist/es6/button/lib/parts/ButtonLabelIcon.js +5 -5
- package/dist/es6/card/lib/Card.js +3 -3
- package/dist/es6/card/lib/CardBody.js +1 -1
- package/dist/es6/card/lib/CardHeading.js +1 -1
- package/dist/es6/checkbox/lib/CheckBackground.js +6 -6
- package/dist/es6/checkbox/lib/CheckboxCheck.js +6 -6
- package/dist/es6/checkbox/lib/CheckboxContainer.js +2 -2
- package/dist/es6/checkbox/lib/CheckboxInput.js +5 -5
- package/dist/es6/checkbox/lib/CheckboxRipple.js +1 -1
- package/dist/es6/collection/lib/ListBox.js +3 -3
- package/dist/es6/collection/lib/useOverflowListModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useOverflowListModel.js +2 -0
- package/dist/es6/color-picker/lib/ColorInput.js +3 -3
- package/dist/es6/color-picker/lib/ColorPreview.js +1 -1
- package/dist/es6/color-picker/lib/parts/ColorSwatch.js +2 -2
- package/dist/es6/combobox/lib/ComboboxMenuList.js +1 -1
- package/dist/es6/common/lib/AccessibleHide.js +1 -1
- package/dist/es6/common/lib/CanvasProvider.js +1 -1
- package/dist/es6/common/lib/EllipsisText.js +1 -1
- package/dist/es6/common/lib/styles/cornerShape.js +1 -1
- package/dist/es6/expandable/lib/Expandable.js +1 -1
- package/dist/es6/expandable/lib/ExpandableAvatar.js +1 -1
- package/dist/es6/expandable/lib/ExpandableContent.js +1 -1
- package/dist/es6/expandable/lib/ExpandableIcon.js +10 -10
- package/dist/es6/expandable/lib/ExpandableTarget.js +1 -1
- package/dist/es6/expandable/lib/ExpandableTitle.js +1 -1
- package/dist/es6/form-field/lib/FormFieldField.js +1 -1
- package/dist/es6/form-field/lib/FormFieldGroupLabel.js +5 -5
- package/dist/es6/form-field/lib/FormFieldGroupList.js +3 -3
- package/dist/es6/form-field/lib/FormFieldHint.js +3 -3
- package/dist/es6/form-field/lib/FormFieldLabel.js +6 -6
- package/dist/es6/form-field/lib/formFieldStencil.js +8 -8
- package/dist/es6/icon/lib/AccentIcon.js +2 -2
- package/dist/es6/icon/lib/AppletIcon.js +1 -1
- package/dist/es6/icon/lib/ExpressiveIcon.js +1 -1
- package/dist/es6/icon/lib/Graphic.js +4 -4
- package/dist/es6/icon/lib/Svg.js +3 -3
- package/dist/es6/icon/lib/SystemIcon.js +1 -1
- package/dist/es6/icon/lib/SystemIconCircle.js +2 -2
- package/dist/es6/information-highlight/lib/InformationHighlight.js +9 -9
- package/dist/es6/information-highlight/lib/parts/Body.js +3 -3
- package/dist/es6/information-highlight/lib/parts/Heading.js +3 -3
- package/dist/es6/information-highlight/lib/parts/Link.js +3 -3
- package/dist/es6/loading-dots/lib/LoadingDots.js +3 -3
- package/dist/es6/menu/lib/MenuCard.js +1 -1
- package/dist/es6/menu/lib/MenuDivider.js +1 -1
- package/dist/es6/menu/lib/MenuGroup.js +1 -1
- package/dist/es6/menu/lib/MenuItem.js +1 -1
- package/dist/es6/menu/lib/MenuList.js +3 -3
- package/dist/es6/modal/lib/ModalBody.js +1 -1
- package/dist/es6/modal/lib/ModalCard.js +1 -1
- package/dist/es6/modal/lib/ModalHeading.js +1 -1
- package/dist/es6/modal/lib/ModalOverflowOverlay.js +1 -1
- package/dist/es6/modal/lib/ModalOverlay.js +2 -2
- package/dist/es6/pagination/lib/Pagination/AdditionalDetails.js +2 -2
- package/dist/es6/pagination/lib/Pagination/Controls.js +2 -2
- package/dist/es6/pagination/lib/Pagination/GoTo/Form.js +1 -1
- package/dist/es6/pagination/lib/Pagination/GoTo/Label.js +1 -1
- package/dist/es6/pagination/lib/Pagination/GoTo/TextInput.js +1 -1
- package/dist/es6/pagination/lib/Pagination/Nav.js +1 -1
- package/dist/es6/pagination/lib/Pagination/PageButton.js +2 -2
- package/dist/es6/pagination/lib/Pagination/PageList.js +1 -1
- package/dist/es6/pagination/lib/Pagination/Pagination.js +1 -1
- package/dist/es6/pagination/lib/Pagination/common/List.js +2 -2
- package/dist/es6/pill/lib/Pill.js +3 -3
- package/dist/es6/pill/lib/PillAvatar.js +1 -1
- package/dist/es6/pill/lib/PillCount.js +1 -1
- package/dist/es6/pill/lib/PillIcon.js +1 -1
- package/dist/es6/pill/lib/PillIconButton.js +1 -1
- package/dist/es6/pill/lib/PillLabel.js +1 -1
- package/dist/es6/popup/lib/PopupBody.js +1 -1
- package/dist/es6/popup/lib/PopupButtonGroup.js +5 -5
- package/dist/es6/popup/lib/PopupCard.js +2 -2
- package/dist/es6/popup/lib/PopupCloseIcon.js +1 -1
- package/dist/es6/popup/lib/PopupHeading.js +1 -1
- package/dist/es6/popup/lib/hooks/useDisableBodyScroll.js +1 -1
- package/dist/es6/segmented-control/lib/SegmentedControlItem.js +16 -16
- package/dist/es6/segmented-control/lib/SegmentedControlList.js +6 -6
- package/dist/es6/select/lib/SelectCard.js +1 -1
- package/dist/es6/select/lib/SelectInput.js +3 -3
- package/dist/es6/side-panel/lib/SidePanel.js +8 -8
- package/dist/es6/side-panel/lib/SidePanelHeading.js +3 -3
- package/dist/es6/side-panel/lib/SidePanelToggleButton.js +7 -7
- package/dist/es6/skeleton/lib/Skeleton.js +2 -2
- package/dist/es6/skeleton/lib/parts/SkeletonHeader.js +1 -1
- package/dist/es6/skeleton/lib/parts/SkeletonShape.js +2 -2
- package/dist/es6/skeleton/lib/parts/SkeletonText.js +2 -2
- package/dist/es6/switch/lib/Switch.js +7 -7
- package/dist/es6/table/lib/BaseTable.js +1 -1
- package/dist/es6/table/lib/Table.js +7 -7
- package/dist/es6/table/lib/parts/BaseTableBody.js +1 -1
- package/dist/es6/table/lib/parts/BaseTableCaption.js +1 -1
- package/dist/es6/table/lib/parts/BaseTableCell.js +1 -1
- package/dist/es6/table/lib/parts/BaseTableHead.js +1 -1
- package/dist/es6/table/lib/parts/BaseTableHeader.js +1 -1
- package/dist/es6/table/lib/parts/css-grid-table/TableRow.js +1 -1
- package/dist/es6/tabs/lib/TabsItem.d.ts +3 -1
- package/dist/es6/tabs/lib/TabsItem.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsItem.js +36 -4
- package/dist/es6/tabs/lib/TabsList.d.ts +329 -2
- package/dist/es6/tabs/lib/TabsList.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsList.js +69 -15
- package/dist/es6/tabs/lib/TabsOverflowButton.d.ts +24 -214
- package/dist/es6/tabs/lib/TabsOverflowButton.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsOverflowButton.js +73 -9
- package/dist/es6/tabs/lib/TabsPanels.d.ts +14 -14
- package/dist/es6/tabs/lib/TabsPanels.js +2 -2
- package/dist/es6/tabs/lib/useTabsModel.d.ts +5 -0
- package/dist/es6/tabs/lib/useTabsModel.d.ts.map +1 -1
- package/dist/es6/tabs/lib/useTabsModel.js +146 -7
- package/dist/es6/testing/lib/ComponentStatesTable.js +1 -1
- package/dist/es6/text/lib/LabelText.js +6 -6
- package/dist/es6/text/lib/Text.js +16 -16
- package/dist/es6/text/lib/TypeLevelComponents.js +4 -4
- package/dist/es6/text-area/lib/TextArea.js +5 -5
- package/dist/es6/text-input/lib/InputGroup.js +7 -7
- package/dist/es6/text-input/lib/TextInput.js +5 -5
- package/dist/es6/toast/lib/Toast.js +1 -1
- package/dist/es6/toast/lib/ToastBody.js +1 -1
- package/dist/es6/toast/lib/ToastCloseIcon.js +1 -1
- package/dist/es6/toast/lib/ToastIcon.js +1 -1
- package/dist/es6/toast/lib/ToastMessage.js +1 -1
- package/dist/es6/tooltip/lib/TooltipContainer.js +4 -4
- package/dist/es6/version/lib/version.js +1 -1
- package/package.json +4 -4
- package/tabs/lib/TabsItem.tsx +39 -0
- package/tabs/lib/TabsList.tsx +84 -5
- package/tabs/lib/TabsOverflowButton.tsx +78 -6
- package/tabs/lib/TabsPanels.tsx +2 -2
- package/tabs/lib/useTabsModel.tsx +161 -3
package/tabs/lib/TabsList.tsx
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
ListRenderItemContext,
|
|
5
|
+
isCursor,
|
|
6
6
|
useOverflowListMeasure,
|
|
7
7
|
} from '@workday/canvas-kit-react/collection';
|
|
8
8
|
import {
|
|
9
9
|
ExtractProps,
|
|
10
|
+
Generic,
|
|
10
11
|
composeHooks,
|
|
11
12
|
createElemPropsHook,
|
|
12
13
|
createSubcomponent,
|
|
13
14
|
useLocalRef,
|
|
14
15
|
useModalityType,
|
|
16
|
+
useMountLayout,
|
|
15
17
|
} from '@workday/canvas-kit-react/common';
|
|
16
18
|
import {Flex, mergeStyles} from '@workday/canvas-kit-react/layout';
|
|
17
19
|
import {createStencil, px2rem} from '@workday/canvas-kit-styling';
|
|
18
20
|
import {base, system} from '@workday/canvas-tokens-web';
|
|
19
21
|
|
|
20
|
-
import {
|
|
22
|
+
import {orientationKeyMap} from '../../collection/lib/keyUtils';
|
|
23
|
+
import {TABS_OVERFLOW_BUTTON_ID, useTabsModel} from './useTabsModel';
|
|
21
24
|
|
|
22
25
|
export interface TabListProps<T = any> extends Omit<ExtractProps<typeof Flex, never>, 'children'> {
|
|
23
26
|
/**
|
|
@@ -100,6 +103,49 @@ export const useTabOverflowScroll = createElemPropsHook(useTabsModel)((
|
|
|
100
103
|
};
|
|
101
104
|
});
|
|
102
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Resets the tablist cursor on blur to the selected tab when visible, or to the first visible
|
|
108
|
+
* item (e.g. the overflow button) when the selected tab is hidden. This ensures the roving
|
|
109
|
+
* tabindex always lands on a focusable element when only the "More" button is visible.
|
|
110
|
+
*/
|
|
111
|
+
export const useTabsListResetCursorOnBlur = createElemPropsHook(useTabsModel)(({state, events}) => {
|
|
112
|
+
const programmaticFocusRef = React.useRef(false);
|
|
113
|
+
const requestAnimationFrameRef = React.useRef(0);
|
|
114
|
+
|
|
115
|
+
useMountLayout(() => {
|
|
116
|
+
return () => {
|
|
117
|
+
cancelAnimationFrame(requestAnimationFrameRef.current);
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
onKeyDown(event: React.KeyboardEvent) {
|
|
123
|
+
if (Object.keys(orientationKeyMap[state.orientation]).indexOf(event.key) !== -1) {
|
|
124
|
+
programmaticFocusRef.current = true;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
onFocus() {
|
|
128
|
+
programmaticFocusRef.current = false;
|
|
129
|
+
},
|
|
130
|
+
onBlur() {
|
|
131
|
+
if (!programmaticFocusRef.current) {
|
|
132
|
+
requestAnimationFrameRef.current = requestAnimationFrame(() => {
|
|
133
|
+
const selectedId =
|
|
134
|
+
state.selectedIds !== 'all' && state.selectedIds.length
|
|
135
|
+
? state.selectedIds[0]
|
|
136
|
+
: undefined;
|
|
137
|
+
const visibleItems = state.items.filter(item => !state.hiddenIds.includes(item.id));
|
|
138
|
+
const targetId =
|
|
139
|
+
selectedId && !state.hiddenIds.includes(selectedId) ? selectedId : visibleItems[0]?.id;
|
|
140
|
+
if (targetId && !isCursor(state, targetId)) {
|
|
141
|
+
events.goTo({id: targetId});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
|
|
103
149
|
export const useTabsList = composeHooks(
|
|
104
150
|
useTabOverflowScroll,
|
|
105
151
|
createElemPropsHook(useTabsModel)(model => {
|
|
@@ -109,13 +155,14 @@ export const useTabsList = composeHooks(
|
|
|
109
155
|
} as const;
|
|
110
156
|
}),
|
|
111
157
|
useOverflowListMeasure,
|
|
112
|
-
|
|
158
|
+
useTabsListResetCursorOnBlur
|
|
113
159
|
);
|
|
114
160
|
|
|
115
161
|
export const tabsListStencil = createStencil({
|
|
116
162
|
base: {
|
|
117
163
|
display: 'flex',
|
|
118
164
|
position: 'relative',
|
|
165
|
+
minWidth: 0,
|
|
119
166
|
borderBlockEnd: `${px2rem(1)} solid ${system.legacy.color.border.default}`,
|
|
120
167
|
gap: system.legacy.gap.xs,
|
|
121
168
|
// TODO: update this to use a grid token if we make those available as tokens
|
|
@@ -159,6 +206,38 @@ export const tabsListStencil = createStencil({
|
|
|
159
206
|
},
|
|
160
207
|
});
|
|
161
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Custom render function for tabs that filters out the synthetic overflow button item.
|
|
211
|
+
* This is needed because the overflow button is included in the model's items array
|
|
212
|
+
* for navigation purposes, but should not be rendered by the list render function.
|
|
213
|
+
*/
|
|
214
|
+
export function useTabsListRenderItems<T>(
|
|
215
|
+
model: ReturnType<typeof useTabsModel>,
|
|
216
|
+
children: ((item: Generic, index: number) => React.ReactNode) | React.ReactNode
|
|
217
|
+
): React.ReactNode {
|
|
218
|
+
// Filter out the synthetic overflow button from rendering
|
|
219
|
+
const itemsToRender = model.state.items.filter(item => item.id !== TABS_OVERFLOW_BUTTON_ID);
|
|
220
|
+
|
|
221
|
+
const items =
|
|
222
|
+
typeof children === 'function' ? (
|
|
223
|
+
itemsToRender.map(item => {
|
|
224
|
+
const child = (children as (item: Generic, index: number) => React.ReactNode)(
|
|
225
|
+
item.value,
|
|
226
|
+
item.index
|
|
227
|
+
);
|
|
228
|
+
return (
|
|
229
|
+
<ListRenderItemContext.Provider key={item.id || item.index} value={{item}}>
|
|
230
|
+
{child}
|
|
231
|
+
</ListRenderItemContext.Provider>
|
|
232
|
+
);
|
|
233
|
+
})
|
|
234
|
+
) : (
|
|
235
|
+
<ListRenderItemContext.Provider value={{}}>{children}</ListRenderItemContext.Provider>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return items;
|
|
239
|
+
}
|
|
240
|
+
|
|
162
241
|
export const TabsList = createSubcomponent('div')({
|
|
163
242
|
displayName: 'Tabs.List',
|
|
164
243
|
modelHook: useTabsModel,
|
|
@@ -176,7 +255,7 @@ export const TabsList = createSubcomponent('div')({
|
|
|
176
255
|
})
|
|
177
256
|
)}
|
|
178
257
|
>
|
|
179
|
-
{
|
|
258
|
+
{useTabsListRenderItems(model, children)}
|
|
180
259
|
{overflowButton}
|
|
181
260
|
</Element>
|
|
182
261
|
);
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useListItemRegister,
|
|
5
|
+
useListItemRovingFocus,
|
|
6
|
+
useOverflowListModel,
|
|
7
|
+
} from '@workday/canvas-kit-react/collection';
|
|
4
8
|
import {
|
|
5
9
|
composeHooks,
|
|
6
10
|
createElemPropsHook,
|
|
7
11
|
createSubModelElemPropsHook,
|
|
8
12
|
createSubcomponent,
|
|
13
|
+
useLocalRef,
|
|
14
|
+
useResizeObserver,
|
|
9
15
|
} from '@workday/canvas-kit-react/common';
|
|
10
16
|
import {SystemIcon} from '@workday/canvas-kit-react/icon';
|
|
11
17
|
import {mergeStyles} from '@workday/canvas-kit-react/layout';
|
|
@@ -14,7 +20,10 @@ import {createStencil} from '@workday/canvas-kit-styling';
|
|
|
14
20
|
import {chevronDownSmallIcon} from '@workday/canvas-system-icons-web';
|
|
15
21
|
|
|
16
22
|
import {StyledTabItem} from './TabsItem';
|
|
17
|
-
import {useTabsModel} from './useTabsModel';
|
|
23
|
+
import {TABS_OVERFLOW_BUTTON_ID, useTabsModel} from './useTabsModel';
|
|
24
|
+
|
|
25
|
+
// Re-export for consumers who may need to reference the overflow button ID
|
|
26
|
+
export {TABS_OVERFLOW_BUTTON_ID} from './useTabsModel';
|
|
18
27
|
|
|
19
28
|
export interface OverflowButtonProps {
|
|
20
29
|
/**
|
|
@@ -32,21 +41,84 @@ const tabsOverflowButtonStencil = createStencil({
|
|
|
32
41
|
},
|
|
33
42
|
});
|
|
34
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Measures the overflow button and reports its size to the model for overflow calculation.
|
|
46
|
+
* Unlike useOverflowListTarget, this does NOT set aria-hidden or visibility styles because
|
|
47
|
+
* we handle visibility via conditional rendering in the TabsOverflowButton component.
|
|
48
|
+
*/
|
|
49
|
+
const useTabsOverflowButtonMeasure = createElemPropsHook(useOverflowListModel)((model, ref) => {
|
|
50
|
+
const {elementRef, localRef} = useLocalRef(ref as React.Ref<HTMLElement>);
|
|
51
|
+
|
|
52
|
+
useResizeObserver({
|
|
53
|
+
ref: localRef,
|
|
54
|
+
onResize: ({width = 0, height = 0}) => {
|
|
55
|
+
if (localRef.current && (width > 0 || height > 0)) {
|
|
56
|
+
const styles = getComputedStyle(localRef.current);
|
|
57
|
+
const w = width + parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
|
|
58
|
+
const h = height + parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
|
|
59
|
+
model.events.setOverflowTargetSize({width: w, height: h});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
ref: elementRef,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
35
69
|
export const useTabsOverflowButton = composeHooks(
|
|
70
|
+
// Measures the overflow button for overflow calculation (no aria-hidden or visibility styles)
|
|
71
|
+
useTabsOverflowButtonMeasure,
|
|
72
|
+
// Adds roving tabindex behavior for arrow key navigation within the tablist
|
|
73
|
+
useListItemRovingFocus,
|
|
74
|
+
// Registers the overflow button as an item in the collection for cursor navigation
|
|
75
|
+
useListItemRegister,
|
|
76
|
+
// Provides the stable data-id needed for collection registration
|
|
36
77
|
createElemPropsHook(useTabsModel)(() => {
|
|
37
78
|
return {
|
|
38
|
-
'
|
|
79
|
+
'data-id': TABS_OVERFLOW_BUTTON_ID,
|
|
39
80
|
} as const;
|
|
40
81
|
}),
|
|
41
|
-
|
|
42
|
-
createSubModelElemPropsHook(useTabsModel)(m => m.menu, useMenuTarget)
|
|
82
|
+
// Connects to the menu sub-model for popup behavior
|
|
83
|
+
createSubModelElemPropsHook(useTabsModel)(m => m.menu, useMenuTarget),
|
|
84
|
+
// Syncs the cursor to the overflow button when it receives focus.
|
|
85
|
+
// This is needed because when the menu closes and focus returns to the overflow button,
|
|
86
|
+
// the cursor state needs to be updated so arrow key navigation works correctly.
|
|
87
|
+
createElemPropsHook(useTabsModel)(model => {
|
|
88
|
+
return {
|
|
89
|
+
onFocus() {
|
|
90
|
+
model.events.goTo({id: TABS_OVERFLOW_BUTTON_ID});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}),
|
|
94
|
+
// Runs FIRST - Sets ARIA attributes for the overflow tab
|
|
95
|
+
// In composeHooks, hooks run right-to-left, and mergeProps gives precedence to elemProps
|
|
96
|
+
// (props from earlier-running hooks). So this runs first and its props win.
|
|
97
|
+
// Note: We intentionally do NOT include useListItemSelect here because clicking
|
|
98
|
+
// the overflow button should open the menu, not select it as the active tab
|
|
99
|
+
createElemPropsHook(useTabsModel)(() => {
|
|
100
|
+
return {
|
|
101
|
+
'aria-haspopup': 'menu',
|
|
102
|
+
'aria-selected': false,
|
|
103
|
+
role: 'tab',
|
|
104
|
+
} as const;
|
|
105
|
+
})
|
|
43
106
|
);
|
|
44
107
|
|
|
45
108
|
export const TabsOverflowButton = createSubcomponent('button')({
|
|
46
109
|
displayName: 'Tabs.OverflowButton',
|
|
47
110
|
modelHook: useTabsModel,
|
|
48
111
|
elemPropsHook: useTabsOverflowButton,
|
|
49
|
-
})<OverflowButtonProps>(({children, ...elemProps}, Element) => {
|
|
112
|
+
})<OverflowButtonProps>(({children, ...elemProps}, Element, model) => {
|
|
113
|
+
// Don't render the overflow button if there are no hidden items.
|
|
114
|
+
// This removes it from the DOM entirely, which:
|
|
115
|
+
// - Removes it from keyboard navigation (roving focus)
|
|
116
|
+
// - Removes it from screen reader announcements
|
|
117
|
+
// - Prevents the "8 tabs" announcement when only 7 are visible
|
|
118
|
+
if (model.state.hiddenIds.length === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
50
122
|
return (
|
|
51
123
|
<StyledTabItem
|
|
52
124
|
type="button"
|
package/tabs/lib/TabsPanels.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {useListRenderItems} from '@workday/canvas-kit-react/collection';
|
|
4
3
|
import {createSubcomponent} from '@workday/canvas-kit-react/common';
|
|
5
4
|
|
|
5
|
+
import {useTabsListRenderItems} from './TabsList';
|
|
6
6
|
import {useTabsModel} from './useTabsModel';
|
|
7
7
|
|
|
8
8
|
export interface TabsPanelsProps<T = any> {
|
|
@@ -16,5 +16,5 @@ export const TabsPanels = createSubcomponent()({
|
|
|
16
16
|
displayName: 'Tabs.Panels',
|
|
17
17
|
modelHook: useTabsModel,
|
|
18
18
|
})<TabsPanelsProps>(({children}, _, model) => {
|
|
19
|
-
return <>{
|
|
19
|
+
return <>{useTabsListRenderItems(model, children)}</>;
|
|
20
20
|
});
|
|
@@ -5,9 +5,15 @@ import {
|
|
|
5
5
|
useListModel,
|
|
6
6
|
useOverflowListModel,
|
|
7
7
|
} from '@workday/canvas-kit-react/collection';
|
|
8
|
-
import {createModelHook, useModalityType} from '@workday/canvas-kit-react/common';
|
|
8
|
+
import {createModelHook, slugify, useModalityType} from '@workday/canvas-kit-react/common';
|
|
9
9
|
import {useMenuModel} from '@workday/canvas-kit-react/menu';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* This constant is used as the stable identifier for the overflow button in the tabs collection.
|
|
13
|
+
* It uses a `__` prefix to avoid conflicts with user-provided item IDs.
|
|
14
|
+
*/
|
|
15
|
+
export const TABS_OVERFLOW_BUTTON_ID = '__tabs-overflow__';
|
|
16
|
+
|
|
11
17
|
/**
|
|
12
18
|
* The TabsModel extends the [Collection
|
|
13
19
|
* System](/get-started/for-developers/guides/collection-api/). Tabs have tab items and
|
|
@@ -51,11 +57,83 @@ export const useTabsModel = createModelHook({
|
|
|
51
57
|
contextOverride: useOverflowListModel.Context,
|
|
52
58
|
})(config => {
|
|
53
59
|
const initialSelectedRef = React.useRef(config.initialTab);
|
|
54
|
-
const
|
|
60
|
+
const userGetId = config.getId || defaultGetId;
|
|
55
61
|
const modality = useModalityType();
|
|
56
62
|
|
|
63
|
+
// Stable object so getId can recognize the synthetic overflow item. Callers
|
|
64
|
+
// often pass a getId that only understands their own item shape (for example
|
|
65
|
+
// `item => item.contextId`). Without this, the overflow item gets an empty id
|
|
66
|
+
// and Tabs.List renders it as a normal tab.
|
|
67
|
+
const overflowItemRef = React.useRef({
|
|
68
|
+
id: TABS_OVERFLOW_BUTTON_ID,
|
|
69
|
+
text: 'More',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const getId = (item: Parameters<typeof userGetId>[0]) => {
|
|
73
|
+
if (item === overflowItemRef.current) {
|
|
74
|
+
return TABS_OVERFLOW_BUTTON_ID;
|
|
75
|
+
}
|
|
76
|
+
const id = userGetId(item);
|
|
77
|
+
if (id === TABS_OVERFLOW_BUTTON_ID) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Tabs item id "${TABS_OVERFLOW_BUTTON_ID}" is reserved for the overflow tab. Choose a different id.`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return id;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// When using dynamic items, append a synthetic overflow button item to the
|
|
86
|
+
// items array. This ensures the overflow button is included in the navigation
|
|
87
|
+
// sequence for roving tabindex. The overflow button component will handle
|
|
88
|
+
// conditional rendering (not showing when there are no hidden items).
|
|
89
|
+
// The overflow button is NOT included in itemSizeCache (measured separately
|
|
90
|
+
// via setOverflowTargetSize), so it won't be incorrectly hidden.
|
|
91
|
+
const itemsWithOverflowButton = React.useMemo(() => {
|
|
92
|
+
if (config.items?.length) {
|
|
93
|
+
return [...config.items, overflowItemRef.current];
|
|
94
|
+
}
|
|
95
|
+
return config.items;
|
|
96
|
+
}, [config.items]);
|
|
97
|
+
|
|
98
|
+
// Track whether the overflow button should be non-interactive based on previous
|
|
99
|
+
// render's hiddenIds. We use a ref because hiddenIds isn't available until after
|
|
100
|
+
// the model is created, but we need to pass nonInteractiveIds to the model config.
|
|
101
|
+
// On first render, assume non-interactive (no overflow calculated yet).
|
|
102
|
+
// On subsequent renders, use the previous hiddenIds.length to determine.
|
|
103
|
+
const prevHiddenIdsLengthRef = React.useRef(0);
|
|
104
|
+
const [, setNonInteractiveTick] = React.useState(0);
|
|
105
|
+
|
|
106
|
+
const overflowButtonNonInteractive =
|
|
107
|
+
!!config.items?.length && prevHiddenIdsLengthRef.current === 0;
|
|
108
|
+
|
|
109
|
+
// Compute nonInteractiveIds to pass to the model, including overflow button when appropriate
|
|
110
|
+
const nonInteractiveIdsForModel = React.useMemo(() => {
|
|
111
|
+
const baseIds = config.nonInteractiveIds || [];
|
|
112
|
+
if (overflowButtonNonInteractive) {
|
|
113
|
+
return [...baseIds, TABS_OVERFLOW_BUTTON_ID];
|
|
114
|
+
}
|
|
115
|
+
return baseIds;
|
|
116
|
+
}, [config.nonInteractiveIds, overflowButtonNonInteractive]);
|
|
117
|
+
|
|
118
|
+
// Stores the ID of a tab that should receive focus after the menu closes.
|
|
119
|
+
// This is used when selecting a tab from the overflow menu - we want focus
|
|
120
|
+
// to go to the newly selected tab, not back to the overflow button.
|
|
121
|
+
const pendingFocusTabIdRef = React.useRef<string | null>(null);
|
|
122
|
+
const pendingFocusRafOuterRef = React.useRef(0);
|
|
123
|
+
const pendingFocusRafInnerRef = React.useRef(0);
|
|
124
|
+
|
|
125
|
+
React.useLayoutEffect(() => {
|
|
126
|
+
return () => {
|
|
127
|
+
cancelAnimationFrame(pendingFocusRafOuterRef.current);
|
|
128
|
+
cancelAnimationFrame(pendingFocusRafInnerRef.current);
|
|
129
|
+
};
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
57
132
|
const model = useOverflowListModel(
|
|
58
133
|
useOverflowListModel.mergeConfig(config, {
|
|
134
|
+
items: itemsWithOverflowButton,
|
|
135
|
+
getId,
|
|
136
|
+
nonInteractiveIds: nonInteractiveIdsForModel,
|
|
59
137
|
shouldCalculateOverflow: modality !== 'touch',
|
|
60
138
|
orientation: config.orientation || 'horizontal',
|
|
61
139
|
onRegisterItem(data) {
|
|
@@ -73,6 +151,63 @@ export const useTabsModel = createModelHook({
|
|
|
73
151
|
})
|
|
74
152
|
);
|
|
75
153
|
|
|
154
|
+
// Update the ref after each render so the next render knows the current hiddenIds.length.
|
|
155
|
+
// If hiddenIds.length changed (e.g. overflow just calculated), force a re-render so
|
|
156
|
+
// we pass the correct nonInteractiveIds and the overflow button is not stuck disabled.
|
|
157
|
+
React.useLayoutEffect(() => {
|
|
158
|
+
const nextLen = model.state.hiddenIds.length;
|
|
159
|
+
if (prevHiddenIdsLengthRef.current !== nextLen) {
|
|
160
|
+
prevHiddenIdsLengthRef.current = nextLen;
|
|
161
|
+
setNonInteractiveTick(t => t + 1);
|
|
162
|
+
} else {
|
|
163
|
+
prevHiddenIdsLengthRef.current = nextLen;
|
|
164
|
+
}
|
|
165
|
+
}, [model.state.hiddenIds.length]);
|
|
166
|
+
|
|
167
|
+
// When the cursor is on an item that isn't in the DOM, move it to a visible one so the
|
|
168
|
+
// roving tabindex lands on a focusable element. This covers: (1) cursor on a hidden tab when
|
|
169
|
+
// only "More" is visible, and (2) cursor on the overflow button when we widen and it unmounts.
|
|
170
|
+
React.useLayoutEffect(() => {
|
|
171
|
+
const {cursorId, hiddenIds, items} = model.state;
|
|
172
|
+
if (!cursorId) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const currentCursorId = typeof cursorId === 'string' ? cursorId : (cursorId.slice(-1)[0] ?? '');
|
|
176
|
+
const cursorOnHidden = currentCursorId ? hiddenIds.includes(currentCursorId) : false;
|
|
177
|
+
const cursorOnOverflowWhenNoOverflow =
|
|
178
|
+
currentCursorId === TABS_OVERFLOW_BUTTON_ID && hiddenIds.length === 0;
|
|
179
|
+
if (cursorOnHidden) {
|
|
180
|
+
// Move to first visible item (including overflow button when it's the only one visible)
|
|
181
|
+
const firstVisible = items.find(item => !hiddenIds.includes(item.id));
|
|
182
|
+
if (firstVisible) {
|
|
183
|
+
model.events.goTo({id: firstVisible.id});
|
|
184
|
+
}
|
|
185
|
+
} else if (cursorOnOverflowWhenNoOverflow) {
|
|
186
|
+
// Overflow button unmounted; move to selected tab or first tab (not the overflow button)
|
|
187
|
+
const selectedIds = model.state.selectedIds;
|
|
188
|
+
const selectedId =
|
|
189
|
+
selectedIds !== 'all' && Array.isArray(selectedIds) && selectedIds.length
|
|
190
|
+
? selectedIds[0]
|
|
191
|
+
: undefined;
|
|
192
|
+
const firstVisibleTab = items.find(
|
|
193
|
+
item => item.id !== TABS_OVERFLOW_BUTTON_ID && !hiddenIds.includes(item.id)
|
|
194
|
+
);
|
|
195
|
+
const targetId =
|
|
196
|
+
selectedId && !hiddenIds.includes(selectedId) ? selectedId : firstVisibleTab?.id;
|
|
197
|
+
if (targetId) {
|
|
198
|
+
model.events.goTo({id: targetId});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Use field-level deps instead of `model.state` so this does not re-run on every model update.
|
|
202
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
203
|
+
}, [
|
|
204
|
+
model.state.cursorId,
|
|
205
|
+
model.state.hiddenIds,
|
|
206
|
+
model.state.items,
|
|
207
|
+
model.state.selectedIds,
|
|
208
|
+
model.events,
|
|
209
|
+
]);
|
|
210
|
+
|
|
76
211
|
const panels = useListModel();
|
|
77
212
|
|
|
78
213
|
const state = {
|
|
@@ -120,8 +255,31 @@ export const useTabsModel = createModelHook({
|
|
|
120
255
|
getTextValue: config.menuConfig?.getTextValue || config.getTextValue,
|
|
121
256
|
nonInteractiveIds: state.nonInteractiveIds.filter(key => !state.hiddenIds.includes(key)),
|
|
122
257
|
onSelect(data) {
|
|
123
|
-
menu
|
|
258
|
+
// Store the tab ID to focus after the menu closes and React re-renders
|
|
259
|
+
pendingFocusTabIdRef.current = data.id;
|
|
260
|
+
|
|
261
|
+
// Update state: select the tab, move cursor, then close menu
|
|
124
262
|
events.select(data);
|
|
263
|
+
model.events.goTo({id: data.id});
|
|
264
|
+
menu.events.hide();
|
|
265
|
+
|
|
266
|
+
// Focus the selected tab AFTER React has re-rendered.
|
|
267
|
+
// Double rAF is required because useReturnFocus restores focus to the overflow
|
|
268
|
+
// button on a single rAF after hide; the second frame runs after that restore.
|
|
269
|
+
pendingFocusRafOuterRef.current = requestAnimationFrame(() => {
|
|
270
|
+
pendingFocusRafInnerRef.current = requestAnimationFrame(() => {
|
|
271
|
+
const tabId = pendingFocusTabIdRef.current;
|
|
272
|
+
if (tabId) {
|
|
273
|
+
const tabElement = document.querySelector<HTMLElement>(
|
|
274
|
+
`[data-focus-id="${slugify(`${model.state.id}-${tabId}`)}"]`
|
|
275
|
+
);
|
|
276
|
+
if (tabElement) {
|
|
277
|
+
tabElement.focus();
|
|
278
|
+
}
|
|
279
|
+
pendingFocusTabIdRef.current = null;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
});
|
|
125
283
|
},
|
|
126
284
|
onShow() {
|
|
127
285
|
// Always select the first item when the menu is opened
|