Skip to content

Commit f28dda1

Browse files
authored
feat!: refactor Tooltip to use radix-ui (#1722)
1 parent 330117f commit f28dda1

29 files changed

+426
-898
lines changed

.changeset/fair-swans-shake.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@strapi/design-system': major
3+
---
4+
5+
chore!: streamline IconButton API
6+
7+
- remove `icon` prop
8+
- remove `ariaLabel` prop
9+
- add `withTooltip` prop (default false)
10+
11+
`children` & `label` are now required props.

.changeset/wild-colts-return.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@strapi/design-system': major
3+
---
4+
5+
feat!: refactor Tooltip to use radix-ui
6+
7+
The Tooltip API has changed significently whilst retaining it's functionality, we recommend your review the documentation to understand the changes and how to migrate your code.

docs/stories/00-getting started/migration guides/migration-v1-v2.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ of our APIs will change, but functionality should still remain the same. We reco
203203
for any of these components to understand better how to migrate your code.
204204

205205
- `Accordion`
206+
- `Tooltip`
206207

207208
### Removed `ThemeProvider`
208209

@@ -213,6 +214,17 @@ for any of these components to understand better how to migrate your code.
213214
+ import { DesignSystemProvider } from '@strapi/design-system';
214215
```
215216

217+
### IconButton API changes
218+
219+
The `IconButton` API has been streamlined, namely `icon` and `ariaLabel` have been removed. Users should instead use
220+
`label` and `children`, by default we always show a tooltip to preserve old functionality but this will deprecated in a
221+
future release. If you don't want a tooltip you should set `withTooltip` to `false`:
222+
223+
```diff
224+
- <IconButton icon={Plus} ariaLabel="Add" />
225+
+ <IconButton withTooltip={false} label="Add"><Plus /></IconButton>
226+
```
227+
216228
---
217229

218230
## Icons

docs/stories/04-components/Accordion.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,10 @@ export const WithActions = {
307307
{title}
308308
</Accordion.Trigger>
309309
<Accordion.Actions>
310-
<IconButton aria-label="Duplicate record" onClick={duplicateOnClick}>
310+
<IconButton withTooltip={false} label="Duplicate record" onClick={duplicateOnClick}>
311311
<Duplicate />
312312
</IconButton>
313-
<IconButton aria-label="Delete record" onClick={deleteOnClick}>
313+
<IconButton withTooltip={false} label="Delete record" onClick={deleteOnClick}>
314314
<Trash />
315315
</IconButton>
316316
</Accordion.Actions>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Meta, Canvas, ArgTypes, Controls } from '@storybook/blocks';
2+
import { Tooltip } from '@strapi/design-system';
3+
4+
import * as TooltipStories from './Tooltip.stories';
5+
6+
<Meta of={TooltipStories} />
7+
8+
# Tooltip
9+
10+
- [Overview](#overview)
11+
- [Usage](#usage)
12+
- [Props](#props)
13+
- [Positioning](#positioning)
14+
15+
## Overview
16+
17+
Tooltips are a specific type of popover that displays information related to an element when said element recieves focus
18+
or the hover.
19+
20+
<ViewSource path="components/Tooltip" />
21+
22+
## Usage
23+
24+
```js
25+
import { Tooltip } from '@strapi/design-system';
26+
```
27+
28+
They shouldn't be used to display critical or urgent information, but rather to provide additional context or
29+
information. Information should be short & concise.
30+
31+
<Canvas of={TooltipStories.Base} />
32+
33+
## Props
34+
35+
<ArgTypes of={Tooltip} />
36+
37+
## Positioning
38+
39+
Use a combination of `align` and `side` to dictate the position of a tooltip, the tooltip will still move itself if it's
40+
going to colide with the viewport. The default position is `top` and `center`.
41+
42+
<Canvas of={TooltipStories.Positioned} />
43+
<Controls of={TooltipStories.Positioned} />
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Meta, StoryObj } from '@storybook/react';
2+
import { Tooltip, IconButton } from '@strapi/design-system';
3+
import { Trash } from '@strapi/icons';
4+
import { outdent } from 'outdent';
5+
6+
const meta: Meta<typeof Tooltip> = {
7+
title: 'Components/Tooltip',
8+
component: Tooltip,
9+
args: {
10+
label: 'Delete all items',
11+
},
12+
render: (args) => {
13+
return (
14+
<Tooltip {...args}>
15+
<IconButton withTooltip={false} label="delete">
16+
<Trash />
17+
</IconButton>
18+
</Tooltip>
19+
);
20+
},
21+
parameters: {
22+
docs: {
23+
source: {
24+
code: outdent`
25+
<Tooltip label="Delete all items">
26+
<button aria-label="delete">
27+
<Trash aria-hidden focusable={false} />
28+
</button>
29+
</Tooltip>
30+
`,
31+
},
32+
},
33+
/* this will never show the component without interaction, so we never want it snapshot. */
34+
chromatic: { disableSnapshot: true },
35+
},
36+
};
37+
38+
export default meta;
39+
40+
type Story = StoryObj<typeof Tooltip>;
41+
42+
export const Base = {
43+
name: 'base',
44+
} satisfies Story;
45+
46+
export const Positioned = {
47+
name: 'positioned',
48+
argTypes: {
49+
align: {
50+
control: 'select',
51+
options: ['start', 'center', 'end'],
52+
},
53+
side: {
54+
control: 'select',
55+
options: ['left', 'right', 'top', 'bottom'],
56+
},
57+
},
58+
args: {
59+
align: 'center',
60+
open: true,
61+
side: 'right',
62+
},
63+
parameters: {
64+
docs: {
65+
source: {
66+
code: outdent`
67+
<Tooltip label="Delete all items" align="center" side="right">
68+
<button aria-label="delete">
69+
<Trash aria-hidden focusable={false} />
70+
</button>
71+
</Tooltip>
72+
`,
73+
},
74+
},
75+
chromatic: { disableSnapshot: false },
76+
},
77+
} satisfies Story;

docs/stories/Card.stories.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ export const Base = {
3737
<CardHeader>
3838
<CardCheckbox value />
3939
<CardAction position="end">
40-
<IconButton label="Edit the thing" icon={<Pencil />} />
40+
<IconButton label="Edit the thing">
41+
<Pencil />
42+
</IconButton>
4143
</CardAction>
4244
<CardAsset src={'/stories/carousel/first.jpg'} />
4345
<CardTimer>05:39</CardTimer>

docs/stories/Carousel.stories.tsx

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ export const Base = {
3737
hint="Description line"
3838
actions={
3939
<CarouselActions>
40-
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit" icon={<Pencil />} />
41-
<IconButton onClick={() => console.log('Create')} label="Create" icon={<Plus />} />
42-
<IconButton onClick={() => console.log('Delete')} label="Delete" icon={<Trash />} />
43-
<IconButton onClick={() => console.log('Publish')} label="Publish" icon={<Play />} />
40+
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit">
41+
<Pencil />
42+
</IconButton>
43+
<IconButton onClick={() => console.log('Create')} label="Create">
44+
<Plus />
45+
</IconButton>
46+
<IconButton onClick={() => console.log('Delete')} label="Delete">
47+
<Trash />
48+
</IconButton>
49+
<IconButton onClick={() => console.log('Publish')} label="Publish">
50+
<Play />
51+
</IconButton>
4452
</CarouselActions>
4553
}
4654
style={{
@@ -74,10 +82,18 @@ export const OneSlideOnly = {
7482
hint="Description line"
7583
actions={
7684
<CarouselActions>
77-
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit" icon={<Pencil />} />
78-
<IconButton onClick={() => console.log('Create')} label="Create" icon={<Plus />} />
79-
<IconButton onClick={() => console.log('Delete')} label="Delete" icon={<Trash />} />
80-
<IconButton onClick={() => console.log('Publish')} label="Publish" icon={<Play />} />
85+
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit">
86+
<Pencil />
87+
</IconButton>
88+
<IconButton onClick={() => console.log('Create')} label="Create">
89+
<Plus />
90+
</IconButton>
91+
<IconButton onClick={() => console.log('Delete')} label="Delete">
92+
<Trash />
93+
</IconButton>
94+
<IconButton onClick={() => console.log('Publish')} label="Publish">
95+
<Play />
96+
</IconButton>
8197
</CarouselActions>
8298
}
8399
style={{
@@ -105,10 +121,18 @@ export const BrokenAsset = {
105121
hint="Description line"
106122
actions={
107123
<CarouselActions>
108-
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit" icon={<Pencil />} />
109-
<IconButton onClick={() => console.log('Create')} label="Create" icon={<Plus />} />
110-
<IconButton onClick={() => console.log('Delete')} label="Delete" icon={<Trash />} />
111-
<IconButton onClick={() => console.log('Publish')} label="Publish" icon={<Play />} />
124+
<IconButton onClick={() => console.log('edit')} label="Edit" id="edit">
125+
<Pencil />
126+
</IconButton>
127+
<IconButton onClick={() => console.log('Create')} label="Create">
128+
<Plus />
129+
</IconButton>
130+
<IconButton onClick={() => console.log('Delete')} label="Delete">
131+
<Trash />
132+
</IconButton>
133+
<IconButton onClick={() => console.log('Publish')} label="Publish">
134+
<Play />
135+
</IconButton>
112136
</CarouselActions>
113137
}
114138
style={{

docs/stories/IconButton.stories.tsx

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ export const Base = {
2323
<Typography>{currentAction}</Typography>
2424
</Box>
2525
<Flex background="neutral100" gap={1} padding={2}>
26-
<IconButton onClick={() => setCurrentAction('edit')} label="Edit" icon={<Pencil />} />
27-
<IconButton onClick={() => setCurrentAction('Create')} label="Create" icon={<Plus />} />
28-
<IconButton onClick={() => setCurrentAction('Delete')} label="Delete" icon={<Trash />} />
29-
<IconButton onClick={() => setCurrentAction('Publish')} label="Publish" icon={<Play />} />
26+
<IconButton onClick={() => setCurrentAction('edit')} label="Edit">
27+
<Pencil />
28+
</IconButton>
29+
<IconButton onClick={() => setCurrentAction('Create')} label="Create">
30+
<Plus />
31+
</IconButton>
32+
<IconButton onClick={() => setCurrentAction('Delete')} label="Delete">
33+
<Trash />
34+
</IconButton>
35+
<IconButton onClick={() => setCurrentAction('Publish')} label="Publish">
36+
<Play />
37+
</IconButton>
3038
</Flex>
3139
</Box>
3240
);
@@ -45,10 +53,18 @@ export const Disabled = {
4553
<Typography>{currentAction}</Typography>
4654
</Box>
4755
<Flex background="neutral100" gap={1} padding={2}>
48-
<IconButton disabled onClick={() => setCurrentAction('edit')} label="Edit" icon={<Pencil />} />
49-
<IconButton disabled onClick={() => setCurrentAction('Create')} label="Create" icon={<Plus />} />
50-
<IconButton disabled onClick={() => setCurrentAction('Delete')} label="Delete" icon={<Trash />} />
51-
<IconButton disabled onClick={() => setCurrentAction('Publish')} label="Publish" icon={<Play />} />
56+
<IconButton disabled onClick={() => setCurrentAction('edit')} label="Edit">
57+
<Pencil />
58+
</IconButton>
59+
<IconButton disabled onClick={() => setCurrentAction('Create')} label="Create">
60+
<Plus />
61+
</IconButton>
62+
<IconButton disabled onClick={() => setCurrentAction('Delete')} label="Delete">
63+
<Trash />
64+
</IconButton>
65+
<IconButton disabled onClick={() => setCurrentAction('Publish')} label="Publish">
66+
<Play />
67+
</IconButton>
5268
</Flex>
5369
</Box>
5470
);
@@ -61,7 +77,9 @@ export const WithoutTooltip = {
6177
render: () => (
6278
<Box padding={7}>
6379
<Flex background="neutral100" gap={1} padding={2}>
64-
<IconButton onClick={() => console.log('edit')} aria-label="Edit" icon={<Pencil />} />
80+
<IconButton onClick={() => console.log('edit')} withTooltip={false} label="Edit">
81+
<Pencil />
82+
</IconButton>
6583
</Flex>
6684
</Box>
6785
),
@@ -74,10 +92,18 @@ export const Group = {
7492
<Box padding={7}>
7593
<Flex background="neutral100" gap={1} padding={2}>
7694
<IconButtonGroup>
77-
<IconButton onClick={() => console.log('edit')} label="Edit" icon={<Pencil />} />
78-
<IconButton onClick={() => console.log('Create')} label="Create" icon={<Plus />} />
79-
<IconButton onClick={() => console.log('Delete')} label="Delete" icon={<Trash />} />
80-
<IconButton onClick={() => console.log('Publish')} label="Publish" icon={<Play />} />
95+
<IconButton onClick={() => console.log('edit')} label="Edit">
96+
<Pencil />
97+
</IconButton>
98+
<IconButton onClick={() => console.log('Create')} label="Create">
99+
<Plus />
100+
</IconButton>
101+
<IconButton onClick={() => console.log('Delete')} label="Delete">
102+
<Trash />
103+
</IconButton>
104+
<IconButton onClick={() => console.log('Publish')} label="Publish">
105+
<Play />
106+
</IconButton>
81107
</IconButtonGroup>
82108
</Flex>
83109
</Box>
@@ -89,9 +115,15 @@ export const Group = {
89115
export const Sizes = {
90116
render: () => (
91117
<Flex gap={1}>
92-
<IconButton label="Small" icon={<Pencil />} size="S" />
93-
<IconButton label="Medium" icon={<Pencil />} size="M" />
94-
<IconButton label="Large" icon={<Pencil />} size="L" />
118+
<IconButton label="Small" size="S">
119+
<Pencil />
120+
</IconButton>
121+
<IconButton label="Medium" size="M">
122+
<Pencil />
123+
</IconButton>
124+
<IconButton label="Large" size="L">
125+
<Pencil />
126+
</IconButton>
95127
</Flex>
96128
),
97129

@@ -102,7 +134,9 @@ export const Variants = {
102134
render: () => (
103135
<Flex gap={2}>
104136
{(['tertiary', 'secondary'] as const).map((variant) => (
105-
<IconButton icon={<Pencil />} variant={variant} key={variant} label={variant} />
137+
<IconButton variant={variant} key={variant} label={variant}>
138+
<Pencil />
139+
</IconButton>
106140
))}
107141
</Flex>
108142
),
@@ -120,16 +154,16 @@ export const Children = {
120154
<Typography>{currentAction}</Typography>
121155
</Box>
122156
<Flex background="neutral100" gap={1} padding={2}>
123-
<IconButton onClick={() => setCurrentAction('Edit')} aria-label="Edit">
157+
<IconButton onClick={() => setCurrentAction('Edit')} withTooltip={false} label="Edit">
124158
<Pencil />
125159
</IconButton>
126-
<IconButton onClick={() => setCurrentAction('Create')} aria-label="Create">
160+
<IconButton onClick={() => setCurrentAction('Create')} withTooltip={false} label="Create">
127161
<Plus />
128162
</IconButton>
129-
<IconButton onClick={() => setCurrentAction('Delete')} aria-label="Delete">
163+
<IconButton onClick={() => setCurrentAction('Delete')} withTooltip={false} label="Delete">
130164
<Trash />
131165
</IconButton>
132-
<IconButton onClick={() => setCurrentAction('Publish')} aria-label="Publish">
166+
<IconButton onClick={() => setCurrentAction('Publish')} withTooltip={false} label="Publish">
133167
<Play />
134168
</IconButton>
135169
</Flex>

0 commit comments

Comments
 (0)