Skip to content

Commit

Permalink
tooltip arrow
Browse files Browse the repository at this point in the history
  • Loading branch information
j8seangel committed Apr 24, 2024
1 parent bdfe4c9 commit 452a620
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 20 deletions.
16 changes: 13 additions & 3 deletions apps/fishing-map/features/map/popups/MapPopups.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Fragment } from 'react'
import { Fragment, useCallback } from 'react'
import { useSelector } from 'react-redux'
import { useMapHoverInteraction } from '@globalfishingwatch/deck-layer-composer'
import PopupWrapper from 'features/map/popups/PopupWrapper'
import { selectClickedEvent } from '../map.slice'
import { useClickedEventConnect } from '../map-interactions.hooks'

function MapPopups() {
const hoverInteraction = useMapHoverInteraction()
const clickInteraction = useSelector(selectClickedEvent)
const { dispatchClickedEvent, cancelPendingInteractionRequests } = useClickedEventConnect()

const closePopup = useCallback(() => {
// cleanFeatureState('click')
dispatchClickedEvent(null)
cancelPendingInteractionRequests()
}, [cancelPendingInteractionRequests, dispatchClickedEvent])

return (
<Fragment>
{/* {hoverInteraction && <PopupWrapper interaction={hoverInteraction} type="hover" />} */}
{clickInteraction && <PopupWrapper interaction={clickInteraction} type="click" />}
{hoverInteraction && <PopupWrapper interaction={hoverInteraction} type="hover" />}
{clickInteraction && (
<PopupWrapper interaction={clickInteraction} type="click" onClose={closePopup} />
)}
</Fragment>
)
}
Expand Down
31 changes: 31 additions & 0 deletions apps/fishing-map/features/map/popups/Popup.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@
z-index: 2;
}

.arrow {
position: absolute;
width: 14px;
height: 14px;
z-index: 1;
pointer-events: none;
background: var(--color-white);
transform: rotate(45deg);
}

.close {
position: absolute;
width: var(--size-S);
height: var(--size-S);
border-radius: 50%;
font: var(--font-L);
line-height: 1;
margin: var(--space-XS);
transition: opacity 0.15s linear, color 0.15s linear;
z-index: 1;
top: -2rem;
right: -2rem;
background-color: var(--color-primary-blue);
color: rgba(var(--white-rgb), 0.8);
opacity: 1;
border: var(--border-white);
display: flex;
align-items: center;
justify-content: center;
}

.popup.click {
pointer-events: all;
}
Expand Down
76 changes: 59 additions & 17 deletions apps/fishing-map/features/map/popups/PopupWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fragment } from 'react'
import { Fragment, forwardRef, useRef } from 'react'
import cx from 'classnames'
import { groupBy } from 'lodash'
import { useSelector } from 'react-redux'
Expand All @@ -8,9 +8,10 @@ import {
useFloating,
detectOverflow,
Middleware,
arrow,
} from '@floating-ui/react'
import { DataviewCategory } from '@globalfishingwatch/api-types'
import { Spinner } from '@globalfishingwatch/ui-components'
import { IconButton, Spinner } from '@globalfishingwatch/ui-components'
import { InteractionEvent } from '@globalfishingwatch/deck-layer-composer'
import { ContextPickingObject, VesselEventPickingObject } from '@globalfishingwatch/deck-layers'
import { POPUP_CATEGORY_ORDER } from 'data/config'
Expand Down Expand Up @@ -59,27 +60,64 @@ type PopupWrapperProps = {
type?: 'hover' | 'click'
}

function PopupWrapper({
interaction,
closeButton = false,
closeOnClick = false,
type = 'hover',
className = '',
onClose,
}: PopupWrapperProps) {
const PopupArrow = forwardRef(function (
{
arrow = {},
placement,
}: {
arrow?: { x?: number; y?: number }
placement: string
},
ref: any
) {
const { x, y } = arrow
const side = placement.split('-')[0]
const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[side] as string
const arrowLen = ref?.current?.clientWidth || 0
return (
<div
className={styles.arrow}
ref={ref}
style={{
left: x != null ? `${x}px` : '',
top: y != null ? `${y}px` : '',
// Ensure the static side gets unset when
// flipping to other placements' axes.
right: '',
bottom: '',
[staticSide]: `${-arrowLen / 2}px`,
}}
/>
)
})

function PopupWrapper({ interaction, type = 'hover', className = '', onClose }: PopupWrapperProps) {
// Assuming only timeComparison heatmap is visible, so timerange description apply to all
const timeCompareTimeDescription = useTimeCompareTimeDescription()
const mapViewport = useMapViewport()

const activityInteractionStatus = useSelector(selectFishingInteractionStatus)
const apiEventStatus = useSelector(selectApiEventStatus)

const { refs, floatingStyles /*, update, elements */ } = useFloating({
const arrowRef = useRef<HTMLDivElement>(null)
const { refs, floatingStyles, placement, middlewareData /*, update, elements */ } = useFloating({
whileElementsMounted: autoUpdate,
middleware: [autoPlacement({ padding: 10 }), overflowMiddlware],
middleware: [
autoPlacement({ padding: 10 }),
overflowMiddlware,
arrow({
element: arrowRef,
padding: -5,
}),
],
})

if (!mapViewport || !interaction || !interaction.features) return null
if (!mapViewport || !interaction || !interaction.features?.length) return null

// const visibleFeatures = interaction.features.filter(
// (feature) => feature.visible || feature.source === WORKSPACE_GENERATOR_ID
Expand All @@ -104,7 +142,6 @@ function PopupWrapper({
// const cleanup = autoUpdate(elements.reference, elements.floating, update)
// return cleanup
// }
// }, [left, top, elements, update])

return (
<div
Expand All @@ -113,9 +150,14 @@ function PopupWrapper({
className={cx(styles.popup, styles[type], className)}
>
<div ref={refs.setFloating} style={floatingStyles}>
{/* <div>
<IconButton icon="close" onClick={onClose} />
</div> */}
{type === 'click' && (
<PopupArrow ref={arrowRef} placement={placement} arrow={middlewareData.arrow} />
)}
{type === 'click' && onClose !== undefined && (
<div className={styles.close}>
<IconButton type="invert" size="small" icon="close" onClick={onClose} />
</div>
)}
<div className={styles.content}>
{timeCompareTimeDescription && (
<div className={styles.popupSection}>{timeCompareTimeDescription}</div>
Expand Down

0 comments on commit 452a620

Please sign in to comment.