Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Replace all Ant Popover with Lemon #17607

Merged
merged 5 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading