diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png index 7fa6a1adfa8..b7042da2aaf 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png index a2c6fb8fa5d..da10d5a2ea4 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Groups.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Groups.png index 38a2db062f5..6f699a50ec6 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Groups.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Groups.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Nested_Options_Groups.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Nested_Options_Groups.png index 38a2db062f5..6f699a50ec6 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Nested_Options_Groups.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiComboBox_Nested_Options_Groups.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png index 2afc5775f24..c4a961b6415 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png index 41df97e6918..bf3953d37be 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png index 3678147fcf4..8196c1f80c4 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png index 5e62e1a3732..c43ab3fe28f 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png index 0ed7e06c6d5..c76efb162dc 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png index 0ed7e06c6d5..35521170bbb 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeaderLinks_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeaderLinks_Playground.png index 6653d562191..a41e1c1cd15 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeaderLinks_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeaderLinks_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeader_Dark_Theme_With_Sitewide_Search.png b/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeader_Dark_Theme_With_Sitewide_Search.png index 73dff6354a0..3881dab7904 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeader_Dark_Theme_With_Sitewide_Search.png and b/packages/eui/.loki/reference/chrome_desktop_Layout_EuiHeader_EuiHeader_Dark_Theme_With_Sitewide_Search.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png index fb60ed6cca2..017e5ac6d43 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefreshButton_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png index 925ab912d1d..fd924ac4fe2 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiAutoRefresh_EuiAutoRefresh_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Groups.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Groups.png index bd00849b0b8..661b6537bdb 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Groups.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Groups.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Nested_Options_Groups.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Nested_Options_Groups.png index bd00849b0b8..661b6537bdb 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Nested_Options_Groups.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiComboBox_Nested_Options_Groups.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png index 94c44ecdbf7..c47290a1b4b 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png index b43c64c987b..9159441dff0 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png index 80a55d2f4f2..a87e7ba5261 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png index a939092c2af..adfa6857b3a 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png index fa3393a4c64..28a69a24121 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png index fa3393a4c64..32277cccdf5 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Layout_EuiHeader_EuiHeaderLinks_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Layout_EuiHeader_EuiHeaderLinks_Playground.png index 7e8da064785..8298908276c 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Layout_EuiHeader_EuiHeaderLinks_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Layout_EuiHeader_EuiHeaderLinks_Playground.png differ diff --git a/packages/eui/.storybook/loki.ts b/packages/eui/.storybook/loki.ts index 06770517202..9c8879cb44b 100644 --- a/packages/eui/.storybook/loki.ts +++ b/packages/eui/.storybook/loki.ts @@ -25,12 +25,7 @@ export const LOKI_SELECTORS = { /** * Portal element content selector */ - portal: '[data-euiportal="true"]', - /** - * Body selector - * TODO: remove when LOKI_SELECTORS.portal selector works as expected again - */ - body: 'body', + portal: '#storybook-root', } as const; /** diff --git a/packages/eui/.storybook/preview.tsx b/packages/eui/.storybook/preview.tsx index d8be14a6169..385ee472dff 100644 --- a/packages/eui/.storybook/preview.tsx +++ b/packages/eui/.storybook/preview.tsx @@ -10,6 +10,7 @@ import React from 'react'; import type { Preview } from '@storybook/react'; +import { useState, useMemo } from '@storybook/preview-api'; import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport'; /* @@ -57,24 +58,41 @@ import { hideStorybookControls } from './utils'; const preview: Preview = { decorators: [ customJsxDecorator, - (Story, context) => ( - -
*/ - id="story-wrapper" - css={[ - writingModeStyles.writingMode, - // @ts-ignore - we're manually ensuring `writingMode` globals match our Emotion style keys - writingModeStyles[context.globals.writingMode], - ]} + (Story, context) => { + const [portalSibling, setPortalSibling] = useState( + null + ); + const portalInsert = useMemo(() => { + if (portalSibling) { + return { + EuiPortal: { + insert: { sibling: portalSibling, position: 'after' as const }, + }, + }; + } + }, [portalSibling]); + + return ( + - -
-
- ), +
*/ + id="story-wrapper" + css={[ + writingModeStyles.writingMode, + // @ts-ignore - we're manually ensuring `writingMode` globals match our Emotion style keys + writingModeStyles[context.globals.writingMode], + ]} + > + {portalInsert && } +
+ + ); + }, ], globalTypes: { colorMode: { diff --git a/packages/eui/.storybook/test.ts b/packages/eui/.storybook/test.ts new file mode 100644 index 00000000000..0cc66d08a92 --- /dev/null +++ b/packages/eui/.storybook/test.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { queries, within, waitFor, fireEvent, expect } from '@storybook/test'; +import * as dataTestSubjQueries from '../src/test/rtl/data_test_subj_queries'; + +/** + * Custom Storybook within util with EUI query helpers + * + additional chained async/waitFor component utils + * + * @see https://storybook.js.org/docs/writing-stories/play-function#writing-stories-with-the-play-function + * @see https://testing-library.com/docs/dom-testing-library/api-within/ + */ +const customWithin = (canvasElement: HTMLElement) => { + const canvas = within( + canvasElement, + { ...queries, ...dataTestSubjQueries } + ); + + return { + ...canvas, + + /** + * 1. Loki doesn't like userEvent, only fireEvent + * 2. Storybook fires fireEvents too early (esp. on page load), so we add a waitFor + */ + waitForAndClick: async (testSubject: string) => { + await waitFor(() => + expect(canvas.getByTestSubject(testSubject)).toBeInTheDocument() + ); + await fireEvent.click(canvas.getByTestSubject(testSubject)); + }, + + waitForEuiPopoverVisible: async () => + await waitFor(() => + expect(canvasElement.querySelector('[data-popover-open]')).toBeVisible() + ), + }; +}; + +export { customWithin as within }; diff --git a/packages/eui/changelogs/upcoming/8003.md b/packages/eui/changelogs/upcoming/8003.md new file mode 100644 index 00000000000..456e5c1fead --- /dev/null +++ b/packages/eui/changelogs/upcoming/8003.md @@ -0,0 +1,3 @@ +**Bug fixes** + +- Fixed `EuiPopover` to correctly inherit from `EuiProvider`'s `componentDefaults.EuiPortal.insert` diff --git a/packages/eui/src/components/combo_box/combo_box.stories.tsx b/packages/eui/src/components/combo_box/combo_box.stories.tsx index c65dcb5aaba..880c9d93496 100644 --- a/packages/eui/src/components/combo_box/combo_box.stories.tsx +++ b/packages/eui/src/components/combo_box/combo_box.stories.tsx @@ -139,7 +139,7 @@ export const Groups: Story = { include: ['options'], }, loki: { - chromeSelector: LOKI_SELECTORS.body, + chromeSelector: LOKI_SELECTORS.portal, }, }, args: { @@ -167,7 +167,7 @@ export const NestedOptionsGroups: Story = { include: ['options'], }, loki: { - chromeSelector: LOKI_SELECTORS.body, + chromeSelector: LOKI_SELECTORS.portal, }, }, args: { diff --git a/packages/eui/src/components/date_picker/auto_refresh/auto_refresh.stories.tsx b/packages/eui/src/components/date_picker/auto_refresh/auto_refresh.stories.tsx index 0da22bd1990..e538b50e4a8 100644 --- a/packages/eui/src/components/date_picker/auto_refresh/auto_refresh.stories.tsx +++ b/packages/eui/src/components/date_picker/auto_refresh/auto_refresh.stories.tsx @@ -7,10 +7,12 @@ */ import type { Meta, StoryObj } from '@storybook/react'; - +import { fireEvent, waitFor } from '@storybook/test'; +import { within } from '../../../../.storybook/test'; +import { LOKI_SELECTORS } from '../../../../.storybook/loki'; import { enableFunctionToggleControls } from '../../../../.storybook/utils'; -import { REFRESH_UNIT_OPTIONS } from '../types'; +import { REFRESH_UNIT_OPTIONS } from '../types'; import { EuiAutoRefresh, EuiAutoRefreshProps } from './auto_refresh'; const meta: Meta = { @@ -18,8 +20,7 @@ const meta: Meta = { component: EuiAutoRefresh, parameters: { loki: { - // TODO: uncomment once loki CLI is fixed for portal component stories - // chromeSelector: LOKI_SELECTORS.portal, + chromeSelector: LOKI_SELECTORS.portal, }, }, argTypes: { @@ -42,15 +43,13 @@ export default meta; type Story = StoryObj; export const Playground: Story = { - // TODO: uncomment once loki CLI is fixed for portal component stories - // play: lokiPlayDecorator(async (context) => { - // const { bodyElement, step } = context; - // const canvas = within(bodyElement); - // await step('show popover on click of the input', async () => { - // await userEvent.click(canvas.getByLabelText('Auto refresh')); - // await waitFor(() => { - // expect(canvas.getByRole('dialog')).toBeVisible(); - // }); - // }); - // }), + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await step('show popover on click', async () => { + await waitFor(async () => { + await fireEvent.click(canvas.getByLabelText('Auto refresh')); + }); + await canvas.waitForEuiPopoverVisible(); + }); + }, }; diff --git a/packages/eui/src/components/date_picker/date_picker.stories.tsx b/packages/eui/src/components/date_picker/date_picker.stories.tsx index 4f1d681f66f..d8d51d6f3e1 100644 --- a/packages/eui/src/components/date_picker/date_picker.stories.tsx +++ b/packages/eui/src/components/date_picker/date_picker.stories.tsx @@ -9,12 +9,14 @@ import React, { useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import moment from 'moment'; - +import { fireEvent, waitFor } from '@storybook/test'; +import { within } from '../../../.storybook/test'; +import { LOKI_SELECTORS } from '../../../.storybook/loki'; import { disableStorybookControls, enableFunctionToggleControls, } from '../../../.storybook/utils'; -import { LOKI_SELECTORS } from '../../../.storybook/loki'; + import { EuiDatePicker, EuiDatePickerProps, @@ -119,6 +121,16 @@ const meta: Meta = { selected: null, utcOffset: undefined, }, + // Open the datepicker automatically for Loki VRT + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await step('show popover on click', async () => { + await waitFor(async () => { + await fireEvent.click(canvas.getByRole('textbox')); + }); + await canvas.waitForEuiPopoverVisible(); + }); + }, }; disableStorybookControls(meta, ['inputRef']); enableFunctionToggleControls(meta, ['onClear', 'onChange']); @@ -135,9 +147,6 @@ export const Playground: Story = { }, }, args: { - // NOTE: loki play interactions won't work in CLI somehow - // TODO: exchange with loki play() interactions once fixed - autoFocus: true, // setting a selected date to ensure VRT does not // automatically updated based on the current date selected: moment('Tue Mar 19 2024 18:54:51 GMT+0100'), @@ -162,7 +171,6 @@ export const TimeSelect: Story = { }, }, args: { - autoFocus: true, // Open the datepicker automatically for Loki VRT showTimeSelect: true, showTimeSelectOnly: false, selected: moment('01/01/1970').hours(23).minutes(0), @@ -191,7 +199,6 @@ export const RestrictedDaySelect: Story = { }, }, args: { - autoFocus: true, // Open the datepicker automatically for Lok VRT, selected: moment('01/02/1970'), maxDate: moment('01/01/1970'), minDate: moment('12/31/1969'), diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx index be308e909ca..528d9baf4b3 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx @@ -8,8 +8,11 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; - +import { expect } from '@storybook/test'; +import { within } from '../../../../.storybook/test'; +import { LOKI_SELECTORS } from '../../../../.storybook/loki'; import { enableFunctionToggleControls } from '../../../../.storybook/utils'; + import { EuiLink } from '../../link'; import { ApplyTime, REFRESH_UNIT_OPTIONS } from '../types'; @@ -21,12 +24,6 @@ import { const meta: Meta = { title: 'Forms/EuiSuperDatePicker/EuiSuperDatePicker', component: EuiSuperDatePicker, - parameters: { - loki: { - // TODO: uncomment once loki CLI is fixed for portal component stories - // chromeSelector: LOKI_SELECTORS.portal, - }, - }, argTypes: { refreshIntervalUnits: { control: 'radio', @@ -70,6 +67,9 @@ export const CustomQuickSelectPanel: Story = { controls: { include: ['customQuickSelectPanels', 'onTimeChange'], }, + loki: { + chromeSelector: LOKI_SELECTORS.portal, + }, }, args: { customQuickSelectPanels: [ @@ -79,18 +79,14 @@ export const CustomQuickSelectPanel: Story = { }, ], }, - // TODO: uncomment once loki CLI is fixed for portal component stories - // play: lokiPlayDecorator(async (context) => { - // const { bodyElement, step } = context; - // const canvas = within(bodyElement); - // await step('show popover on click of the quick select button', async () => { - // await userEvent.click(canvas.getByLabelText('Date quick select')); - // await waitFor(() => { - // expect(canvas.getByRole('dialog')).toBeVisible(); - // expect(canvas.getByText('Custom quick select panel')).toBeVisible(); - // }); - // }); - // }), + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await step('show popover on click of the quick select button', async () => { + canvas.waitForAndClick('superDatePickerToggleQuickMenuButton'); + await canvas.waitForEuiPopoverVisible(); + expect(canvas.getByText('Custom quick select panel')).toBeVisible(); + }); + }, }; function CustomPanel({ applyTime }: { applyTime?: ApplyTime }) { diff --git a/packages/eui/src/components/header/header.stories.tsx b/packages/eui/src/components/header/header.stories.tsx index 7b4d45767cc..a10a86299b6 100644 --- a/packages/eui/src/components/header/header.stories.tsx +++ b/packages/eui/src/components/header/header.stories.tsx @@ -90,7 +90,7 @@ export const DarkThemeWithSitewideSearch: Story = { parameters: { layout: 'fullscreen', controls: { include: ['theme'] }, - loki: { chromeSelector: LOKI_SELECTORS.body }, // Required to capture the open popover + loki: { chromeSelector: LOKI_SELECTORS.portal }, // Required to capture the open popover }, args: { theme: 'dark', @@ -155,8 +155,8 @@ export const DarkThemeWithSitewideSearch: Story = { }; const MultipleFixedHeadersExample = () => { - const [fixedHeadersCount, setFixedHeadersCount] = useState(3); // eslint-disable-line react-hooks/rules-of-hooks - const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); // eslint-disable-line react-hooks/rules-of-hooks + const [fixedHeadersCount, setFixedHeadersCount] = useState(3); + const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); const sections = [ { diff --git a/packages/eui/src/components/header/header_links/header_links.stories.tsx b/packages/eui/src/components/header/header_links/header_links.stories.tsx index 982146901ee..32eeb36d6f7 100644 --- a/packages/eui/src/components/header/header_links/header_links.stories.tsx +++ b/packages/eui/src/components/header/header_links/header_links.stories.tsx @@ -8,6 +8,8 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { fireEvent, waitFor } from '@storybook/test'; +import { within } from '../../../../.storybook/test'; import { LOKI_SELECTORS } from '../../../../.storybook/loki'; import { EuiHeader, EuiHeaderSection, EuiHeaderSectionItem } from '../'; @@ -22,11 +24,9 @@ const meta: Meta = { // Component defaults gutterSize: 's', popoverBreakpoints: ['xs', 's'], - // VRT - popoverProps: { isOpen: true }, }, // Required to capture mobile popover - parameters: { loki: { chromeSelector: LOKI_SELECTORS.body } }, + parameters: { loki: { chromeSelector: LOKI_SELECTORS.portal } }, }; export default meta; @@ -46,4 +46,18 @@ export const Playground: Story = { ), + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + await waitFor(() => canvas.getByLabelText('App menu')); // Wait for rendering to finish + + step('Open mobile popover', async () => { + await waitFor(async () => { + const mobilePopover = canvas.queryByLabelText('Open menu'); + if (mobilePopover) { + await fireEvent.click(mobilePopover); + await canvas.waitForEuiPopoverVisible(); + } + }); + }); + }, }; diff --git a/packages/eui/src/components/popover/popover.spec.tsx b/packages/eui/src/components/popover/popover.spec.tsx index 926391dbf89..811a995b83b 100644 --- a/packages/eui/src/components/popover/popover.spec.tsx +++ b/packages/eui/src/components/popover/popover.spec.tsx @@ -10,7 +10,13 @@ /// /// -import React, { useState, FC, MouseEventHandler } from 'react'; +import React, { + useState, + useEffect, + FC, + MouseEventHandler, + PropsWithChildren, +} from 'react'; import { EuiButton, EuiConfirmModal } from '../../components'; import { EuiPopover, EuiPopoverProps } from './popover'; @@ -182,8 +188,10 @@ describe('EuiPopover', () => { // Assert that the popover rendered horizontally and not vertically cy.get('[data-popover-panel]') .invoke('offset') - .then(({ top, left }) => { - expect(left).to.be.gt(top); + .then((offset) => { + if (offset) { + expect(offset.left).to.be.gt(offset.top); + } }); }); @@ -201,9 +209,69 @@ describe('EuiPopover', () => { // Assert that the popover vertically and not horizontally cy.get('[data-popover-panel]') .invoke('offset') - .then(({ top, left }) => { - expect(top).to.be.gt(left); + .then((offset) => { + if (offset) { + expect(offset.top).to.be.gt(offset.left); + } }); }); }); + + describe('insert', () => { + const sibling = document.createElement('div'); + sibling.id = 'sibling'; + const componentDefaults = { + EuiPortal: { insert: { sibling, position: 'before' as const } }, + }; + + const Wrapper: FC = ({ children }) => { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + document.body.appendChild(sibling); + setMounted(true); + }, []); + + return <>{mounted && children}; + }; + + it('inherits from componentDefaults.EuiPortal', () => { + cy.mount( + + + , + { providerProps: { componentDefaults } } + ); + + // verify the popover was appended before the sibling + cy.get('div[data-euiportal]').then((portal) => { + cy.get('div#sibling').then((sibling) => { + expect(portal).to.have.lengthOf(1); + expect(sibling).to.have.lengthOf(1); + expect(sibling.get(0).previousElementSibling).to.equal(portal.get(0)); + }); + }); + }); + + it('still allows overriding defaults via component props', () => { + cy.mount( + + + , + { providerProps: { componentDefaults } } + ); + + // verify portal elements were appended before and after the sibling + cy.get('div[data-euiportal]').then((portal) => { + cy.get('div#sibling').then((sibling) => { + expect(portal).to.have.lengthOf(1); + expect(sibling).to.have.lengthOf(1); + expect(sibling.get(0).nextElementSibling).to.equal(portal.get(0)); + }); + }); + }); + }); }); diff --git a/packages/eui/src/components/popover/popover.tsx b/packages/eui/src/components/popover/popover.tsx index e31db77517b..78c13b94226 100644 --- a/packages/eui/src/components/popover/popover.tsx +++ b/packages/eui/src/components/popover/popover.tsx @@ -709,7 +709,7 @@ export class EuiPopover extends Component { const returnFocus = this.state.isOpenStable ? returnFocusConfig : false; panel = ( - + /// -import React, { useState, useEffect, FunctionComponent } from 'react'; +import React, { + useState, + useEffect, + FunctionComponent, + PropsWithChildren, +} from 'react'; import { EuiPortal, EuiPortalProps } from './portal'; @@ -130,7 +135,7 @@ describe('EuiPortal', () => { const sibling = document.createElement('div'); sibling.id = 'sibling'; - const Wrapper: FunctionComponent = ({ children }) => { + const Wrapper: FunctionComponent = ({ children }) => { const [mounted, setMounted] = useState(false); useEffect(() => {