Have links clickable within tooltips without clicking content below them (#3204)

* Have links clickable within tooltips without clicking content below them

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-08-02 12:25:57 -04:00
committed by GitHub
parent 7b9f40c4cb
commit 9b594efe53
6 changed files with 103 additions and 96 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -190,49 +190,59 @@ export function Toolbar({
maybeIconConfig[0].onClick(configCallbackProps) maybeIconConfig[0].onClick(configCallbackProps)
} }
> >
<ToolbarItemContents <span
itemConfig={maybeIconConfig[0]} className={!maybeIconConfig[0].showTitle ? 'sr-only' : ''}
configCallbackProps={configCallbackProps} >
/> {maybeIconConfig[0].title}
</span>
</ActionButton> </ActionButton>
<ToolbarItemTooltip
itemConfig={maybeIconConfig[0]}
configCallbackProps={configCallbackProps}
/>
</ActionButtonDropdown> </ActionButtonDropdown>
) )
} }
const itemConfig = maybeIconConfig const itemConfig = maybeIconConfig
return ( return (
<ActionButton <div className="relative" key={itemConfig.id}>
Element="button" <ActionButton
key={itemConfig.id} Element="button"
id={itemConfig.id} key={itemConfig.id}
data-testid={itemConfig.id} id={itemConfig.id}
iconStart={{ data-testid={itemConfig.id}
icon: itemConfig.icon, iconStart={{
className: iconClassName, icon: itemConfig.icon,
bgClassName: bgClassName, className: iconClassName,
}} bgClassName: bgClassName,
className={ }}
'pressed:!text-chalkboard-10 pressed:enabled:hovered:!text-chalkboard-10 ' + className={
buttonBorderClassName + 'pressed:!text-chalkboard-10 pressed:enabled:hovered:!text-chalkboard-10 ' +
' ' + buttonBorderClassName +
buttonBgClassName + ' ' +
(!itemConfig.showTitle ? ' !px-0' : '') buttonBgClassName +
} (!itemConfig.showTitle ? ' !px-0' : '')
name={itemConfig.title} }
aria-description={itemConfig.description} name={itemConfig.title}
aria-pressed={itemConfig.isActive} aria-description={itemConfig.description}
disabled={ aria-pressed={itemConfig.isActive}
disableAllButtons || disabled={
itemConfig.status !== 'available' || disableAllButtons ||
itemConfig.disabled itemConfig.status !== 'available' ||
} itemConfig.disabled
onClick={() => itemConfig.onClick(configCallbackProps)} }
> onClick={() => itemConfig.onClick(configCallbackProps)}
<ToolbarItemContents >
<span className={!itemConfig.showTitle ? 'sr-only' : ''}>
{itemConfig.title}
</span>
</ActionButton>
<ToolbarItemTooltip
itemConfig={itemConfig} itemConfig={itemConfig}
configCallbackProps={configCallbackProps} configCallbackProps={configCallbackProps}
/> />
</ActionButton> </div>
) )
})} })}
</ul> </ul>
@ -250,7 +260,7 @@ export function Toolbar({
* It contains a tooltip with the title, description, and links * It contains a tooltip with the title, description, and links
* and a hotkey listener * and a hotkey listener
*/ */
const ToolbarItemContents = memo(function ToolbarItemContents({ const ToolbarItemTooltip = memo(function ToolbarItemContents({
itemConfig, itemConfig,
configCallbackProps, configCallbackProps,
}: { }: {
@ -272,73 +282,69 @@ const ToolbarItemContents = memo(function ToolbarItemContents({
) )
return ( return (
<> <Tooltip
<span className={!itemConfig.showTitle ? 'sr-only' : ''}> inert={false}
{itemConfig.title} position="bottom"
</span> wrapperClassName="!p-4 !pointer-events-auto"
<Tooltip contentClassName="!text-left text-wrap !text-xs !p-0 !pb-2 flex gap-2 !max-w-none !w-72 flex-col items-stretch"
position="bottom" >
wrapperClassName="!p-4 !pointer-events-auto" <div className="rounded-top flex items-center gap-2 pt-3 pb-2 px-2 bg-chalkboard-20/50 dark:bg-chalkboard-80/50">
contentClassName="!text-left text-wrap !text-xs !p-0 !pb-2 flex gap-2 !max-w-none !w-72 flex-col items-stretch" <span
> className={`text-sm flex-1 ${
<div className="rounded-top flex items-center gap-2 pt-3 pb-2 px-2 bg-chalkboard-20/50 dark:bg-chalkboard-80/50"> itemConfig.status !== 'available'
<span ? 'text-chalkboard-70 dark:text-chalkboard-40'
className={`text-sm flex-1 ${ : ''
itemConfig.status !== 'available' }`}
? 'text-chalkboard-70 dark:text-chalkboard-40' >
: '' {itemConfig.title}
}`} </span>
> {itemConfig.status === 'available' && itemConfig.hotkey ? (
{itemConfig.title} <kbd className="flex-none hotkey">{itemConfig.hotkey}</kbd>
</span> ) : itemConfig.status === 'kcl-only' ? (
{itemConfig.status === 'available' && itemConfig.hotkey ? ( <>
<kbd className="flex-none hotkey">{itemConfig.hotkey}</kbd> <span className="text-wrap font-sans flex-0 text-chalkboard-70 dark:text-chalkboard-40">
) : itemConfig.status === 'kcl-only' ? ( KCL code only
</span>
<CustomIcon
name="code"
className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
) : (
itemConfig.status === 'unavailable' && (
<> <>
<span className="text-wrap font-sans flex-0 text-chalkboard-70 dark:text-chalkboard-40"> <span className="text-wrap font-sans flex-0 text-chalkboard-70 dark:text-chalkboard-40">
KCL code only In development
</span> </span>
<CustomIcon <CustomIcon
name="code" name="lockClosed"
className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40" className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40"
/> />
</> </>
) : ( )
itemConfig.status === 'unavailable' && (
<>
<span className="text-wrap font-sans flex-0 text-chalkboard-70 dark:text-chalkboard-40">
In development
</span>
<CustomIcon
name="lockClosed"
className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40"
/>
</>
)
)}
</div>
<p className="px-2 text-ch font-sans">{itemConfig.description}</p>
{itemConfig.links.length > 0 && (
<>
<hr className="border-chalkboard-20 dark:border-chalkboard-80" />
<ul className="p-0 px-1 m-0 flex flex-col">
{itemConfig.links.map((link) => (
<li key={link.label} className="contents">
<a
href={link.url}
target="_blank"
rel="noreferrer"
className="flex items-center rounded-sm p-1 no-underline text-inherit hover:bg-primary/10 hover:text-primary dark:hover:bg-chalkboard-70 dark:hover:text-inherit"
>
<span className="flex-1">Open {link.label}</span>
<CustomIcon name="link" className="w-4 h-4" />
</a>
</li>
))}
</ul>
</>
)} )}
</Tooltip> </div>
</> <p className="px-2 text-ch font-sans">{itemConfig.description}</p>
{itemConfig.links.length > 0 && (
<>
<hr className="border-chalkboard-20 dark:border-chalkboard-80" />
<ul className="p-0 px-1 m-0 flex flex-col">
{itemConfig.links.map((link) => (
<li key={link.label} className="contents">
<a
href={link.url}
target="_blank"
rel="noreferrer"
className="flex items-center rounded-sm p-1 no-underline text-inherit hover:bg-primary/10 hover:text-primary dark:hover:bg-chalkboard-70 dark:hover:text-inherit"
>
<span className="flex-1">Open {link.label}</span>
<CustomIcon name="link" className="w-4 h-4" />
</a>
</li>
))}
</ul>
</>
)}
</Tooltip>
) )
}) })

View File

@ -57,7 +57,8 @@
transition-delay: var(--_delay); transition-delay: var(--_delay);
} }
:is(:focus-visible) > .tooltipWrapper.withFocus { :is(:focus-visible) > .tooltipWrapper.withFocus,
:focus-within > .tooltipWrapper.withFocus {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
} }

View File

@ -29,7 +29,7 @@ export default function Tooltip({
return ( return (
<div <div
// @ts-ignore while awaiting merge of this PR for support of "inert" https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60822 // @ts-ignore while awaiting merge of this PR for support of "inert" https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60822
inert={inert} {...{ inert: inert ? '' : undefined }}
role="tooltip" role="tooltip"
className={`p-3 ${ className={`p-3 ${
position !== 'left' && position !== 'right' ? 'px-0' : '' position !== 'left' && position !== 'right' ? 'px-0' : ''