Merge pull request #274 from GRA0007/feat/tooltip-avoidance-scheme

Position tooltip to avoid screen edges
This commit is contained in:
Benji Grant 2023-06-14 14:05:26 +10:00 committed by GitHub
commit ba4cb919bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 15 deletions

View file

@ -11,6 +11,7 @@
},
"dependencies": {
"@azure/msal-browser": "^2.37.1",
"@floating-ui/react-dom": "^2.0.1",
"@giraugh/tools": "^1.6.0",
"@js-temporal/polyfill": "^0.4.4",
"@microsoft/microsoft-graph-client": "^3.0.5",

View file

@ -98,6 +98,7 @@
background-origin: border-box;
transition: background-color .1s;
touch-action: none;
position: relative;
border-top-width: 2px;
border-top-style: solid;
@ -108,6 +109,13 @@
}
}
.nonEditable:hover::after {
content: '';
position: absolute;
inset: 0;
background-color: var(--highlight-color, rgba(0,0,0,.3));
}
.editable {
@media (hover: hover) {
&:hover:not(:active) {
@ -185,7 +193,6 @@
.tooltip {
position: absolute;
transform: translateX(-50%);
border: 1px solid var(--text);
border-radius: 3px;
padding: 4px 8px;

View file

@ -1,6 +1,7 @@
'use client'
import { Fragment, useEffect, useMemo, useRef, useState } from 'react'
import { Fragment, useEffect, useMemo, useState } from 'react'
import { flip, offset, shift, useFloating } from '@floating-ui/react-dom'
import { Temporal } from '@js-temporal/polyfill'
import Content from '/src/components/Content/Content'
@ -29,14 +30,16 @@ const AvailabilityViewer = ({ times, people, table }: AvailabilityViewerProps) =
const [tempFocus, setTempFocus] = useState<string>()
const [focusCount, setFocusCount] = useState<number>()
const wrapperRef = useRef<HTMLDivElement>(null)
const [tooltip, setTooltip] = useState<{
x: number
y: number
anchor: HTMLDivElement
available: string
date: string
people: string[]
}>()
const { refs, floatingStyles } = useFloating({
middleware: [offset(6), flip(), shift()],
elements: { reference: tooltip?.anchor },
})
// Calculate availabilities
const { availabilities, min, max } = useMemo(() =>
@ -80,6 +83,7 @@ const AvailabilityViewer = ({ times, people, table }: AvailabilityViewerProps) =
key={y}
className={makeClass(
styles.time,
styles.nonEditable,
(focusCount === undefined || focusCount === peopleHere.length) && highlight && (peopleHere.length === max || tempFocus) && peopleHere.length > 0 && styles.highlight,
)}
style={{
@ -90,11 +94,8 @@ const AvailabilityViewer = ({ times, people, table }: AvailabilityViewerProps) =
} as React.CSSProperties}
aria-label={peopleHere.join(', ')}
onMouseEnter={e => {
const cellBox = e.currentTarget.getBoundingClientRect()
const wrapperBox = wrapperRef.current?.getBoundingClientRect() ?? { x: 0, y: 0 }
setTooltip({
x: Math.round(cellBox.x - wrapperBox.x + cellBox.width / 2),
y: Math.round(cellBox.y - wrapperBox.y + cellBox.height) + 6,
anchor: e.currentTarget,
available: `${peopleHere.length} / ${filteredPeople.length} ${t('available')}`,
date: cell.label,
people: peopleHere,
@ -158,7 +159,7 @@ const AvailabilityViewer = ({ times, people, table }: AvailabilityViewerProps) =
</>}
</Content>
<div className={styles.wrapper} ref={wrapperRef}>
<div className={styles.wrapper}>
<div>
<div className={styles.heatmap}>
{useMemo(() => <div className={styles.timeLabels}>
@ -176,7 +177,8 @@ const AvailabilityViewer = ({ times, people, table }: AvailabilityViewerProps) =
{tooltip && <div
className={styles.tooltip}
style={{ top: tooltip.y, left: tooltip.x }}
ref={refs.setFloating}
style={floatingStyles}
>
<h3>{tooltip.available}</h3>
<span>{tooltip.date}</span>

View file

@ -15,9 +15,13 @@ export const usePalette = (steps: number) => {
})
.format('rgba')
.map(([r, g, b, a]) => color(r, g, b, a / 255))
.map(c => ({
string: c.hex('rgba'),
highlight: c.luminance() > .5 ? c.darker().hex('rgba') : c.brighter().hex('rgba'),
})),
.map(c => {
let highlight = c.luminance() > .5 ? c.darker() : c.brighter()
highlight = highlight.alpha(highlight.alpha() + .3)
return {
string: c.hex('rgba'),
highlight: highlight.hex('rgba'),
}
}),
[steps, colormap])
}

View file

@ -65,6 +65,25 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.42.0.tgz#484a1d638de2911e6f5a30c12f49c7e4a3270fb6"
integrity sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==
"@floating-ui/core@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.3.0.tgz#113bc85fa102cf890ae801668f43ee265c547a09"
integrity sha512-vX1WVAdPjZg9DkDkC+zEx/tKtnST6/qcNpwcjeBgco3XRNHz5PUA+ivi/yr6G3o0kMR60uKBJcfOdfzOFI7PMQ==
"@floating-ui/dom@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.3.0.tgz#69456f2164fc3d33eb40837686eaf71537235ac9"
integrity sha512-qIAwejE3r6NeA107u4ELDKkH8+VtgRKdXqtSPaKflL2S2V+doyN+Wt9s5oHKXPDo4E8TaVXaHT3+6BbagH31xw==
dependencies:
"@floating-ui/core" "^1.3.0"
"@floating-ui/react-dom@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.1.tgz#7972a4fc488a8c746cded3cfe603b6057c308a91"
integrity sha512-rZtAmSht4Lry6gdhAJDrCp/6rKN7++JnL1/Anbr/DdeyYXQPxvg/ivrbYvJulbRf4vL8b212suwMM2lxbv+RQA==
dependencies:
"@floating-ui/dom" "^1.3.0"
"@giraugh/tools@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@giraugh/tools/-/tools-1.6.0.tgz#6bf501161a3a848c00d3f6f960d9cfe386860941"