diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/horizontalFilterBar.test.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/horizontalFilterBar.test.ts index ec20224fc..b89e9f8a4 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/horizontalFilterBar.test.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/horizontalFilterBar.test.ts @@ -161,7 +161,7 @@ describe('Horizontal FilterBar', () => { cy.getBySel('filter-control-name') .contains('test_12') .should('not.be.visible'); - cy.get('.ant-popover-inner-content').scrollTo('bottom'); + cy.get('.antd5-popover-inner').scrollTo('bottom'); cy.getBySel('filter-control-name').contains('test_12').should('be.visible'); }); @@ -226,7 +226,7 @@ describe('Horizontal FilterBar', () => { cy.getBySel('slice-header').within(() => { cy.get('.filter-counts').trigger('mouseover'); }); - cy.get('.filterStatusPopover').contains('test_9').click(); + cy.getBySel('filter-status-popover').contains('test_9').click(); cy.getBySel('dropdown-content').should('be.visible'); cy.get('.ant-select-focused').should('be.visible'); }); diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts index fa85de54c..c39a9b633 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts @@ -456,19 +456,19 @@ export function applyAdvancedTimeRangeFilterOnDashboard( endRange?: string, ) { cy.get('.control-label').contains('RANGE TYPE').should('be.visible'); - cy.get('.ant-popover-content .ant-select-selector') + cy.get('.antd5-popover-content .ant-select-selector') .should('be.visible') .click(); cy.get(`[label="Advanced"]`).should('be.visible').click(); cy.get('.section-title').contains('Advanced Time Range').should('be.visible'); if (startRange) { - cy.get('.ant-popover-inner-content') + cy.get('.antd5-popover-inner-content') .find('[class^=ant-input]') .first() .type(`${startRange}`); } if (endRange) { - cy.get('.ant-popover-inner-content') + cy.get('.antd5-popover-inner-content') .find('[class^=ant-input]') .last() .type(`${endRange}`); diff --git a/superset-frontend/cypress-base/cypress/support/directories.ts b/superset-frontend/cypress-base/cypress/support/directories.ts index c2754e454..286f86544 100644 --- a/superset-frontend/cypress-base/cypress/support/directories.ts +++ b/superset-frontend/cypress-base/cypress/support/directories.ts @@ -555,7 +555,7 @@ export const exploreView = { timeSection: { timeRangeFilter: dataTestLocator('time-range-trigger'), timeRangeFilterModal: { - container: '.ant-popover-content', + container: '.antd5-popover-content', footer: '.footer', cancelButton: dataTestLocator('cancel-button'), configureLastTimeRange: { diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx index a848a2e9f..3a29c4885 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx @@ -17,9 +17,9 @@ * under the License. */ import { useEffect, useState } from 'react'; -import { Popover } from 'antd'; +import { Popover } from 'antd-v5'; import type ReactAce from 'react-ace'; -import type { PopoverProps } from 'antd/lib/popover'; +import type { PopoverProps } from 'antd-v5/lib/popover'; import { CalculatorOutlined } from '@ant-design/icons'; import { css, styled, useTheme, t } from '@superset-ui/core'; @@ -72,7 +72,7 @@ export const SQLPopover = (props: PopoverProps & { sqlExpression: string }) => { /> } placement="bottomLeft" - arrowPointAtCenter + arrow={{ pointAtCenter: true }} title={t('SQL expression')} {...props} > diff --git a/superset-frontend/src/GlobalStyles.tsx b/superset-frontend/src/GlobalStyles.tsx index d213faac8..e80d32e7e 100644 --- a/superset-frontend/src/GlobalStyles.tsx +++ b/superset-frontend/src/GlobalStyles.tsx @@ -39,14 +39,18 @@ export const GlobalStyles = () => ( .echarts-tooltip[style*='visibility: hidden'] { display: none !important; } + // Ant Design is applying inline z-index styles causing troubles // TODO: Remove z-indexes when Ant Design is fully upgraded to v5 // Prefer vanilla Ant Design z-indexes that should work out of the box - .ant-popover, + .antd5-dropdown, + .ant-dropdown, .ant-select-dropdown, .antd5-modal-wrap, .antd5-modal-mask, - .antd5-picker-dropdown { + .antd5-picker-dropdown, + .ant-popover, + .antd5-popover { z-index: ${theme.zIndex.max} !important; } diff --git a/superset-frontend/src/components/DropdownContainer/index.tsx b/superset-frontend/src/components/DropdownContainer/index.tsx index 744b7f61d..0d2da00f8 100644 --- a/superset-frontend/src/components/DropdownContainer/index.tsx +++ b/superset-frontend/src/components/DropdownContainer/index.tsx @@ -137,7 +137,6 @@ const DropdownContainer = forwardRef( const { current } = ref; const [itemsWidth, setItemsWidth] = useState([]); const [popoverVisible, setPopoverVisible] = useState(false); - // We use React.useState to be able to mock the state in Jest const [overflowingIndex, setOverflowingIndex] = useState(-1); @@ -181,11 +180,13 @@ const DropdownContainer = forwardRef( ); useLayoutEffect(() => { + if (popoverVisible) { + return; + } const container = current?.children.item(0); if (container) { const { children } = container; const childrenArray = Array.from(children); - // If items length change, add all items to the container // and recalculate the widths if (itemsWidth.length !== items.length) { @@ -341,11 +342,7 @@ const DropdownContainer = forwardRef( <> + setPopoverVisible(visible)} + open={popoverVisible} + onOpenChange={visible => setPopoverVisible(visible)} placement="bottom" forceRender={forceRender} > diff --git a/superset-frontend/src/components/Popover/Popover.stories.tsx b/superset-frontend/src/components/Popover/Popover.stories.tsx index d9baaf107..4f23a7024 100644 --- a/superset-frontend/src/components/Popover/Popover.stories.tsx +++ b/superset-frontend/src/components/Popover/Popover.stories.tsx @@ -17,8 +17,7 @@ * under the License. */ import Button from 'src/components/Button'; -import { PopoverProps } from 'antd/lib/popover'; -import Popover from '.'; +import Popover, { PopoverProps } from 'src/components/Popover'; export default { title: 'Popover', @@ -66,6 +65,8 @@ const TRIGGERS = { InteractivePopover.args = { content: 'Popover sample content', title: 'Popover title', + arrow: true, + color: '#fff', }; InteractivePopover.argTypes = { @@ -79,4 +80,14 @@ InteractivePopover.argTypes = { control: { type: 'select' }, options: TRIGGERS.options, }, + arrow: { + name: 'arrow', + control: { type: 'boolean' }, + description: "Change arrow's visible state", + }, + color: { + name: 'color', + control: { type: 'color' }, + description: 'The background color of the popover.', + }, }; diff --git a/superset-frontend/src/components/Popover/Popover.test.tsx b/superset-frontend/src/components/Popover/Popover.test.tsx index cf4cb65da..395abb67e 100644 --- a/superset-frontend/src/components/Popover/Popover.test.tsx +++ b/superset-frontend/src/components/Popover/Popover.test.tsx @@ -21,7 +21,7 @@ import userEvent from '@testing-library/user-event'; import { supersetTheme } from '@superset-ui/core'; import Icons from 'src/components/Icons'; import Button from 'src/components/Button'; -import Popover from '.'; +import Popover from 'src/components/Popover'; test('should render', () => { const { container } = render(); @@ -29,12 +29,12 @@ test('should render', () => { }); test('should render a title when visible', () => { - render(); + render(); expect(screen.getByText('Popover title')).toBeInTheDocument(); }); test('should render some content when visible', () => { - render(); + render(); expect(screen.getByText('Content sample')).toBeInTheDocument(); }); @@ -61,22 +61,22 @@ test('renders with icon child', async () => { }); test('fires an event when visibility is changed', async () => { - const onVisibleChange = jest.fn(); + const onOpenChange = jest.fn(); render( , ); userEvent.hover(screen.getByRole('button')); - await waitFor(() => expect(onVisibleChange).toHaveBeenCalledTimes(1)); + await waitFor(() => expect(onOpenChange).toHaveBeenCalledTimes(1)); }); test('renders with theme', () => { - render(); + render(); const title = screen.getByText('Popover title'); expect(title).toHaveStyle({ fontSize: supersetTheme.gridUnit * 3.5, diff --git a/superset-frontend/src/components/Popover/Popover.tsx b/superset-frontend/src/components/Popover/Popover.tsx deleted file mode 100644 index 14fded78f..000000000 --- a/superset-frontend/src/components/Popover/Popover.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Popover as AntdPopover } from 'antd'; -import type { PopoverProps as AntdPopoverProps } from 'antd/lib/popover'; - -export interface PopoverProps extends AntdPopoverProps { - forceRender?: boolean; -} - -export const Popover = (props: PopoverProps) => ; diff --git a/superset-frontend/src/components/Popover/index.tsx b/superset-frontend/src/components/Popover/index.tsx index d147a75ed..4c290ed62 100644 --- a/superset-frontend/src/components/Popover/index.tsx +++ b/superset-frontend/src/components/Popover/index.tsx @@ -16,9 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -export type { PopoverProps } from 'antd/lib/popover'; -export type { TooltipPlacement } from 'antd/lib/tooltip'; +import { Popover as AntdPopover } from 'antd-v5'; +import { PopoverProps as AntdPopoverProps } from 'antd-v5/lib/popover'; -// Eventually Popover can be wrapped and customized in this file -// for now we're just redirecting -export { Popover as default } from './Popover'; +export interface PopoverProps extends AntdPopoverProps { + forceRender?: boolean; +} + +const Popover = (props: PopoverProps) => ; + +export default Popover; diff --git a/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx b/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx index 3aedff2b4..ba91d167d 100644 --- a/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx +++ b/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx @@ -44,7 +44,7 @@ function HeaderWithRadioGroup(props: HeaderWithRadioGroupProps) { >
} placement="bottomLeft" - arrowPointAtCenter + arrow={{ pointAtCenter: true }} > { - .filterStatusPopover.ant-popover{z-index: 101}`} - `} - /> {!editMode && !topLevelTabs && dashboardLayout[DASHBOARD_GRID_ID]?.children?.length === 0 && ( diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx index a3b5a6512..65776ed91 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx @@ -19,8 +19,7 @@ import { RefObject, useEffect, useRef, KeyboardEvent } from 'react'; import { useSelector } from 'react-redux'; -import { Global, css } from '@emotion/react'; -import { t } from '@superset-ui/core'; +import { t, useTheme } from '@superset-ui/core'; import Popover from 'src/components/Popover'; import { FiltersContainer, @@ -120,7 +119,7 @@ const DetailsPanelPopover = ({ const indicatorKey = (indicator: Indicator): string => `${indicator.column} - ${indicator.name}`; - + const theme = useTheme(); const content = ( - css` - .filterStatusPopover { - .ant-popover-inner { - background-color: ${theme.colors.grayscale.dark2}cc; - .ant-popover-inner-content { - padding: ${theme.gridUnit * 2}px; - } - } - &.ant-popover-placement-bottom, - &.ant-popover-placement-bottomLeft, - &.ant-popover-placement-bottomRight { - & > .ant-popover-content > .ant-popover-arrow { - border-top-color: ${theme.colors.grayscale.dark2}cc; - border-left-color: ${theme.colors.grayscale.dark2}cc; - } - } - &.ant-popover-placement-top, - &.ant-popover-placement-topLeft, - &.ant-popover-placement-topRight { - & > .ant-popover-content > .ant-popover-arrow { - border-bottom-color: ${theme.colors.grayscale.dark2}cc; - border-right-color: ${theme.colors.grayscale.dark2}cc; - } - } - &.ant-popover-placement-left, - &.ant-popover-placement-leftTop, - &.ant-popover-placement-leftBottom { - & > .ant-popover-content > .ant-popover-arrow { - border-top-color: ${theme.colors.grayscale.dark2}cc; - border-right-color: ${theme.colors.grayscale.dark2}cc; - } - } - &.ant-popover-placement-right, - &.ant-popover-placement-rightTop, - &.ant-popover-placement-rightBottom { - & > .ant-popover-content > .ant-popover-arrow { - border-bottom-color: ${theme.colors.grayscale.dark2}cc; - border-left-color: ${theme.colors.grayscale.dark2}cc; - } - } - &.ant-popover { - color: ${theme.colors.grayscale.light4}; - z-index: 99; - } - } - `} - />
{appliedCrossFilterIndicators.length ? (
@@ -224,12 +175,13 @@ const DetailsPanelPopover = ({ return ( {children} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx index 35806f363..dd5847e7b 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx @@ -30,7 +30,6 @@ export const FilterCard = ({ placement, }: FilterCardProps) => { const [internalIsVisible, setInternalIsVisible] = useState(false); - const hidePopover = () => { setInternalIsVisible(false); }; @@ -43,15 +42,18 @@ export const FilterCard = ({ return ( { + onOpenChange={visible => { setInternalIsVisible(externalIsVisible && visible); }} - visible={externalIsVisible && internalIsVisible} + open={externalIsVisible && internalIsVisible} content={} getPopupContainer={getPopupContainer ?? (() => document.body)} + arrow={false} > {children} diff --git a/superset-frontend/src/dashboard/styles.ts b/superset-frontend/src/dashboard/styles.ts index f3f0d753b..1ac9a2ee2 100644 --- a/superset-frontend/src/dashboard/styles.ts +++ b/superset-frontend/src/dashboard/styles.ts @@ -66,32 +66,6 @@ export const chartHeaderStyles = (theme: SupersetTheme) => css` `; export const filterCardPopoverStyle = (theme: SupersetTheme) => css` - .filter-card-popover { - width: 240px; - padding: 0; - border-radius: 4px; - - &.ant-popover-placement-bottom { - padding-top: ${theme.gridUnit}px; - } - - &.ant-popover-placement-left { - padding-right: ${theme.gridUnit * 3}px; - } - - .ant-popover-inner { - box-shadow: 0 0 8px rgb(0 0 0 / 10%); - } - - .ant-popover-inner-content { - padding: ${theme.gridUnit * 4}px; - } - - .ant-popover-arrow { - display: none; - } - } - .filter-card-tooltip { &.antd5-tooltip-placement-bottom { padding-top: 0; diff --git a/superset-frontend/src/explore/components/DataTableControl/index.tsx b/superset-frontend/src/explore/components/DataTableControl/index.tsx index 20e2a4775..e84d06a32 100644 --- a/superset-frontend/src/explore/components/DataTableControl/index.tsx +++ b/superset-frontend/src/explore/components/DataTableControl/index.tsx @@ -27,7 +27,6 @@ import { TimeFormats, useTheme, } from '@superset-ui/core'; -import { Global } from '@emotion/react'; import { Column } from 'react-table'; import { debounce } from 'lodash'; import { Input } from 'src/components/Input'; @@ -195,13 +194,6 @@ const DataTableTemporalHeaderCell = ({ datasourceId ? ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions e.stopPropagation()}> {/* hack to disable click propagation from popover content to table header, which triggers sorting column */} - {t('Column Formatting')} { anno, this.props.annotationError[anno.name], )} - visible={this.state.popoverVisible[i]} - onVisibleChange={visible => this.handleVisibleChange(visible, i)} + open={this.state.popoverVisible[i]} + onOpenChange={visible => this.handleVisibleChange(visible, i)} > {anno.name} @@ -254,9 +254,9 @@ class AnnotationLayerControl extends PureComponent { '', )} title={t('Add annotation layer')} - visible={this.state.popoverVisible[addLayerPopoverKey]} + open={this.state.popoverVisible[addLayerPopoverKey]} destroyTooltipOnHide - onVisibleChange={visible => + onOpenChange={visible => this.handleVisibleChange(visible, addLayerPopoverKey) } > diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopover.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopover.tsx index 26b0cbe88..5b03a5b27 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopover.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopover.tsx @@ -51,8 +51,8 @@ export const FormattingPopover = ({ extraColorChoices={extraColorChoices} /> } - visible={visible} - onVisibleChange={setVisible} + open={visible} + onOpenChange={setVisible} trigger={['click']} overlayStyle={{ width: '450px' }} {...props} diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/types.ts b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/types.ts index c352ca818..a1252ba68 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/types.ts +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/types.ts @@ -18,7 +18,7 @@ */ import { ReactNode } from 'react'; -import { PopoverProps } from 'antd/lib/popover'; +import { PopoverProps } from 'src/components/Popover'; import { Comparator, ControlComponentProps } from '@superset-ui/chart-controls'; export type ConditionalFormattingConfig = { diff --git a/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx index 3a106e728..315a34e79 100644 --- a/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx @@ -47,9 +47,9 @@ const ContourPopoverTrigger = ({ {props.children} diff --git a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx index 575f05f12..1d8e3c0db 100644 --- a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx +++ b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx @@ -88,7 +88,7 @@ test('Should lock the vertical scroll when the popover is visible', () => { test('Should place popover at the top', async () => { const { setStateMock } = setupTest({ ...createProps(), - getVisibilityRatio: () => 0.2, + getVisibilityRatio: () => ({ yRatio: 0.2, xRatio: 0.3 }), }); expect(screen.getByTestId('control-popover')).toBeInTheDocument(); @@ -102,21 +102,21 @@ test('Should place popover at the top', async () => { test('Should place popover at the center', async () => { const { setStateMock } = setupTest({ ...createProps(), - getVisibilityRatio: () => 0.5, + getVisibilityRatio: () => ({ yRatio: 0.5, xRatio: 0.7 }), }); expect(screen.getByTestId('control-popover')).toBeInTheDocument(); userEvent.click(screen.getByTestId('control-popover')); await waitFor(() => { - expect(setStateMock).toHaveBeenCalledWith('right'); + expect(setStateMock).toHaveBeenCalledWith('left'); }); }); test('Should place popover at the bottom', async () => { const { setStateMock } = setupTest({ ...createProps(), - getVisibilityRatio: () => 0.7, + getVisibilityRatio: () => ({ yRatio: 0.9, xRatio: 0.2 }), }); expect(screen.getByTestId('control-popover')).toBeInTheDocument(); @@ -162,7 +162,7 @@ test('Controlled mode', async () => { const baseProps = { ...createProps(), destroyTooltipOnHide: true, - visible: false, + open: false, }; const { rerender } = setupTest(baseProps); @@ -170,7 +170,7 @@ test('Controlled mode', async () => { expect(screen.getByTestId('control-popover')).toBeInTheDocument(); expect(screen.queryByText('Control Popover Test')).not.toBeInTheDocument(); - rerender(); + rerender(); expect(await screen.findByText('Control Popover Test')).toBeInTheDocument(); rerender(); diff --git a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx index 2f2664e28..b7be6cc59 100644 --- a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx +++ b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx @@ -21,49 +21,70 @@ import React, { FC, useCallback, useRef, useEffect, useState } from 'react'; import Popover, { PopoverProps as BasePopoverProps, - TooltipPlacement, } from 'src/components/Popover'; +import { TooltipPlacement } from 'src/components/Tooltip'; + const sectionContainerId = 'controlSections'; export const getSectionContainerElement = () => document.getElementById(sectionContainerId)?.lastElementChild as HTMLElement; -const getElementYVisibilityRatioOnContainer = (node: HTMLElement) => { +const getElementVisibilityRatio = (node?: HTMLElement) => { const containerHeight = window?.innerHeight; - const nodePositionInViewport = node?.getBoundingClientRect()?.top; - if (!containerHeight || !nodePositionInViewport) { - return 0; + const containerWidth = window?.innerWidth; + + const rect = node?.getBoundingClientRect(); + if (!containerHeight || !containerWidth || !rect?.top) { + return { yRatio: 0, xRatio: 0 }; } - return nodePositionInViewport / containerHeight; + const yRatio = rect.top / containerHeight; + const xRatio = rect.left / containerWidth; + return { yRatio, xRatio }; }; export type PopoverProps = BasePopoverProps & { - getVisibilityRatio?: typeof getElementYVisibilityRatioOnContainer; + getVisibilityRatio?: typeof getElementVisibilityRatio; }; const ControlPopover: FC = ({ getPopupContainer, - getVisibilityRatio = getElementYVisibilityRatioOnContainer, - visible: visibleProp, + getVisibilityRatio = getElementVisibilityRatio, + open: visibleProp, destroyTooltipOnHide = false, + placement: initialPlacement = 'right', ...props }) => { const triggerElementRef = useRef(); const [visible, setVisible] = useState( - visibleProp === undefined ? props.defaultVisible : visibleProp, + visibleProp === undefined ? props.defaultOpen : visibleProp, ); - const [placement, setPlacement] = React.useState('right'); + const [placement, setPlacement] = + React.useState(initialPlacement); const calculatePlacement = useCallback(() => { - const visibilityRatio = getVisibilityRatio(triggerElementRef.current!); - if (visibilityRatio < 0.35 && placement !== 'rightTop') { - setPlacement('rightTop'); - } else if (visibilityRatio > 0.65 && placement !== 'rightBottom') { - setPlacement('rightBottom'); - } else { - setPlacement('right'); + if (!triggerElementRef.current) return; + + const { yRatio, xRatio } = getVisibilityRatio(triggerElementRef.current); + + const horizontalPlacement = + xRatio < 0.35 ? 'right' : xRatio > 0.65 ? 'left' : ''; + + const verticalPlacement = (() => { + if (yRatio < 0.35) return horizontalPlacement ? 'top' : 'bottom'; + if (yRatio > 0.65) return horizontalPlacement ? 'bottom' : 'top'; + return ''; + })(); + + const newPlacement = + ((horizontalPlacement + ? horizontalPlacement + + verticalPlacement.charAt(0).toUpperCase() + + verticalPlacement.slice(1) + : verticalPlacement) as TooltipPlacement) || 'left'; + if (newPlacement !== placement) { + setPlacement(newPlacement); } }, [getVisibilityRatio]); @@ -97,7 +118,7 @@ const ControlPopover: FC = ({ } setVisible(!!visible); - props.onVisibleChange?.(!!visible); + props.onOpenChange?.(!!visible); }, [props, changeContainerScrollStatus], ); @@ -106,7 +127,7 @@ const ControlPopover: FC = ({ (event: KeyboardEvent) => { if (event.key === 'Escape') { setVisible(false); - props.onVisibleChange?.(false); + props.onOpenChange?.(false); } }, [props], @@ -143,10 +164,10 @@ const ControlPopover: FC = ({ return ( diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx index dc4057f33..5626a0938 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx @@ -355,23 +355,24 @@ export default function DateFilterLabel(props: DateFilterControlProps) { {t('Edit time range')} ); - const popoverContent = ( + destroyTooltipOnHide + getPopupContainer={nodeTrigger => isOverflowingFilterBar - ? (triggerNode.parentNode as HTMLElement) + ? (nodeTrigger.parentNode as HTMLElement) : document.body } - destroyTooltipOnHide + overlayClassName="time-range-popover" > diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx index 3dd76af37..2a2670ee8 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx @@ -106,9 +106,9 @@ class AdhocFilterPopoverTrigger extends PureComponent< {this.props.children} diff --git a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsControl.tsx b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsControl.tsx index 89fa40d3c..c997b7604 100644 --- a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsControl.tsx +++ b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsControl.tsx @@ -18,7 +18,7 @@ */ import { ControlHeader } from '@superset-ui/chart-controls'; import { css, styled, t } from '@superset-ui/core'; -import { Popover } from 'antd'; +import Popover from 'src/components/Popover'; import { FC, useState } from 'react'; import { EditItem, LayerConf, LayerConfigsControlProps } from './types'; import LayerConfigsPopoverContent from './LayerConfigsPopoverContent'; @@ -160,7 +160,7 @@ export const LayerConfigsControl: FC = ({
= ({ {isCustomMode() && value && ( diff --git a/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx b/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx index 7aab12531..e6fa51a8d 100644 --- a/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx @@ -361,8 +361,8 @@ export default class TimeSeriesColumnControl extends Component { trigger="click" content={this.renderPopover()} title={t('Column Configuration')} - visible={this.state.popoverVisible} - onVisibleChange={this.onPopoverVisibleChange} + open={this.state.popoverVisible} + onOpenChange={this.onPopoverVisibleChange} >