This is an automated email from the ASF dual-hosted git repository.

diegopucci pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 0030f46d2d refactor(Popover): Upgrade Popover to Antd5 (#31973)
0030f46d2d is described below

commit 0030f46d2d477db56a92c8ee722d1cddcbb79ada
Author: Alexandru Soare <[email protected]>
AuthorDate: Mon Feb 10 16:38:17 2025 +0200

    refactor(Popover): Upgrade Popover to Antd5 (#31973)
    
    Co-authored-by: Geido <[email protected]>
---
 .../e2e/dashboard/horizontalFilterBar.test.ts      |  4 +-
 .../cypress-base/cypress/e2e/dashboard/utils.ts    |  6 +-
 .../cypress-base/cypress/support/directories.ts    |  2 +-
 .../src/components/SQLPopover.tsx                  |  6 +-
 superset-frontend/src/GlobalStyles.tsx             |  8 ++-
 .../src/components/DropdownContainer/index.tsx     | 20 ++++---
 .../src/components/Popover/Popover.stories.tsx     | 15 ++++-
 .../src/components/Popover/Popover.test.tsx        | 14 ++---
 .../src/components/Popover/Popover.tsx             | 27 ---------
 superset-frontend/src/components/Popover/index.tsx | 14 +++--
 .../header-renderers/HeaderWithRadioGroup.tsx      |  4 +-
 .../DashboardBuilder/DashboardBuilder.tsx          |  8 ---
 .../components/FiltersBadge/DetailsPanel/index.tsx | 60 ++-----------------
 .../components/nativeFilters/FilterCard/index.tsx  | 10 ++--
 superset-frontend/src/dashboard/styles.ts          | 26 ---------
 .../explore/components/DataTableControl/index.tsx  | 11 +---
 .../controls/AnnotationLayerControl/index.tsx      |  8 +--
 .../FormattingPopover.tsx                          |  4 +-
 .../controls/ConditionalFormattingControl/types.ts |  2 +-
 .../ContourControl/ContourPopoverTrigger.tsx       |  6 +-
 .../ControlPopover/ControlPopover.test.tsx         | 12 ++--
 .../controls/ControlPopover/ControlPopover.tsx     | 67 ++++++++++++++--------
 .../controls/DateFilterControl/DateFilterLabel.tsx | 17 +++---
 .../ColumnSelectPopoverTrigger.tsx                 |  6 +-
 .../AdhocFilterPopoverTrigger/index.tsx            |  6 +-
 .../LayerConfigsControl/LayerConfigsControl.tsx    |  4 +-
 .../controls/MapViewControl/MapViewControl.tsx     |  5 +-
 .../MapViewControl/MapViewPopoverContent.tsx       |  3 +-
 .../MetricControl/AdhocMetricPopoverTrigger.tsx    |  6 +-
 .../controls/TimeSeriesColumnControl/index.jsx     |  4 +-
 30 files changed, 157 insertions(+), 228 deletions(-)

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 ec20224fce..b89e9f8a4b 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 fa85de54c0..c39a9b6334 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 c2754e4543..286f865444 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 a848a2e9fc..3a29c4885c 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 d213faac8d..e80d32e7ec 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 744b7f61de..0d2da00f8d 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<number[]>([]);
     const [popoverVisible, setPopoverVisible] = useState(false);
-
     // We use React.useState to be able to mock the state in Jest
     const [overflowingIndex, setOverflowingIndex] = useState<number>(-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(
           <>
             <Global
               styles={css`
-                .ant-popover-inner-content {
-                  max-height: ${MAX_HEIGHT}px;
-                  overflow: ${showOverflow ? 'auto' : 'visible'};
-                  padding: ${theme.gridUnit * 3}px ${theme.gridUnit * 4}px;
-
+                .antd5-popover-inner {
                   // Some OS versions only show the scroll when hovering.
                   // These settings will make the scroll always visible.
                   ::-webkit-scrollbar {
@@ -365,11 +362,16 @@ const DropdownContainer = forwardRef(
                 }
               `}
             />
+
             <Popover
+              overlayInnerStyle={{
+                maxHeight: `${MAX_HEIGHT}px`,
+                overflow: showOverflow ? 'auto' : 'visible',
+              }}
               content={popoverContent}
               trigger="click"
-              visible={popoverVisible}
-              onVisibleChange={visible => 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 d9baaf1078..4f23a70243 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 cf4cb65da4..395abb67e5 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(<Popover />);
@@ -29,12 +29,12 @@ test('should render', () => {
 });
 
 test('should render a title when visible', () => {
-  render(<Popover title="Popover title" visible />);
+  render(<Popover title="Popover title" open />);
   expect(screen.getByText('Popover title')).toBeInTheDocument();
 });
 
 test('should render some content when visible', () => {
-  render(<Popover content="Content sample" visible />);
+  render(<Popover content="Content sample" open />);
   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(
     <Popover
       content="Content sample"
       title="Popover title"
-      onVisibleChange={onVisibleChange}
+      onOpenChange={onOpenChange}
     >
       <Button>Hover me</Button>
     </Popover>,
   );
   userEvent.hover(screen.getByRole('button'));
-  await waitFor(() => expect(onVisibleChange).toHaveBeenCalledTimes(1));
+  await waitFor(() => expect(onOpenChange).toHaveBeenCalledTimes(1));
 });
 
 test('renders with theme', () => {
-  render(<Popover content="Content sample" title="Popover title" visible />);
+  render(<Popover content="Content sample" title="Popover title" open />);
   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 14fded78f8..0000000000
--- 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) => <AntdPopover {...props} />;
diff --git a/superset-frontend/src/components/Popover/index.tsx 
b/superset-frontend/src/components/Popover/index.tsx
index d147a75ed5..4c290ed623 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) => <AntdPopover {...props} />;
+
+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 3aedff2b47..ba91d167dd 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) {
     >
       <Popover
         trigger="click"
-        visible={popoverVisible}
+        open={popoverVisible}
         content={
           <div>
             <div
@@ -72,7 +72,7 @@ function HeaderWithRadioGroup(props: 
HeaderWithRadioGroupProps) {
           </div>
         }
         placement="bottomLeft"
-        arrowPointAtCenter
+        arrow={{ pointAtCenter: true }}
       >
         <Icons.SettingOutlined
           iconSize="m"
diff --git 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index e18583ad78..b9dfeb3099 100644
--- 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -30,7 +30,6 @@ import {
   useTheme,
   useElementOnScreen,
 } from '@superset-ui/core';
-import { Global } from '@emotion/react';
 import { useDispatch, useSelector } from 'react-redux';
 import ErrorBoundary from 'src/components/ErrorBoundary';
 import BuilderComponentPane from 
'src/dashboard/components/BuilderComponentPane';
@@ -653,13 +652,6 @@ const DashboardBuilder = () => {
         </Droppable>
       </StyledHeader>
       <StyledContent fullSizeChartId={fullSizeChartId}>
-        <Global
-          styles={css`
-            // @z-index-above-dashboard-header (100) + 1 = 101
-            ${fullSizeChartId &&
-            `div > .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 a3b5a6512c..65776ed915 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 = (
     <FiltersDetailsContainer
       ref={popoverContentRef}
@@ -129,54 +128,6 @@ const DetailsPanelPopover = ({
       onKeyDown={handleKeyDown}
       role="menu"
     >
-      <Global
-        styles={theme => 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;
-            }
-          }
-        `}
-      />
       <div>
         {appliedCrossFilterIndicators.length ? (
           <div>
@@ -224,12 +175,13 @@ const DetailsPanelPopover = ({
 
   return (
     <Popover
-      overlayClassName="filterStatusPopover"
+      color={`${theme.colors.grayscale.dark2}cc`}
       content={content}
-      visible={popoverVisible}
-      onVisibleChange={handleVisibility}
+      open={popoverVisible}
+      onOpenChange={handleVisibility}
       placement="bottomRight"
       trigger={['hover']}
+      data-test="filter-status-popover"
     >
       {children}
     </Popover>
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx
index 35806f3638..dd5847e7b8 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 (
     <Popover
       placement={placement}
-      overlayClassName="filter-card-popover"
+      overlayStyle={{
+        width: '240px',
+      }}
       mouseEnterDelay={0.2}
       mouseLeaveDelay={0.2}
-      onVisibleChange={visible => {
+      onOpenChange={visible => {
         setInternalIsVisible(externalIsVisible && visible);
       }}
-      visible={externalIsVisible && internalIsVisible}
+      open={externalIsVisible && internalIsVisible}
       content={<FilterCardContent filter={filter} hidePopover={hidePopover} />}
       getPopupContainer={getPopupContainer ?? (() => document.body)}
+      arrow={false}
     >
       {children}
     </Popover>
diff --git a/superset-frontend/src/dashboard/styles.ts 
b/superset-frontend/src/dashboard/styles.ts
index f3f0d753bf..1ac9a2ee2a 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 20e2a4775a..e84d06a32a 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
         <FormatPickerContainer onClick={e => e.stopPropagation()}>
           {/* hack to disable click propagation from popover content to table 
header, which triggers sorting column */}
-          <Global
-            styles={css`
-              .column-formatting-popover .ant-popover-inner-content {
-                padding: 0;
-              }
-            `}
-          />
           <FormatPickerLabel>{t('Column Formatting')}</FormatPickerLabel>
           <FormatPicker
             onChange={onChange}
@@ -219,11 +211,10 @@ const DataTableTemporalHeaderCell = ({
   return datasourceId ? (
     <span>
       <Popover
-        overlayClassName="column-formatting-popover"
         trigger="click"
         content={overlayContent}
         placement="bottomLeft"
-        arrowPointAtCenter
+        arrow={{ pointAtCenter: true }}
       >
         <Icons.SettingOutlined
           iconSize="m"
diff --git 
a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
 
b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
index dfa3cbc664..3768b6c5ee 100644
--- 
a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
@@ -231,8 +231,8 @@ class AnnotationLayerControl extends PureComponent<Props, 
PopoverState> {
           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)}
       >
         <CustomListItem selectable>
           <span>{anno.name}</span>
@@ -254,9 +254,9 @@ class AnnotationLayerControl extends PureComponent<Props, 
PopoverState> {
               '',
             )}
             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 26b0cbe883..5b03a5b27a 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 c352ca818b..a1252ba689 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 3a106e7284..315a34e798 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 = ({
     <ControlPopover
       trigger="click"
       content={popoverContent}
-      defaultVisible={visible}
-      visible={visible}
-      onVisibleChange={setVisibility}
+      defaultOpen={visible}
+      open={visible}
+      onOpenChange={setVisibility}
       destroyTooltipOnHide
     >
       {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 575f05f12d..1d8e3c0db9 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(<TestComponent {...baseProps} visible />);
+  rerender(<TestComponent {...baseProps} open />);
   expect(await screen.findByText('Control Popover Test')).toBeInTheDocument();
 
   rerender(<TestComponent {...baseProps} />);
diff --git 
a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx
 
b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx
index 2f2664e286..b7be6cc591 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<PopoverProps> = ({
   getPopupContainer,
-  getVisibilityRatio = getElementYVisibilityRatioOnContainer,
-  visible: visibleProp,
+  getVisibilityRatio = getElementVisibilityRatio,
+  open: visibleProp,
   destroyTooltipOnHide = false,
+  placement: initialPlacement = 'right',
   ...props
 }) => {
   const triggerElementRef = useRef<HTMLElement>();
 
   const [visible, setVisible] = useState(
-    visibleProp === undefined ? props.defaultVisible : visibleProp,
+    visibleProp === undefined ? props.defaultOpen : visibleProp,
   );
-  const [placement, setPlacement] = React.useState<TooltipPlacement>('right');
+  const [placement, setPlacement] =
+    React.useState<TooltipPlacement>(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<PopoverProps> = ({
       }
 
       setVisible(!!visible);
-      props.onVisibleChange?.(!!visible);
+      props.onOpenChange?.(!!visible);
     },
     [props, changeContainerScrollStatus],
   );
@@ -106,7 +127,7 @@ const ControlPopover: FC<PopoverProps> = ({
     (event: KeyboardEvent) => {
       if (event.key === 'Escape') {
         setVisible(false);
-        props.onVisibleChange?.(false);
+        props.onOpenChange?.(false);
       }
     },
     [props],
@@ -143,10 +164,10 @@ const ControlPopover: FC<PopoverProps> = ({
   return (
     <Popover
       {...props}
-      visible={visible}
-      arrowPointAtCenter
+      open={visible}
+      arrow={{ pointAtCenter: true }}
       placement={placement}
-      onVisibleChange={handleOnVisibleChange}
+      onOpenChange={handleOnVisibleChange}
       getPopupContainer={handleGetPopupContainer}
       destroyTooltipOnHide={destroyTooltipOnHide}
     />
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
index dc4057f33b..5626a09380 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) {
       <span className="text">{t('Edit time range')}</span>
     </IconWrapper>
   );
-
   const popoverContent = (
     <ControlPopover
-      placement="right"
+      autoAdjustOverflow={false}
       trigger="click"
+      placement="right"
       content={overlayContent}
       title={title}
-      defaultVisible={show}
-      visible={show}
-      onVisibleChange={toggleOverlay}
+      defaultOpen={show}
+      open={show}
+      onOpenChange={toggleOverlay}
       overlayStyle={{ width: '600px' }}
-      getPopupContainer={triggerNode =>
+      destroyTooltipOnHide
+      getPopupContainer={nodeTrigger =>
         isOverflowingFilterBar
-          ? (triggerNode.parentNode as HTMLElement)
+          ? (nodeTrigger.parentNode as HTMLElement)
           : document.body
       }
-      destroyTooltipOnHide
+      overlayClassName="time-range-popover"
     >
       <Tooltip placement="top" title={tooltipTitle}>
         <DateLabel
diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
index a8579058f2..87ecaee8e3 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
@@ -165,9 +165,9 @@ const ColumnSelectPopoverTrigger = ({
       <ControlPopover
         trigger="click"
         content={overlayContent}
-        defaultVisible={visible}
-        visible={visible}
-        onVisibleChange={handleTogglePopover}
+        defaultOpen={visible}
+        open={visible}
+        onOpenChange={handleTogglePopover}
         title={popoverTitle}
         destroyTooltipOnHide
       >
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 3dd76af371..2a2670ee8c 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<
       <ControlPopover
         trigger="click"
         content={overlayContent}
-        defaultVisible={visible}
-        visible={visible}
-        onVisibleChange={togglePopover}
+        defaultOpen={visible}
+        open={visible}
+        onOpenChange={togglePopover}
         destroyTooltipOnHide
       >
         {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 89fa40d3c9..c997b76046 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<LayerConfigsControlProps> = ({
     <div>
       <ControlHeader {...controlHeaderProps} />
       <Popover
-        visible={popoverVisible}
+        open={popoverVisible}
         trigger="click"
         title={popoverTitle}
         placement="right"
diff --git 
a/superset-frontend/src/explore/components/controls/MapViewControl/MapViewControl.tsx
 
b/superset-frontend/src/explore/components/controls/MapViewControl/MapViewControl.tsx
index d31303521b..ca23247ad1 100644
--- 
a/superset-frontend/src/explore/components/controls/MapViewControl/MapViewControl.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MapViewControl/MapViewControl.tsx
@@ -18,7 +18,8 @@
  */
 import { ControlHeader } from '@superset-ui/chart-controls';
 import { css, styled, t } from '@superset-ui/core';
-import { Button, Popover } from 'antd';
+import Button from 'src/components/Button';
+import Popover from 'src/components/Popover';
 import { FC, useState } from 'react';
 import { mix } from 'polished';
 import { MapViewConfigs, MapViewConfigsControlProps } from './types';
@@ -159,7 +160,7 @@ export const MapViewControl: FC<MapViewConfigsControlProps> 
= ({
 
       {isCustomMode() && value && (
         <Popover
-          visible={popoverVisible}
+          open={popoverVisible}
           trigger="click"
           title={popoverTitle}
           placement="right"
diff --git 
a/superset-frontend/src/explore/components/controls/MapViewControl/MapViewPopoverContent.tsx
 
b/superset-frontend/src/explore/components/controls/MapViewControl/MapViewPopoverContent.tsx
index 5ca8e2ee2f..182d5f3806 100644
--- 
a/superset-frontend/src/explore/components/controls/MapViewControl/MapViewPopoverContent.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MapViewControl/MapViewPopoverContent.tsx
@@ -17,7 +17,8 @@
  * under the License.
  */
 import { css, styled, t } from '@superset-ui/core';
-import { Button, Form } from 'antd';
+import { Form } from 'src/components/Form';
+import Button from 'src/components/Button';
 import { FC, useEffect, useState } from 'react';
 import { mix } from 'polished';
 import { MapViewConfigs, MapViewPopoverContentProps } from './types';
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx
index e6c584b5cd..5e59e4a5c3 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx
@@ -259,9 +259,9 @@ class AdhocMetricPopoverTrigger extends PureComponent<
           placement="right"
           trigger="click"
           content={overlayContent}
-          defaultVisible={visible}
-          visible={visible}
-          onVisibleChange={togglePopover}
+          defaultOpen={visible}
+          open={visible}
+          onOpenChange={togglePopover}
           title={popoverTitle}
           destroyTooltipOnHide
         >
diff --git 
a/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx
 
b/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx
index 7aab125310..e6fa51a8dd 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}
         >
           <InfoTooltipWithTrigger
             icon="edit"


Reply via email to