fix(packing): show who brings a shared item in a card with their pictures, and the others as a +N circle

The row's badges said who brings an item, who it is shared with and who
takes care of it in the browser's own tooltip. They now use TREK's, and
the bringers one lists everyone with their picture on a line of their
own. The others show as a +N circle tucked under the first picture.
Tooltip takes an optional content for tips that hold more than words.
This commit is contained in:
Maurice
2026-11-05 13:02:29 +01:00
parent b9c53d692b
commit c7d5fc12c6
33 changed files with 251 additions and 30 deletions
+12 -1
View File
@@ -1,4 +1,4 @@
// FE-W4TIP-001 to FE-W4TIP-017
// FE-W4TIP-001 to FE-W4TIP-018
import { createRef, useRef } from 'react'
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, fireEvent, act } from '../../../tests/helpers/render'
@@ -213,3 +213,14 @@ describe('Tooltip — with a shortcut', () => {
expect(screen.getByRole('tooltip').querySelector('kbd')).toBeNull()
})
})
describe('Tooltip — with content', () => {
it('FE-W4TIP-018: shows the content in place of the label, which still opens it', () => {
render(<Tooltip label="brought by Anna, Ben" content={<ul><li>Anna</li><li>Ben</li></ul>}><button>x</button></Tooltip>)
hover(screen.getByRole('button'))
const tip = screen.getByRole('tooltip')
expect(tip.querySelectorAll('li')).toHaveLength(2)
expect(tip).not.toHaveTextContent('brought by')
})
})
+10 -5
View File
@@ -11,10 +11,15 @@ interface TooltipProps {
disabled?: boolean
/** The keys that do the same, shown beside the label: ["⌘", "K"]. */
shortcut?: readonly string[]
/**
* Shown in place of the label when the tip holds more than words, such as a list of
* people with their pictures. `label` still names it and decides whether it opens.
*/
content?: React.ReactNode
children: React.ReactElement
}
export function Tooltip({ label, placement = 'bottom', delay = 250, disabled, shortcut, children }: TooltipProps) {
export function Tooltip({ label, placement = 'bottom', delay = 250, disabled, shortcut, content, children }: TooltipProps) {
const [open, setOpen] = useState(false)
const [coords, setCoords] = useState<{ top: number; left: number } | null>(null)
const triggerRef = useRef<HTMLElement | null>(null)
@@ -93,8 +98,8 @@ export function Tooltip({ label, placement = 'bottom', delay = 250, disabled, sh
zIndex: 100000,
fontSize: 'calc(11px * var(--fs-scale-caption, 1))',
fontWeight: 500,
padding: '5px 10px',
borderRadius: 8,
padding: content ? '8px 10px' : '5px 10px',
borderRadius: content ? 10 : 8,
// A label of several lines (the paddle check bench) breaks at its lines and wraps within the window.
whiteSpace: label.includes('\n') ? 'pre-line' : 'nowrap',
maxWidth: label.includes('\n') ? 'min(22rem, calc(100vw - 12px))' : undefined,
@@ -103,12 +108,12 @@ export function Tooltip({ label, placement = 'bottom', delay = 250, disabled, sh
transformOrigin: placement === 'top' ? 'bottom center' : placement === 'bottom' ? 'top center' : placement === 'left' ? 'center right' : 'center left',
}}
>
{shortcut && shortcut.length > 0 ? (
{content ?? (shortcut && shortcut.length > 0 ? (
<span className="inline-flex items-center gap-2">
{label}
<Kbd keys={shortcut} />
</span>
) : label}
) : label)}
</div>,
document.body,
)}