@cube-dev/ui-kit 0.102.0 → 0.104.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/CHANGELOG.md +24 -0
- package/es/_internal/hooks/index.js +1 -1
- package/es/_internal/hooks/use-chained-callback.js +1 -1
- package/es/_internal/hooks/use-debounced-value.js +1 -1
- package/es/_internal/hooks/use-deprecation-warning.js +1 -1
- package/es/_internal/hooks/use-effect-once.js +1 -1
- package/es/_internal/hooks/use-event.js +1 -1
- package/es/_internal/hooks/use-is-first-render.js +1 -1
- package/es/_internal/hooks/use-sync-ref.js +1 -1
- package/es/_internal/hooks/use-timer/index.js +1 -1
- package/es/_internal/hooks/use-timer/timer.js +1 -1
- package/es/_internal/hooks/use-timer/use-timer.js +1 -1
- package/es/_internal/hooks/use-update-effect.js +1 -1
- package/es/_internal/hooks/use-warn.js +1 -1
- package/es/_internal/index.js +1 -1
- package/es/components/Block.js +1 -1
- package/es/components/CollectionItem.js +1 -1
- package/es/components/GlobalStyles.js +1 -1
- package/es/components/GridProvider.js +1 -1
- package/es/components/HiddenInput.js +1 -1
- package/es/components/OpenTrasition.js +1 -1
- package/es/components/Root.js +1 -1
- package/es/components/actions/Action/Action.js +1 -1
- package/es/components/actions/Button/Button.js +16 -2
- package/es/components/actions/Button/index.js +1 -1
- package/es/components/actions/ButtonGroup/ButtonGroup.js +1 -1
- package/es/components/actions/CommandMenu/CommandMenu.js +1 -1
- package/es/components/actions/CommandMenu/index.js +1 -1
- package/es/components/actions/CommandMenu/styled.js +1 -1
- package/es/components/actions/ItemAction/ItemAction.js +20 -3
- package/es/components/actions/ItemAction/index.js +1 -1
- package/es/components/actions/ItemActionContext.js +1 -1
- package/es/components/actions/ItemButton/ItemButton.js +1 -1
- package/es/components/actions/ItemButton/index.js +1 -1
- package/es/components/actions/Link/Link.js +1 -1
- package/es/components/actions/Menu/Menu.js +1 -1
- package/es/components/actions/Menu/MenuItem.js +1 -1
- package/es/components/actions/Menu/MenuSection.js +1 -1
- package/es/components/actions/Menu/MenuTrigger.js +1 -1
- package/es/components/actions/Menu/SubMenuTrigger.js +1 -1
- package/es/components/actions/Menu/SubmenuTriggerContext.js +1 -1
- package/es/components/actions/Menu/context.js +1 -1
- package/es/components/actions/Menu/index.js +1 -1
- package/es/components/actions/Menu/styled.js +1 -1
- package/es/components/actions/index.js +1 -1
- package/es/components/actions/use-action.js +1 -1
- package/es/components/actions/use-anchored-menu.js +1 -1
- package/es/components/actions/use-context-menu.js +1 -1
- package/es/components/content/ActiveZone/ActiveZone.js +1 -1
- package/es/components/content/Alert/Alert.js +1 -1
- package/es/components/content/Alert/index.js +1 -1
- package/es/components/content/Alert/types.js +1 -1
- package/es/components/content/Alert/use-alert.js +1 -1
- package/es/components/content/Avatar/Avatar.js +1 -1
- package/es/components/content/Badge/Badge.js +1 -1
- package/es/components/content/Card/Card.js +1 -1
- package/es/components/content/Content.js +1 -1
- package/es/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
- package/es/components/content/CopyPasteBlock/index.js +1 -1
- package/es/components/content/CopySnippet/CopySnippet.js +1 -1
- package/es/components/content/CopySnippet/index.js +1 -1
- package/es/components/content/Disclosure/Disclosure.js +1 -1
- package/es/components/content/Disclosure/index.js +1 -1
- package/es/components/content/Divider.js +1 -1
- package/es/components/content/Footer.js +1 -1
- package/es/components/content/Header.js +1 -1
- package/es/components/content/HotKeys/HotKeys.js +1 -1
- package/es/components/content/HotKeys/index.js +1 -1
- package/es/components/content/Item/Item.js +30 -9
- package/es/components/content/Item/index.js +1 -1
- package/es/components/content/ItemBadge/ItemBadge.js +1 -1
- package/es/components/content/ItemBadge/index.js +1 -1
- package/es/components/content/Layout/GridLayout.js +1 -1
- package/es/components/content/Layout/Layout.js +1 -1
- package/es/components/content/Layout/LayoutBlock.js +1 -1
- package/es/components/content/Layout/LayoutCenter.js +1 -1
- package/es/components/content/Layout/LayoutContainer.js +1 -1
- package/es/components/content/Layout/LayoutContent.js +1 -1
- package/es/components/content/Layout/LayoutContext.js +1 -1
- package/es/components/content/Layout/LayoutFlex.js +1 -1
- package/es/components/content/Layout/LayoutFooter.js +1 -1
- package/es/components/content/Layout/LayoutGrid.js +1 -1
- package/es/components/content/Layout/LayoutHeader.js +1 -1
- package/es/components/content/Layout/LayoutPane.js +1 -1
- package/es/components/content/Layout/LayoutPanel.js +1 -1
- package/es/components/content/Layout/LayoutPanelHeader.js +1 -1
- package/es/components/content/Layout/LayoutToolbar.js +1 -1
- package/es/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
- package/es/components/content/Layout/index.js +1 -1
- package/es/components/content/Layout/utils.js +1 -1
- package/es/components/content/List/SectionHeading.js +1 -1
- package/es/components/content/List/index.js +1 -1
- package/es/components/content/Paragraph.js +1 -1
- package/es/components/content/Placeholder/Placeholder.js +1 -1
- package/es/components/content/PrismCode/PrismCode.js +1 -1
- package/es/components/content/PrismCode/prismSetup.js +1 -1
- package/es/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
- package/es/components/content/Result/Result.js +1 -1
- package/es/components/content/Skeleton/Skeleton.js +1 -1
- package/es/components/content/Tag/Tag.js +1 -1
- package/es/components/content/Text.js +1 -1
- package/es/components/content/TextItem/TextItem.js +1 -1
- package/es/components/content/TextItem/index.js +1 -1
- package/es/components/content/Title.js +1 -1
- package/es/components/content/highlightText.js +1 -1
- package/es/components/content/use-auto-tooltip.js +1 -1
- package/es/components/fields/Checkbox/Checkbox.js +1 -1
- package/es/components/fields/Checkbox/CheckboxGroup.js +1 -1
- package/es/components/fields/Checkbox/context.js +1 -1
- package/es/components/fields/Checkbox/index.js +1 -1
- package/es/components/fields/ComboBox/ComboBox.js +1 -1
- package/es/components/fields/ComboBox/index.js +1 -1
- package/es/components/fields/DatePicker/DateInput.js +1 -1
- package/es/components/fields/DatePicker/DateInputBase.js +1 -1
- package/es/components/fields/DatePicker/DatePicker.js +1 -1
- package/es/components/fields/DatePicker/DatePickerButton.js +1 -1
- package/es/components/fields/DatePicker/DatePickerElement.js +1 -1
- package/es/components/fields/DatePicker/DatePickerInput.js +1 -1
- package/es/components/fields/DatePicker/DatePickerSegment.js +1 -1
- package/es/components/fields/DatePicker/DateRangePicker.js +1 -1
- package/es/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
- package/es/components/fields/DatePicker/TimeInput.js +1 -1
- package/es/components/fields/DatePicker/index.js +1 -1
- package/es/components/fields/DatePicker/intl.js +1 -1
- package/es/components/fields/DatePicker/parseDate.js +1 -1
- package/es/components/fields/DatePicker/props.js +1 -1
- package/es/components/fields/DatePicker/types.js +1 -1
- package/es/components/fields/DatePicker/utils.js +1 -1
- package/es/components/fields/FileInput/FileInput.js +1 -1
- package/es/components/fields/FilterListBox/FilterListBox.js +1 -1
- package/es/components/fields/FilterListBox/index.js +1 -1
- package/es/components/fields/FilterPicker/FilterPicker.js +3 -3
- package/es/components/fields/FilterPicker/index.js +1 -1
- package/es/components/fields/Input/Input.js +1 -1
- package/es/components/fields/Input/index.js +1 -1
- package/es/components/fields/ListBox/ListBox.js +1 -1
- package/es/components/fields/ListBox/index.js +1 -1
- package/es/components/fields/NumberInput/NumberInput.js +1 -1
- package/es/components/fields/NumberInput/StepButton.js +1 -1
- package/es/components/fields/PasswordInput/PasswordInput.js +1 -1
- package/es/components/fields/Picker/Picker.js +3 -3
- package/es/components/fields/Picker/index.js +1 -1
- package/es/components/fields/RadioGroup/Radio.js +1 -1
- package/es/components/fields/RadioGroup/RadioGroup.js +1 -1
- package/es/components/fields/RadioGroup/context.js +1 -1
- package/es/components/fields/RadioGroup/index.js +1 -1
- package/es/components/fields/SearchInput/SearchInput.js +1 -1
- package/es/components/fields/SearchInput/index.js +1 -1
- package/es/components/fields/Select/Select.js +1 -1
- package/es/components/fields/Select/index.js +1 -1
- package/es/components/fields/Slider/Gradation.js +1 -1
- package/es/components/fields/Slider/Header.js +1 -1
- package/es/components/fields/Slider/RangeSlider.js +1 -1
- package/es/components/fields/Slider/Slider.js +1 -1
- package/es/components/fields/Slider/SliderBase.js +1 -1
- package/es/components/fields/Slider/SliderInput.js +1 -1
- package/es/components/fields/Slider/SliderThumb.js +1 -1
- package/es/components/fields/Slider/SliderTrack.js +1 -1
- package/es/components/fields/Slider/elements.js +1 -1
- package/es/components/fields/Slider/index.js +1 -1
- package/es/components/fields/Slider/types.js +1 -1
- package/es/components/fields/Switch/Switch.js +1 -1
- package/es/components/fields/Switch/index.js +1 -1
- package/es/components/fields/TextArea/TextArea.js +1 -1
- package/es/components/fields/TextArea/index.js +1 -1
- package/es/components/fields/TextInput/TextInput.js +1 -1
- package/es/components/fields/TextInput/TextInputBase.js +1 -1
- package/es/components/fields/TextInput/index.js +1 -1
- package/es/components/fields/TextInputMapper/TextInputMapper.js +1 -1
- package/es/components/fields/TextInputMapper/index.js +1 -1
- package/es/components/fields/index.js +1 -1
- package/es/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/es/components/form/FieldWrapper/extract-field-wrapper-props.js +1 -1
- package/es/components/form/FieldWrapper/index.js +1 -1
- package/es/components/form/FieldWrapper/types.js +1 -1
- package/es/components/form/Form/Field.js +1 -1
- package/es/components/form/Form/Form.js +1 -1
- package/es/components/form/Form/ResetButton/ResetButton.js +1 -1
- package/es/components/form/Form/ResetButton/index.js +1 -1
- package/es/components/form/Form/SubmitButton/SubmitButton.js +1 -1
- package/es/components/form/Form/SubmitButton/index.js +1 -1
- package/es/components/form/Form/SubmitError.js +1 -1
- package/es/components/form/Form/index.js +1 -1
- package/es/components/form/Form/types.js +1 -1
- package/es/components/form/Form/use-field/index.js +1 -1
- package/es/components/form/Form/use-field/types.js +1 -1
- package/es/components/form/Form/use-field/use-field-props.js +1 -1
- package/es/components/form/Form/use-field/use-field.js +1 -1
- package/es/components/form/Form/use-form.js +1 -1
- package/es/components/form/Form/validation.js +1 -1
- package/es/components/form/Label.js +1 -1
- package/es/components/form/index.js +1 -1
- package/es/components/form/wrapper.js +1 -1
- package/es/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
- package/es/components/helpers/DisplayTransition/index.js +1 -1
- package/es/components/helpers/IconSwitch/IconSwitch.js +1 -1
- package/es/components/helpers/index.js +1 -1
- package/es/components/layout/Flex.js +1 -1
- package/es/components/layout/Flow.js +1 -1
- package/es/components/layout/Grid.js +1 -1
- package/es/components/layout/Panel.js +1 -1
- package/es/components/layout/Prefix.js +1 -1
- package/es/components/layout/ResizablePanel.js +1 -1
- package/es/components/layout/Space.js +1 -1
- package/es/components/layout/Suffix.js +1 -1
- package/es/components/navigation/Tabs/DraggableTabList.js +101 -0
- package/es/components/navigation/Tabs/EditableTitle.js +116 -0
- package/es/components/navigation/Tabs/TabButton.js +320 -0
- package/es/components/navigation/Tabs/TabDropIndicator.js +34 -0
- package/es/components/navigation/Tabs/TabPanel.js +128 -0
- package/es/components/navigation/Tabs/TabPicker.js +46 -0
- package/es/components/navigation/Tabs/Tabs.js +212 -707
- package/es/components/navigation/Tabs/TabsAction.js +70 -0
- package/es/components/navigation/Tabs/TabsContext.js +36 -0
- package/es/components/navigation/Tabs/index.js +2 -2
- package/es/components/navigation/Tabs/styled.js +354 -0
- package/es/components/navigation/Tabs/types.js +17 -0
- package/es/components/navigation/Tabs/use-tab-editing.js +61 -0
- package/es/components/navigation/Tabs/use-tab-indicator.js +77 -0
- package/es/components/navigation/index.js +1 -1
- package/es/components/organisms/FileTabs/FileTabs.js +1 -1
- package/es/components/organisms/StatsCard/StatsCard.js +1 -1
- package/es/components/other/Calendar/Calendar.js +1 -1
- package/es/components/other/Calendar/CalendarCell.js +1 -1
- package/es/components/other/Calendar/CalendarGrid.js +1 -1
- package/es/components/other/Calendar/RangeCalendar.js +1 -1
- package/es/components/other/CloudLogo/CloudLogo.js +1 -1
- package/es/components/overlays/AlertDialog/AlertDialog.js +1 -1
- package/es/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
- package/es/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
- package/es/components/overlays/AlertDialog/index.js +1 -1
- package/es/components/overlays/AlertDialog/types.js +1 -1
- package/es/components/overlays/Dialog/Dialog.js +1 -1
- package/es/components/overlays/Dialog/DialogContainer.js +1 -1
- package/es/components/overlays/Dialog/DialogForm.js +1 -1
- package/es/components/overlays/Dialog/DialogTrigger.js +1 -1
- package/es/components/overlays/Dialog/context.js +1 -1
- package/es/components/overlays/Dialog/index.js +1 -1
- package/es/components/overlays/Dialog/use-dialog-container.js +1 -1
- package/es/components/overlays/Modal/Modal.js +1 -1
- package/es/components/overlays/Modal/OpenTransition.js +1 -1
- package/es/components/overlays/Modal/Overlay.js +1 -1
- package/es/components/overlays/Modal/Popover.js +1 -1
- package/es/components/overlays/Modal/Tray.js +1 -1
- package/es/components/overlays/Modal/Underlay.js +1 -1
- package/es/components/overlays/Modal/index.js +1 -1
- package/es/components/overlays/Modal/types.js +1 -1
- package/es/components/overlays/NewNotifications/Bar/FloatingNotification.js +1 -1
- package/es/components/overlays/NewNotifications/Bar/NotificationsBar.js +1 -1
- package/es/components/overlays/NewNotifications/Bar/TransitionComponent.js +1 -1
- package/es/components/overlays/NewNotifications/Bar/index.js +1 -1
- package/es/components/overlays/NewNotifications/Dialog/NotificationsDialogContext.js +1 -1
- package/es/components/overlays/NewNotifications/Dialog/NotificationsDialogTrigger.js +1 -1
- package/es/components/overlays/NewNotifications/Dialog/index.js +1 -1
- package/es/components/overlays/NewNotifications/Notification.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationAction.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationCloseButton.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationDescription.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationFooter.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationHeader.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationIcon.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationProvider.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/NotificationView.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/index.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationView/types.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsContext/NotificationsContext.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsContext/NotificationsProvider.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsContext/index.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsContext/use-notifications.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsList/NotificationsList.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsList/NotificationsListItem.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsList/index.js +1 -1
- package/es/components/overlays/NewNotifications/NotificationsList/types.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/index.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/types.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/use-notification-list-item.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/use-notifications-api.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/use-notifications-list.js +1 -1
- package/es/components/overlays/NewNotifications/hooks/use-notifications-observer.js +1 -1
- package/es/components/overlays/NewNotifications/index.js +1 -1
- package/es/components/overlays/NewNotifications/types.js +1 -1
- package/es/components/overlays/Notification/Notification.js +1 -1
- package/es/components/overlays/OverlayWrapper.js +1 -1
- package/es/components/overlays/Toasts/Toast.js +1 -1
- package/es/components/overlays/Toasts/index.js +1 -1
- package/es/components/overlays/Toasts/types.js +1 -1
- package/es/components/overlays/Toasts/use-toasts-api.js +1 -1
- package/es/components/overlays/Tooltip/Tooltip.js +1 -1
- package/es/components/overlays/Tooltip/TooltipProvider.js +1 -1
- package/es/components/overlays/Tooltip/TooltipTrigger.js +1 -1
- package/es/components/overlays/Tooltip/context.js +1 -1
- package/es/components/overlays/Tooltip/index.js +1 -1
- package/es/components/portal/Portal.js +1 -1
- package/es/components/portal/PortalProvider.js +1 -1
- package/es/components/portal/index.js +1 -1
- package/es/components/portal/types.js +1 -1
- package/es/components/portal/usePortal.js +1 -1
- package/es/components/shared/InvalidIcon.js +1 -1
- package/es/components/shared/ValidIcon.js +1 -1
- package/es/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
- package/es/components/status/LoadingAnimation/index.js +1 -1
- package/es/components/status/Spin/Cube.js +1 -1
- package/es/components/status/Spin/InternalSpinner.js +1 -1
- package/es/components/status/Spin/Spin.js +1 -1
- package/es/components/status/Spin/SpinsContainer.js +1 -1
- package/es/components/status/Spin/index.js +1 -1
- package/es/components/status/Spin/types.js +1 -1
- package/es/components/status/index.js +1 -1
- package/es/data/item-themes.js +249 -5
- package/es/data/themes.js +1 -1
- package/es/icons/AdjustmentsHorizontalIcon.js +1 -1
- package/es/icons/AdjustmentsIcon.js +1 -1
- package/es/icons/AiIcon.js +1 -1
- package/es/icons/AreaChartIcon.js +1 -1
- package/es/icons/BackwardIcon.js +1 -1
- package/es/icons/BarChartIcon.js +1 -1
- package/es/icons/BellFilledIcon.js +1 -1
- package/es/icons/BellIcon.js +1 -1
- package/es/icons/BooleanIcon.js +1 -1
- package/es/icons/CalendarEditIcon.js +1 -1
- package/es/icons/CalendarIcon.js +1 -1
- package/es/icons/CaretDownIcon.js +1 -1
- package/es/icons/CaretUpIcon.js +1 -1
- package/es/icons/ChartAreaStackedIcon.js +1 -1
- package/es/icons/ChartAreaStackedPercentageIcon.js +1 -1
- package/es/icons/ChartBarGroupedHorizontalIcon.js +1 -1
- package/es/icons/ChartBarGroupedIcon.js +1 -1
- package/es/icons/ChartBarHorizontalIcon.js +1 -1
- package/es/icons/ChartBarLineIcon.js +1 -1
- package/es/icons/ChartBarStackedHorizontalIcon.js +1 -1
- package/es/icons/ChartBarStackedIcon.js +1 -1
- package/es/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
- package/es/icons/ChartBarStackedPercentageIcon.js +1 -1
- package/es/icons/ChartBoxPlot2Icon.js +1 -1
- package/es/icons/ChartBoxPlotIcon.js +1 -1
- package/es/icons/ChartBubbleIcon.js +1 -1
- package/es/icons/ChartDonut2Icon.js +1 -1
- package/es/icons/ChartFunnelIcon.js +1 -1
- package/es/icons/ChartHeatmapIcon.js +1 -1
- package/es/icons/ChartKPIIcon.js +1 -1
- package/es/icons/ChartPie2Icon.js +1 -1
- package/es/icons/ChartScatterIcon.js +1 -1
- package/es/icons/CheckCircleFilledIcon.js +1 -1
- package/es/icons/CheckCircleIcon.js +1 -1
- package/es/icons/CheckIcon.js +1 -1
- package/es/icons/CircleFilledIcon.js +1 -1
- package/es/icons/ClearIcon.js +1 -1
- package/es/icons/CloseCircleFilledIcon.js +1 -1
- package/es/icons/CloseCircleIcon.js +1 -1
- package/es/icons/CloseIcon.js +1 -1
- package/es/icons/CodeIcon.js +1 -1
- package/es/icons/ColumnTotalIcon.js +1 -1
- package/es/icons/CopyIcon.js +1 -1
- package/es/icons/CountIcon.js +1 -1
- package/es/icons/CubeIcon.js +1 -1
- package/es/icons/CubePauseIcon.js +1 -1
- package/es/icons/CubePlayIcon.js +1 -1
- package/es/icons/CurrencyDollarIcon.js +1 -1
- package/es/icons/DangerIcon.js +1 -1
- package/es/icons/DashboardIcon.js +1 -1
- package/es/icons/DatabaseIcon.js +1 -1
- package/es/icons/DecimalDecreaseIcon.js +1 -1
- package/es/icons/DecimalIncreaseIcon.js +1 -1
- package/es/icons/DirectionIcon.js +1 -1
- package/es/icons/DonutIcon.js +1 -1
- package/es/icons/DownIcon.js +1 -1
- package/es/icons/EditIcon.js +1 -1
- package/es/icons/ExclamationCircleFilledIcon.js +1 -1
- package/es/icons/ExclamationCircleIcon.js +1 -1
- package/es/icons/ExclamationIcon.js +1 -1
- package/es/icons/EyeIcon.js +1 -1
- package/es/icons/EyeInvisibleIcon.js +1 -1
- package/es/icons/FilterIcon.js +1 -1
- package/es/icons/FolderFilledIcon.js +1 -1
- package/es/icons/FolderIcon.js +1 -1
- package/es/icons/FolderOpenFilledIcon.js +1 -1
- package/es/icons/FolderOpenIcon.js +1 -1
- package/es/icons/ForwardIcon.js +1 -1
- package/es/icons/HierarchyIcon.js +1 -1
- package/es/icons/HierarchyOpenIcon.js +1 -1
- package/es/icons/Icon.js +1 -1
- package/es/icons/InfoCircleIcon.js +1 -1
- package/es/icons/InfoIcon.js +1 -1
- package/es/icons/KeyIcon.js +1 -1
- package/es/icons/LeftIcon.js +1 -1
- package/es/icons/LineChartIcon.js +1 -1
- package/es/icons/LoadingIcon.js +1 -1
- package/es/icons/LockFilledIcon.js +1 -1
- package/es/icons/LockIcon.js +1 -1
- package/es/icons/MoreIcon.js +1 -1
- package/es/icons/NotAllowedIcon.js +1 -1
- package/es/icons/Number123Icon.js +1 -1
- package/es/icons/NumberIcon.js +1 -1
- package/es/icons/PauseCircleFilledIcon.js +1 -1
- package/es/icons/PauseCircleIcon.js +1 -1
- package/es/icons/PauseIcon.js +1 -1
- package/es/icons/PercentageIcon.js +1 -1
- package/es/icons/PieChartIcon.js +1 -1
- package/es/icons/PlayCircleIcon.js +1 -1
- package/es/icons/PlayIcon.js +1 -1
- package/es/icons/PlusIcon.js +1 -1
- package/es/icons/ProgressBarIcon.js +1 -1
- package/es/icons/ReloadIcon.js +1 -1
- package/es/icons/ReportIcon.js +1 -1
- package/es/icons/ReturnIcon.js +1 -1
- package/es/icons/RightIcon.js +1 -1
- package/es/icons/RowTotalsIcon.js +1 -1
- package/es/icons/SchemeIcon.js +1 -1
- package/es/icons/SearchIcon.js +1 -1
- package/es/icons/SemanticQueryIcon.js +1 -1
- package/es/icons/SettingsIcon.js +1 -1
- package/es/icons/ShieldFilledIcon.js +1 -1
- package/es/icons/ShieldIcon.js +1 -1
- package/es/icons/SlashIcon.js +1 -1
- package/es/icons/SparklesIcon.js +1 -1
- package/es/icons/SqlIcon.js +1 -1
- package/es/icons/StatsIcon.js +1 -1
- package/es/icons/StopIcon.js +1 -1
- package/es/icons/StringIcon.js +1 -1
- package/es/icons/SubtotalsIcon.js +1 -1
- package/es/icons/SwitchIcon.js +1 -1
- package/es/icons/TableIcon.js +1 -1
- package/es/icons/ThumbsDownIcon.js +1 -1
- package/es/icons/ThumbsUpIcon.js +1 -1
- package/es/icons/ThunderboltCrossedIcon.js +1 -1
- package/es/icons/ThunderboltFilledIcon.js +1 -1
- package/es/icons/ThunderboltIcon.js +1 -1
- package/es/icons/TimeIcon.js +1 -1
- package/es/icons/TrashIcon.js +1 -1
- package/es/icons/UnlockIcon.js +1 -1
- package/es/icons/UpIcon.js +1 -1
- package/es/icons/UserGroupIcon.js +1 -1
- package/es/icons/UserIcon.js +1 -1
- package/es/icons/UserLockIcon.js +1 -1
- package/es/icons/ViewIcon.js +1 -1
- package/es/icons/WarningFilledIcon.js +1 -1
- package/es/icons/WarningIcon.js +1 -1
- package/es/icons/index.js +1 -1
- package/es/icons/wrap-icon.js +1 -1
- package/es/index.js +1 -1
- package/es/provider.js +1 -1
- package/es/providers/TrackingProvider.js +1 -1
- package/es/providers/navigation.types.js +1 -1
- package/es/providers/navigationAdapter.default.js +1 -1
- package/es/services/notification.js +1 -1
- package/es/shared/form.js +1 -1
- package/es/shared/index.js +1 -1
- package/es/stories/Form.legacy-stories.js +1 -1
- package/es/stories/FormFieldArgs.js +1 -1
- package/es/stories/SimpleLayout.stories.js +1 -1
- package/es/stories/Tasty.stories.js +1 -1
- package/es/stories/components/ConfirmDeletionDialogForm.js +1 -1
- package/es/stories/components/DialogFormApp.js +1 -1
- package/es/stories/components/StyledButton.js +1 -1
- package/es/stories/lists/baseProps.js +1 -1
- package/es/stories/playground/PlaygroundEditor.js +1 -1
- package/es/stories/playground/PlaygroundLayout.js +1 -1
- package/es/stories/playground/PlaygroundOutput.js +1 -1
- package/es/stories/playground/PlaygroundPreview.js +1 -1
- package/es/stories/playground/components/Button.js +1 -1
- package/es/stories/playground/components/Card.js +1 -1
- package/es/stories/playground/components/ScrollProgress.js +1 -1
- package/es/stories/playground/examples.js +1 -1
- package/es/tasty/chunks/cacheKey.js +1 -1
- package/es/tasty/chunks/definitions.js +1 -1
- package/es/tasty/chunks/index.js +1 -1
- package/es/tasty/chunks/renderChunk.js +1 -1
- package/es/tasty/config.js +1 -1
- package/es/tasty/debug.js +1 -1
- package/es/tasty/hooks/index.js +1 -1
- package/es/tasty/hooks/useGlobalStyles.js +1 -1
- package/es/tasty/hooks/useKeyframes.js +1 -1
- package/es/tasty/hooks/useProperty.js +1 -1
- package/es/tasty/hooks/useRawCSS.js +1 -1
- package/es/tasty/hooks/useStyles.js +1 -1
- package/es/tasty/index.js +1 -1
- package/es/tasty/injector/index.js +1 -1
- package/es/tasty/injector/injector.js +1 -1
- package/es/tasty/injector/sheet-manager.js +1 -1
- package/es/tasty/injector/types.js +1 -1
- package/es/tasty/keyframes/index.js +1 -1
- package/es/tasty/parser/classify.js +1 -1
- package/es/tasty/parser/const.js +1 -1
- package/es/tasty/parser/lru.js +1 -1
- package/es/tasty/parser/parser.js +1 -1
- package/es/tasty/parser/tokenizer.js +1 -1
- package/es/tasty/parser/types.js +1 -1
- package/es/tasty/pipeline/conditions.js +1 -1
- package/es/tasty/pipeline/exclusive.js +1 -1
- package/es/tasty/pipeline/index.js +1 -1
- package/es/tasty/pipeline/materialize.js +1 -1
- package/es/tasty/pipeline/parseStateKey.js +1 -1
- package/es/tasty/pipeline/simplify.js +1 -1
- package/es/tasty/plugins/index.js +1 -1
- package/es/tasty/plugins/okhsl-plugin.js +1 -1
- package/es/tasty/plugins/types.js +1 -1
- package/es/tasty/properties/index.js +1 -1
- package/es/tasty/states/index.js +1 -1
- package/es/tasty/static/index.js +1 -1
- package/es/tasty/static/tastyStatic.js +1 -1
- package/es/tasty/static/types.js +1 -1
- package/es/tasty/styles/align.js +1 -1
- package/es/tasty/styles/border.js +1 -1
- package/es/tasty/styles/boxShadow.combinator.js +1 -1
- package/es/tasty/styles/color.js +1 -1
- package/es/tasty/styles/createStyle.js +1 -1
- package/es/tasty/styles/dimension.js +1 -1
- package/es/tasty/styles/display.js +1 -1
- package/es/tasty/styles/fade.js +1 -1
- package/es/tasty/styles/fill.js +1 -1
- package/es/tasty/styles/flow.js +1 -1
- package/es/tasty/styles/gap.js +1 -1
- package/es/tasty/styles/height.js +1 -1
- package/es/tasty/styles/index.js +1 -1
- package/es/tasty/styles/inset.js +6 -5
- package/es/tasty/styles/justify.js +1 -1
- package/es/tasty/styles/list.js +1 -1
- package/es/tasty/styles/margin.js +6 -5
- package/es/tasty/styles/outline.js +1 -1
- package/es/tasty/styles/padding.js +6 -5
- package/es/tasty/styles/place.js +1 -1
- package/es/tasty/styles/predefined.js +1 -1
- package/es/tasty/styles/preset.js +1 -1
- package/es/tasty/styles/radius.js +1 -1
- package/es/tasty/styles/reset.js +1 -1
- package/es/tasty/styles/scrollbar.js +1 -1
- package/es/tasty/styles/shadow.js +1 -1
- package/es/tasty/styles/styledScrollbar.js +1 -1
- package/es/tasty/styles/transition.js +1 -1
- package/es/tasty/styles/types.js +1 -1
- package/es/tasty/styles/width.js +1 -1
- package/es/tasty/tasty.js +1 -1
- package/es/tasty/types.js +1 -1
- package/es/tasty/utils/cache-wrapper.js +1 -1
- package/es/tasty/utils/case-converter.js +1 -1
- package/es/tasty/utils/colors.js +1 -1
- package/es/tasty/utils/dotize.js +1 -1
- package/es/tasty/utils/filter-base-props.js +1 -1
- package/es/tasty/utils/get-display-name.js +1 -1
- package/es/tasty/utils/hsl-to-rgb.js +1 -1
- package/es/tasty/utils/is-dev-env.js +1 -1
- package/es/tasty/utils/merge-styles.js +1 -1
- package/es/tasty/utils/mod-attrs.js +1 -1
- package/es/tasty/utils/okhsl-to-rgb.js +1 -1
- package/es/tasty/utils/process-tokens.js +1 -1
- package/es/tasty/utils/rgb-to-okhsl.js +1 -1
- package/es/tasty/utils/string.js +1 -1
- package/es/tasty/utils/styles.js +1 -1
- package/es/tasty/utils/typography.js +1 -1
- package/es/tasty/utils/warnings.js +1 -1
- package/es/tasty/zero/babel.js +1 -1
- package/es/tasty/zero/css-writer.js +1 -1
- package/es/tasty/zero/extractor.js +1 -1
- package/es/tasty/zero/index.js +1 -1
- package/es/tasty/zero/next.js +1 -1
- package/es/tokens/base.js +1 -1
- package/es/tokens/colors.js +11 -1
- package/es/tokens/index.js +1 -1
- package/es/tokens/layout.js +1 -1
- package/es/tokens/shadows.js +1 -1
- package/es/tokens/sizes.js +1 -1
- package/es/tokens/spacing.js +1 -1
- package/es/tokens/typography.js +1 -1
- package/es/utils/ResizeSensor.js +1 -1
- package/es/utils/index.js +1 -1
- package/es/utils/modules.js +1 -1
- package/es/utils/promise.js +1 -1
- package/es/utils/raf.js +1 -1
- package/es/utils/random.js +1 -1
- package/es/utils/range.js +1 -1
- package/es/utils/react/RenderCache.js +1 -1
- package/es/utils/react/Slots.js +1 -1
- package/es/utils/react/chain.js +1 -1
- package/es/utils/react/forwardRefWithGenerics.js +1 -1
- package/es/utils/react/index.js +1 -1
- package/es/utils/react/interactions.js +1 -1
- package/es/utils/react/isTextOnly.js +1 -1
- package/es/utils/react/mapProps.js +1 -1
- package/es/utils/react/mergeProps.js +1 -1
- package/es/utils/react/nullableValue.js +1 -1
- package/es/utils/react/resolveIcon.js +1 -1
- package/es/utils/react/sharedStore.js +1 -1
- package/es/utils/react/useCombinedRefs.js +1 -1
- package/es/utils/react/useControlledFocusVisible.js +1 -1
- package/es/utils/react/useEventBus.js +1 -1
- package/es/utils/react/useId.js +1 -1
- package/es/utils/react/useIsDarwin.js +1 -1
- package/es/utils/react/useKeySymbols.js +1 -1
- package/es/utils/react/useLayoutEffect.js +1 -1
- package/es/utils/react/useLocalStorage.js +1 -1
- package/es/utils/react/useQaProps.js +1 -1
- package/es/utils/react/useViewportSize.js +1 -1
- package/es/utils/react/wrapNodeIfPlain.js +1 -1
- package/es/utils/tree.js +1 -1
- package/es/utils/warnings.js +1 -1
- package/es/version.js +2 -2
- package/package.json +2 -2
- package/types/components/actions/Button/Button.d.ts +1 -1
- package/types/components/actions/ItemAction/ItemAction.d.ts +2 -2
- package/types/components/navigation/Tabs/DraggableTabList.d.ts +23 -0
- package/types/components/navigation/Tabs/EditableTitle.d.ts +24 -0
- package/types/components/navigation/Tabs/TabButton.d.ts +22 -0
- package/types/components/navigation/Tabs/TabDropIndicator.d.ts +17 -0
- package/types/components/navigation/Tabs/TabPanel.d.ts +49 -0
- package/types/components/navigation/Tabs/TabPicker.d.ts +23 -0
- package/types/components/navigation/Tabs/Tabs.d.ts +6 -189
- package/types/components/navigation/Tabs/TabsAction.d.ts +38 -0
- package/types/components/navigation/Tabs/TabsContext.d.ts +57 -0
- package/types/components/navigation/Tabs/index.d.ts +3 -2
- package/types/components/navigation/Tabs/styled.d.ts +5927 -0
- package/types/components/navigation/Tabs/types.d.ts +261 -0
- package/types/components/navigation/Tabs/use-tab-editing.d.ts +30 -0
- package/types/components/navigation/Tabs/use-tab-indicator.d.ts +20 -0
- package/types/data/item-themes.d.ts +15 -1
- package/types/tokens/colors.d.ts +2 -0
|
@@ -1,646 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license MIT
|
|
3
3
|
* author: Cube Dev Team
|
|
4
|
-
* @cube-dev/ui-kit v0.
|
|
4
|
+
* @cube-dev/ui-kit v0.104.0
|
|
5
5
|
* Released under the MIT license.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { jsx as _jsx,
|
|
9
|
-
import { Children, forwardRef, isValidElement,
|
|
10
|
-
import {
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
9
|
+
import { Children, forwardRef, isValidElement, useEffect, useMemo, useRef, } from 'react';
|
|
10
|
+
import { useTabList } from 'react-aria';
|
|
11
11
|
import { Item as CollectionItem, useTabListState, } from 'react-stately';
|
|
12
|
-
import { useEvent } from '../../../_internal/hooks/index.js';
|
|
13
|
-
import {
|
|
14
|
-
import { extractStyles, OUTER_STYLES
|
|
15
|
-
import {
|
|
16
|
-
import { ItemAction } from '../../actions/ItemAction/index.js';
|
|
17
|
-
import { Item } from '../../content/Item/index.js';
|
|
12
|
+
import { useEvent, useWarn } from '../../../_internal/hooks/index.js';
|
|
13
|
+
import { DirectionIcon } from '../../../icons/index.js';
|
|
14
|
+
import { extractStyles, OUTER_STYLES } from '../../../tasty/index.js';
|
|
15
|
+
import { mergeProps } from '../../../utils/react/index.js';
|
|
18
16
|
import { useTinyScrollbar } from '../../content/Layout/hooks/useTinyScrollbar.js';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'type=radio | type=file | type=panel': 'stretch',
|
|
29
|
-
},
|
|
30
|
-
overflow: 'visible',
|
|
31
|
-
border: {
|
|
32
|
-
'': 0,
|
|
33
|
-
'(type=default | type=file | type=panel) & has-panels': 'bottom',
|
|
34
|
-
},
|
|
35
|
-
width: {
|
|
36
|
-
'': '100%',
|
|
37
|
-
'type=radio': 'max-content',
|
|
38
|
-
},
|
|
39
|
-
padding: {
|
|
40
|
-
'': 0,
|
|
41
|
-
'type=radio': '.5x',
|
|
42
|
-
},
|
|
43
|
-
radius: {
|
|
44
|
-
'': 0,
|
|
45
|
-
'type=radio': '1cr',
|
|
46
|
-
},
|
|
47
|
-
fill: {
|
|
48
|
-
'': '#clear',
|
|
49
|
-
'type=radio': '#dark.06',
|
|
50
|
-
},
|
|
51
|
-
flexShrink: 0,
|
|
52
|
-
flexGrow: 0,
|
|
53
|
-
$transition: '$tab-transition',
|
|
54
|
-
Prefix: {
|
|
55
|
-
display: 'flex',
|
|
56
|
-
placeItems: 'center',
|
|
57
|
-
placeContent: 'center',
|
|
58
|
-
flexShrink: 0,
|
|
59
|
-
placeSelf: 'center',
|
|
60
|
-
},
|
|
61
|
-
Suffix: {
|
|
62
|
-
display: 'flex',
|
|
63
|
-
placeItems: 'center',
|
|
64
|
-
placeContent: 'center',
|
|
65
|
-
flexShrink: 0,
|
|
66
|
-
placeSelf: 'center',
|
|
67
|
-
},
|
|
68
|
-
// Wrapper for scroll area and scrollbar (scrollbar is positioned relative to this)
|
|
69
|
-
ScrollWrapper: {
|
|
70
|
-
position: 'relative',
|
|
71
|
-
display: 'flex',
|
|
72
|
-
flexGrow: 1,
|
|
73
|
-
flexShrink: 1,
|
|
74
|
-
width: 'min 0',
|
|
75
|
-
overflow: {
|
|
76
|
-
'': 'hidden',
|
|
77
|
-
'type=radio': 'visible',
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
Scroll: {
|
|
81
|
-
position: 'relative',
|
|
82
|
-
display: 'block',
|
|
83
|
-
overflow: {
|
|
84
|
-
'': 'auto hidden',
|
|
85
|
-
'type=radio': 'visible',
|
|
86
|
-
},
|
|
87
|
-
scrollbar: 'none',
|
|
88
|
-
flexGrow: 1,
|
|
89
|
-
width: '100%',
|
|
90
|
-
// Add padding/margin for radio type to allow shadow to render outside
|
|
91
|
-
padding: {
|
|
92
|
-
'': 0,
|
|
93
|
-
'type=radio': '.5x',
|
|
94
|
-
},
|
|
95
|
-
margin: {
|
|
96
|
-
'': 0,
|
|
97
|
-
'type=radio': '-.5x',
|
|
98
|
-
},
|
|
99
|
-
// Use multi-group fade with color tokens for smooth transitions
|
|
100
|
-
fade: '2x left #tabs-fade-left #black, 2x right #tabs-fade-right #black',
|
|
101
|
-
// ##name outputs --name-color (literal CSS property name)
|
|
102
|
-
transition: '##tabs-fade-left $tab-transition ease-in, ##tabs-fade-right $tab-transition ease-in',
|
|
103
|
-
// Transition transparent color: opaque (no fade) -> transparent (fade visible)
|
|
104
|
-
'#tabs-fade-left': {
|
|
105
|
-
'': 'rgb(0 0 0 / 1)',
|
|
106
|
-
'fade-left': 'rgb(0 0 0 / 0)',
|
|
107
|
-
},
|
|
108
|
-
'#tabs-fade-right': {
|
|
109
|
-
'': 'rgb(0 0 0 / 1)',
|
|
110
|
-
'fade-right': 'rgb(0 0 0 / 0)',
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
Container: {
|
|
114
|
-
position: 'relative',
|
|
115
|
-
display: 'grid',
|
|
116
|
-
gridAutoFlow: 'column',
|
|
117
|
-
gridAutoColumns: {
|
|
118
|
-
'': 'auto',
|
|
119
|
-
'type=radio': '1fr',
|
|
120
|
-
},
|
|
121
|
-
gap: {
|
|
122
|
-
'': 0,
|
|
123
|
-
'type=radio': '.5x',
|
|
124
|
-
},
|
|
125
|
-
placeContent: 'start',
|
|
126
|
-
overflow: 'visible',
|
|
127
|
-
width: {
|
|
128
|
-
'': 'max-content',
|
|
129
|
-
'type=radio': '100%',
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
// Custom horizontal scrollbar (tiny) - positioned relative to ScrollWrapper
|
|
133
|
-
ScrollbarH: {
|
|
134
|
-
position: 'absolute',
|
|
135
|
-
bottom: '1px',
|
|
136
|
-
left: '$scrollbar-h-left',
|
|
137
|
-
height: '1ow',
|
|
138
|
-
width: '$scrollbar-h-width',
|
|
139
|
-
radius: 'round',
|
|
140
|
-
fill: '#dark.35',
|
|
141
|
-
opacity: {
|
|
142
|
-
'': 0,
|
|
143
|
-
'focused | scrolling': 1,
|
|
144
|
-
},
|
|
145
|
-
transition: 'opacity 0.15s',
|
|
146
|
-
pointerEvents: 'none',
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
const TabElement = tasty(Item, {
|
|
151
|
-
as: 'button',
|
|
152
|
-
styles: {
|
|
153
|
-
radius: {
|
|
154
|
-
'': false,
|
|
155
|
-
'type=radio': true,
|
|
156
|
-
'type=default': 'top',
|
|
157
|
-
},
|
|
158
|
-
color: {
|
|
159
|
-
'': '#dark-02',
|
|
160
|
-
'type=default & selected': '#purple-text',
|
|
161
|
-
},
|
|
162
|
-
fill: {
|
|
163
|
-
'': '#clear',
|
|
164
|
-
'type=file | type=panel': '#light',
|
|
165
|
-
'(type=file | type=panel | type=radio) & selected': '#white',
|
|
166
|
-
},
|
|
167
|
-
border: {
|
|
168
|
-
'': '0 #clear',
|
|
169
|
-
'type=panel & selected': '1ow #purple bottom',
|
|
170
|
-
},
|
|
171
|
-
preset: {
|
|
172
|
-
'': 't3m',
|
|
173
|
-
'size=small | size=xsmall': 't4',
|
|
174
|
-
'size=large | size=xlarge': 't2m',
|
|
175
|
-
},
|
|
176
|
-
shadow: {
|
|
177
|
-
'': 'none',
|
|
178
|
-
editing: 'inset 0 0 0 1bw #purple-text',
|
|
179
|
-
'type=radio & selected': '$item-shadow',
|
|
180
|
-
},
|
|
181
|
-
Label: {
|
|
182
|
-
placeSelf: {
|
|
183
|
-
'': 'center start',
|
|
184
|
-
'type=radio': 'center start',
|
|
185
|
-
'type=radio & !has-prefix & !has-suffix & !has-icon & !has-right-icon': 'center',
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
const TabContainer = tasty({
|
|
191
|
-
styles: {
|
|
192
|
-
position: 'relative',
|
|
193
|
-
display: 'grid',
|
|
194
|
-
border: {
|
|
195
|
-
'': 0,
|
|
196
|
-
'type=file | type=panel': 'right',
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
// =============================================================================
|
|
201
|
-
// EditableTitle Component (inline title editing)
|
|
202
|
-
// =============================================================================
|
|
203
|
-
const EditableTitleInputElement = tasty({
|
|
204
|
-
as: 'input',
|
|
205
|
-
styles: {
|
|
206
|
-
border: 0,
|
|
207
|
-
padding: 0,
|
|
208
|
-
margin: 0,
|
|
209
|
-
fill: 'transparent',
|
|
210
|
-
outline: 0,
|
|
211
|
-
preset: 'inherit',
|
|
212
|
-
color: 'inherit',
|
|
213
|
-
width: 'initial $input-width 100%',
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
const HiddenMeasure = tasty({
|
|
217
|
-
styles: {
|
|
218
|
-
position: 'absolute',
|
|
219
|
-
visibility: 'hidden',
|
|
220
|
-
whiteSpace: 'pre',
|
|
221
|
-
font: 'inherit',
|
|
222
|
-
pointerEvents: 'none',
|
|
223
|
-
height: 0,
|
|
224
|
-
overflow: 'hidden',
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
function EditableTitle({ title, isEditing, editValue, onEditValueChange, onStartEditing, onSubmit, onCancel, }) {
|
|
228
|
-
const inputRef = useRef(null);
|
|
229
|
-
const measureRef = useRef(null);
|
|
230
|
-
const [inputWidth, setInputWidth] = useState(null);
|
|
231
|
-
const justEnteredEditModeRef = useRef(false);
|
|
232
|
-
// React Aria text field hook
|
|
233
|
-
const { inputProps } = useTextField({
|
|
234
|
-
'aria-label': 'Edit tab title',
|
|
235
|
-
value: editValue,
|
|
236
|
-
onChange: onEditValueChange,
|
|
237
|
-
}, inputRef);
|
|
238
|
-
// Focus and select input when entering edit mode
|
|
239
|
-
useLayoutEffect(() => {
|
|
240
|
-
if (isEditing && inputRef.current) {
|
|
241
|
-
const input = inputRef.current;
|
|
242
|
-
// Set flag to ignore immediate blur events
|
|
243
|
-
justEnteredEditModeRef.current = true;
|
|
244
|
-
input.focus();
|
|
245
|
-
// Use requestAnimationFrame to ensure selection happens after focus
|
|
246
|
-
requestAnimationFrame(() => {
|
|
247
|
-
input.select();
|
|
248
|
-
// Clear the flag after focus is established (allow 2 frames for menu to fully close)
|
|
249
|
-
requestAnimationFrame(() => {
|
|
250
|
-
requestAnimationFrame(() => {
|
|
251
|
-
justEnteredEditModeRef.current = false;
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
justEnteredEditModeRef.current = false;
|
|
258
|
-
}
|
|
259
|
-
}, [isEditing]);
|
|
260
|
-
// Measure text width and update input width
|
|
261
|
-
useLayoutEffect(() => {
|
|
262
|
-
if (isEditing && measureRef.current) {
|
|
263
|
-
const width = measureRef.current.scrollWidth;
|
|
264
|
-
setInputWidth(width);
|
|
265
|
-
}
|
|
266
|
-
}, [isEditing, editValue]);
|
|
267
|
-
const handleKeyDown = useEvent((e) => {
|
|
268
|
-
if (e.key === 'Enter') {
|
|
269
|
-
e.preventDefault();
|
|
270
|
-
onSubmit();
|
|
271
|
-
}
|
|
272
|
-
else if (e.key === 'Escape') {
|
|
273
|
-
e.preventDefault();
|
|
274
|
-
onCancel();
|
|
275
|
-
}
|
|
276
|
-
else if (e.key === 'ArrowLeft' ||
|
|
277
|
-
e.key === 'ArrowRight' ||
|
|
278
|
-
e.key === ' ') {
|
|
279
|
-
// Stop propagation to prevent tab navigation while editing
|
|
280
|
-
e.stopPropagation();
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
const handleBlur = useEvent(() => {
|
|
284
|
-
// Ignore blur events immediately after entering edit mode (menu closing causes focus loss)
|
|
285
|
-
if (justEnteredEditModeRef.current) {
|
|
286
|
-
// Re-focus the input since something else stole focus
|
|
287
|
-
requestAnimationFrame(() => {
|
|
288
|
-
inputRef.current?.focus();
|
|
289
|
-
inputRef.current?.select();
|
|
290
|
-
});
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
// Submit on blur (per user preference)
|
|
294
|
-
onSubmit();
|
|
295
|
-
});
|
|
296
|
-
const handleDoubleClick = useEvent((e) => {
|
|
297
|
-
e.preventDefault();
|
|
298
|
-
e.stopPropagation();
|
|
299
|
-
onStartEditing();
|
|
300
|
-
});
|
|
301
|
-
if (isEditing) {
|
|
302
|
-
// Merge our handlers with React Aria's inputProps
|
|
303
|
-
const mergedProps = {
|
|
304
|
-
...inputProps,
|
|
305
|
-
onKeyDown: (e) => {
|
|
306
|
-
handleKeyDown(e);
|
|
307
|
-
inputProps.onKeyDown?.(e);
|
|
308
|
-
},
|
|
309
|
-
onBlur: (e) => {
|
|
310
|
-
handleBlur();
|
|
311
|
-
inputProps.onBlur?.(e);
|
|
312
|
-
},
|
|
313
|
-
};
|
|
314
|
-
return (_jsxs(_Fragment, { children: [_jsx(HiddenMeasure, { ref: measureRef, "aria-hidden": "true", children: editValue || ' ' }), _jsx(EditableTitleInputElement, { ...mergedProps, ref: inputRef, tokens: { '$input-width': inputWidth ? `${inputWidth}px` : 'auto' } })] }));
|
|
315
|
-
}
|
|
316
|
-
return _jsx("span", { onDoubleClick: handleDoubleClick, children: title });
|
|
317
|
-
}
|
|
318
|
-
const TabPanelElement = tasty({
|
|
319
|
-
as: 'section',
|
|
320
|
-
styles: {
|
|
321
|
-
display: 'contents',
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
const TabIndicatorElement = tasty({
|
|
325
|
-
styles: {
|
|
326
|
-
position: 'absolute',
|
|
327
|
-
bottom: '0',
|
|
328
|
-
left: 0,
|
|
329
|
-
height: '1ow',
|
|
330
|
-
fill: '#purple',
|
|
331
|
-
transition: 'left, width',
|
|
332
|
-
transitionDuration: '.2s',
|
|
333
|
-
transitionTimingFunction: 'ease-out',
|
|
334
|
-
pointerEvents: 'none',
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
/**
|
|
338
|
-
* Hook to track and animate tab indicator position.
|
|
339
|
-
* Returns null if disabled (e.g., for non-default types).
|
|
340
|
-
*/
|
|
341
|
-
function useTabIndicator(containerRef, selectedKey, enabled) {
|
|
342
|
-
const [style, setStyle] = useState(null);
|
|
343
|
-
const cancelRef = useRef(null);
|
|
344
|
-
const updateIndicator = useCallback(() => {
|
|
345
|
-
if (!enabled || !containerRef.current || selectedKey == null) {
|
|
346
|
-
setStyle(null);
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
// Find the selected tab button within the container
|
|
350
|
-
const selectedTab = containerRef.current.querySelector('[aria-selected="true"]');
|
|
351
|
-
if (!selectedTab) {
|
|
352
|
-
setStyle(null);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
const containerRect = containerRef.current.getBoundingClientRect();
|
|
356
|
-
const tabRect = selectedTab.getBoundingClientRect();
|
|
357
|
-
// Only update if dimensions are valid (element has been painted)
|
|
358
|
-
if (tabRect.width > 0) {
|
|
359
|
-
setStyle({
|
|
360
|
-
left: tabRect.left - containerRect.left + containerRef.current.scrollLeft,
|
|
361
|
-
width: tabRect.width,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}, [containerRef, selectedKey, enabled]);
|
|
365
|
-
// Update on selectedKey change - use chainRaf to ensure DOM is fully painted
|
|
366
|
-
useLayoutEffect(() => {
|
|
367
|
-
// Cancel any pending RAF chain
|
|
368
|
-
if (cancelRef.current) {
|
|
369
|
-
cancelRef.current();
|
|
370
|
-
}
|
|
371
|
-
// Schedule update after 2 frames to ensure layout is complete
|
|
372
|
-
cancelRef.current = chainRaf(() => {
|
|
373
|
-
updateIndicator();
|
|
374
|
-
}, 2);
|
|
375
|
-
return () => {
|
|
376
|
-
if (cancelRef.current) {
|
|
377
|
-
cancelRef.current();
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
}, [updateIndicator]);
|
|
381
|
-
// Update on window resize
|
|
382
|
-
useEffect(() => {
|
|
383
|
-
if (!enabled)
|
|
384
|
-
return;
|
|
385
|
-
const handleResize = () => updateIndicator();
|
|
386
|
-
window.addEventListener('resize', handleResize);
|
|
387
|
-
return () => window.removeEventListener('resize', handleResize);
|
|
388
|
-
}, [enabled, updateIndicator]);
|
|
389
|
-
return enabled ? style : null;
|
|
390
|
-
}
|
|
17
|
+
import { DraggableTabList } from './DraggableTabList.js';
|
|
18
|
+
import { TabIndicatorElement, TabsElement } from './styled.js';
|
|
19
|
+
import { TabButton } from './TabButton.js';
|
|
20
|
+
import { CachedPanelRenderer, TabPanelRenderer } from './TabPanel.js';
|
|
21
|
+
import { TabPicker } from './TabPicker.js';
|
|
22
|
+
import { TabsAction } from './TabsAction.js';
|
|
23
|
+
import { TabsProvider } from './TabsContext.js';
|
|
24
|
+
import { useTabEditing } from './use-tab-editing.js';
|
|
25
|
+
import { useTabIndicator } from './use-tab-indicator.js';
|
|
391
26
|
// =============================================================================
|
|
392
27
|
// Helper Functions
|
|
393
28
|
// =============================================================================
|
|
394
29
|
/**
|
|
395
|
-
*
|
|
30
|
+
* Generic helper to check if a child is a specific component by displayName.
|
|
396
31
|
*/
|
|
397
|
-
function
|
|
32
|
+
function isComponentElement(child, displayName) {
|
|
398
33
|
return (isValidElement(child) &&
|
|
399
34
|
typeof child.type === 'function' &&
|
|
400
|
-
child.type.displayName ===
|
|
35
|
+
child.type.displayName === displayName);
|
|
401
36
|
}
|
|
37
|
+
/** Checks if a child is a Tab component. */
|
|
38
|
+
const isTabElement = (child) => isComponentElement(child, 'CubeTab');
|
|
39
|
+
/** Checks if a child is a TabPanel component. */
|
|
40
|
+
const isTabPanelElement = (child) => isComponentElement(child, 'CubeTabPanel');
|
|
41
|
+
/** Checks if a child is a TabList component. */
|
|
42
|
+
const isTabListElement = (child) => isComponentElement(child, 'CubeTabList');
|
|
402
43
|
/**
|
|
403
|
-
*
|
|
44
|
+
* Extracts the raw key from a React element, stripping the ".$" prefix
|
|
45
|
+
* that React adds via Children.map/toArray.
|
|
404
46
|
*/
|
|
405
|
-
function
|
|
406
|
-
|
|
407
|
-
typeof child.type === 'function' &&
|
|
408
|
-
child.type.displayName === 'CubeTabPanel');
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Checks if a child is a TabList component.
|
|
412
|
-
*/
|
|
413
|
-
function isTabListElement(child) {
|
|
414
|
-
return (isValidElement(child) &&
|
|
415
|
-
typeof child.type === 'function' &&
|
|
416
|
-
child.type.displayName === 'CubeTabList');
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Extracts the raw key from a React child (strips the ".$" prefix added by Children.map).
|
|
420
|
-
*
|
|
421
|
-
* Note: All keys are converted to strings for React Aria compatibility.
|
|
422
|
-
* This means numeric keys like `key={1}` become `"1"`.
|
|
423
|
-
*
|
|
424
|
-
* @returns The key as a string, or null if no key is present
|
|
425
|
-
*/
|
|
426
|
-
function getRawKey(child) {
|
|
427
|
-
if (child.key == null)
|
|
47
|
+
function getRawKey(element) {
|
|
48
|
+
if (element.key == null)
|
|
428
49
|
return null;
|
|
429
|
-
const keyStr = String(
|
|
430
|
-
|
|
431
|
-
if (keyStr.startsWith('.$')) {
|
|
432
|
-
return keyStr.slice(2);
|
|
433
|
-
}
|
|
434
|
-
return keyStr;
|
|
50
|
+
const keyStr = String(element.key);
|
|
51
|
+
return keyStr.startsWith('.$') ? keyStr.slice(2) : keyStr;
|
|
435
52
|
}
|
|
436
53
|
// =============================================================================
|
|
437
|
-
// Tab Component (
|
|
54
|
+
// Tab Component (configuration only - not rendered directly)
|
|
438
55
|
// =============================================================================
|
|
439
56
|
function Tab(_props) {
|
|
440
|
-
// This component is never rendered directly - it's used for configuration
|
|
441
|
-
// The actual rendering happens in TabButton
|
|
442
57
|
return null;
|
|
443
58
|
}
|
|
444
59
|
Tab.displayName = 'CubeTab';
|
|
445
|
-
function TabButton({ item, state, tabData, type, size, onDelete, showActionsOnHover: parentShowActionsOnHover, isEditing = false, editValue = '', onEditValueChange, onStartEditing, onSubmitEditing, onCancelEditing, }) {
|
|
446
|
-
const ref = useRef(null);
|
|
447
|
-
const { tabProps } = useTab({ key: item.key }, state, ref);
|
|
448
|
-
const isActive = state.selectedKey === item.key;
|
|
449
|
-
const isDisabled = state.disabledKeys.has(item.key);
|
|
450
|
-
const isDeletable = !!onDelete;
|
|
451
|
-
const isEditable = tabData.isEditable ?? false;
|
|
452
|
-
const effectiveType = tabData.type ?? type ?? 'default';
|
|
453
|
-
const handleDelete = useEvent(() => {
|
|
454
|
-
onDelete?.(item.key);
|
|
455
|
-
});
|
|
456
|
-
const handleStartEditing = useEvent(() => {
|
|
457
|
-
if (!isEditable || isDisabled)
|
|
458
|
-
return;
|
|
459
|
-
const titleText = typeof tabData.title === 'string' ? tabData.title : String(item.key);
|
|
460
|
-
onStartEditing?.(item.key, titleText);
|
|
461
|
-
});
|
|
462
|
-
const handleSubmitEditing = useEvent(() => {
|
|
463
|
-
onSubmitEditing?.(item.key, editValue, tabData.onTitleChange);
|
|
464
|
-
});
|
|
465
|
-
const handleCancelEditing = useEvent(() => {
|
|
466
|
-
onCancelEditing?.();
|
|
467
|
-
});
|
|
468
|
-
const handleEditValueChange = useEvent((value) => {
|
|
469
|
-
onEditValueChange?.(value);
|
|
470
|
-
});
|
|
471
|
-
const mods = useMemo(() => ({
|
|
472
|
-
type: effectiveType,
|
|
473
|
-
active: isActive,
|
|
474
|
-
deletable: isDeletable,
|
|
475
|
-
disabled: isDisabled,
|
|
476
|
-
editing: isEditing,
|
|
477
|
-
}), [effectiveType, isActive, isDeletable, isDisabled, isEditing]);
|
|
478
|
-
// Scroll active tab into view
|
|
479
|
-
useEffect(() => {
|
|
480
|
-
if (ref.current && isActive) {
|
|
481
|
-
ref.current.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });
|
|
482
|
-
}
|
|
483
|
-
}, [isActive]);
|
|
484
|
-
// Build actions for the tab (custom actions + delete button)
|
|
485
|
-
const deleteAction = isDeletable ? (_jsx(ItemAction, { icon: _jsx(CloseIcon, {}), tooltip: "Delete tab", onPress: handleDelete })) : null;
|
|
486
|
-
// Combine tab's custom actions with delete action
|
|
487
|
-
const actions = tabData.actions || deleteAction ? (_jsxs(_Fragment, { children: [tabData.actions, deleteAction] })) : undefined;
|
|
488
|
-
// Determine effective size - map 'medium'/'large' to Item size values
|
|
489
|
-
const isRadioType = effectiveType === 'radio';
|
|
490
|
-
const isFileOrPanelType = effectiveType === 'file' || effectiveType === 'panel';
|
|
491
|
-
const effectiveSize = tabData.size ?? size ?? 'medium';
|
|
492
|
-
// For radio type, use smaller sizes like RadioGroup tabs mode
|
|
493
|
-
let itemSize;
|
|
494
|
-
if (isRadioType) {
|
|
495
|
-
// Map sizes similar to RadioGroup tabs mode
|
|
496
|
-
if (effectiveSize === 'medium') {
|
|
497
|
-
itemSize = 'xsmall';
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
// large -> medium
|
|
501
|
-
itemSize = 'medium';
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
itemSize = effectiveSize === 'large' ? 'large' : 'medium';
|
|
506
|
-
}
|
|
507
|
-
// Determine Item type prop
|
|
508
|
-
let itemType = effectiveType === 'default' ? (isActive ? 'clear' : 'neutral') : 'neutral';
|
|
509
|
-
// Determine shape - file/panel types use sharp edges
|
|
510
|
-
const itemShape = isFileOrPanelType ? 'sharp' : undefined;
|
|
511
|
-
// Determine showActionsOnHover - tab-level overrides parent-level
|
|
512
|
-
const effectiveShowActionsOnHover = tabData.showActionsOnHover ?? parentShowActionsOnHover;
|
|
513
|
-
// Render title with editing support if editable
|
|
514
|
-
const titleContent = isEditable ? (_jsx(EditableTitle, { title: tabData.title, isEditing: isEditing, editValue: editValue, onEditValueChange: handleEditValueChange, onStartEditing: handleStartEditing, onSubmit: handleSubmitEditing, onCancel: handleCancelEditing })) : (tabData.title);
|
|
515
|
-
// Extract tab-specific props and pass through the rest (style props) to the Item
|
|
516
|
-
const { title: _title, content: _content, key: _key, isDisabled: _isDisabled, prerender: _prerender, keepMounted: _keepMounted, size: _size, type: _type, actions: _actions, showActionsOnHover: _showActionsOnHover, isEditable: _isEditable, onTitleChange: _onTitleChange, qa, qaVal, styles, ...itemStyleProps } = tabData;
|
|
517
|
-
return (_jsx(TabContainer, { mods: mods, children: _jsx(TabElement, { preserveActionsSpace: true, showActionsOnHover: effectiveShowActionsOnHover, as: "button", ...tabProps, ...itemStyleProps, ref: ref, qa: qa ?? `Tab-${String(item.key)}`, qaVal: qaVal, styles: styles, mods: mods, isSelected: isActive, isDisabled: isDisabled, size: itemSize, type: itemType, shape: itemShape, actions: actions, children: titleContent }) }));
|
|
518
|
-
}
|
|
519
|
-
function TabPanelRenderer({ tabKey, state, content, prerender, keepMounted, tabPrerender, tabKeepMounted, visitedKeys, panelStyles, qa, qaVal, }) {
|
|
520
|
-
const ref = useRef(null);
|
|
521
|
-
const { tabPanelProps } = useTabPanel({ key: tabKey }, state, ref);
|
|
522
|
-
const isActive = state.selectedKey === tabKey;
|
|
523
|
-
// Determine effective prerender/keepMounted (tab-level overrides global)
|
|
524
|
-
const effectivePrerender = tabPrerender ?? prerender;
|
|
525
|
-
const effectiveKeepMounted = tabKeepMounted ?? keepMounted;
|
|
526
|
-
// Determine if panel should render using shared utility
|
|
527
|
-
if (!shouldRenderPanel(isActive, visitedKeys.has(tabKey), effectivePrerender, effectiveKeepMounted)) {
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
return (_jsx(TabPanelElement, { ...tabPanelProps, ref: ref, qa: qa ?? 'TabPanel', qaVal: qaVal ?? String(tabKey), styles: panelStyles, style: {
|
|
531
|
-
display: isActive ? 'contents' : 'none',
|
|
532
|
-
}, children: content }));
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Determines if a panel should be rendered based on prerender/keepMounted settings.
|
|
536
|
-
*/
|
|
537
|
-
function shouldRenderPanel(isActive, wasVisited, effectivePrerender, effectiveKeepMounted) {
|
|
538
|
-
return (!!effectivePrerender || isActive || (!!effectiveKeepMounted && wasVisited));
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Renders panels with optional content caching.
|
|
542
|
-
* Only the content from renderPanel is cached - the TabPanelRenderer wrapper
|
|
543
|
-
* is always rendered fresh so it can correctly determine the active state.
|
|
544
|
-
*
|
|
545
|
-
* Caching behavior:
|
|
546
|
-
* - By default, panels re-render on every Tabs render (no caching)
|
|
547
|
-
* - When a panel has a non-undefined cache key in `panelCacheKeys`, caching is enabled
|
|
548
|
-
* - Cached content is reused until the cache key changes
|
|
549
|
-
* - Setting a cache key to `undefined` is the same as not having it (no caching)
|
|
550
|
-
*/
|
|
551
|
-
function CachedPanelRenderer({ parsedTabs, explicitPanels, state, renderPanel, panelCacheKeys, prerender, keepMounted, visitedKeys, }) {
|
|
552
|
-
// Cache for rendered content - stores { content, cacheKey } per panel
|
|
553
|
-
const contentCacheRef = useRef(new Map());
|
|
554
|
-
/**
|
|
555
|
-
* Get the cache key for a panel.
|
|
556
|
-
* Returns undefined if no cache key is defined or if set to undefined (no caching).
|
|
557
|
-
*/
|
|
558
|
-
const getCacheKey = (key) => {
|
|
559
|
-
if (!panelCacheKeys)
|
|
560
|
-
return undefined;
|
|
561
|
-
if (Object.prototype.hasOwnProperty.call(panelCacheKeys, key)) {
|
|
562
|
-
const value = panelCacheKeys[key];
|
|
563
|
-
// undefined means no caching
|
|
564
|
-
return value;
|
|
565
|
-
}
|
|
566
|
-
return undefined;
|
|
567
|
-
};
|
|
568
|
-
/**
|
|
569
|
-
* Check if a panel has caching enabled.
|
|
570
|
-
* Only enabled when a non-undefined cache key is defined.
|
|
571
|
-
*/
|
|
572
|
-
const hasCacheKey = (key) => {
|
|
573
|
-
if (!panelCacheKeys)
|
|
574
|
-
return false;
|
|
575
|
-
if (!Object.prototype.hasOwnProperty.call(panelCacheKeys, key))
|
|
576
|
-
return false;
|
|
577
|
-
// undefined value means no caching
|
|
578
|
-
return panelCacheKeys[key] !== undefined;
|
|
579
|
-
};
|
|
580
|
-
// Clean up cache entries for removed tabs
|
|
581
|
-
const currentTabKeys = useMemo(() => new Set(parsedTabs.map((t) => t.key)), [parsedTabs]);
|
|
582
|
-
// Use effect to clean up stale cache entries when tabs change
|
|
583
|
-
useEffect(() => {
|
|
584
|
-
for (const key of contentCacheRef.current.keys()) {
|
|
585
|
-
if (!currentTabKeys.has(key)) {
|
|
586
|
-
contentCacheRef.current.delete(key);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}, [currentTabKeys]);
|
|
590
|
-
return (_jsx(_Fragment, { children: parsedTabs.map((tab) => {
|
|
591
|
-
const explicitPanel = explicitPanels.get(tab.key);
|
|
592
|
-
const tabPrerender = explicitPanel?.prerender ?? tab.prerender;
|
|
593
|
-
const tabKeepMounted = explicitPanel?.keepMounted ?? tab.keepMounted;
|
|
594
|
-
const effectivePrerender = tabPrerender ?? prerender;
|
|
595
|
-
const effectiveKeepMounted = tabKeepMounted ?? keepMounted;
|
|
596
|
-
const isActive = state.selectedKey === tab.key;
|
|
597
|
-
const wasVisited = visitedKeys.has(tab.key);
|
|
598
|
-
if (!shouldRenderPanel(isActive, wasVisited, effectivePrerender, effectiveKeepMounted)) {
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
// Check if this panel has caching enabled
|
|
602
|
-
const isCachingEnabled = hasCacheKey(tab.key);
|
|
603
|
-
let content;
|
|
604
|
-
if (isCachingEnabled) {
|
|
605
|
-
// Caching is enabled for this panel - check cache
|
|
606
|
-
const currentCacheKey = getCacheKey(tab.key);
|
|
607
|
-
const cached = contentCacheRef.current.get(tab.key);
|
|
608
|
-
// Cache hit if keys match (currentCacheKey is guaranteed non-undefined here)
|
|
609
|
-
if (cached !== undefined && cached.cacheKey === currentCacheKey) {
|
|
610
|
-
// Cache hit - use cached content
|
|
611
|
-
content = cached.content;
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
// Cache miss or key changed - compute fresh and cache
|
|
615
|
-
content = renderPanel(tab.key);
|
|
616
|
-
contentCacheRef.current.set(tab.key, {
|
|
617
|
-
content,
|
|
618
|
-
cacheKey: currentCacheKey,
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
else {
|
|
623
|
-
// No caching - always compute fresh
|
|
624
|
-
content = renderPanel(tab.key);
|
|
625
|
-
// Clear any stale cache entry
|
|
626
|
-
contentCacheRef.current.delete(tab.key);
|
|
627
|
-
}
|
|
628
|
-
return (_jsx(TabPanelRenderer, { tabKey: tab.key, state: state, content: content, prerender: prerender, keepMounted: keepMounted, tabPrerender: tabPrerender, tabKeepMounted: tabKeepMounted, visitedKeys: visitedKeys, panelStyles: explicitPanel?.styles, qa: explicitPanel?.qa, qaVal: explicitPanel?.qaVal }, tab.key));
|
|
629
|
-
}) }));
|
|
630
|
-
}
|
|
631
60
|
// =============================================================================
|
|
632
|
-
// TabPanel Component (
|
|
61
|
+
// TabPanel Component (configuration only - not rendered directly)
|
|
633
62
|
// =============================================================================
|
|
634
63
|
function TabPanel(_props) {
|
|
635
|
-
// This component is never rendered directly - it's used for configuration
|
|
636
64
|
return null;
|
|
637
65
|
}
|
|
638
66
|
TabPanel.displayName = 'CubeTabPanel';
|
|
639
67
|
// =============================================================================
|
|
640
|
-
// TabList Component (
|
|
68
|
+
// TabList Component (configuration only - not rendered directly)
|
|
641
69
|
// =============================================================================
|
|
642
70
|
function TabList(_props) {
|
|
643
|
-
// This component is never rendered directly - it's used for configuration
|
|
644
71
|
return null;
|
|
645
72
|
}
|
|
646
73
|
TabList.displayName = 'CubeTabList';
|
|
@@ -648,47 +75,21 @@ TabList.displayName = 'CubeTabList';
|
|
|
648
75
|
// Main Tabs Component
|
|
649
76
|
// =============================================================================
|
|
650
77
|
function TabsComponent(props, ref) {
|
|
651
|
-
const { label = 'Tabs', defaultActiveKey, activeKey, size, type = 'default', onChange, onDelete, onTitleChange, showActionsOnHover, children, prefix, suffix, prerender = false, keepMounted = false, qa = 'Tabs', renderPanel, panelCacheKeys, ...otherProps } = props;
|
|
652
|
-
// Extract outer styles
|
|
78
|
+
const { label = 'Tabs', defaultActiveKey, activeKey, size, type = 'default', onChange, onDelete, onTitleChange, showActionsOnHover, isEditable: parentIsEditable, menu: parentMenu, menuTriggerProps: parentMenuTriggerProps, menuProps: parentMenuProps, contextMenu: parentContextMenu, onAction: parentOnAction, children, prefix, suffix, prerender = false, keepMounted = false, qa = 'Tabs', renderPanel, panelCacheKeys, isReorderable = false, keyOrder, onReorder, showTabPicker = false, showScrollArrows = false, tabPickerPosition = 'suffix', scrollArrowsPosition = 'suffix', ...otherProps } = props;
|
|
79
|
+
// Extract outer styles
|
|
653
80
|
const combinedStyles = extractStyles(otherProps, OUTER_STYLES);
|
|
654
|
-
// DOM element
|
|
655
|
-
const elementRef = useRef(null);
|
|
81
|
+
// DOM element refs
|
|
656
82
|
const listRef = useRef(null);
|
|
657
83
|
const scrollRef = useRef(null);
|
|
658
84
|
// Track visited tabs for keepMounted functionality
|
|
659
85
|
const visitedKeysRef = useRef(new Set());
|
|
660
86
|
// =========================================================================
|
|
661
|
-
// Tab Title Editing
|
|
87
|
+
// Tab Title Editing Hook
|
|
88
|
+
// =========================================================================
|
|
89
|
+
const { editingKey, editValue, setEditValue, startEditing, cancelEditing, submitEditing, } = useTabEditing({ onChange, onTitleChange });
|
|
662
90
|
// =========================================================================
|
|
663
|
-
const [editingKey, setEditingKey] = useState(null);
|
|
664
|
-
const [editValue, setEditValue] = useState('');
|
|
665
|
-
const startEditing = useCallback((key, currentTitle) => {
|
|
666
|
-
// Also select the tab being edited
|
|
667
|
-
onChange?.(key);
|
|
668
|
-
chainRaf(() => {
|
|
669
|
-
setEditingKey(key);
|
|
670
|
-
setEditValue(currentTitle);
|
|
671
|
-
}, 2);
|
|
672
|
-
}, [onChange]);
|
|
673
|
-
const cancelEditing = useCallback(() => {
|
|
674
|
-
setEditingKey(null);
|
|
675
|
-
setEditValue('');
|
|
676
|
-
}, []);
|
|
677
|
-
const submitEditing = useCallback((key, newTitle, tabOnTitleChange) => {
|
|
678
|
-
const trimmed = newTitle.trim();
|
|
679
|
-
if (trimmed) {
|
|
680
|
-
// Tab-level callback takes precedence
|
|
681
|
-
if (tabOnTitleChange) {
|
|
682
|
-
tabOnTitleChange(trimmed);
|
|
683
|
-
}
|
|
684
|
-
else if (onTitleChange) {
|
|
685
|
-
onTitleChange(key, trimmed);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
setEditingKey(null);
|
|
689
|
-
setEditValue('');
|
|
690
|
-
}, [onTitleChange]);
|
|
691
91
|
// Parse children to extract tabs and explicit panels
|
|
92
|
+
// =========================================================================
|
|
692
93
|
const { parsedTabs, explicitPanels, hasAnyContent } = useMemo(() => {
|
|
693
94
|
const childArray = Children.toArray(children);
|
|
694
95
|
const tabs = [];
|
|
@@ -724,16 +125,15 @@ function TabsComponent(props, ref) {
|
|
|
724
125
|
let hasContent = panels.size > 0;
|
|
725
126
|
for (const child of tabChildren) {
|
|
726
127
|
if (isTabElement(child)) {
|
|
727
|
-
// Get key from the element's key prop or id prop (convert to string)
|
|
728
128
|
const key = getRawKey(child) ?? child.props.id;
|
|
729
129
|
if (key != null) {
|
|
730
|
-
const { id: _id, children:
|
|
130
|
+
const { id: _id, children: tabContent, ...tabProps } = child.props;
|
|
731
131
|
tabs.push({
|
|
732
132
|
...tabProps,
|
|
733
133
|
key,
|
|
734
|
-
content:
|
|
134
|
+
content: tabContent,
|
|
735
135
|
});
|
|
736
|
-
if (
|
|
136
|
+
if (tabContent != null) {
|
|
737
137
|
hasContent = true;
|
|
738
138
|
}
|
|
739
139
|
}
|
|
@@ -754,46 +154,47 @@ function TabsComponent(props, ref) {
|
|
|
754
154
|
}
|
|
755
155
|
}
|
|
756
156
|
}, [currentTabKeysSet]);
|
|
757
|
-
//
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
157
|
+
// =========================================================================
|
|
158
|
+
// Order tabs according to keyOrder
|
|
159
|
+
// =========================================================================
|
|
160
|
+
const orderedParsedTabs = useMemo(() => {
|
|
161
|
+
if (!keyOrder || keyOrder.length === 0) {
|
|
162
|
+
return parsedTabs;
|
|
163
|
+
}
|
|
164
|
+
const tabMap = new Map();
|
|
764
165
|
for (const tab of parsedTabs) {
|
|
765
|
-
|
|
166
|
+
tabMap.set(tab.key, tab);
|
|
766
167
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
// Convert key to string for internal lookup
|
|
774
|
-
const keyStr = String(key);
|
|
775
|
-
const tabData = tabDataMap.get(keyStr);
|
|
776
|
-
if (tabData?.isEditable && !tabData?.isDisabled) {
|
|
777
|
-
const titleText = typeof tabData.title === 'string'
|
|
778
|
-
? tabData.title
|
|
779
|
-
: String(tabData.key);
|
|
780
|
-
startEditing(keyStr, titleText);
|
|
168
|
+
const ordered = [];
|
|
169
|
+
for (const key of keyOrder) {
|
|
170
|
+
const tab = tabMap.get(String(key));
|
|
171
|
+
if (tab) {
|
|
172
|
+
ordered.push(tab);
|
|
173
|
+
tabMap.delete(String(key));
|
|
781
174
|
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
|
|
175
|
+
}
|
|
176
|
+
// Append any tabs not in keyOrder
|
|
177
|
+
for (const tab of parsedTabs) {
|
|
178
|
+
if (tabMap.has(tab.key)) {
|
|
179
|
+
ordered.push(tab);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return ordered;
|
|
183
|
+
}, [parsedTabs, keyOrder]);
|
|
184
|
+
// Create collection items for React Stately
|
|
185
|
+
const collectionItems = useMemo(() => {
|
|
186
|
+
return orderedParsedTabs.map((tab) => (_jsx(CollectionItem, { textValue: typeof tab.title === 'string' ? tab.title : String(tab.key), children: tab.title }, tab.key)));
|
|
187
|
+
}, [orderedParsedTabs]);
|
|
785
188
|
// Determine disabled keys
|
|
786
189
|
const disabledKeys = useMemo(() => {
|
|
787
190
|
return new Set(parsedTabs.filter((tab) => tab.isDisabled).map((tab) => tab.key));
|
|
788
191
|
}, [parsedTabs]);
|
|
789
192
|
// Handle selection change
|
|
790
193
|
const handleSelectionChange = useEvent((key) => {
|
|
791
|
-
// Convert to string for internal tracking
|
|
792
194
|
visitedKeysRef.current.add(String(key));
|
|
793
195
|
onChange?.(key);
|
|
794
196
|
});
|
|
795
197
|
// Convert keys to strings for React Aria compatibility
|
|
796
|
-
// (all internal tab keys are strings via getRawKey)
|
|
797
198
|
const selectedKey = activeKey != null ? String(activeKey) : undefined;
|
|
798
199
|
const defaultSelectedKey = defaultActiveKey != null ? String(defaultActiveKey) : undefined;
|
|
799
200
|
// Create aria props for useTabListState
|
|
@@ -822,34 +223,155 @@ function TabsComponent(props, ref) {
|
|
|
822
223
|
}, [state.selectedKey]);
|
|
823
224
|
// Get tablist props from react-aria
|
|
824
225
|
const { tabListProps } = useTabList(ariaProps, state, listRef);
|
|
825
|
-
//
|
|
826
|
-
const
|
|
827
|
-
|
|
226
|
+
// Handle selection from TabPicker (needs to update internal state in uncontrolled mode)
|
|
227
|
+
const handleTabPickerSelect = useEvent((key) => {
|
|
228
|
+
// Update internal state (for uncontrolled mode)
|
|
229
|
+
state.setSelectedKey(key);
|
|
230
|
+
// Also call the external onChange handler
|
|
231
|
+
handleSelectionChange(key);
|
|
232
|
+
});
|
|
233
|
+
// =========================================================================
|
|
234
|
+
// Tab Indicator (for default type)
|
|
235
|
+
// =========================================================================
|
|
236
|
+
// Create order token that changes when tab order changes (for indicator recalculation)
|
|
237
|
+
const orderToken = useMemo(() => orderedParsedTabs.map((t) => t.key).join(','), [orderedParsedTabs]);
|
|
238
|
+
const indicatorStyle = useTabIndicator(listRef, state.selectedKey, type === 'default' || type === 'narrow', orderToken);
|
|
239
|
+
// =========================================================================
|
|
240
|
+
// Tiny Scrollbar (not for radio type)
|
|
241
|
+
// =========================================================================
|
|
828
242
|
const isTinyScrollbar = type !== 'radio';
|
|
829
243
|
const { handleHStyle, hasOverflowX, isScrolling, isAtStartX, isAtEndX } = useTinyScrollbar(scrollRef, isTinyScrollbar);
|
|
830
244
|
const hasPanels = hasAnyContent || !!renderPanel;
|
|
245
|
+
// =========================================================================
|
|
246
|
+
// Tab Picker visibility
|
|
247
|
+
// =========================================================================
|
|
248
|
+
useWarn(showTabPicker && type === 'radio', {
|
|
249
|
+
key: ['tabs-tabpicker-radio-unsupported'],
|
|
250
|
+
args: [
|
|
251
|
+
'Tabs:',
|
|
252
|
+
'`showTabPicker` is not supported when `type="radio"`. The TabPicker will not be rendered.',
|
|
253
|
+
],
|
|
254
|
+
});
|
|
255
|
+
const shouldShowTabPicker = type !== 'radio' &&
|
|
256
|
+
(showTabPicker === true || (showTabPicker === 'auto' && hasOverflowX));
|
|
257
|
+
// =========================================================================
|
|
258
|
+
// Scroll Arrows visibility and handlers
|
|
259
|
+
// =========================================================================
|
|
260
|
+
useWarn(showScrollArrows && type === 'radio', {
|
|
261
|
+
key: ['tabs-scrollarrows-radio-unsupported'],
|
|
262
|
+
args: [
|
|
263
|
+
'Tabs:',
|
|
264
|
+
'`showScrollArrows` is not supported when `type="radio"`. The scroll arrows will not be rendered.',
|
|
265
|
+
],
|
|
266
|
+
});
|
|
267
|
+
const shouldShowScrollArrows = type !== 'radio' &&
|
|
268
|
+
(showScrollArrows === true ||
|
|
269
|
+
(showScrollArrows === 'auto' && hasOverflowX));
|
|
270
|
+
const handleScrollLeft = useEvent(() => {
|
|
271
|
+
const el = scrollRef.current;
|
|
272
|
+
if (el) {
|
|
273
|
+
el.scrollTo({
|
|
274
|
+
left: el.scrollLeft - el.clientWidth,
|
|
275
|
+
behavior: 'smooth',
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
const handleScrollRight = useEvent(() => {
|
|
280
|
+
const el = scrollRef.current;
|
|
281
|
+
if (el) {
|
|
282
|
+
el.scrollTo({
|
|
283
|
+
left: el.scrollLeft + el.clientWidth,
|
|
284
|
+
behavior: 'smooth',
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
// =========================================================================
|
|
289
|
+
// Base Context Value (without drag/drop states)
|
|
290
|
+
// =========================================================================
|
|
291
|
+
const baseContextValue = useMemo(() => ({
|
|
292
|
+
state,
|
|
293
|
+
type,
|
|
294
|
+
size,
|
|
295
|
+
showActionsOnHover,
|
|
296
|
+
isEditable: parentIsEditable,
|
|
297
|
+
menu: parentMenu,
|
|
298
|
+
menuTriggerProps: parentMenuTriggerProps,
|
|
299
|
+
menuProps: parentMenuProps,
|
|
300
|
+
contextMenu: parentContextMenu,
|
|
301
|
+
onDelete,
|
|
302
|
+
onAction: parentOnAction,
|
|
303
|
+
editingKey,
|
|
304
|
+
editValue,
|
|
305
|
+
setEditValue,
|
|
306
|
+
startEditing,
|
|
307
|
+
submitEditing,
|
|
308
|
+
cancelEditing,
|
|
309
|
+
}), [
|
|
310
|
+
state,
|
|
311
|
+
type,
|
|
312
|
+
size,
|
|
313
|
+
showActionsOnHover,
|
|
314
|
+
parentIsEditable,
|
|
315
|
+
parentMenu,
|
|
316
|
+
parentMenuTriggerProps,
|
|
317
|
+
parentMenuProps,
|
|
318
|
+
parentContextMenu,
|
|
319
|
+
onDelete,
|
|
320
|
+
parentOnAction,
|
|
321
|
+
editingKey,
|
|
322
|
+
editValue,
|
|
323
|
+
setEditValue,
|
|
324
|
+
startEditing,
|
|
325
|
+
submitEditing,
|
|
326
|
+
cancelEditing,
|
|
327
|
+
]);
|
|
328
|
+
// Helper to create full context value with optional drag/drop states
|
|
329
|
+
const createContextValue = (dragState, dropState) => ({
|
|
330
|
+
...baseContextValue,
|
|
331
|
+
dragState,
|
|
332
|
+
dropState,
|
|
333
|
+
});
|
|
334
|
+
// =========================================================================
|
|
335
|
+
// Tab List Content Renderer
|
|
336
|
+
// =========================================================================
|
|
337
|
+
const renderTabListContent = (contextValue, collectionProps = {}) => (_jsxs("div", { ...mergeProps(tabListProps, collectionProps), ref: listRef, "data-element": "Container", children: [_jsx(TabsProvider, { value: contextValue, children: orderedParsedTabs.map((tab, index) => {
|
|
338
|
+
const item = state.collection.getItem(tab.key);
|
|
339
|
+
if (!item)
|
|
340
|
+
return null;
|
|
341
|
+
return (_jsx(TabButton, { item: item, tabData: tab, isLastTab: index === orderedParsedTabs.length - 1 }, item.key));
|
|
342
|
+
}) }), indicatorStyle && (_jsx(TabIndicatorElement, { style: {
|
|
343
|
+
left: indicatorStyle.left,
|
|
344
|
+
width: indicatorStyle.width,
|
|
345
|
+
} }))] }));
|
|
346
|
+
// =========================================================================
|
|
347
|
+
// Mods for styling
|
|
348
|
+
// =========================================================================
|
|
831
349
|
const mods = useMemo(() => ({
|
|
832
350
|
type,
|
|
351
|
+
size,
|
|
833
352
|
deletable: !!onDelete,
|
|
834
353
|
scrolling: isScrolling,
|
|
835
354
|
'fade-left': !isAtStartX,
|
|
836
355
|
'fade-right': !isAtEndX,
|
|
837
356
|
'has-panels': hasPanels,
|
|
838
|
-
}), [type, onDelete, isScrolling, isAtStartX, isAtEndX, hasPanels]);
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
357
|
+
}), [type, size, onDelete, isScrolling, isAtStartX, isAtEndX, hasPanels]);
|
|
358
|
+
// =========================================================================
|
|
359
|
+
// Action Elements (TabPicker and Scroll Arrows)
|
|
360
|
+
// =========================================================================
|
|
361
|
+
const scrollArrowsElement = shouldShowScrollArrows ? (_jsxs(_Fragment, { children: [_jsx(TabsAction, { icon: _jsx(DirectionIcon, { to: "left" }), "aria-label": "Scroll tabs left", isDisabled: isAtStartX, onPress: handleScrollLeft }), _jsx(TabsAction, { icon: _jsx(DirectionIcon, { to: "right" }), "aria-label": "Scroll tabs right", isDisabled: isAtEndX, onPress: handleScrollRight })] })) : null;
|
|
362
|
+
const tabPickerElement = shouldShowTabPicker ? (_jsx(TabPicker, { tabs: orderedParsedTabs, selectedKey: state.selectedKey, size: size, type: type, onSelect: handleTabPickerSelect, onDelete: onDelete })) : null;
|
|
363
|
+
// Determine which actions go in prefix/suffix
|
|
364
|
+
// In prefix: TabPicker first (left), then scroll arrows (right)
|
|
365
|
+
// In suffix: scroll arrows first (left), then TabPicker (right)
|
|
366
|
+
const prefixHasActions = (shouldShowTabPicker && tabPickerPosition === 'prefix') ||
|
|
367
|
+
(shouldShowScrollArrows && scrollArrowsPosition === 'prefix');
|
|
368
|
+
const suffixHasActions = (shouldShowTabPicker && tabPickerPosition === 'suffix') ||
|
|
369
|
+
(shouldShowScrollArrows && scrollArrowsPosition === 'suffix');
|
|
370
|
+
// Wrap with TabsProvider so prefix/suffix can access context (size, type)
|
|
371
|
+
// The inner TabsProvider in renderTabListContent will override for tab buttons
|
|
372
|
+
return (_jsxs(TabsProvider, { value: baseContextValue, children: [_jsxs(TabsElement, { ref: ref, qa: qa, mods: mods, styles: combinedStyles, style: handleHStyle, "data-size": size, children: [prefix || prefixHasActions ? (_jsxs("div", { "data-element": "Prefix", children: [tabPickerPosition === 'prefix' && tabPickerElement, scrollArrowsPosition === 'prefix' && scrollArrowsElement, prefix] })) : null, _jsxs("div", { "data-element": "ScrollWrapper", children: [_jsx("div", { ref: scrollRef, "data-element": "Scroll", children: isReorderable ? (_jsx(DraggableTabList, { state: state, listRef: listRef, orderedKeys: orderedParsedTabs.map((t) => t.key), onReorder: onReorder, children: (dragState, dropState, collectionProps) => renderTabListContent(createContextValue(dragState, dropState), collectionProps) })) : (renderTabListContent(createContextValue())) }), isTinyScrollbar && hasOverflowX && _jsx("div", { "data-element": "ScrollbarH" })] }), suffix || suffixHasActions ? (_jsxs("div", { "data-element": "Suffix", children: [scrollArrowsPosition === 'suffix' && scrollArrowsElement, tabPickerPosition === 'suffix' && tabPickerElement, suffix] })) : null] }), renderPanel && (_jsx(CachedPanelRenderer, { parsedTabs: parsedTabs, explicitPanels: explicitPanels, state: state, renderPanel: renderPanel, panelCacheKeys: panelCacheKeys, prerender: prerender, keepMounted: keepMounted, visitedKeys: visitedKeysRef.current })), !renderPanel &&
|
|
850
373
|
hasAnyContent &&
|
|
851
374
|
parsedTabs.map((tab) => {
|
|
852
|
-
// Use explicit panel if provided, otherwise use tab's content
|
|
853
375
|
const explicitPanel = explicitPanels.get(tab.key);
|
|
854
376
|
const content = explicitPanel?.content ?? tab.content;
|
|
855
377
|
if (content == null)
|
|
@@ -866,8 +388,6 @@ const _Tabs = forwardRef(TabsComponent);
|
|
|
866
388
|
* Built with React Aria for full accessibility support.
|
|
867
389
|
*
|
|
868
390
|
* **Note:** Tab keys are internally converted to strings for React Aria compatibility.
|
|
869
|
-
* When using `activeKey`, `onChange`, etc., be aware that numeric keys will be
|
|
870
|
-
* converted to their string equivalents.
|
|
871
391
|
*
|
|
872
392
|
* @example
|
|
873
393
|
* // Simple usage
|
|
@@ -893,28 +413,13 @@ const _Tabs = forwardRef(TabsComponent);
|
|
|
893
413
|
* <Tabs.Panel key="tab1">Content 1</Tabs.Panel>
|
|
894
414
|
* <Tabs.Panel key="tab2">Content 2</Tabs.Panel>
|
|
895
415
|
* </Tabs>
|
|
896
|
-
*
|
|
897
|
-
* @example
|
|
898
|
-
* // Optimized lazy rendering with renderPanel
|
|
899
|
-
* <Tabs
|
|
900
|
-
* defaultActiveKey="tab1"
|
|
901
|
-
* renderPanel={(key) => {
|
|
902
|
-
* switch (key) {
|
|
903
|
-
* case 'tab1': return <ExpensiveComponent />;
|
|
904
|
-
* case 'tab2': return <AnotherExpensive />;
|
|
905
|
-
* default: return null;
|
|
906
|
-
* }
|
|
907
|
-
* }}
|
|
908
|
-
* >
|
|
909
|
-
* <Tab key="tab1" title="Tab 1" />
|
|
910
|
-
* <Tab key="tab2" title="Tab 2" />
|
|
911
|
-
* </Tabs>
|
|
912
416
|
*/
|
|
913
417
|
export const Tabs = Object.assign(_Tabs, {
|
|
914
418
|
Tab,
|
|
915
419
|
List: TabList,
|
|
916
420
|
Panel: TabPanel,
|
|
421
|
+
Action: TabsAction,
|
|
917
422
|
});
|
|
918
|
-
export { Tab, TabList, TabPanel };
|
|
423
|
+
export { Tab, TabList, TabPanel, TabsAction };
|
|
919
424
|
|
|
920
425
|
|