Skip to content

Commit 15d77f6

Browse files
committed
Merge branch 'dev' into pr/13700
2 parents f7a8a47 + 9e4a8c9 commit 15d77f6

File tree

14 files changed

+772
-715
lines changed

14 files changed

+772
-715
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@radix-ui/react-radio-group": "^1.2.0",
4747
"@radix-ui/react-slot": "^1.1.0",
4848
"@radix-ui/react-switch": "^1.1.0",
49+
"@radix-ui/react-tooltip": "^1.1.2",
4950
"@radix-ui/react-visually-hidden": "^1.1.0",
5051
"@sentry/nextjs": "^8.19.0",
5152
"@socialgouv/matomo-next": "^1.8.0",
@@ -63,7 +64,6 @@
6364
"lodash.merge": "^4.6.2",
6465
"lodash.shuffle": "^4.2.0",
6566
"lodash.union": "^4.6.0",
66-
"lucide-react": "^0.400.0",
6767
"next": "^14.2.3",
6868
"next-i18next": "^14.0.3",
6969
"next-mdx-remote": "^3.0.8",

src/components/Glossary/GlossaryTooltip/GlossaryTooltip.stories.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Center } from "@chakra-ui/react"
22
import { Meta, StoryObj } from "@storybook/react"
33

4+
import { TooltipProvider } from "@/components/ui/tooltip"
5+
46
import GlossaryTooltipComponent from "."
57

