diff --git a/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/usePluginLinks.spec.ts b/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/usePluginLinks.spec.ts index 852fe00fa85..11c20cd9702 100644 --- a/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/usePluginLinks.spec.ts +++ b/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/usePluginLinks.spec.ts @@ -3,13 +3,14 @@ import { test, expect } from '@grafana/plugin-e2e'; import pluginJson from '../plugin.json'; import testApp3pluginJson from '../plugins/grafana-extensionexample3-app/plugin.json'; import { testIds } from '../testIds'; +import { selectors } from '@grafana/e2e-selectors'; test.describe('grafana-extensionstest-app', { tag: ['@plugins'] }, () => { test('should extend the actions menu with a link to a-app plugin', async ({ page }) => { await page.goto(`/a/${pluginJson.id}/added-links`); const section = await page.getByTestId(testIds.addedLinksPage.section1); await section.getByTestId(testIds.actions.button).click(); - await page.getByTestId(testIds.container).getByText('Go to A').click(); + await page.getByTestId(selectors.components.Portal.container).getByText('Go to A').click(); await page.getByTestId(testIds.modal.open).click(); await expect(page.getByTestId(testIds.appA.container)).toBeVisible(); }); @@ -18,7 +19,7 @@ test.describe('grafana-extensionstest-app', { tag: ['@plugins'] }, () => { await page.goto(`/a/${pluginJson.id}/added-links`); const section = await page.getByTestId(testIds.addedLinksPage.section1); await section.getByTestId(testIds.actions.button).click(); - await page.getByTestId(testIds.container).getByText('Open from B').click(); + await page.getByTestId(selectors.components.Portal.container).getByText('Open from B').click(); await expect(page.getByTestId(testIds.appB.modal)).toBeVisible(); }); @@ -26,7 +27,7 @@ test.describe('grafana-extensionstest-app', { tag: ['@plugins'] }, () => { await page.goto(`/a/${pluginJson.id}/added-links`); const section = await page.getByTestId(testIds.addedLinksPage.section1); await section.getByTestId(testIds.actions.button).click(); - await page.getByTestId(testIds.container).getByText('Basic link').click(); + await page.getByTestId(selectors.components.Portal.container).getByText('Basic link').click(); await page.getByTestId(testIds.modal.open).click(); await expect(page.getByTestId(testIds.appA.container)).toBeVisible(); }); diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx index 199aa1c279e..12e3eb08354 100644 --- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx +++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx @@ -1,17 +1,15 @@ -import { css } from '@emotion/css'; -import { autoUpdate, offset, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react'; -import { FocusScope } from '@react-aria/focus'; import { memo, HTMLAttributes, useState } from 'react'; -import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { SelectableValue } from '@grafana/data'; -import { useStyles2 } from '../../themes/ThemeContext'; -import { getPositioningMiddleware } from '../../utils/floating'; import { Menu } from '../Menu/Menu'; import { MenuItem } from '../Menu/MenuItem'; +import { ScrollContainer } from '../ScrollContainer/ScrollContainer'; import { ToolbarButton, ToolbarButtonVariant } from '../ToolbarButton/ToolbarButton'; import { PopoverContent } from '../Tooltip/types'; +import { Dropdown } from './Dropdown'; + export interface Props extends HTMLAttributes { className?: string; options: Array>; @@ -29,70 +27,34 @@ export interface Props extends HTMLAttributes { */ const ButtonSelectComponent = (props: Props) => { const { className, options, value, onChange, narrow, variant, ...restProps } = props; - const styles = useStyles2(getStyles); const [isOpen, setIsOpen] = useState(false); - const placement = 'bottom-end'; - // the order of middleware is important! - const middleware = [offset(0), ...getPositioningMiddleware(placement)]; - - const { context, refs, floatingStyles } = useFloating({ - open: isOpen, - placement, - onOpenChange: setIsOpen, - middleware, - whileElementsMounted: autoUpdate, - }); - - const click = useClick(context); - const dismiss = useDismiss(context); - - const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, click]); - - const onChangeInternal = (item: SelectableValue) => { - onChange(item); - setIsOpen(false); - }; + const renderMenu = () => ( + setIsOpen(false)}> + + {options.map((item) => ( + onChange(item)} + active={item.value === value?.value} + ariaChecked={item.value === value?.value} + ariaLabel={item.ariaLabel || item.label} + disabled={item.isDisabled} + component={item.component} + role="menuitemradio" + /> + ))} + + + ); return ( -
- + + {value?.label || (value?.value != null ? String(value?.value) : null)} - {isOpen && ( -
- - {/* - tabIndex=-1 is needed here to support highlighting text within the menu when using FocusScope - see https://github.com/adobe/react-spectrum/issues/1604#issuecomment-781574668 - */} - setIsOpen(false)}> - {options.map((item) => ( - onChangeInternal(item)} - active={item.value === value?.value} - ariaChecked={item.value === value?.value} - ariaLabel={item.ariaLabel || item.label} - disabled={item.isDisabled} - component={item.component} - role="menuitemradio" - /> - ))} - - -
- )} -
+ ); }; @@ -102,17 +64,3 @@ ButtonSelectComponent.displayName = 'ButtonSelect'; // see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37087#issuecomment-656596623 // eslint-disable-next-line @typescript-eslint/consistent-type-assertions export const ButtonSelect = memo(ButtonSelectComponent) as typeof ButtonSelectComponent; - -const getStyles = (theme: GrafanaTheme2) => { - return { - wrapper: css({ - position: 'relative', - display: 'inline-flex', - }), - menuWrapper: css({ - zIndex: theme.zIndex.dropdown, - maxHeight: '100vh', - overflow: 'auto', - }), - }; -};