Skip to content

Commit

Permalink
refactor: Replace all Ant Popover with Lemon (#17607)
Browse files Browse the repository at this point in the history
* Add on-hover LemonDropdown option

* Convert all the Ant Popover cases to Lemon

* Remove dead CSS

* Also convert plugin error popover title

* Update UI snapshots for `chromium` (1)

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
Twixes and github-actions[bot] authored Sep 27, 2023
1 parent cb22ba7 commit 2832f97
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 65 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions frontend/src/lib/components/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { PropsWithChildren } from 'react'
import { Drawer as AntDrawer } from 'antd'
import { DrawerProps } from 'antd/lib/drawer'
import { styles } from '~/styles/vars'

export function Drawer(props: PropsWithChildren<DrawerProps>): JSX.Element {
return <AntDrawer {...props} zIndex={styles.zDrawer} />
return <AntDrawer {...props} zIndex={950} />
}
14 changes: 7 additions & 7 deletions frontend/src/lib/components/TZLabel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import './index.scss'
import { Popover } from 'antd'
import { useActions, useValues } from 'kea'
import { ProjectOutlined, LaptopOutlined, GlobalOutlined } from '@ant-design/icons'
import { humanFriendlyDetailedTime, shortTimeZone } from 'lib/utils'
Expand All @@ -8,8 +7,7 @@ import { teamLogic } from '../../../scenes/teamLogic'
import { dayjs } from 'lib/dayjs'
import clsx from 'clsx'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { styles } from '../../../styles/vars'
import { LemonButton, LemonDivider } from '@posthog/lemon-ui'
import { LemonButton, LemonDivider, LemonDropdown } from '@posthog/lemon-ui'
import { IconSettings } from 'lib/lemon-ui/icons'
import { urls } from 'scenes/urls'

Expand Down Expand Up @@ -121,12 +119,14 @@ function TZLabelRaw({

if (showPopover) {
return (
<Popover
content={<TZLabelPopoverContent time={parsedTime} showSeconds={showSeconds} />}
zIndex={styles.zPopover}
<LemonDropdown
trigger="hover"
placement="top"
showArrow
overlay={<TZLabelPopoverContent time={parsedTime} showSeconds={showSeconds} />}
>
{innerContent}
</Popover>
</LemonDropdown>
)
}

Expand Down
31 changes: 29 additions & 2 deletions frontend/src/lib/lemon-ui/LemonDropdown/LemonDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { MouseEventHandler, useContext, useEffect, useState } from 'react'
import React, { MouseEventHandler, useContext, useEffect, useRef, useState } from 'react'
import { Popover, PopoverOverlayContext, PopoverProps } from '../Popover'

export interface LemonDropdownProps extends Omit<PopoverProps, 'children' | 'visible'> {
Expand All @@ -9,6 +9,8 @@ export interface LemonDropdownProps extends Omit<PopoverProps, 'children' | 'vis
* @default true
*/
closeOnClickInside?: boolean
/** @default 'click' */
trigger?: 'click' | 'hover'
children: React.ReactElement<
Record<string, any> & {
onClick: MouseEventHandler
Expand All @@ -27,7 +29,9 @@ export const LemonDropdown: React.FunctionComponent<LemonDropdownProps & React.R
onVisibilityChange,
onClickOutside,
onClickInside,
onMouseLeaveInside,
closeOnClickInside = true,
trigger = 'click',
children,
...popoverProps
},
Expand All @@ -36,6 +40,9 @@ export const LemonDropdown: React.FunctionComponent<LemonDropdownProps & React.R
const [, parentPopoverLevel] = useContext(PopoverOverlayContext)
const [localVisible, setLocalVisible] = useState(false)

const floatingRef = useRef<HTMLDivElement>(null)
const referenceRef = useRef<HTMLSpanElement>(null)

const effectiveVisible = visible ?? localVisible

useEffect(() => {
Expand All @@ -45,15 +52,25 @@ export const LemonDropdown: React.FunctionComponent<LemonDropdownProps & React.R
return (
<Popover
ref={ref}
floatingRef={floatingRef}
referenceRef={referenceRef}
onClickOutside={(e) => {
setLocalVisible(false)
if (trigger === 'click') {
setLocalVisible(false)
}
onClickOutside?.(e)
}}
onClickInside={(e) => {
e.stopPropagation()
closeOnClickInside && setLocalVisible(false)
onClickInside?.(e)
}}
onMouseLeaveInside={(e) => {
if (trigger === 'hover' && !referenceRef.current?.contains(e.relatedTarget as Node)) {
setLocalVisible(false)
}
onMouseLeaveInside?.(e)
}}
visible={effectiveVisible}
{...popoverProps}
>
Expand All @@ -67,6 +84,16 @@ export const LemonDropdown: React.FunctionComponent<LemonDropdownProps & React.R
e.stopPropagation()
}
},
onMouseEnter: (): void => {
if (trigger === 'hover') {
setLocalVisible(true)
}
},
onMouseLeave: (e: React.MouseEvent): void => {
if (trigger === 'hover' && !floatingRef.current?.contains(e.relatedTarget as Node)) {
setLocalVisible(false)
}
},
'aria-haspopup': 'true',
})}
</Popover>
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/lib/lemon-ui/Popover/Popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
}

.Popover__box {
position: relative; // For arrow
transition: opacity 100ms ease, transform 100ms ease;
transform-origin: top;
box-shadow: var(--shadow-elevation);
Expand All @@ -38,20 +39,39 @@
border-color: var(--primary);
}

// We set the offset below instead of using floating-ui's offset(), because we need there to be no gap between
// the reference and the floating element. This makes hover-based popovers possible

.Popover[data-placement^='bottom'] & {
transform-origin: top;
margin-top: 0.25rem;
}
.Popover[data-placement^='bottom'].Popover--with-arrow & {
margin-top: 0.5rem;
}

.Popover[data-placement^='top'] & {
transform-origin: bottom;
margin-bottom: 0.25rem;
}
.Popover[data-placement^='top'].Popover--with-arrow & {
margin-bottom: 0.5rem;
}

.Popover[data-placement^='left'] & {
transform-origin: right;
margin-right: 0.25rem;
}
.Popover[data-placement^='left'].Popover--with-arrow & {
margin-right: 0.5rem;
}

.Popover[data-placement^='right'] & {
transform-origin: left;
margin-left: 0.25rem;
}
.Popover[data-placement^='right'].Popover--with-arrow & {
margin-left: 0.5rem;
}

.Popover[data-placement^='bottom'] & {
Expand Down
15 changes: 11 additions & 4 deletions frontend/src/lib/lemon-ui/Popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React, { MouseEventHandler, ReactElement, useContext, useEffect, useLayou
import { CLICK_OUTSIDE_BLOCK_CLASS, useOutsideClickHandler } from 'lib/hooks/useOutsideClickHandler'
import clsx from 'clsx'
import {
offset,
useFloating,
autoUpdate,
Middleware,
Expand All @@ -24,6 +23,8 @@ export interface PopoverProps {
visible: boolean
onClickOutside?: (event: Event) => void
onClickInside?: MouseEventHandler<HTMLDivElement>
onMouseEnterInside?: MouseEventHandler<HTMLDivElement>
onMouseLeaveInside?: MouseEventHandler<HTMLDivElement>
/** Popover trigger element. If you pass one <Component/> child, it will get the `ref` prop automatically. */
children?: React.ReactChild
/** External reference element not passed as a direct child */
Expand All @@ -46,6 +47,7 @@ export interface PopoverProps {
* **/
additionalRefs?: (React.MutableRefObject<HTMLDivElement | null> | string)[]
referenceRef?: UseFloatingReturn['refs']['reference']
floatingRef?: UseFloatingReturn['refs']['floating']
style?: React.CSSProperties
/**
* Whether the parent popover should be closed as well on click. Useful for menus.
Expand Down Expand Up @@ -76,6 +78,8 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
visible,
onClickOutside,
onClickInside,
onMouseEnterInside,
onMouseLeaveInside,
placement = 'bottom-start',
fallbackPlacements = ['bottom-start', 'bottom-end', 'top-start', 'top-end'],
className,
Expand All @@ -86,6 +90,7 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
additionalRefs = [],
closeParentPopoverOnClickInside = false,
referenceRef: extraReferenceRef,
floatingRef: extraFloatingRef,
style,
getPopupContainer,
showArrow = false,
Expand All @@ -107,7 +112,6 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
x,
y,
reference,
floating,
refs: { reference: referenceRef, floating: floatingRef },
strategy,
placement: effectivePlacement,
Expand All @@ -118,7 +122,6 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
placement,
strategy: 'fixed',
middleware: [
offset(showArrow ? 8 : 4),
...(fallbackPlacements ? [flip({ fallbackPlacements, fallbackStrategy: 'initialPlacement' })] : []),
shift(),
size({
Expand All @@ -134,6 +137,7 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
],
})
const mergedReferenceRef = useMergeRefs([referenceRef, extraReferenceRef || null]) as React.RefCallback<HTMLElement>
const mergedFloatingRef = useMergeRefs([floatingRef, extraFloatingRef || null]) as React.RefCallback<HTMLElement>

const arrowStyle = middlewareData.arrow
? {
Expand Down Expand Up @@ -214,10 +218,11 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
actionable && 'Popover--actionable',
maxContentWidth && 'Popover--max-content-width',
!isAttached && 'Popover--top-centered',
showArrow && 'Popover--with-arrow',
className
)}
data-placement={effectivePlacement}
ref={floating}
ref={mergedFloatingRef}
// eslint-disable-next-line react/forbid-dom-props
style={{
display: middlewareData.hide?.referenceHidden ? 'none' : undefined,
Expand All @@ -227,6 +232,8 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(function P
...style,
}}
onClick={_onClickInside}
onMouseEnter={onMouseEnterInside}
onMouseLeave={onMouseLeaveInside}
aria-level={currentPopoverLevel}
>
<div className="Popover__box">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/dashboard/DashboardItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function DashboardItems(): JSX.Element {
isDragging.current = false
}, 250)
}}
draggableCancel=".anticon,.ant-dropdown,table,.ant-popover-content,button,.Popover"
draggableCancel=".anticon,.ant-dropdown,table,button,.Popover"
>
{tiles?.map((tile: DashboardTile) => {
const { insight, text } = tile
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/scenes/funnels/FunnelBarGraph/Bar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useEffect, useRef, useState } from 'react'
import { capitalizeFirstLetter, percentage } from 'lib/utils'
import { Popover } from 'antd'
import { LEGACY_InsightTooltip } from 'scenes/insights/InsightTooltip/LEGACY_InsightTooltip'
import { getSeriesPositionName } from '../funnelUtils'
import { getSeriesColor } from 'lib/colors'
import { Noun } from '~/models/groupsModel'
import { MetricRow } from './MetricRow'
import { LemonDropdown } from '@posthog/lemon-ui'

interface BarProps {
percentage: number
Expand Down Expand Up @@ -79,10 +79,11 @@ export function Bar({
}, [wrapperWidth])

return (
<Popover
<LemonDropdown
trigger="hover"
placement="right"
content={
showArrow
overlay={
<LEGACY_InsightTooltip altTitle={popoverTitle}>
{popoverMetrics.map(({ title, value, visible }, index) =>
visible !== false ? <MetricRow key={index} title={title} value={value} /> : null
Expand Down Expand Up @@ -121,6 +122,6 @@ export function Bar({
</div>
)}
</div>
</Popover>
</LemonDropdown>
)
}
21 changes: 0 additions & 21 deletions frontend/src/scenes/funnels/FunnelBarGraph/FunnelBarGraph.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,6 @@ $glyph_height: 23px; // Based on .funnel-step-glyph
padding-right: 1rem;
}

.ant-popover {
.ant-popover-content {
background: #fafafa;
border-radius: var(--radius);
border: 1px solid var(--border);
}

.ant-popover-inner {
background: #fafafa;
}

.ant-popover-inner-content {
padding: 8px 0;
min-width: 300px;
}

.ant-popover-arrow {
background: #fafafa;
}
}

.funnel-step {
position: relative;
padding-left: $series_container_width + 0.5rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.legacy-ph-graph-tooltip,
.ant-popover {
.legacy-ph-graph-tooltip {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
font-size: 14px;
overflow-x: hidden;
Expand Down
34 changes: 18 additions & 16 deletions frontend/src/scenes/plugins/plugin/PluginError.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import { Button, Popover, Tag } from 'antd'
import { ClearOutlined } from '@ant-design/icons'
import { PluginErrorType } from '~/types'
import { Tag } from 'antd'
import { CodeSnippet, Language } from 'lib/components/CodeSnippet'
import { dayjs } from 'lib/dayjs'
import { LemonButton, LemonDropdown } from '@posthog/lemon-ui'
import { TZLabel } from '@posthog/apps-common'
import { IconClose } from 'lib/lemon-ui/icons'

export function PluginError({ error, reset }: { error: PluginErrorType; reset?: () => void }): JSX.Element | null {
if (!error) {
return null
}
return (
<Popover
title={<div style={{ textAlign: 'center' }}>{dayjs(error.time).format('YYYY-MM-DD - HH:mm:ss')}</div>}
content={
<LemonDropdown
overlay={
<>
{reset ? (
<Button size="small" onClick={reset} style={{ float: 'right', marginLeft: 10 }}>
<ClearOutlined /> Delete
</Button>
) : null}
<div>
{error.name ? <strong>{error.name}: </strong> : ''}
{error.message}
<div className="flex items-center">
<span className="grow mr-2">
{error.name ? <strong>{error.name} </strong> : ''}
<TZLabel time={error.time} />
</span>
{reset ? (
<LemonButton size="small" type="secondary" onClick={reset} icon={<IconClose />}>
Clear
</LemonButton>
) : null}
</div>
{error.stack ? (
<CodeSnippet wrap style={{ fontSize: 10 }} language={Language.JavaScript}>
Expand All @@ -34,12 +36,12 @@ export function PluginError({ error, reset }: { error: PluginErrorType; reset?:
) : null}
</>
}
trigger="click"
placement="top"
showArrow
>
<Tag color="red" style={{ cursor: 'pointer' }}>
ERROR
</Tag>
</Popover>
</LemonDropdown>
)
}
Loading

0 comments on commit 2832f97

Please sign in to comment.