68
const meta = {
@@ -13,7 +15,9 @@ const meta = {
1315
decorators: [
1416
(Story) => (
1517
<Center boxSize="md">
16-
<Story />
18+
<TooltipProvider>
19+
<Story />
20+
</TooltipProvider>
1721
</Center>
1822
),
1923
],
@@ -28,6 +32,6 @@ export const Basic: Story = {}
2832
// for chromatic story snapshot showing the rendered popover
2933
export const OnOpen: Story = {
3034
args: {
31-
isOpen: true,
35+
open: true,
3236
},
3337
}

src/components/Glossary/GlossaryTooltip/index.tsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import React, { ReactNode } from "react"
22
import { useRouter } from "next/router"
3-
import { Box, Text, VStack } from "@chakra-ui/react"
43

5-
import Heading from "@/components/Heading"
64
import InlineLink from "@/components/Link"
75
import Tooltip, { type TooltipProps } from "@/components/Tooltip"
86
import Translation from "@/components/Translation"
@@ -23,36 +21,36 @@ const GlossaryTooltip = ({
2321
const { asPath } = useRouter()
2422

2523
return (
26-
<Box as="span" display="inline-block">
24+
<span className="inline-block">
2725
<Tooltip
2826
{...props}
2927
content={
30-
<VStack spacing={2} align="stretch" textAlign="start">
31-
<Heading as="h6">
28+
<div className="flex flex-col items-stretch gap-2 text-start">
29+
<h6>
3230
<Translation
3331
id={termKey + "-term"}
3432
options={{ ns: "glossary-tooltip" }}
3533
// Override the default `a` tag transformation to avoid circular
3634
// dependency issues
3735
transform={{ a: InlineLink }}
3836
/>
39-
</Heading>
37+
</h6>
4038
{/**
4139
* `as="span"` prevents hydration warnings for strings that contain
4240
* elements that cannot be nested inside `p` tags, like `ul` tags
4341
* (found in some Glossary definition).
4442
* TODO: Develop a better solution to handle this case.
4543
*/}
46-
<Text as="span">
44+
<span>
4745
<Translation
4846
id={termKey + "-definition"}
4947
options={{ ns: "glossary-tooltip" }}
5048
// Override the default `a` tag transformation to avoid circular
5149
// dependency issues
5250
transform={{ a: InlineLink }}
5351
/>
54-
</Text>
55-
</VStack>
52+
</span>
53+
</div>
5654
}
5755
onBeforeOpen={() => {
5856
trackCustomEvent({
@@ -62,20 +60,11 @@ const GlossaryTooltip = ({
6260
})
6361
}}
6462
>
65-
<Text
66-
as="u"
67-
textDecorationStyle="dotted"
68-
textUnderlineOffset="3px"
69-
_hover={{
70-
textDecorationColor: "primary.hover",
71-
color: "primary.hover",
72-
}}
73-
cursor="help"
74-
>
63+
<u className="cursor-help decoration-dotted underline-offset-3 hover:text-primary-hover hover:decoration-primary-hover">
7564
{children}
76-
</Text>
65+
</u>
7766
</Tooltip>
78-
</Box>
67+
</span>
7968
)
8069
}
8170

src/components/Tooltip/Tooltip.stories.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Meta, StoryObj } from "@storybook/react"
44

55
import InlineLink from "../Link"
66
import Translation from "../Translation"
7+
import { TooltipProvider } from "../ui/tooltip"
78

89
// TODO: remove `index` when we delete the old tooltip
910
import TooltipComponent from "./index"
@@ -46,7 +47,9 @@ const meta = {
4647
decorators: [
4748
(Story) => (
4849
<Center boxSize="md">
49-
<Story />
50+
<TooltipProvider>
51+
<Story />
52+
</TooltipProvider>
5053
</Center>
5154
),
5255
],
@@ -61,6 +64,6 @@ export const Basic: Story = {}
6164
// for chromatic story snapshot showing the rendered popover
6265
export const OnOpen: Story = {
6366
args: {
64-
isOpen: true,
67+
open: true,
6568
},
6669
}

src/components/Tooltip/index.tsx

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import React, { ReactNode, useEffect } from "react"
2-
import {
3-
Popover,
4-
PopoverArrow,
5-
PopoverBody,
6-
PopoverContent,
7-
PopoverProps,
8-
PopoverTrigger,
9-
Portal,
10-
useDisclosure,
11-
} from "@chakra-ui/react"
1+
import React, { ComponentProps, ReactNode, useEffect } from "react"
122

133
import { isMobile } from "@/lib/utils/isMobile"
144

15-
export interface TooltipProps extends PopoverProps {
5+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"
6+
import {
7+
Tooltip as Tooltipcomponent,
8+
TooltipContent,
9+
TooltipTrigger,
10+
} from "../ui/tooltip"
11+
12+
import { useDisclosure } from "@/hooks/useDisclosure"
13+
import { useIsClient } from "@/hooks/useIsClient"
14+
15+
export type TooltipProps = ComponentProps<typeof Popover> & {
1616
content: ReactNode
1717
children?: ReactNode
1818
onBeforeOpen?: () => void
@@ -22,9 +22,10 @@ const Tooltip = ({
2222
content,
2323
children,
2424
onBeforeOpen,
25-
...rest
25+
...props
2626
}: TooltipProps) => {
2727
const { isOpen, onOpen, onClose } = useDisclosure()
28+
const isClient = useIsClient()
2829

2930
// Close the popover when the user scrolls.
3031
// This is useful for mobile devices where the popover is open by clicking the
@@ -57,24 +58,39 @@ const Tooltip = ({
5758
onOpen()
5859
}
5960

61+
const handleOpenChange = (open: boolean) => {
62+
if (open) {
63+
handleOpen()
64+
} else {
65+
onClose()
66+
}
67+
}
68+
69+
// Avoid rendering on the server since the user can't interact with it and we
70+
// need to use different components depending on the device
71+
if (!isClient) {
72+
return null
73+
}
74+
75+
// Use Popover on mobile devices since the user can't hover
76+
const Component = isMobile() ? Popover : Tooltipcomponent
77+
const Trigger = isMobile() ? PopoverTrigger : TooltipTrigger
78+
const Content = isMobile() ? PopoverContent : TooltipContent
79+
6080
return (
61-
<Popover
62-
isOpen={isOpen}
63-
onOpen={handleOpen}
64-
onClose={onClose}
65-
placement="top"
66-
trigger={isMobile() ? "click" : "hover"}
67-
gutter={8}
68-
{...rest}
69-
>
70-
<PopoverTrigger>{children}</PopoverTrigger>
71-
<Portal>
72-
<PopoverContent data-testid="tooltip-popover">
73-
<PopoverArrow />
74-
<PopoverBody>{content}</PopoverBody>
75-
</PopoverContent>
76-
</Portal>
77-
</Popover>
81+
<Component open={isOpen} onOpenChange={handleOpenChange} {...props}>
82+
<Trigger className="focus-visible:rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-hover">
83+
{children}
84+
</Trigger>
85+
<Content
86+
side="top"
87+
sideOffset={2}
88+
className="w-80 px-5 text-sm"
89+
data-testid="tooltip-popover"
90+
>
91+
{content}
92+
</Content>
93+
</Component>
7894
)
7995
}
8096

src/components/ui/buttons/Button.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,40 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
108108
)
109109
Button.displayName = "Button"
110110

111-
type ButtonLinkProps = Omit<LinkProps, "onClick"> & {
112-
buttonProps?: ButtonProps
113-
customEventOptions?: MatomoEventOptions
114-
}
111+
type ButtonLinkProps = Omit<LinkProps, "onClick"> &
112+
Pick<ButtonProps, "size" | "variant" | "isSecondary"> & {
113+
buttonProps?: Omit<ButtonProps, "size" | "variant">
114+
customEventOptions?: MatomoEventOptions
115+
}
115116

116117
const ButtonLink = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(
117-
({ buttonProps, customEventOptions, children, ...linkProps }, ref) => {
118+
(
119+
{
120+
size,
121+
variant,
122+
isSecondary,
123+
buttonProps,
124+
customEventOptions,
125+
children,
126+
className,
127+
...linkProps
128+
},
129+
ref
130+
) => {
118131
const handleClick = () => {
119132
customEventOptions && trackCustomEvent(customEventOptions)
120133
}
121134
return (
122-
<Button asChild {...buttonProps}>
135+
<Button
136+
asChild
137+
size={size}
138+
variant={variant}
139+
isSecondary={isSecondary}
140+
{...buttonProps}
141+
>
123142
<BaseLink
124143
ref={ref}
125-
className="no-underline hover:no-underline"
144+
className={cn("no-underline hover:no-underline", className)}
126145
activeClassName=""
127146
{...linkProps}
128147
onClick={handleClick}

src/components/ui/dialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react"
2-
import { X } from "lucide-react"
2+
import { MdClose } from "react-icons/md"
33
import * as DialogPrimitive from "@radix-ui/react-dialog"
44

55
import { cn } from "@/lib/utils/cn"
@@ -43,7 +43,7 @@ const DialogContent = React.forwardRef<
4343
>
4444
{children}
4545
<DialogPrimitive.Close className="focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
46-
<X className="h-4 w-4" />
46+
<MdClose className="h-4 w-4" />
4747
<span className="sr-only">Close</span>
4848
</DialogPrimitive.Close>
4949
</DialogPrimitive.Content>

src/components/ui/popover.tsx

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,28 @@ const PopoverTrigger = PopoverPrimitive.Trigger
1010
const PopoverContent = React.forwardRef<
1111
React.ElementRef<typeof PopoverPrimitive.Content>,
1212
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
13-
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
14-
<PopoverPrimitive.Portal>
15-
<PopoverPrimitive.Content
16-
ref={ref}
17-
align={align}
18-
sideOffset={sideOffset}
19-
className={cn(
20-
"text-popover-foreground z-popover w-72 rounded-md border bg-background p-4 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
21-
className
22-
)}
23-
{...props}
24-
/>
25-
</PopoverPrimitive.Portal>
26-
))
13+
>(
14+
(
15+
{ className, children, align = "center", sideOffset = 4, ...props },
16+
ref
17+
) => (
18+
<PopoverPrimitive.Portal>
19+
<PopoverPrimitive.Content
20+
ref={ref}
21+
align={align}
22+
sideOffset={sideOffset}
23+
className={cn(
24+
"text-popover-foreground z-popover w-72 rounded border border-background-highlight bg-background-highlight p-4 shadow-lg outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
25+
className
26+
)}
27+
{...props}
28+
>
29+
{children}
30+
<PopoverPrimitive.Arrow className="z-popover fill-background-highlight" />
31+
</PopoverPrimitive.Content>
32+
</PopoverPrimitive.Portal>
33+
)
34+
)
2735
PopoverContent.displayName = PopoverPrimitive.Content.displayName
2836

2937
const PopoverClose = PopoverPrimitive.Close

src/components/ui/tooltip.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as React from "react"
2+
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
3+
4+
import { cn } from "@/lib/utils/cn"
5+
6+
const TooltipProvider = TooltipPrimitive.Provider
7+
8+
const Tooltip = TooltipPrimitive.Root
9+
10+
const TooltipTrigger = TooltipPrimitive.Trigger
11+
12+
const TooltipContent = React.forwardRef<
13+
React.ElementRef<typeof TooltipPrimitive.Content>,
14+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
15+
>(({ children, className, sideOffset = 4, ...props }, ref) => (
16+
<TooltipPrimitive.Content
17+
ref={ref}
18+
sideOffset={sideOffset}
19+
className={cn(
20+
"z-popover overflow-hidden rounded-md border border-background-highlight bg-background-highlight p-4 text-sm text-body shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
21+
className
22+
)}
23+
{...props}
24+
>
25+
{children}
26+
<TooltipPrimitive.Arrow className="z-popover fill-background-highlight" />
27+
</TooltipPrimitive.Content>
28+
))
29+
TooltipContent.displayName = TooltipPrimitive.Content.displayName
30+
31+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }

0 commit comments

Comments
 (0)