Skip to content

Commit 33c693b

Browse files
Barsnesmimarz
andauthored
feat(Popover): Add Popover.Trigger (#1406)
Co-authored-by: Michael Marszalek <mimarz@gmail.com>
1 parent 75777db commit 33c693b

File tree

8 files changed

+503
-398
lines changed

8 files changed

+503
-398
lines changed

packages/react/src/components/HelpText/HelpText.tsx

+34-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ButtonHTMLAttributes } from 'react';
2-
import React, { useRef, useState } from 'react';
2+
import React from 'react';
33
import cl from 'clsx';
44
import type { Placement } from '@floating-ui/utils';
55

@@ -30,55 +30,54 @@ export type HelpTextProps = {
3030
ButtonHTMLAttributes<HTMLButtonElement>;
3131

3232
const HelpText = ({
33-
className,
34-
children,
3533
title,
3634
placement = 'right',
37-
onClick,
3835
size = 'medium',
3936
portal,
37+
className,
38+
children,
4039
...rest
4140
}: HelpTextProps) => {
42-
const [open, setOpen] = useState(false);
43-
const buttonRef = useRef<HTMLButtonElement>(null);
41+
const [open, setOpen] = React.useState(false);
4442

4543
return (
4644
<>
47-
<button
48-
ref={buttonRef}
49-
className={cl(classes.helpTextButton, utilClasses.focusable, className)}
50-
aria-expanded={open}
51-
onClick={(event) => {
52-
setOpen((isOpen) => !isOpen);
53-
onClick?.(event);
54-
}}
55-
{...rest}
56-
>
57-
<HelpTextIcon
58-
filled
59-
className={cl(
60-
classes.helpTextIcon,
61-
classes.helpTextIconFilled,
62-
classes[size],
63-
className,
64-
)}
65-
openState={open}
66-
/>
67-
<HelpTextIcon
68-
className={cl(classes.helpTextIcon, classes[size], className)}
69-
openState={open}
70-
/>
71-
<span className={utilClasses.visuallyHidden}>{title}</span>
72-
</button>
7345
<Popover
7446
variant='info'
75-
anchorEl={buttonRef.current}
7647
placement={placement}
77-
open={open}
7848
size={size}
79-
onClose={() => setOpen(false)}
8049
portal={portal}
50+
open={open}
51+
onClose={() => setOpen(false)}
8152
>
53+
<Popover.Trigger asChild>
54+
<button
55+
className={cl(
56+
classes.helpTextButton,
57+
utilClasses.focusable,
58+
className,
59+
)}
60+
aria-expanded={open}
61+
onClick={() => setOpen(!open)}
62+
{...rest}
63+
>
64+
<HelpTextIcon
65+
filled
66+
className={cl(
67+
classes.helpTextIcon,
68+
classes.helpTextIconFilled,
69+
classes[size],
70+
className,
71+
)}
72+
openState={open}
73+
/>
74+
<HelpTextIcon
75+
className={cl(classes.helpTextIcon, classes[size], className)}
76+
openState={open}
77+
/>
78+
<span className={utilClasses.visuallyHidden}>{title}</span>
79+
</button>
80+
</Popover.Trigger>
8281
<Popover.Content className={classes.helpTextContent}>
8382
{children}
8483
</Popover.Content>

packages/react/src/components/Popover/Popover.mdx

+19-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,32 @@ import * as PopoverStories from './Popover.stories.tsx';
99
<Primary />
1010
<Controls />
1111

12-
Elementet som åpner popoveren bør bruke `aria-expanded=true/false` for å indikere om den er åpen eller ikke.
12+
`Popover.Trigger` styrer om innholdet i `Popover` skal vises eller ikke. Du kan bruke `asChild` for å endre hvordan `Popover.Trigger` rendres.
1313

1414
## Variants
1515

1616
<Canvas of={PopoverStories.Variants} />
1717

18-
## Interactive content
18+
## Kontrollert
1919

20-
<Canvas of={PopoverStories.InteractiveContent} />
20+
Dersom du sender inn `open`, så bruker du `Popover` kontrollert. Du kan bruke `onClose` for å få beskjed når `Popover` vil lukkes.
21+
22+
<Canvas of={PopoverStories.Controlled} />
2123

2224
## In Portal
2325

2426
<Canvas of={PopoverStories.InPortal} />
27+
28+
## `anchorEl`
29+
30+
Du kan bruke `anchorEl` istedenfor `Popover.Trigger` for å styre hvor `Popover` skal vises, men da må du styre åpning og lukking av `Popover` selv.
31+
Vi anbefaler å bruke `Popover.Trigger` istedenfor `anchorEl` fordi det er bygd inn tilgjenelighetshåndtering for deg.
32+
Dette vil bli fjernet i fremtiden, og vi anbefaler å bruke `Popover.Trigger` istedenfor.
33+
34+
<Canvas of={PopoverStories.AnchorEl} />
35+
36+
## `Popover.Trigger`
37+
38+
Med `Popover.Trigger` kan du styre hvordan triggeren `Popover` skal vises. Du kan bruke `asChild` for å endre hvordan `Popover.Trigger` rendres.
39+
Dersom du skal legge på funksjoner som `onClick`, legg det på ditt element, og legg `asChild``Popover.Trigger`.
40+
Triggeren rendres som [Button](/docs/felles-button--docs) som standard.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Meta, StoryFn } from '@storybook/react';
2-
import React, { useRef, useState } from 'react';
2+
import React, { useEffect } from 'react';
33

44
import { Button, Paragraph } from '../..';
55

@@ -17,84 +17,69 @@ export default {
1717
} as Meta;
1818

1919
export const Preview: StoryFn<typeof Popover> = (args) => {
20-
const buttonRef = useRef<HTMLButtonElement | null>(null);
21-
const [open, setOpen] = useState(false);
22-
2320
return (
24-
<>
25-
<Button
26-
ref={buttonRef}
27-
onClick={() => setOpen(!open)}
28-
aria-expanded={open}
29-
>
30-
My trigger
31-
</Button>
32-
<Popover
33-
{...args}
34-
open={open || args.open}
35-
onClose={() => setOpen(false)}
36-
anchorEl={buttonRef.current}
37-
>
38-
<Popover.Content>popover content</Popover.Content>
39-
</Popover>
40-
</>
21+
<Popover {...args}>
22+
<Popover.Trigger>My trigger!</Popover.Trigger>
23+
<Popover.Content>popover content</Popover.Content>
24+
</Popover>
4125
);
4226
};
4327

4428
Preview.args = {
4529
placement: 'top',
4630
variant: 'default',
47-
open: false,
4831
size: 'medium',
32+
onOpenChange: () => {},
4933
};
5034

5135
Preview.decorators = [marginDecorator];
5236

5337
export const Variants: StoryFn<typeof Popover> = () => {
54-
const buttonRef = useRef<HTMLButtonElement | null>(null);
55-
const [open, setOpen] = useState(false);
38+
const [open, setOpen] = React.useState(false);
5639

57-
React.useEffect(() => {
40+
useEffect(() => {
5841
setOpen(true);
5942
}, []);
6043

6144
return (
6245
<>
63-
<Button
64-
ref={buttonRef}
65-
aria-expanded={open}
66-
>
67-
My trigger
68-
</Button>
6946
<Popover
70-
anchorEl={buttonRef.current}
7147
open={open}
7248
placement='top'
7349
>
50+
<Popover.Trigger asChild>
51+
<span>popover</span>
52+
</Popover.Trigger>
7453
<Popover.Content>default</Popover.Content>
7554
</Popover>
7655
<Popover
77-
anchorEl={buttonRef.current}
7856
open={open}
79-
placement='right'
57+
placement='bottom'
8058
variant='danger'
8159
>
60+
<Popover.Trigger asChild>
61+
<span>popover</span>
62+
</Popover.Trigger>
8263
<Popover.Content>danger</Popover.Content>
8364
</Popover>
8465
<Popover
85-
anchorEl={buttonRef.current}
8666
open={open}
87-
placement='bottom'
67+
placement='top'
8868
variant='info'
8969
>
70+
<Popover.Trigger asChild>
71+
<span>popover</span>
72+
</Popover.Trigger>
9073
<Popover.Content>info</Popover.Content>
9174
</Popover>
9275
<Popover
93-
anchorEl={buttonRef.current}
9476
open={open}
95-
placement='left'
77+
placement='bottom'
9678
variant='warning'
9779
>
80+
<Popover.Trigger asChild>
81+
<span>popover</span>
82+
</Popover.Trigger>
9883
<Popover.Content>warning</Popover.Content>
9984
</Popover>
10085
</>
@@ -103,25 +88,18 @@ export const Variants: StoryFn<typeof Popover> = () => {
10388

10489
Variants.decorators = [marginDecorator];
10590

106-
export const InteractiveContent: StoryFn<typeof Popover> = () => {
107-
const buttonRef = useRef<HTMLButtonElement | null>(null);
108-
const [open, setOpen] = useState(false);
91+
export const Controlled: StoryFn<typeof Popover> = () => {
92+
const [open, setOpen] = React.useState(false);
10993

11094
return (
11195
<>
112-
<Button
113-
ref={buttonRef}
114-
onClick={() => setOpen(!open)}
115-
aria-expanded={open}
116-
>
117-
My trigger
118-
</Button>
11996
<Popover
120-
anchorEl={buttonRef.current}
121-
placement='top'
12297
open={open}
12398
onClose={() => setOpen(false)}
12499
>
100+
<Popover.Trigger onClick={() => setOpen(!open)}>
101+
My trigger
102+
</Popover.Trigger>
125103
<Popover.Content>
126104
<Paragraph>Er du sikker på at du vil slette?</Paragraph>
127105
<Button
@@ -137,30 +115,38 @@ export const InteractiveContent: StoryFn<typeof Popover> = () => {
137115
);
138116
};
139117

140-
InteractiveContent.decorators = [marginDecorator];
118+
Controlled.decorators = [marginDecorator];
141119

142120
export const InPortal = () => {
143-
const buttonRef = useRef<HTMLButtonElement | null>(null);
144-
const [open, setOpen] = useState(false);
121+
return (
122+
<Popover portal>
123+
<Popover.Trigger>My trigger</Popover.Trigger>
124+
<Popover.Content>popover content</Popover.Content>
125+
</Popover>
126+
);
127+
};
128+
129+
export const AnchorEl = () => {
130+
const anchorEl = React.useRef<HTMLButtonElement>(null);
131+
const [open, setOpen] = React.useState(false);
145132

146133
return (
147134
<>
148135
<Button
149-
ref={buttonRef}
136+
ref={anchorEl}
150137
onClick={() => setOpen(!open)}
151-
aria-expanded={open}
152138
>
153139
My trigger
154140
</Button>
155141
<Popover
156-
anchorEl={buttonRef.current}
157-
placement='top'
158142
open={open}
159143
onClose={() => setOpen(false)}
160-
portal
144+
anchorEl={anchorEl.current}
161145
>
162146
<Popover.Content>popover content</Popover.Content>
163147
</Popover>
164148
</>
165149
);
166150
};
151+
152+
AnchorEl.decorators = [marginDecorator];

0 commit comments

Comments
 (0)