Skip to content

Commit 158ffaa

Browse files
committed
fix: dropdown button state handling
1 parent 70399b1 commit 158ffaa

File tree

4 files changed

+91
-93
lines changed

4 files changed

+91
-93
lines changed

package-lock.json

Lines changed: 5 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/components/base/src/dropdown/DropdownButton.tsx

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ import { Dropdown, type DropdownProps } from "./Dropdown";
33

44
export interface DropdownButtonRenderProps {
55
ref: React.RefObject<HTMLButtonElement>;
6-
open: boolean;
7-
onOpen: () => void;
8-
onClose: () => void;
6+
isOpen: boolean;
7+
open: () => void;
8+
close: () => void;
99
}
1010

1111
export interface DropdownButtonProps extends Omit<DropdownProps, "anchorRef"> {
12-
readonly renderButton: (props: DropdownButtonRenderProps) => React.ReactNode;
12+
renderButton: (props: DropdownButtonRenderProps) => React.ReactNode;
13+
onOpenChange?: (open: boolean) => void;
1314
}
1415

15-
export const DropdownButton: React.FC<DropdownButtonProps> = ({
16+
export const DropdownButton: React.FC<Readonly<DropdownButtonProps>> = ({
1617
renderButton,
1718
open = false,
1819
onClose,
20+
onOpenChange,
1921
children,
2022
...props
2123
}) => {
@@ -27,19 +29,25 @@ export const DropdownButton: React.FC<DropdownButtonProps> = ({
2729
onClose?.();
2830
}, [onClose]);
2931

32+
const internalOnOpen = useCallback(() => {
33+
setInternalOpen(true);
34+
}, []);
35+
3036
const button = useMemo(
3137
() =>
3238
renderButton({
3339
ref: buttonRef,
34-
open: internalOpen,
35-
onOpen: () => {
36-
setInternalOpen(true);
37-
},
38-
onClose: internalOnClose,
40+
isOpen: internalOpen,
41+
open: internalOnOpen,
42+
close: internalOnClose,
3943
}),
40-
[renderButton, internalOpen, internalOnClose],
44+
[renderButton, internalOpen, internalOnOpen, internalOnClose],
4145
);
4246

47+
useEffect(() => {
48+
onOpenChange?.(internalOpen);
49+
}, [internalOpen, onOpenChange]);
50+
4351
useEffect(() => {
4452
setInternalOpen(open);
4553
}, [open]);

packages/docs/stories/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"@react-ck/layers": "^1.4.1",
2727
"@react-ck/manager": "^1.3.12",
2828
"@react-ck/misc-utils": "^1.0.2",
29-
"@react-ck/base-components": "^5.0.3",
29+
"@react-ck/base-components": "^6.0.1",
3030
"@react-ck/react-hooks": "^1.0.9",
3131
"@react-ck/react-utils": "^1.4.0",
3232
"@react-ck/scss-utils": "^1.1.13",

packages/docs/stories/src/generic-dropdown.stories.tsx

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from "react";
1+
import React, { useState } from "react";
22
import { type Meta, type StoryObj } from "@storybook/react";
33
import { Manager } from "@react-ck/manager";
44
import { configureStory } from "@react-ck/story-config";
@@ -10,20 +10,26 @@ type Story = StoryObj<typeof Dropdown>;
1010

1111
const meta: Meta<typeof Dropdown> = {
1212
title: "Generic/Dropdown",
13-
...configureStory(Dropdown, {
14-
parameters: {
15-
source: {
16-
type: "code",
13+
...configureStory(
14+
Dropdown,
15+
{
16+
parameters: {
17+
source: {
18+
type: "code",
19+
},
1720
},
21+
decorators: [
22+
(Story): React.ReactElement => (
23+
<Manager usePortal={false}>
24+
<Story />
25+
</Manager>
26+
),
27+
],
1828
},
19-
decorators: [
20-
(Story): React.ReactElement => (
21-
<Manager usePortal={false}>
22-
<Story />
23-
</Manager>
24-
),
25-
],
26-
}),
29+
{
30+
subComponents: [DropdownButton],
31+
},
32+
),
2733
};
2834

2935
export default meta;
@@ -36,8 +42,8 @@ export const Component: Story = {
3642
<Flex>
3743
<DropdownButton
3844
open={props.open}
39-
renderButton={({ ref, onOpen }) => (
40-
<Button rootRef={ref} onClick={onOpen}>
45+
renderButton={({ ref, open }) => (
46+
<Button rootRef={ref} onClick={open}>
4147
Dropdown 1
4248
</Button>
4349
)}>
@@ -53,8 +59,8 @@ export const Component: Story = {
5359
</DropdownButton>
5460

5561
<DropdownButton
56-
renderButton={({ ref, onOpen }) => (
57-
<Button rootRef={ref} onClick={onOpen}>
62+
renderButton={({ ref, open }) => (
63+
<Button rootRef={ref} onClick={open}>
5864
Button 2
5965
</Button>
6066
)}>
@@ -72,12 +78,51 @@ export const Component: Story = {
7278
),
7379
};
7480

81+
export const ExternalState: Story = {
82+
args: {
83+
open: false,
84+
},
85+
render: ({ ...props }): React.ReactElement => {
86+
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is a story
87+
const [open, setOpen] = useState(props.open);
88+
89+
return (
90+
<DropdownButton
91+
open={open}
92+
renderButton={({ ref, open }) => (
93+
<Button rootRef={ref} onClick={open}>
94+
Dropdown 1
95+
</Button>
96+
)}
97+
onOpenChange={setOpen}>
98+
Content Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione nulla est, quidem
99+
enim a molestias accusantium quo officia provident maxime voluptatem, beatae delectus
100+
aliquid ipsa perferendis accusamus! Eius, laborum quisquam. Eius soluta deserunt aspernatur
101+
tenetur, laudantium quod corrupti natus facilis est ab esse sunt dolore magni cum accusamus
102+
nemo. Optio adipisci itaque exercitationem quo nulla, odit eligendi natus est cupiditate
103+
aperiam nemo, vero explicabo. Non eveniet ipsum, dolores suscipit sit deserunt doloribus.
104+
Dolorum aspernatur iusto, aliquid officiis illo modi vitae. Exercitationem laudantium
105+
inventore nemo harum commodi doloribus totam porro aliquam. Quae aliquam iusto neque ipsam
106+
non? Consequuntur saepe inventore aliquam!
107+
<Button
108+
skin="negative"
109+
skinVariation="ghost"
110+
onClick={() => {
111+
setOpen(false);
112+
}}>
113+
close
114+
</Button>
115+
</DropdownButton>
116+
);
117+
},
118+
};
119+
75120
export const IconButton: Story = {
76121
render: ({ ...props }): React.ReactElement => (
77122
<Flex>
78123
<DropdownButton
79124
open={props.open}
80-
renderButton={({ ref, onOpen }) => (
125+
renderButton={({ ref, open }) => (
81126
<Button
82127
rootRef={ref}
83128
skin="secondary"
@@ -87,7 +132,7 @@ export const IconButton: Story = {
87132
<IconVerticalDots />
88133
</Icon>
89134
}
90-
onClick={onOpen}
135+
onClick={open}
91136
/>
92137
)}>
93138
Content Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione nulla est, quidem
@@ -102,7 +147,7 @@ export const IconButton: Story = {
102147
</DropdownButton>
103148
<DropdownButton
104149
open={props.open}
105-
renderButton={({ ref, onOpen }) => (
150+
renderButton={({ ref, open }) => (
106151
<Button
107152
rootRef={ref}
108153
skin="secondary"
@@ -112,7 +157,7 @@ export const IconButton: Story = {
112157
<IconVerticalDots />
113158
</Icon>
114159
}
115-
onClick={onOpen}
160+
onClick={open}
116161
/>
117162
)}>
118163
Content Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione nulla est, quidem

0 commit comments

Comments
 (0)