Skip to content

Commit 7750c93

Browse files
committed
Reapply "buttonbar: support dropdowns (#91886)"
This reverts commit 450d59c.
1 parent deec424 commit 7750c93

File tree

3 files changed

+105
-69
lines changed

3 files changed

+105
-69
lines changed

static/app/components/actions/resolve.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ function ResolveActions({
269269
itemsHidden={shouldDisplayCta}
270270
items={items}
271271
trigger={(triggerProps, isOpen) => (
272-
<DropdownTrigger
272+
<Button
273273
{...triggerProps}
274274
size={size}
275275
priority={priority}
@@ -382,12 +382,6 @@ const ResolveButton = withChonk(
382382
`
383383
);
384384

385-
const DropdownTrigger = styled(Button)`
386-
box-shadow: none;
387-
border-radius: 0 ${p => p.theme.borderRadius} ${p => p.theme.borderRadius} 0;
388-
border-left: none;
389-
`;
390-
391385
/**
392386
* Used to hide the list items when prompting to set up releases
393387
*/

static/app/components/core/button/buttonBar.stories.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import {Fragment, useState} from 'react';
22

33
import {Button, type ButtonProps} from 'sentry/components/core/button';
44
import {ButtonBar} from 'sentry/components/core/button/buttonBar';
5+
import {DropdownMenu} from 'sentry/components/dropdownMenu';
56
import JSXNode from 'sentry/components/stories/jsxNode';
7+
import {IconChevron} from 'sentry/icons';
68
import storyBook from 'sentry/stories/storyBook';
79

810
// eslint-disable-next-line import/no-webpack-loader-syntax
@@ -83,6 +85,43 @@ export default storyBook('ButtonBar', (story, APIReference) => {
8385
<ButtonBar>
8486
<Button>One Lonely Button</Button>
8587
</ButtonBar>
88+
89+
<p>
90+
You can also use a <JSXNode name="DropdownMenu" /> inside a{' '}
91+
<JSXNode name="ButtonBar" /> to create a button with secondary actions.
92+
</p>
93+
<ButtonBar merged>
94+
<Button>One</Button>
95+
<Button>One</Button>
96+
<Button>One</Button>
97+
<DropdownMenu
98+
items={[
99+
{
100+
key: 'click-me',
101+
label: 'Click me',
102+
// eslint-disable-next-line no-alert
103+
onAction: () => alert('clicked'),
104+
},
105+
]}
106+
trigger={(triggerProps, isOpen) => (
107+
<Button
108+
{...triggerProps}
109+
aria-label="options"
110+
icon={<IconChevron direction={isOpen ? 'up' : 'down'} size="xs" />}
111+
/>
112+
)}
113+
/>
114+
<Button>One</Button>
115+
<Button>One</Button>
116+
<Button>One</Button>
117+
<Button>One</Button>
118+
<Button>One</Button>
119+
<Button>One</Button>
120+
<Button>One</Button>
121+
<Button>One</Button>
122+
<Button>One</Button>
123+
<Button>One</Button>
124+
</ButtonBar>
86125
</Fragment>
87126
);
88127
});
Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react';
12
import {css} from '@emotion/react';
23
import styled from '@emotion/styled';
34

@@ -13,85 +14,87 @@ interface ButtonBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'cla
1314

1415
export function ButtonBar({children, merged = false, gap = 0, ...props}: ButtonBarProps) {
1516
return (
16-
<StyledButtonBar merged={merged} gap={gap} {...props}>
17+
<StyledButtonBar
18+
merged={merged}
19+
gap={gap}
20+
{...props}
21+
listSize={React.Children.count(children)}
22+
>
1723
{children}
1824
</StyledButtonBar>
1925
);
2026
}
2127

22-
const StyledButtonBar = styled('div')<{gap: ValidSize | 0; merged: boolean}>`
28+
const getChildTransforms = (count: number) => {
29+
return Array.from(
30+
{length: count},
31+
(_, index) => css`
32+
> *:nth-child(${index + 1}),
33+
> *:nth-child(${index + 1}) > button {
34+
transform: translateX(-${index}px);
35+
}
36+
`
37+
);
38+
};
39+
40+
const StyledButtonBar = styled('div')<{
41+
gap: ValidSize | 0;
42+
listSize: number;
43+
merged: boolean;
44+
}>`
2345
display: grid;
2446
grid-auto-flow: column;
2547
grid-column-gap: ${p => (p.gap === 0 ? '0' : space(p.gap))};
2648
align-items: center;
2749
28-
${p => p.merged && MergedButtonBarStyles}
29-
`;
30-
31-
const MergedButtonBarStyles = () => css`
32-
/* Raised buttons show borders on both sides. Useful to create pill bars */
33-
& > .active {
34-
z-index: 2;
35-
}
36-
37-
& > .dropdown,
38-
& > button,
39-
& > input,
40-
& > a {
41-
position: relative;
50+
${p => getChildTransforms(p.listSize)}
4251
43-
/* First button is square on the right side */
44-
&:first-child:not(:last-child) {
45-
border-top-right-radius: 0;
46-
border-bottom-right-radius: 0;
47-
48-
& > .dropdown-actor > ${StyledButton} {
49-
border-top-right-radius: 0;
50-
border-bottom-right-radius: 0;
52+
${p =>
53+
p.merged &&
54+
css`
55+
/* Raised buttons show borders on both sides. Useful to create pill bars */
56+
& > .active,
57+
& > *:focus-within,
58+
& > *:focus-within > * {
59+
z-index: 2;
5160
}
52-
}
5361
54-
/* Middle buttons are square */
55-
&:not(:last-child):not(:first-child) {
56-
border-radius: 0;
62+
& > * {
63+
position: relative;
5764
58-
& > .dropdown-actor > ${StyledButton} {
59-
border-radius: 0;
60-
}
61-
}
65+
/* First button is square on the right side */
66+
&:first-child:not(:last-child),
67+
&:first-child:not(:last-child) > button {
68+
border-top-right-radius: 0;
69+
border-bottom-right-radius: 0;
6270
63-
/* Middle buttons only need one border so we don't get a double line */
64-
&:first-child {
65-
& + .dropdown:not(:last-child),
66-
& + a:not(:last-child),
67-
& + input:not(:last-child),
68-
& + button:not(:last-child) {
69-
margin-left: -1px;
70-
}
71-
}
71+
& > .dropdown-actor > ${StyledButton} {
72+
border-top-right-radius: 0;
73+
border-bottom-right-radius: 0;
74+
}
75+
}
7276
73-
/* Middle buttons only need one border so we don't get a double line */
74-
/* stylelint-disable-next-line no-duplicate-selectors */
75-
&:not(:last-child):not(:first-child) {
76-
& + .dropdown,
77-
& + button,
78-
& + input,
79-
& + a {
80-
margin-left: -1px;
81-
}
82-
}
77+
/* Middle buttons are square */
78+
&:not(:last-child):not(:first-child),
79+
&:not(:last-child):not(:first-child) > button {
80+
border-radius: 0;
81+
82+
& > .dropdown-actor > ${StyledButton} {
83+
border-radius: 0;
84+
}
85+
}
8386
84-
/* Last button is square on the left side */
85-
&:last-child:not(:first-child) {
86-
border-top-left-radius: 0;
87-
border-bottom-left-radius: 0;
88-
margin-left: -1px;
87+
/* Last button is square on the left side */
88+
&:last-child:not(:first-child) {
89+
border-top-left-radius: 0;
90+
border-bottom-left-radius: 0;
8991
90-
& > .dropdown-actor > ${StyledButton} {
91-
border-top-left-radius: 0;
92-
border-bottom-left-radius: 0;
93-
margin-left: -1px;
92+
& > button,
93+
& > .dropdown-actor > ${StyledButton} {
94+
border-top-left-radius: 0;
95+
border-bottom-left-radius: 0;
96+
}
97+
}
9498
}
95-
}
96-
}
99+
`}
97100
`;

0 commit comments

Comments
 (0)