From 696eb6dac337dec1e5d81d5609719b74b88854f7 Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Tue, 25 Nov 2025 14:57:25 +0100 Subject: [PATCH 01/25] add a vertical separator for tabs --- .../src/components/tab/tab.tsx | 7 ++ .../src/components/tabs_bar/tabs_bar.tsx | 84 +++++++++++-------- .../tab_with_background.tsx | 19 ++++- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx index 0dc2c45c75915..54a0927e7f8a9 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx @@ -40,6 +40,8 @@ export interface TabProps { isSelected: boolean; isUnsaved?: boolean; isDragging?: boolean; + hideRightSeparator?: boolean; + onHoverChange?: (itemId: string, isHovered: boolean) => void; dragHandleProps?: DraggableProvidedDragHandleProps | null; tabContentId: string; tabsSizeConfig: TabsSizeConfig; @@ -69,6 +71,8 @@ export const Tab: React.FC = (props) => { isSelected, isUnsaved, isDragging, + hideRightSeparator, + onHoverChange, dragHandleProps, tabContentId, tabsSizeConfig, @@ -296,7 +300,10 @@ export const Tab: React.FC = (props) => { data-test-subj={`unifiedTabs_tab_${item.id}`} isSelected={isSelected} isDragging={isDragging} + hideRightSeparator={hideRightSeparator} services={services} + onMouseEnter={() => onHoverChange?.(item.id, true)} + onMouseLeave={() => onHoverChange?.(item.id, false)} > {mainTabContent} diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx index 6f74d9b16302b..557e7a7eba8c1 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx @@ -112,6 +112,7 @@ export const TabsBar = forwardRef( componentRef ) => { const { euiTheme } = useEuiTheme(); + const [hoveredTabId, setHoveredTabId] = useState(null); const [tabsContainerWithPlusElement, setTabsContainerWithPlusElement] = useState(null); const [tabsContainerElement, setTabsContainerElement] = useState(null); @@ -130,6 +131,10 @@ export const TabsBar = forwardRef( [onEBTEvent] ); + const handleHoverChange = useCallback((itemId: string, isHovered: boolean) => { + setHoveredTabId(isHovered ? itemId : null); + }, []); + const moveFocusToNextSelectedItem = useCallback((item: TabItem) => { moveFocusToItemIdRef.current = item.id; }, []); @@ -285,40 +290,51 @@ export const TabsBar = forwardRef( */} {/* Render each tab, optionally wrapped with drag functionality */} - {items.map((item, index) => ( - /* - OptionalDraggable uses render prop pattern to conditionally wrap each tab with EuiDraggable. - */ - - {/* Render prop receives drag-related props when drag is enabled */} - {({ dragHandleProps, isDragging }) => ( - 1 ? onClose : undefined} // prevents closing the last tab - disableCloseButton={disableCloseButton} - disableInlineLabelEditing={disableInlineLabelEditing} - disableDragAndDrop={disableDragAndDrop} - /> - )} - - ))} + {items.map((item, index) => { + const nextItem = items[index + 1]; + const hideRightSeparator = + item.id === hoveredTabId || // hide own separator if hovered + item.id === selectedItem?.id || // hide own separator if selected + nextItem?.id === selectedItem?.id || // hide left sibling separator if next is selected + nextItem?.id === hoveredTabId; // hide left sibling separator if next is hovered + + return ( + /* + OptionalDraggable uses render prop pattern to conditionally wrap each tab with EuiDraggable. + */ + + {/* Render prop receives drag-related props when drag is enabled */} + {({ dragHandleProps, isDragging }) => ( + 1 ? onClose : undefined} // prevents closing the last tab + disableCloseButton={disableCloseButton} + disableInlineLabelEditing={disableInlineLabelEditing} + disableDragAndDrop={disableDragAndDrop} + /> + )} + + ); + })} diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 8d290a558a6f8..a5cb79c3b4067 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -15,12 +15,13 @@ import type { TabsServices } from '../../types'; export interface TabWithBackgroundProps extends HTMLAttributes { isSelected: boolean; isDragging?: boolean; + hideRightSeparator?: boolean; services: TabsServices; children: React.ReactNode; } export const TabWithBackground = React.forwardRef( - ({ isSelected, isDragging, services, children, ...otherProps }, ref) => { + ({ isSelected, isDragging, hideRightSeparator, services, children, ...otherProps }, ref) => { const euiThemeContext = useEuiTheme(); const { euiTheme } = euiThemeContext; @@ -30,6 +31,7 @@ export const TabWithBackground = React.forwardRef
Date: Tue, 25 Nov 2025 15:05:20 +0100 Subject: [PATCH 02/25] adjust border --- .../tabs_visual_glue_to_app_container/tab_with_background.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index a5cb79c3b4067..0ba369228e329 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -68,7 +68,7 @@ export const TabWithBackground = React.forwardRef Date: Tue, 25 Nov 2025 14:37:53 +0000 Subject: [PATCH 03/25] Changes from node scripts/regenerate_moon_projects.js --update --- packages/kbn-check-saved-objects-cli/moon.yml | 3 +++ x-pack/solutions/observability/test/moon.yml | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/kbn-check-saved-objects-cli/moon.yml b/packages/kbn-check-saved-objects-cli/moon.yml index be7edc021ab8f..e5794979cd906 100644 --- a/packages/kbn-check-saved-objects-cli/moon.yml +++ b/packages/kbn-check-saved-objects-cli/moon.yml @@ -35,6 +35,9 @@ dependsOn: - '@kbn/core-saved-objects-server-internal' - '@kbn/core-root-server-internal' - '@kbn/core-test-helpers-so-type-serializer' + - '@kbn/core-saved-objects-api-server' + - '@kbn/migrator-test-kit' + - '@kbn/config-schema' tags: - shared-common - package diff --git a/x-pack/solutions/observability/test/moon.yml b/x-pack/solutions/observability/test/moon.yml index 6fa817d2b1850..c1554db1e2f73 100644 --- a/x-pack/solutions/observability/test/moon.yml +++ b/x-pack/solutions/observability/test/moon.yml @@ -84,9 +84,6 @@ dependsOn: - '@kbn/observability-ai-assistant-app-plugin' - '@kbn/dev-utils' - '@kbn/serverless-observability-settings' - - '@kbn/cypress-config' - - '@kbn/dev-proc-runner' - - '@kbn/cypress-test-helper' - '@kbn/streams-schema' - '@kbn/data-quality' - '@kbn/onechat-common' From 7311ccfaef02f3f5f069723a9b56c24c54d70449 Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Tue, 25 Nov 2025 15:42:39 +0100 Subject: [PATCH 04/25] adjust offset --- .../tabs_visual_glue_to_app_container/tab_with_background.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 0ba369228e329..fc2a0dddd6ef4 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -64,7 +64,9 @@ export const TabWithBackground = React.forwardRef Date: Tue, 25 Nov 2025 15:40:24 +0000 Subject: [PATCH 05/25] Changes from node scripts/regenerate_moon_projects.js --update --- x-pack/solutions/security/test/moon.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/solutions/security/test/moon.yml b/x-pack/solutions/security/test/moon.yml index 2b32f900a757f..67af1f662b975 100644 --- a/x-pack/solutions/security/test/moon.yml +++ b/x-pack/solutions/security/test/moon.yml @@ -53,6 +53,7 @@ dependsOn: - '@kbn/management-settings-ids' - '@kbn/connector-schemas' - '@kbn/cloud-security-posture-graph' + - '@kbn/securitysolution-list-constants' tags: - test-helper - package From 6224ef6d8a048fcf159a5f1711a2e363100984e1 Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Thu, 27 Nov 2025 13:47:08 +0100 Subject: [PATCH 06/25] fix border radius of loading spinner --- .../kbn-unified-tabs/src/components/tab/tab.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx index 54a0927e7f8a9..f0bd22e002a17 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx @@ -221,7 +221,16 @@ export const Tab: React.FC = (props) => { ) : (
{previewData?.status === TabStatus.RUNNING && ( - + )} Date: Thu, 27 Nov 2025 14:00:10 +0100 Subject: [PATCH 07/25] adjust min tab width --- src/platform/packages/shared/kbn-unified-tabs/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts index 2867a36d6aa61..18a3d02a0c6c3 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts +++ b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts @@ -10,7 +10,7 @@ export const MAX_TAB_LABEL_LENGTH = 120; export const MAX_TAB_WIDTH = 280; -export const MIN_TAB_WIDTH = 112; +export const MIN_TAB_WIDTH = 90; export const PREVIEW_WIDTH = 280; From c42745964234d37b443e58bd073e078f17581765 Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Thu, 27 Nov 2025 16:58:27 +0100 Subject: [PATCH 08/25] dismiss action popover on tab change --- .../kbn-unified-tabs/src/components/tab/tab.tsx | 11 +++++++++++ .../src/components/tabs_bar/tabs_bar.tsx | 1 + 2 files changed, 12 insertions(+) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx index f0bd22e002a17..cce26ad6941e7 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.tsx @@ -38,6 +38,7 @@ import { useTabLabelWidth } from './use_tab_label_width'; export interface TabProps { item: TabItem; isSelected: boolean; + selectedItemId?: string; isUnsaved?: boolean; isDragging?: boolean; hideRightSeparator?: boolean; @@ -69,6 +70,7 @@ export const Tab: React.FC = (props) => { const { item, isSelected, + selectedItemId, isUnsaved, isDragging, hideRightSeparator, @@ -93,6 +95,7 @@ export const Tab: React.FC = (props) => { const [isInlineEditActive, setIsInlineEditActive] = useState(false); const [showPreview, setShowPreview] = useState(false); const [isActionPopoverOpen, setActionPopover] = useState(false); + const prevSelectedItemIdRef = useRef(selectedItemId); const previewData = useMemo(() => getPreviewData?.(item), [getPreviewData, item]); const hidePreview = useCallback(() => setShowPreview(false), [setShowPreview]); @@ -192,6 +195,14 @@ export const Tab: React.FC = (props) => { } }, [isInlineEditActive, isSelected, setIsInlineEditActive]); + // dismisses action popover when the selected tab changes + useEffect(() => { + if (prevSelectedItemIdRef.current !== selectedItemId && !isSelected && isActionPopoverOpen) { + setActionPopover(false); + } + prevSelectedItemIdRef.current = selectedItemId; + }, [selectedItemId, isSelected, isActionPopoverOpen]); + const mainTabContent = (
( Date: Fri, 28 Nov 2025 12:18:42 +0100 Subject: [PATCH 09/25] fix overflow scroll --- .../tab_with_background.tsx | 2 +- .../tabs_bar_with_background.tsx | 1 - .../src/hooks/use_responsive_tabs.tsx | 16 +++++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 21a649a13d9ad..e56ce135e584c 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -40,13 +40,13 @@ export const TabWithBackground = React.forwardRef = ({ css={css` // tabs bar background background: ${euiTheme.colors.lightestShade}; - padding-left: ${euiTheme.size.xs}; `} > {children} diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx index 3cac56fe713aa..c3e1e5ccc8327 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx @@ -38,15 +38,16 @@ export const useResponsiveTabs = ({ }: UseResponsiveTabsProps) => { const { euiTheme } = useEuiTheme(); const dimensions = useResizeObserver(tabsContainerWithPlusElement); + const horizontalGap = parseInt(euiTheme.size.s, 10); // matches gap between tabs + const tabsSizeConfig = useMemo(() => { - const horizontalGap = parseInt(euiTheme.size.s, 10); // matches gap between tabs return calculateResponsiveTabs({ items, containerWidth: dimensions.width, hasReachedMaxItemsCount, horizontalGap, }); - }, [items, dimensions.width, hasReachedMaxItemsCount, euiTheme.size.s]); + }, [items, dimensions.width, hasReachedMaxItemsCount, horizontalGap]); const [scrollState, setScrollState] = useState(); @@ -135,8 +136,8 @@ export const useResponsiveTabs = ({ mask-image: linear-gradient( to right, rgba(255, 0, 0, 0.1) 0%, - rgb(255, 0, 0) ${euiTheme.size.s}, - rgb(255, 0, 0) calc(100% - ${euiTheme.size.s}), + rgb(255, 0, 0) ${euiTheme.size.l}, + rgb(255, 0, 0) calc(100% - ${euiTheme.size.l}), rgba(255, 0, 0, 0.1) 100% ); `; @@ -145,14 +146,14 @@ export const useResponsiveTabs = ({ mask-image: linear-gradient( to right, rgba(255, 0, 0, 0.1) 0%, - rgb(255, 0, 0) ${euiTheme.size.s} + rgb(255, 0, 0) ${euiTheme.size.l} ); `; } else if (scrollState?.isScrollableRight) { overflowGradient = ` mask-image: linear-gradient( to right, - rgb(255, 0, 0) calc(100% - ${euiTheme.size.s}), + rgb(255, 0, 0) calc(100% - ${euiTheme.size.l}), rgba(255, 0, 0, 0.1) 100% ); `; @@ -164,13 +165,14 @@ export const useResponsiveTabs = ({ user-select: none; scrollbar-width: none; // hide the scrollbar scroll-behavior: smooth; + padding-inline: ${euiTheme.size.xs}; // space for curved notch &::-webkit-scrollbar { display: none; } transform: translateZ(0); ${overflowGradient} `; - }, [scrollState, euiTheme.size.s]); + }, [scrollState, euiTheme.size.l, euiTheme.size.xs]); return { tabsSizeConfig, From b235cf5e98a638c89cb27a0a77b211abe493b84e Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Fri, 28 Nov 2025 12:26:09 +0100 Subject: [PATCH 10/25] change tabs color on drag-n-drop --- .../tabs_bar/optional_droppable.tsx | 19 ++++++++++++++++++- .../tab_with_background.tsx | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx index 0d440a8cb2d42..8839f25b430c8 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx @@ -26,6 +26,15 @@ const droppableCss = css` wrap: no-wrap; `; +/** + * Additional styling when dragging is active. + */ +const draggingCss = css` + .unifiedTabs__tabWithBackground { + background-color: transparent; + } +`; + interface DroppableWrapperProps { /** Content to render inside the droppable zone */ children: React.ReactNode; @@ -67,7 +76,15 @@ export const OptionalDroppable: FC = ({ grow data-test-subj="unifiedTabs_droppable_enabled" > - {() => <>{children}} + {(provided, snapshot) => ( +
+ {children} +
+ )} ); diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index e56ce135e584c..5b9238b1e116c 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -29,6 +29,7 @@ export const TabWithBackground = React.forwardRef Date: Fri, 28 Nov 2025 12:31:05 +0100 Subject: [PATCH 11/25] fix padding --- .../tabs_visual_glue_to_app_container/tab_with_background.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 5b9238b1e116c..4dd482d5abc11 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -41,13 +41,13 @@ export const TabWithBackground = React.forwardRef Date: Fri, 28 Nov 2025 12:35:45 +0100 Subject: [PATCH 12/25] improve drag n drop styles --- .../src/components/tabs_bar/optional_droppable.tsx | 2 +- .../tab_with_background.tsx | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx index 8839f25b430c8..2d972ce19c565 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx @@ -30,7 +30,7 @@ const droppableCss = css` * Additional styling when dragging is active. */ const draggingCss = css` - .unifiedTabs__tabWithBackground { + .unifiedTabs__tabWithBackground:not(.unifiedTabs__tabWithBackground--selected) { background-color: transparent; } `; diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 4dd482d5abc11..d0c0668e54705 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -10,6 +10,7 @@ import React, { type HTMLAttributes } from 'react'; import { css } from '@emotion/react'; import { useEuiTheme, euiSlightShadowHover, type EuiThemeComputed } from '@elastic/eui'; +import classNames from 'classnames'; import type { TabsServices } from '../../types'; export interface TabWithBackgroundProps extends HTMLAttributes { @@ -29,7 +30,9 @@ export const TabWithBackground = React.forwardRef Date: Fri, 28 Nov 2025 12:46:59 +0100 Subject: [PATCH 13/25] change color of separators while dragging --- .../tabs_bar/optional_droppable.tsx | 23 +++++++++++-------- .../tab_with_background.tsx | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx index 2d972ce19c565..47a06dd4e95ed 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx @@ -11,7 +11,7 @@ import React, { type FC } from 'react'; import { css } from '@emotion/react'; import type { DropResult } from '@elastic/eui'; -import { EuiDragDropContext, EuiDroppable } from '@elastic/eui'; +import { EuiDragDropContext, EuiDroppable, useEuiTheme } from '@elastic/eui'; /** Unique identifier for the droppable zone containing tabs */ const DROPPABLE_ID = 'unifiedTabsOrder'; @@ -26,15 +26,6 @@ const droppableCss = css` wrap: no-wrap; `; -/** - * Additional styling when dragging is active. - */ -const draggingCss = css` - .unifiedTabs__tabWithBackground:not(.unifiedTabs__tabWithBackground--selected) { - background-color: transparent; - } -`; - interface DroppableWrapperProps { /** Content to render inside the droppable zone */ children: React.ReactNode; @@ -57,6 +48,18 @@ export const OptionalDroppable: FC = ({ disableDragAndDrop, onDragEnd, }) => { + const { euiTheme } = useEuiTheme(); + + const draggingCss = css` + .unifiedTabs__tabWithBackground:not(.unifiedTabs__tabWithBackground--selected) { + background-color: transparent; + + &::before { + background-color: ${euiTheme.colors.accentSecondary}; + } + } + `; + // When drag-and-drop is disabled, render children in a plain flex container if (disableDragAndDrop) { return ( diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index d0c0668e54705..42bb5942673ee 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -74,7 +74,7 @@ export const TabWithBackground = React.forwardRef Date: Mon, 1 Dec 2025 11:03:42 +0100 Subject: [PATCH 14/25] increase min tab width --- src/platform/packages/shared/kbn-unified-tabs/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts index 18a3d02a0c6c3..8965507674b33 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts +++ b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts @@ -10,7 +10,7 @@ export const MAX_TAB_LABEL_LENGTH = 120; export const MAX_TAB_WIDTH = 280; -export const MIN_TAB_WIDTH = 90; +export const MIN_TAB_WIDTH = 100; export const PREVIEW_WIDTH = 280; From f198be05815d96334b7e66bbd18e5a966914647f Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Mon, 1 Dec 2025 13:12:01 +0100 Subject: [PATCH 15/25] revert tab width --- src/platform/packages/shared/kbn-unified-tabs/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts index 8965507674b33..2867a36d6aa61 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts +++ b/src/platform/packages/shared/kbn-unified-tabs/src/constants.ts @@ -10,7 +10,7 @@ export const MAX_TAB_LABEL_LENGTH = 120; export const MAX_TAB_WIDTH = 280; -export const MIN_TAB_WIDTH = 100; +export const MIN_TAB_WIDTH = 112; export const PREVIEW_WIDTH = 280; From 7391b93e3f50e6c8e11802a4afcb408213ed9140 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 2 Dec 2025 22:06:52 -0400 Subject: [PATCH 16/25] Remove border from label width calculation --- .../src/components/tab/use_tab_label_width.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/use_tab_label_width.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/use_tab_label_width.tsx index 56064063b10aa..67a86f7ac5b8f 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/use_tab_label_width.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tab/use_tab_label_width.tsx @@ -33,9 +33,8 @@ export const useTabLabelWidth = ({ const indicatorWidth = euiTheme.base * 1.25; const textWithIndicatorWidth = textWidth + indicatorWidth; const tabPaddingWidth = euiTheme.base; - const tabBorderWidth = parseInt(String(euiTheme.border.width.thin), 10); - const maxLabelWidth = tabsSizeConfig.regularTabMaxWidth - tabPaddingWidth - tabBorderWidth; - const minLabelWidth = tabsSizeConfig.regularTabMinWidth - tabPaddingWidth - tabBorderWidth; + const maxLabelWidth = tabsSizeConfig.regularTabMaxWidth - tabPaddingWidth; + const minLabelWidth = tabsSizeConfig.regularTabMinWidth - tabPaddingWidth; const resolvedLabelWidth = Math.max( Math.min(textWithIndicatorWidth, maxLabelWidth), minLabelWidth @@ -47,7 +46,6 @@ export const useTabLabelWidth = ({ }; }, [ euiTheme.base, - euiTheme.border.width.thin, item.label, tabsSizeConfig.regularTabMaxWidth, tabsSizeConfig.regularTabMinWidth, From 6dfca27d76ee56d6525a2e9738d6171c724a5180 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 2 Dec 2025 22:07:55 -0400 Subject: [PATCH 17/25] Fix tabs bar overflow behaviour when resizing window --- .../kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx index c3e1e5ccc8327..89df262e428de 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx @@ -71,9 +71,9 @@ export const useResponsiveTabs = ({ useEvent('scroll', onScrollThrottled, tabsContainerElement); useEffect(() => { - onScrollThrottled(); - // `isScrollable` added here to trigger in cases when the container width changes - }, [tabsContainerElement, onScrollThrottled, tabsSizeConfig.isScrollable]); + onScroll(); + // `dimensions.width` added here to trigger in cases when the container width changes + }, [onScroll, dimensions.width]); const scrollLeft = useCallback(() => { if (tabsContainerElement) { From fafdfd11dc90610008f0497c172c8828b27799bb Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 2 Dec 2025 22:10:57 -0400 Subject: [PATCH 18/25] Fix tabs bar menu button right padding --- .../kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx | 2 +- .../src/components/tabs_bar_menu/tabs_bar_menu.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx index db6e441163d70..acbd7afcc75e4 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx @@ -275,7 +275,7 @@ export const TabsBar = forwardRef( alignItems="center" gutterSize="s" css={css` - padding-right: ${euiTheme.size.base}; + padding-right: ${euiTheme.size.s}; `} > diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar_menu/tabs_bar_menu.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar_menu/tabs_bar_menu.tsx index 11cbb6ddf2611..25e95d94812dc 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar_menu/tabs_bar_menu.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar_menu/tabs_bar_menu.tsx @@ -103,6 +103,7 @@ export const TabsBarMenu: React.FC = React.memo( panelPaddingSize="none" anchorPosition="downRight" hasArrow={false} + buffer={0} panelProps={{ css: popoverCss, ['data-test-subj']: 'unifiedTabs_tabsBarMenuPanel', From 2906a35d55003a50099fc401c9d9c1fab631f8df Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 2 Dec 2025 22:44:18 -0400 Subject: [PATCH 19/25] Adjust separator alignment --- .../tabs_visual_glue_to_app_container/tab_with_background.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 42bb5942673ee..2c01591b4ef28 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -67,7 +67,7 @@ export const TabWithBackground = React.forwardRef Date: Tue, 2 Dec 2025 22:52:46 -0400 Subject: [PATCH 20/25] Account for gaps before and after tabs in width calculations --- .../kbn-unified-tabs/src/utils/calculate_responsive_tabs.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/utils/calculate_responsive_tabs.ts b/src/platform/packages/shared/kbn-unified-tabs/src/utils/calculate_responsive_tabs.ts index 66d6469cb78e4..34ed6f2005a5d 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/utils/calculate_responsive_tabs.ts +++ b/src/platform/packages/shared/kbn-unified-tabs/src/utils/calculate_responsive_tabs.ts @@ -28,7 +28,10 @@ export const calculateResponsiveTabs = ({ const availableContainerWidth = (containerWidth || window.innerWidth) - (hasReachedMaxItemsCount ? 0 : PLUS_BUTTON_SPACE); - const totalGapWidth = (horizontalGap || 0) * Math.max(items.length - 1, 0); + const gapWidth = horizontalGap ?? 0; + const gapWidthBetweenTabs = gapWidth * Math.max(items.length - 1, 0); + const gapWidthBeforeFirstTabAndAfterLastTab = gapWidth * 2; + const totalGapWidth = gapWidthBetweenTabs + gapWidthBeforeFirstTabAndAfterLastTab; const availableSpaceForTabs = Math.max(availableContainerWidth - totalGapWidth, 0); let wasSpaceEquallyDivided = items.length > 0; From 1ddebd5d9d6d1c234e94492cc4954932b465e10f Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 2 Dec 2025 23:45:25 -0400 Subject: [PATCH 21/25] Remove bottom padding when dragging --- .../tabs_visual_glue_to_app_container/tab_with_background.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx index 2c01591b4ef28..c9261f87d07c0 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_visual_glue_to_app_container/tab_with_background.tsx @@ -44,7 +44,7 @@ export const TabWithBackground = React.forwardRef Date: Wed, 3 Dec 2025 00:32:40 -0400 Subject: [PATCH 22/25] Improve drag n drop styles --- .../tabs_bar/optional_droppable.tsx | 61 ++++++++++++------- .../src/components/tabs_bar/tabs_bar.tsx | 10 ++- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx index 47a06dd4e95ed..87aef1a8e73f2 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.tsx @@ -7,10 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { type FC } from 'react'; +import React, { useCallback, useMemo, useState, type FC } from 'react'; import { css } from '@emotion/react'; -import type { DropResult } from '@elastic/eui'; +import type { DragStart, DropResult } from '@elastic/eui'; import { EuiDragDropContext, EuiDroppable, useEuiTheme } from '@elastic/eui'; /** Unique identifier for the droppable zone containing tabs */ @@ -31,6 +31,8 @@ interface DroppableWrapperProps { children: React.ReactNode; /** When false, wraps children with drag-drop context; when true, renders as plain div */ disableDragAndDrop: boolean; + /** Callback fired when a drag operation starts */ + onDragStart: (start: DragStart) => void; /** Callback fired when a drag operation completes with new ordering */ onDragEnd: (result: DropResult) => void; } @@ -46,19 +48,44 @@ interface DroppableWrapperProps { export const OptionalDroppable: FC = ({ children, disableDragAndDrop, - onDragEnd, + onDragStart: originalOnDragStart, + onDragEnd: originalOnDragEnd, }) => { const { euiTheme } = useEuiTheme(); + const [isDragging, setIsDragging] = useState(false); - const draggingCss = css` - .unifiedTabs__tabWithBackground:not(.unifiedTabs__tabWithBackground--selected) { - background-color: transparent; + const draggingCss = useMemo( + () => css` + .unifiedTabs__tabWithBackground { + pointer-events: none; + } + + .unifiedTabs__tabWithBackground:not(.unifiedTabs__tabWithBackground--selected) { + background-color: transparent; - &::before { - background-color: ${euiTheme.colors.accentSecondary}; + &::before { + background-color: ${euiTheme.colors.accentSecondary}; + } } - } - `; + `, + [euiTheme.colors.accentSecondary] + ); + + const onDragStart = useCallback( + (start: DragStart) => { + setIsDragging(true); + originalOnDragStart(start); + }, + [originalOnDragStart] + ); + + const onDragEnd = useCallback( + (result: DropResult) => { + setIsDragging(false); + originalOnDragEnd(result); + }, + [originalOnDragEnd] + ); // When drag-and-drop is disabled, render children in a plain flex container if (disableDragAndDrop) { @@ -71,23 +98,15 @@ export const OptionalDroppable: FC = ({ // When enabled, provide drag-drop context and droppable zone return ( - + - {(provided, snapshot) => ( -
- {children} -
- )} + {() => <>{children}}
); diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx index acbd7afcc75e4..8ab688642c5f4 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/tabs_bar.tsx @@ -185,6 +185,10 @@ export const TabsBar = forwardRef( } }, [selectedItem]); + const onDragStart = useCallback(() => { + setHoveredTabId(null); + }, []); + const onDragEnd = useCallback( ({ source, destination }: DropResult) => { if (source && destination) { @@ -288,7 +292,11 @@ export const TabsBar = forwardRef( When false, it renders a plain flex container with consistent styling. This eliminates conditional rendering logic from this file. */} - + {/* Render each tab, optionally wrapped with drag functionality */} {items.map((item, index) => { const nextItem = items[index + 1]; From a9b652a934d9db3a1b032be58e2cfd5ee81d0e53 Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Wed, 3 Dec 2025 10:20:19 +0100 Subject: [PATCH 23/25] revert overflow shadow mask position --- .../kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx index c3e1e5ccc8327..43f9a4a04199c 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/hooks/use_responsive_tabs.tsx @@ -136,8 +136,8 @@ export const useResponsiveTabs = ({ mask-image: linear-gradient( to right, rgba(255, 0, 0, 0.1) 0%, - rgb(255, 0, 0) ${euiTheme.size.l}, - rgb(255, 0, 0) calc(100% - ${euiTheme.size.l}), + rgb(255, 0, 0) ${euiTheme.size.s}, + rgb(255, 0, 0) calc(100% - ${euiTheme.size.s}), rgba(255, 0, 0, 0.1) 100% ); `; @@ -146,14 +146,14 @@ export const useResponsiveTabs = ({ mask-image: linear-gradient( to right, rgba(255, 0, 0, 0.1) 0%, - rgb(255, 0, 0) ${euiTheme.size.l} + rgb(255, 0, 0) ${euiTheme.size.s} ); `; } else if (scrollState?.isScrollableRight) { overflowGradient = ` mask-image: linear-gradient( to right, - rgb(255, 0, 0) calc(100% - ${euiTheme.size.l}), + rgb(255, 0, 0) calc(100% - ${euiTheme.size.s}), rgba(255, 0, 0, 0.1) 100% ); `; @@ -172,7 +172,7 @@ export const useResponsiveTabs = ({ transform: translateZ(0); ${overflowGradient} `; - }, [scrollState, euiTheme.size.l, euiTheme.size.xs]); + }, [scrollState, euiTheme.size.s, euiTheme.size.xs]); return { tabsSizeConfig, From d19dc594145af8b17d1cb8d91f40c6891140855f Mon Sep 17 00:00:00 2001 From: Ania Kowalska Date: Wed, 3 Dec 2025 13:59:36 +0100 Subject: [PATCH 24/25] fix test after types change --- .../src/components/tabs_bar/optional_draggable.test.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_draggable.test.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_draggable.test.tsx index 009d8d13f7ed6..5bffc3c50717b 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_draggable.test.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_draggable.test.tsx @@ -22,7 +22,11 @@ import { OptionalDroppable } from './optional_droppable'; const renderDraggableWithDroppable = (disableDragAndDrop: boolean = false) => render( - + Date: Wed, 3 Dec 2025 15:53:01 +0100 Subject: [PATCH 25/25] fix types --- .../src/components/tabs_bar/optional_droppable.test.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.test.tsx b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.test.tsx index 82e267a969ece..570e5514f648c 100644 --- a/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.test.tsx +++ b/src/platform/packages/shared/kbn-unified-tabs/src/components/tabs_bar/optional_droppable.test.tsx @@ -19,11 +19,15 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { OptionalDroppable } from './optional_droppable'; -const mockOnDragEnd = jest.fn(); +const mockOnDrag = jest.fn(); const renderOptionalDroppable = (disableDragAndDrop: boolean) => { render( - +
Test Content
);