mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-20 01:25:16 +00:00
Make annotations visible on hover, fix accessibility and outro animations (#3822)
This commit is contained in:
@@ -27,7 +27,7 @@ export function Annotation(props: InlineProps<DocumentInlineAnnotation>) {
|
||||
ancestorBlocks={[]}
|
||||
context={context}
|
||||
nodes={fragment.nodes}
|
||||
style={['space-y-4']}
|
||||
style={['contents']}
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,84 +1,30 @@
|
||||
'use client';
|
||||
|
||||
import * as Popover from '@radix-ui/react-popover';
|
||||
import type React from 'react';
|
||||
|
||||
import { tString, useLanguage } from '@/intl/client';
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { Tooltip } from '@/components/primitives';
|
||||
|
||||
export function AnnotationPopover(props: { children: React.ReactNode; body: React.ReactNode }) {
|
||||
const { children, body } = props;
|
||||
const language = useLanguage();
|
||||
|
||||
return (
|
||||
<Popover.Root>
|
||||
<Popover.Trigger asChild>
|
||||
<button
|
||||
data-testid="annotation-button"
|
||||
aria-label={tString(language, 'annotation_button_label')}
|
||||
className={tcls(
|
||||
'decoration-dotted',
|
||||
'decoration-1',
|
||||
'underline',
|
||||
'underline-offset-2'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
<Popover.Portal>
|
||||
<Popover.Content
|
||||
className={tcls(
|
||||
'text-sm',
|
||||
'max-w-[280px]',
|
||||
'bg-tint',
|
||||
'ring-1',
|
||||
'ring-tint',
|
||||
'rounded-sm',
|
||||
'shadow-1xs',
|
||||
'shadow-tint-12/1',
|
||||
'dark:shadow-tint-1/2',
|
||||
'p-3',
|
||||
'[&_p]:leading-snug',
|
||||
'-outline-offset-2',
|
||||
'outline-2',
|
||||
'outline-primary/8',
|
||||
'z-20'
|
||||
)}
|
||||
sideOffset={4}
|
||||
>
|
||||
{body}
|
||||
<Popover.Arrow asChild>
|
||||
<svg
|
||||
viewBox="0 0 8 5"
|
||||
className={tcls(
|
||||
'relative',
|
||||
'z-2',
|
||||
'fill-tint-3', // Same as bg-tint
|
||||
'stroke-tint-7', // Same as ring-tint
|
||||
'[paint-order:stroke_fill]'
|
||||
)}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clipAnnotation)">
|
||||
<path
|
||||
d="M0 0L4 4L8 0"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
stroke="inherit"
|
||||
fill="inherit"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clipAnnotation">
|
||||
<rect width="8" height="5" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</Popover.Arrow>
|
||||
</Popover.Content>
|
||||
</Popover.Portal>
|
||||
</Popover.Root>
|
||||
<Tooltip
|
||||
label={body}
|
||||
contentProps={{
|
||||
role: 'definition',
|
||||
}}
|
||||
className="bg-tint-base px-4 py-3 text-sm text-tint-strong shadow-lg shadow-tint-12/4 ring-1 ring-tint-subtle dark:shadow-tint-1"
|
||||
arrow={true}
|
||||
arrowProps={{ className: 'fill-tint-1' }}
|
||||
>
|
||||
<dfn
|
||||
data-testid="annotation-button"
|
||||
className="cursor-help underline decoration-1 decoration-dotted underline-offset-2"
|
||||
// biome-ignore lint/a11y/noNoninteractiveTabindex: we want to be able to focus the definition to open the tooltip
|
||||
tabIndex={0}
|
||||
>
|
||||
{children}
|
||||
</dfn>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export function HoverCard(
|
||||
<RadixHoverCard.Portal>
|
||||
<RadixHoverCard.Content
|
||||
side={props.side ?? 'top'}
|
||||
className="z-40 w-screen max-w-md animate-present px-4 sm:w-auto"
|
||||
className="z-40 w-screen max-w-md animate-scale-in px-4 data-[state='closed']:animate-scale-out sm:w-auto"
|
||||
>
|
||||
<div
|
||||
className={tcls(
|
||||
|
||||
@@ -20,7 +20,7 @@ export function Popover(props: {
|
||||
collisionPadding={contentProps?.collisionPadding ?? 16}
|
||||
sideOffset={contentProps?.sideOffset ?? 4}
|
||||
className={tcls(
|
||||
'z-50 max-h-(--radix-popover-content-available-height) max-w-xs animate-scale-in overflow-y-auto overflow-x-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint px-4 py-3 text-sm text-tint depth-subtle:shadow-xl shadow-tint-12/4 outline-hidden ring-1 ring-tint transition-all empty:hidden dark:shadow-tint-1/6',
|
||||
'z-50 max-h-(--radix-popover-content-available-height) max-w-xs animate-scale-in overflow-y-auto overflow-x-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint px-4 py-3 text-sm text-tint depth-subtle:shadow-xl shadow-tint-12/4 outline-hidden ring-1 ring-tint transition-all empty:hidden data-[state="closed"]:animate-scale-out dark:shadow-tint-1/6',
|
||||
contentProps?.className
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import * as RadixTooltip from '@radix-ui/react-tooltip';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function Tooltip(props: {
|
||||
children: React.ReactNode;
|
||||
label?: string | React.ReactNode;
|
||||
triggerProps?: RadixTooltip.TooltipTriggerProps;
|
||||
contentProps?: RadixTooltip.TooltipContentProps;
|
||||
portalProps?: RadixTooltip.TooltipPortalProps;
|
||||
rootProps?: RadixTooltip.TooltipProps;
|
||||
arrowProps?: RadixTooltip.TooltipArrowProps;
|
||||
arrow?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
@@ -17,27 +20,34 @@ export function Tooltip(props: {
|
||||
label,
|
||||
triggerProps,
|
||||
contentProps,
|
||||
portalProps,
|
||||
rootProps,
|
||||
arrowProps,
|
||||
arrow = false,
|
||||
className,
|
||||
} = props;
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [clicked, setClicked] = useState(false);
|
||||
|
||||
return (
|
||||
<RadixTooltip.Root delayDuration={300} {...rootProps}>
|
||||
<RadixTooltip.Trigger asChild {...triggerProps}>
|
||||
<RadixTooltip.Root open={open || clicked} onOpenChange={setOpen} {...rootProps}>
|
||||
<RadixTooltip.Trigger asChild onClick={() => setClicked(true)} {...triggerProps}>
|
||||
{children}
|
||||
</RadixTooltip.Trigger>
|
||||
<RadixTooltip.Portal>
|
||||
<RadixTooltip.Portal {...portalProps}>
|
||||
<RadixTooltip.Content
|
||||
sideOffset={4}
|
||||
collisionPadding={8}
|
||||
className={tcls(
|
||||
'z-50 max-w-xs animate-scale-in circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint-12 px-2 py-1 text-contrast-tint-12 text-sm',
|
||||
'z-50 max-w-xs circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint-12 px-2 py-1 text-contrast-tint-12 text-sm data-[state$="closed"]:animate-scale-out data-[state$="open"]:animate-scale-in',
|
||||
className
|
||||
)}
|
||||
onPointerDownOutside={() => setClicked(false)}
|
||||
{...contentProps}
|
||||
>
|
||||
{label}
|
||||
{arrow && <RadixTooltip.Arrow />}
|
||||
{arrow && <RadixTooltip.Arrow {...arrowProps} />}
|
||||
</RadixTooltip.Content>
|
||||
</RadixTooltip.Portal>
|
||||
</RadixTooltip.Root>
|
||||
|
||||
Reference in New Issue
Block a user