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:
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 |
194
src/Toolbar.tsx
194
src/Toolbar.tsx
@ -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>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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' : ''
|
||||||
|
Reference in New Issue
Block a user