diff --git a/packages/bruno-app/src/components/Dropdown/StyledWrapper.js b/packages/bruno-app/src/components/Dropdown/StyledWrapper.js
index d4068b42f..8eada99ab 100644
--- a/packages/bruno-app/src/components/Dropdown/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Dropdown/StyledWrapper.js
@@ -1,153 +1,165 @@
import styled from 'styled-components';
const Wrapper = styled.div`
- .dropdown-toggle {
- &:hover {
- color: black;
+ min-width: 160px;
+ font-size: ${(props) => props.theme.font.size.base};
+ color: ${(props) => props.theme.dropdown.color};
+ background-color: ${(props) => props.theme.dropdown.bg};
+ box-shadow: ${(props) => props.theme.shadow.sm};
+ border-radius: ${(props) => props.theme.border.radius.base};
+ max-height: 90vh;
+ overflow-y: auto;
+ max-width: unset !important;
+ padding: 0.25rem;
+
+ [role="menu"] {
+ outline: none;
+ &:focus {
+ outline: none;
+ }
+ &:focus-visible {
+ outline: none;
}
}
- .tippy-box {
- min-width: 160px;
- font-size: ${(props) => props.theme.font.size.base};
+ .label-item {
+ display: flex;
+ align-items: center;
+ padding: 0.375rem 0.625rem 0.25rem 0.625rem;
+ font-size: 0.6875rem;
+ font-weight: 600;
+ letter-spacing: 0.025em;
color: ${(props) => props.theme.dropdown.color};
- background-color: ${(props) => props.theme.dropdown.bg};
- box-shadow: ${(props) => props.theme.shadow.sm};
- border-radius: ${(props) => props.theme.border.radius.base};
- max-height: 90vh;
- overflow-y: auto;
- max-width: unset !important;
- padding: 0.25rem;
+ opacity: 0.6;
+ margin-top: 0.25rem;
+ &:first-child {
+ margin-top: 0;
+ }
+ }
- .tippy-content {
- padding-left: 0;
- padding-right: 0;
- padding-top: 0;
- padding-bottom: 0;
+ .dropdown-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.275rem 0.625rem;
+ cursor: pointer;
+ border-radius: 6px;
+ margin: 0.0625rem 0;
+ font-size: 0.8125rem;
- [role="menu"] {
- outline: none;
- &:focus {
- outline: none;
- }
- &:focus-visible {
- outline: none;
- }
- }
-
- .label-item {
- display: flex;
- align-items: center;
- padding: 0.375rem 0.625rem 0.25rem 0.625rem;
- font-size: 0.6875rem;
- font-weight: 600;
- letter-spacing: 0.025em;
- color: ${(props) => props.theme.dropdown.color};
- opacity: 0.6;
- margin-top: 0.25rem;
-
- &:first-child {
- margin-top: 0;
- }
- }
-
- .dropdown-item {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.275rem 0.625rem;
- cursor: pointer;
- border-radius: 6px;
- margin: 0.0625rem 0;
- font-size: 0.8125rem;
-
- &.active {
- color: ${(props) => props.theme.colors.text.yellow} !important;
- .dropdown-icon {
- color: ${(props) => props.theme.colors.text.yellow} !important;
- }
- }
-
- .dropdown-label {
- flex: 1;
- }
-
- .dropdown-icon {
- flex-shrink: 0;
- width: 16px;
- height: 16px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: ${(props) => props.theme.dropdown.iconColor};
- opacity: 0.8;
- }
-
- .dropdown-right-section {
- margin-left: auto;
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- &:hover:not(:disabled) {
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &.selected-focused:not(:disabled) {
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &:focus-visible:not(:disabled) {
- outline: none;
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &:focus:not(:focus-visible) {
- outline: none;
- }
-
- &:disabled {
- cursor: not-allowed;
- opacity: 0.5;
- }
-
- &.delete-item {
- color: ${(props) => props.theme.colors.text.danger};
- .dropdown-icon {
- color: ${(props) => props.theme.colors.text.danger};
- }
- &:hover {
- background-color: ${({ theme }) => {
- const hex = theme.colors.text.danger.replace('#', '');
- const r = parseInt(hex.substring(0, 2), 16);
- const g = parseInt(hex.substring(2, 4), 16);
- const b = parseInt(hex.substring(4, 6), 16);
- return `rgba(${r}, ${g}, ${b}, 0.04)`; // 4% opacity
- }} !important;
-
- color: ${(props) => props.theme.colors.text.danger} !important;
- }
- }
-
- &.border-top {
- border-top: solid 1px ${(props) => props.theme.dropdown.separator};
- margin-top: 0.25rem;
- padding-top: 0.375rem;
- }
-
- &.dropdown-item-select {
- padding-left: 1.5rem;
- }
- }
-
- .dropdown-separator {
- height: 1px;
- background-color: ${(props) => props.theme.dropdown.separator};
- margin: 0.25rem 0;
+ &.active {
+ color: ${(props) => props.theme.colors.text.yellow} !important;
+ .dropdown-icon {
+ color: ${(props) => props.theme.colors.text.yellow} !important;
}
}
+
+ .dropdown-label {
+ flex: 1;
+ }
+
+ .dropdown-icon {
+ flex-shrink: 0;
+ width: 16px;
+ height: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: ${(props) => props.theme.dropdown.iconColor};
+ opacity: 0.8;
+ }
+
+ .dropdown-right-section {
+ margin-left: auto;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ &:hover:not(:disabled):not(.disabled) {
+ background-color: ${(props) => props.theme.dropdown.hoverBg};
+ }
+
+ &.selected-focused:not(:disabled):not(.disabled) {
+ background-color: ${(props) => props.theme.dropdown.hoverBg};
+ }
+
+ &:focus-visible:not(:disabled):not(.disabled) {
+ outline: none;
+ background-color: ${(props) => props.theme.dropdown.hoverBg};
+ }
+
+ &:focus:not(:focus-visible) {
+ outline: none;
+ }
+
+ &:disabled,
+ &.disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+ }
+
+ &.delete-item {
+ color: ${(props) => props.theme.colors.text.danger};
+ .dropdown-icon {
+ color: ${(props) => props.theme.colors.text.danger};
+ }
+ &:hover {
+ background-color: ${({ theme }) => {
+ const hex = theme.colors.text.danger.replace('#', '');
+ const r = parseInt(hex.substring(0, 2), 16);
+ const g = parseInt(hex.substring(2, 4), 16);
+ const b = parseInt(hex.substring(4, 6), 16);
+ return `rgba(${r}, ${g}, ${b}, 0.04)`; // 4% opacity
+ }} !important;
+
+ color: ${(props) => props.theme.colors.text.danger} !important;
+ }
+ }
+
+ &.border-top {
+ border-top: solid 1px ${(props) => props.theme.dropdown.separator};
+ margin-top: 0.25rem;
+ padding-top: 0.375rem;
+ }
+
+ &.dropdown-item-select {
+ padding-left: 1.5rem;
+ }
+
+ /* Focused state - applied during keyboard navigation */
+ &.dropdown-item-focused {
+ background-color: ${({ theme }) => theme.dropdown.hoverBg};
+ outline: none;
+ }
+
+ /* Active/selected state - applied to the currently selected item */
+ &.dropdown-item-active {
+ color: ${({ theme }) => theme.colors.text.yellow};
+ background-color: ${({ theme }) => theme.dropdown.activeBg};
+ font-weight: 500;
+ .dropdown-icon {
+ color: ${({ theme }) => theme.colors.text.yellow};
+ }
+ }
+
+ /* Combined state - when active item is also focused */
+ &.dropdown-item-active.dropdown-item-focused {
+ background-color: ${({ theme }) => theme.dropdown.activeHoverBg};
+ }
+
+ /* Focus visible for accessibility */
+ &:focus-visible {
+ outline: 2px solid ${({ theme }) => theme.dropdown.focusRing};
+ outline-offset: -2px;
+ }
+ }
+
+ .dropdown-separator {
+ height: 1px;
+ background-color: ${(props) => props.theme.dropdown.separator};
+ margin: 0.25rem 0;
}
`;
diff --git a/packages/bruno-app/src/components/Dropdown/index.js b/packages/bruno-app/src/components/Dropdown/index.js
index 7c2d0f98a..5f1771a23 100644
--- a/packages/bruno-app/src/components/Dropdown/index.js
+++ b/packages/bruno-app/src/components/Dropdown/index.js
@@ -2,25 +2,27 @@ import React from 'react';
import Tippy from '@tippyjs/react';
import StyledWrapper from './StyledWrapper';
-const Dropdown = ({ icon, children, onCreate, placement, transparent, visible, ...props }) => {
+const Dropdown = ({ icon, children, onCreate, placement, transparent, visible, appendTo, ...props }) => {
// When in controlled mode (visible prop is provided), don't use trigger prop
const tippyProps = visible !== undefined
- ? { ...props, visible, interactive: true, appendTo: 'parent' }
- : { ...props, trigger: 'click', interactive: true, appendTo: 'parent' };
+ ? { ...props, visible, interactive: true, appendTo: appendTo || 'parent' }
+ : { ...props, trigger: 'click', interactive: true, appendTo: appendTo || 'parent' };
return (
-
-
- {icon}
-
-
+ (
+
+ {children}
+
+ )}
+ placement={placement || 'bottom-end'}
+ animation={false}
+ arrow={false}
+ onCreate={onCreate}
+ {...tippyProps}
+ >
+ {icon}
+
);
};
diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
index 8998ca9cc..2ad6f9cd7 100644
--- a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
+++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
@@ -17,7 +17,7 @@ import ConfirmCloseEnvironment from 'components/Environments/ConfirmCloseEnviron
import RequestTabNotFound from './RequestTabNotFound';
import SpecialTab from './SpecialTab';
import StyledWrapper from './StyledWrapper';
-import Dropdown from 'components/Dropdown';
+import MenuDropdown from 'ui/MenuDropdown';
import CloneCollectionItem from 'components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index';
import NewRequest from 'components/Sidebar/NewRequest/index';
import GradientCloseButton from './GradientCloseButton';
@@ -26,11 +26,12 @@ import { closeWsConnection } from 'utils/network/index';
import ExampleTab from '../ExampleTab';
import toast from 'react-hot-toast';
-const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUid, hasOverflow, setHasOverflow }) => {
+const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUid, hasOverflow, setHasOverflow, dropdownContainerRef }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const theme = storedTheme === 'dark' ? darkTheme : lightTheme;
const tabNameRef = useRef(null);
+ const tabLabelRef = useRef(null);
const lastOverflowStateRef = useRef(null);
const [showConfirmClose, setShowConfirmClose] = useState(false);
const [showConfirmCollectionClose, setShowConfirmCollectionClose] = useState(false);
@@ -38,8 +39,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
const [showConfirmEnvironmentClose, setShowConfirmEnvironmentClose] = useState(false);
const [showConfirmGlobalEnvironmentClose, setShowConfirmGlobalEnvironmentClose] = useState(false);
- const dropdownTippyRef = useRef();
- const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
+ const menuDropdownRef = useRef();
const item = findItemInCollection(collection, tab.uid);
@@ -99,17 +99,10 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
);
};
- const handleRightClick = (_event) => {
- const menuDropdown = dropdownTippyRef.current;
- if (!menuDropdown) {
- return;
- }
-
- if (menuDropdown.state.isShown) {
- menuDropdown.hide();
- } else {
- menuDropdown.show();
- }
+ const handleRightClick = (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ menuDropdownRef.current?.show();
};
const handleMouseUp = (e) => {
@@ -383,6 +376,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
/>
)}
dispatch(makeTabPermanent({ uid: tab.uid }))}
@@ -403,13 +397,13 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
{item.name}
{
+ if (!tabLabelRef.current) {
+ return { width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0 };
+ }
+ return tabLabelRef.current.getBoundingClientRect();
+ };
+
const totalTabs = collectionRequestTabs.length || 0;
const currentTabUid = collectionRequestTabs[tabIndex]?.uid;
const currentTabItem = findItemInCollection(collection, currentTabUid);
@@ -442,10 +445,7 @@ function RequestTabMenu({ onDropdownCreate, collectionRequestTabs, tabIndex, col
const hasRightTabs = totalTabs > tabIndex + 1;
const hasOtherTabs = totalTabs > 1;
- async function handleCloseTab(event, tabUid) {
- event.stopPropagation();
- dropdownTippyRef.current.hide();
-
+ async function handleCloseTab(tabUid) {
if (!tabUid) {
return;
}
@@ -461,10 +461,7 @@ function RequestTabMenu({ onDropdownCreate, collectionRequestTabs, tabIndex, col
} catch (err) { }
}
- function handleRevertChanges(event) {
- event.stopPropagation();
- dropdownTippyRef.current.hide();
-
+ function handleRevertChanges() {
if (!currentTabUid) {
return;
}
@@ -480,40 +477,96 @@ function RequestTabMenu({ onDropdownCreate, collectionRequestTabs, tabIndex, col
} catch (err) { }
}
- function handleCloseOtherTabs(event) {
- dropdownTippyRef.current.hide();
-
+ async function handleCloseOtherTabs() {
const otherTabs = collectionRequestTabs.filter((_, index) => index !== tabIndex);
- otherTabs.forEach((tab) => handleCloseTab(event, tab.uid));
+ await Promise.all(otherTabs.map((tab) => handleCloseTab(tab.uid)));
}
- function handleCloseTabsToTheLeft(event) {
- dropdownTippyRef.current.hide();
-
+ async function handleCloseTabsToTheLeft() {
const leftTabs = collectionRequestTabs.filter((_, index) => index < tabIndex);
- leftTabs.forEach((tab) => handleCloseTab(event, tab.uid));
+ await Promise.all(leftTabs.map((tab) => handleCloseTab(tab.uid)));
}
- function handleCloseTabsToTheRight(event) {
- dropdownTippyRef.current.hide();
-
+ async function handleCloseTabsToTheRight() {
const rightTabs = collectionRequestTabs.filter((_, index) => index > tabIndex);
- rightTabs.forEach((tab) => handleCloseTab(event, tab.uid));
+ await Promise.all(rightTabs.map((tab) => handleCloseTab(tab.uid)));
}
- function handleCloseSavedTabs(event) {
- event.stopPropagation();
-
+ function handleCloseSavedTabs() {
const items = flattenItems(collection?.items);
const savedTabs = items?.filter?.((item) => !hasRequestChanges(item));
const savedTabIds = savedTabs?.map((item) => item.uid) || [];
dispatch(closeTabs({ tabUids: savedTabIds }));
}
- function handleCloseAllTabs(event) {
- collectionRequestTabs.forEach((tab) => handleCloseTab(event, tab.uid));
+ async function handleCloseAllTabs() {
+ await Promise.all(collectionRequestTabs.map((tab) => handleCloseTab(tab.uid)));
}
+ const menuItems = useMemo(() => [
+ {
+ id: 'new-request',
+ label: 'New Request',
+ onClick: () => setShowAddNewRequestModal(true)
+ },
+ {
+ id: 'clone-request',
+ label: 'Clone Request',
+ onClick: () => setShowCloneRequestModal(true)
+ },
+ {
+ id: 'revert-changes',
+ label: 'Revert Changes',
+ onClick: handleRevertChanges,
+ disabled: !currentTabItem?.draft
+ },
+ {
+ id: 'close',
+ label: 'Close',
+ onClick: () => handleCloseTab(currentTabUid)
+ },
+ {
+ id: 'close-others',
+ label: 'Close Others',
+ onClick: handleCloseOtherTabs,
+ disabled: !hasOtherTabs
+ },
+ {
+ id: 'close-left',
+ label: 'Close to the Left',
+ onClick: handleCloseTabsToTheLeft,
+ disabled: !hasLeftTabs
+ },
+ {
+ id: 'close-right',
+ label: 'Close to the Right',
+ onClick: handleCloseTabsToTheRight,
+ disabled: !hasRightTabs
+ },
+ {
+ id: 'close-saved',
+ label: 'Close Saved',
+ onClick: handleCloseSavedTabs
+ },
+ {
+ id: 'close-all',
+ label: 'Close All',
+ onClick: handleCloseAllTabs
+ }
+ ], [currentTabUid, currentTabItem, hasOtherTabs, hasLeftTabs, hasRightTabs, collection, collectionRequestTabs, tabIndex, dispatch]);
+
+ const menuDropdown = (
+
+
+
+ );
+
return (
{showAddNewRequestModal && (
@@ -528,51 +581,7 @@ function RequestTabMenu({ onDropdownCreate, collectionRequestTabs, tabIndex, col
/>
)}
- } placement="bottom-start">
-
-
-
-
-
-
-
-
-
-
+ {menuDropdown}
);
}
diff --git a/packages/bruno-app/src/components/RequestTabs/index.js b/packages/bruno-app/src/components/RequestTabs/index.js
index 34c8f479b..79498cbb6 100644
--- a/packages/bruno-app/src/components/RequestTabs/index.js
+++ b/packages/bruno-app/src/components/RequestTabs/index.js
@@ -17,6 +17,7 @@ const RequestTabs = () => {
const dispatch = useDispatch();
const tabsRef = useRef();
const scrollContainerRef = useRef();
+ const collectionTabsRef = useRef();
const [newRequestModalOpen, setNewRequestModalOpen] = useState(false);
const [tabOverflowStates, setTabOverflowStates] = useState({});
const [showChevrons, setShowChevrons] = useState(false);
@@ -115,7 +116,7 @@ const RequestTabs = () => {
{collectionRequestTabs && collectionRequestTabs.length ? (
<>
-
+
{showChevrons ? (
-
@@ -158,6 +159,7 @@ const RequestTabs = () => {
folderUid={tab.folderUid}
hasOverflow={tabOverflowStates[tab.uid]}
setHasOverflow={createSetHasOverflow(tab.uid)}
+ dropdownContainerRef={collectionTabsRef}
/>
);
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
index 8aaf15e4e..3ddbe96e4 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
@@ -53,8 +53,10 @@ import CreateExampleModal from 'components/ResponseExample/CreateExampleModal';
import { openDevtoolsAndSwitchToTerminal } from 'utils/terminal';
import ActionIcon from 'ui/ActionIcon';
import MenuDropdown from 'ui/MenuDropdown';
+import { useSidebarAccordion } from 'components/Sidebar/SidebarAccordionContext';
const CollectionItem = ({ item, collectionUid, collectionPathname, searchText }) => {
+ const { dropdownContainerRef } = useSidebarAccordion();
const _isTabForItemActiveSelector = isTabForItemActiveSelector({ itemUid: item.uid });
const isTabForItemActive = useSelector(_isTabForItemActiveSelector, isEqual);
@@ -640,8 +642,9 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
onClick={handleClick}
onDoubleClick={handleDoubleClick}
>
-
- {isFolder ? (
+
+ {isFolder ? (
+
- ) : hasExamples ? (
+
+ ) : hasExamples ? (
+
- ) : null}
-
+
+ ) : null}
+
@@ -676,6 +682,8 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
items={buildMenuItems()}
placement="bottom-start"
data-testid="collection-item-menu"
+ popperOptions={{ strategy: 'fixed' }}
+ appendTo={dropdownContainerRef?.current || document.body}
>
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
index b9ecb1210..98256e073 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
@@ -45,8 +45,10 @@ import { sortByNameThenSequence } from 'utils/common/index';
import { openDevtoolsAndSwitchToTerminal } from 'utils/terminal';
import ActionIcon from 'ui/ActionIcon';
import MenuDropdown from 'ui/MenuDropdown';
+import { useSidebarAccordion } from 'components/Sidebar/SidebarAccordionContext';
const Collection = ({ collection, searchText }) => {
+ const { dropdownContainerRef } = useSidebarAccordion();
const [showNewFolderModal, setShowNewFolderModal] = useState(false);
const [showNewRequestModal, setShowNewRequestModal] = useState(false);
const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false);
@@ -434,6 +436,8 @@ const Collection = ({ collection, searchText }) => {
ref={menuDropdownRef}
items={menuItems}
placement="bottom-start"
+ appendTo={dropdownContainerRef?.current || document.body}
+ popperOptions={{ strategy: 'fixed' }}
data-testid="collection-actions"
>
diff --git a/packages/bruno-app/src/components/Sidebar/SidebarAccordionContext.js b/packages/bruno-app/src/components/Sidebar/SidebarAccordionContext.js
index d093753d6..ba51b8894 100644
--- a/packages/bruno-app/src/components/Sidebar/SidebarAccordionContext.js
+++ b/packages/bruno-app/src/components/Sidebar/SidebarAccordionContext.js
@@ -1,4 +1,4 @@
-import React, { createContext, useContext, useState, useCallback } from 'react';
+import React, { createContext, useContext, useState, useCallback, useRef } from 'react';
const SidebarAccordionContext = createContext();
@@ -12,6 +12,7 @@ export const useSidebarAccordion = () => {
export const SidebarAccordionProvider = ({ children, defaultExpanded = ['collections'] }) => {
const [expandedSections, setExpandedSections] = useState(new Set(defaultExpanded));
+ const dropdownContainerRef = useRef(null);
const toggleSection = useCallback((sectionId) => {
setExpandedSections((prev) => {
@@ -52,10 +53,13 @@ export const SidebarAccordionProvider = ({ children, defaultExpanded = ['collect
toggleSection,
setSectionExpanded,
isExpanded,
- getExpandedCount
+ getExpandedCount,
+ dropdownContainerRef
}}
>
- {children}
+
+ {children}
+
);
};
diff --git a/packages/bruno-app/src/ui/MenuDropdown/StyledWrapper.js b/packages/bruno-app/src/ui/MenuDropdown/StyledWrapper.js
deleted file mode 100644
index fbe183bbb..000000000
--- a/packages/bruno-app/src/ui/MenuDropdown/StyledWrapper.js
+++ /dev/null
@@ -1,150 +0,0 @@
-import styled from 'styled-components';
-
-const StyledWrapper = styled.div`
- .tippy-box {
- .tippy-content {
- .label-item {
- display: flex;
- align-items: center;
- padding: 0.375rem 0.625rem 0.25rem 0.625rem;
- font-size: 0.6875rem;
- font-weight: 600;
- letter-spacing: 0.025em;
- color: ${(props) => props.theme.dropdown.color};
- opacity: 0.6;
- margin-top: 0.25rem;
-
- &:first-child {
- margin-top: 0;
- }
- }
-
- .dropdown-item {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.275rem 0.625rem;
- cursor: pointer;
- border-radius: 6px;
- margin: 0.0625rem 0;
- font-size: 0.8125rem;
-
- &.active {
- color: ${(props) => props.theme.colors.text.yellow} !important;
- .dropdown-icon {
- color: ${(props) => props.theme.colors.text.yellow} !important;
- }
- }
-
- .dropdown-label {
- flex: 1;
- }
-
- .dropdown-icon {
- flex-shrink: 0;
- width: 16px;
- height: 16px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: ${(props) => props.theme.dropdown.iconColor};
- opacity: 0.8;
- }
-
- .dropdown-right-section {
- margin-left: auto;
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- &:hover:not(:disabled):not(.disabled) {
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &.selected-focused:not(:disabled):not(.disabled) {
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &:focus-visible:not(:disabled):not(.disabled) {
- outline: none;
- background-color: ${(props) => props.theme.dropdown.hoverBg};
- }
-
- &:focus:not(:focus-visible) {
- outline: none;
- }
-
- &:disabled,
- &.disabled {
- cursor: not-allowed;
- opacity: 0.5;
- }
-
- &.delete-item {
- color: ${(props) => props.theme.colors.text.danger};
- .dropdown-icon {
- color: ${(props) => props.theme.colors.text.danger};
- }
- &:hover {
- background-color: ${({ theme }) => {
- const hex = theme.colors.text.danger.replace('#', '');
- const r = parseInt(hex.substring(0, 2), 16);
- const g = parseInt(hex.substring(2, 4), 16);
- const b = parseInt(hex.substring(4, 6), 16);
- return `rgba(${r}, ${g}, ${b}, 0.04)`; // 4% opacity
- }} !important;
-
- color: ${(props) => props.theme.colors.text.danger} !important;
- }
- }
-
- &.border-top {
- border-top: solid 1px ${(props) => props.theme.dropdown.separator};
- margin-top: 0.25rem;
- padding-top: 0.375rem;
- }
-
- &.dropdown-item-select {
- padding-left: 1.5rem;
- }
-
- /* Focused state - applied during keyboard navigation */
- &.dropdown-item-focused {
- background-color: ${({ theme }) => theme.dropdown.hoverBg};
- outline: none;
- }
-
- /* Active/selected state - applied to the currently selected item */
- &.dropdown-item-active {
- color: ${({ theme }) => theme.colors.text.yellow};
- background-color: ${({ theme }) => theme.dropdown.activeBg};
- font-weight: 500;
- .dropdown-icon {
- color: ${({ theme }) => theme.colors.text.yellow};
- }
- }
-
- /* Combined state - when active item is also focused */
- &.dropdown-item-active.dropdown-item-focused {
- background-color: ${({ theme }) => theme.dropdown.activeHoverBg};
- }
-
- /* Focus visible for accessibility */
- &:focus-visible {
- outline: 2px solid ${({ theme }) => theme.dropdown.focusRing};
- outline-offset: -2px;
- }
- }
-
- .dropdown-separator {
- height: 1px;
- background-color: ${(props) => props.theme.dropdown.separator};
- margin: 0.25rem 0;
- }
- }
- }
-`;
-
-export default StyledWrapper;
diff --git a/packages/bruno-app/src/ui/MenuDropdown/index.js b/packages/bruno-app/src/ui/MenuDropdown/index.js
index 8fc171b15..06dd87964 100644
--- a/packages/bruno-app/src/ui/MenuDropdown/index.js
+++ b/packages/bruno-app/src/ui/MenuDropdown/index.js
@@ -1,6 +1,5 @@
import React, { forwardRef, useRef, useCallback, useState, useImperativeHandle, useEffect, useMemo } from 'react';
import Dropdown from 'components/Dropdown';
-import StyledWrapper from './StyledWrapper';
// Constants
const NAVIGATION_KEYS = ['ArrowDown', 'ArrowUp', 'Home', 'End', 'Escape'];
@@ -432,37 +431,35 @@ const MenuDropdown = forwardRef(({
: {children}
;
return (
-
-
-
- {header && (
-
- )}
-
- {renderMenuContent()}
+
+
+ {header && (
+
- {footer && (
- <>
-
-
- {footer}
-
- >
- )}
+ )}
+
+ {renderMenuContent()}
-
-
+ {footer && (
+ <>
+
+
+ {footer}
+
+ >
+ )}
+
+
);
});
diff --git a/tests/utils/page/actions.ts b/tests/utils/page/actions.ts
index 7e9fe7fbb..9aca75e4f 100644
--- a/tests/utils/page/actions.ts
+++ b/tests/utils/page/actions.ts
@@ -650,7 +650,7 @@ const selectRequestPaneTab = async (page: Page, tabName: string) => {
await overflowButton.click();
// Wait for dropdown to appear and click the menu item (overflow tabs are rendered as menuitems)
- const dropdownItem = page.locator('.tippy-content').getByRole('menuitem', { name: tabName });
+ const dropdownItem = page.locator('.tippy-box .dropdown-item').filter({ hasText: tabName });
await expect(dropdownItem).toBeVisible();
await dropdownItem.click();
return;