Skip to content

Commit 592ecd4

Browse files
committed
feat: add buttongroup and use it from menus
1 parent 972a8e5 commit 592ecd4

10 files changed

Lines changed: 253 additions & 61 deletions

File tree

src/components/Button/Button.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import * as React from 'react';
22
import {
3-
TextStyle,
43
TouchableHighlight,
54
TouchableHighlightProps,
65
View,
7-
ViewStyle,
86
} from 'react-native';
97

108
import { Theme, withTheme } from '../../theme';
@@ -13,6 +11,7 @@ import {
1311
ButtonColor,
1412
ButtonSize,
1513
} from '../../theme/component-variables/buttonVariables';
14+
import { ButtonStyles } from '../../theme/style-getters/getButtonStyles';
1615
import { Spacing } from '../Layout';
1716
import { LoadingDots } from '../Loading';
1817
import { Text } from '../Typography';
@@ -94,10 +93,7 @@ export interface ButtonProps extends TouchableHighlightProps {
9493
/**
9594
* Inline styles for components
9695
*/
97-
dangerouslySetInlineStyle?: {
98-
buttonStyle: ViewStyle;
99-
textStyle: TextStyle;
100-
};
96+
dangerouslySetInlineStyle?: Partial<ButtonStyles>;
10197
}
10298

10399
const ButtonBase = (props: ButtonProps) => {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
name: ButtonGroup
3+
menu: Components
4+
---
5+
6+
import { Playground, PropsTable } from 'docz';
7+
import Button from './Button';
8+
import ButtonGroup from './ButtonGroup';
9+
import { Box } from '../Layout';
10+
11+
## Usage
12+
13+
### Vertical button group
14+
15+
<Playground>
16+
<ButtonGroup>
17+
<Button color="default">Default</Button>
18+
<Button color="primary">Primary</Button>
19+
<Button color="secondary">Secondary</Button>
20+
<Button color="danger">Danger</Button>
21+
</ButtonGroup>
22+
</Playground>
23+
24+
### Vertical button group
25+
26+
<Playground>
27+
<ButtonGroup>
28+
<Button appearance="outline" color="default">
29+
Default
30+
</Button>
31+
<Button appearance="outline" color="primary">
32+
Primary
33+
</Button>
34+
<Button appearance="outline" color="secondary">
35+
Secondary
36+
</Button>
37+
<Button appearance="outline" color="danger">
38+
Danger
39+
</Button>
40+
</ButtonGroup>
41+
</Playground>
42+
43+
### Horizontal button group
44+
45+
<Playground>
46+
<ButtonGroup direction="horizontal">
47+
<Button color="default">Default</Button>
48+
<Button color="primary">Primary</Button>
49+
<Button color="secondary">Secondary</Button>
50+
<Button color="danger">Danger</Button>
51+
</ButtonGroup>
52+
</Playground>
53+
54+
### Horizontal button group
55+
56+
<Playground>
57+
<ButtonGroup direction="horizontal">
58+
<Button appearance="outline" color="default">
59+
Default
60+
</Button>
61+
<Button appearance="outline" color="primary">
62+
Primary
63+
</Button>
64+
<Button appearance="outline" color="secondary">
65+
Secondary
66+
</Button>
67+
<Button appearance="outline" color="danger">
68+
Danger
69+
</Button>
70+
</ButtonGroup>
71+
</Playground>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import * as React from 'react';
2+
3+
import { Theme, withTheme } from '../../theme';
4+
import { Box } from '../Layout';
5+
import { ButtonProps } from './Button';
6+
7+
export type ButtonGroupDirection = 'vertical' | 'horizontal';
8+
9+
export interface ButtonGroupProps {
10+
/**
11+
* @default vertical
12+
*/
13+
direction?: ButtonGroupDirection;
14+
children: Array<React.ReactElement<ButtonProps>>;
15+
theme: Theme;
16+
}
17+
18+
const directionToFlexDirectionMap: { [direction: string]: 'row' | 'column' } = {
19+
horizontal: 'row',
20+
vertical: 'column',
21+
};
22+
23+
const ButtonGroup: React.SFC<ButtonGroupProps> = props => {
24+
const { children, direction = 'vertical', theme } = props;
25+
26+
const childrenLength = React.Children.count(children);
27+
28+
const finalChildren = React.Children.map(children, (child, index) => {
29+
if (!React.isValidElement(child)) {
30+
return child;
31+
}
32+
33+
// @ts-ignore
34+
const button = child as React.ReactElement<ButtonProps>;
35+
const buttonSize = button.props.size || 'medium';
36+
const buttonBorderRadius =
37+
theme.themeVariables.controlBorderRadius[buttonSize];
38+
39+
return React.cloneElement(button, {
40+
dangerouslySetInlineStyle:
41+
direction === 'vertical'
42+
? {
43+
buttonStyle: {
44+
borderBottomWidth: 1,
45+
borderColor: theme.themeVariables.colors.border.default,
46+
borderRadius: 0,
47+
borderWidth: 0,
48+
elevation: 0,
49+
50+
...(index === 0 && {
51+
borderTopLeftRadius: buttonBorderRadius,
52+
borderTopRightRadius: buttonBorderRadius,
53+
}),
54+
...(childrenLength - 1 === index && {
55+
borderBottomLeftRadius: buttonBorderRadius,
56+
borderBottomRightRadius: buttonBorderRadius,
57+
borderBottomWidth: 0,
58+
}),
59+
},
60+
}
61+
: {
62+
buttonStyle: {
63+
borderColor: theme.themeVariables.colors.border.default,
64+
borderLeftWidth: 0,
65+
borderRadius: 0,
66+
elevation: 0,
67+
68+
...(index === 0 && {
69+
borderBottomLeftRadius: buttonBorderRadius,
70+
borderLeftWidth: 2,
71+
borderTopLeftRadius: buttonBorderRadius,
72+
}),
73+
...(childrenLength - 1 === index && {
74+
borderBottomRightRadius: buttonBorderRadius,
75+
borderRightWidth: 2,
76+
borderTopRightRadius: buttonBorderRadius,
77+
}),
78+
},
79+
},
80+
});
81+
});
82+
83+
return (
84+
<Box flexDirection={directionToFlexDirectionMap[direction]}>
85+
{finalChildren}
86+
</Box>
87+
);
88+
};
89+
90+
export default withTheme(ButtonGroup);

src/components/Button/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as Button, ButtonProps } from './Button';
2+
export { default as ButtonGroup, ButtonGroupProps } from './ButtonGroup';
23
export { default as BackButton } from './BackButton';

src/components/Menu/DrawerMenu.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,24 @@ import { Text } from '../Typography';
2828
onPress: toggle,
2929
children: 'Menu Option 1',
3030
color: 'danger',
31+
appearance: 'minimal',
3132
},
3233
{
3334
onPress: toggle,
3435
children: 'Menu Option 2',
3536
color: 'primary',
37+
appearance: 'minimal',
3638
},
3739
{
3840
onPress: toggle,
3941
children: 'Menu Option 3',
4042
color: 'secondary',
43+
appearance: 'minimal',
4144
},
4245
{
4346
onPress: toggle,
4447
children: 'Menu Option 4',
48+
appearance: 'minimal',
4549
},
4650
]}
4751
isVisible={on}

src/components/Menu/DrawerMenu.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import * as React from 'react';
22

33
import { Theme, withTheme } from '../../theme';
44
import { DrawerMenuStyles } from '../../theme/style-getters/getDrawerMenuStyles';
5-
import { Button, ButtonProps } from '../Button';
5+
import { Button, ButtonGroup, ButtonProps } from '../Button';
66
import { Drawer } from '../Drawer';
7-
import { Spacing } from '../Layout';
7+
import { Box, Spacing } from '../Layout';
88

99
export interface DrawerMenuProps {
1010
theme: Theme;
@@ -21,14 +21,23 @@ export interface DrawerMenuProps {
2121
}
2222

2323
const DrawerMenuBase = (props: DrawerMenuProps) => {
24-
const { options = [], isVisible, onClose } = props;
24+
const { options = [], isVisible, onClose, theme } = props;
2525

2626
return (
2727
<Drawer isVisible={isVisible} onClose={onClose}>
2828
<Spacing padding={3}>
29-
{options.map(option => (
30-
<Button key={option.children} {...option} />
31-
))}
29+
<Box
30+
elevation={1}
31+
borderRadius={theme.themeVariables.controlBorderRadius.medium}
32+
borderWidth={1}
33+
borderColor={theme.themeVariables.colors.border.default}
34+
>
35+
<ButtonGroup>
36+
{options.map(option => (
37+
<Button key={option.children} {...option} />
38+
))}
39+
</ButtonGroup>
40+
</Box>
3241
<Spacing paddingTop={3}>
3342
<Button onPress={onClose}>Close</Button>
3443
</Spacing>

src/components/Menu/DropdownMenu.mdx

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,54 @@ import { Toggle } from 'react-powerplug';
88

99
import DropdownMenu from './DropdownMenu';
1010
import { Button } from '../Button';
11-
import { Box, Spacing } from '../Layout';
11+
import { Box } from '../Layout';
1212
import { Text } from '../Typography';
1313

1414
## Usage
1515

1616
### Dropdown Menu
1717

1818
<Playground>
19-
<Toggle>
20-
{({ on, toggle }) => (
21-
<>
22-
<DropdownMenu
23-
options={[
24-
{
25-
onPress: toggle,
26-
children: 'Menu Option 1',
27-
color: 'danger',
28-
},
29-
{
30-
onPress: toggle,
31-
children: 'Menu Option 2',
32-
color: 'primary',
33-
},
34-
{
35-
onPress: toggle,
36-
children: 'Menu Option 3',
37-
color: 'secondary',
38-
},
39-
{
40-
onPress: toggle,
41-
children: 'Menu Option 4',
42-
},
43-
]}
44-
isVisible={on}
45-
onClose={toggle}
46-
>
47-
<Button onPress={toggle}>Open dropdown menu</Button>
48-
</DropdownMenu>
49-
</>
50-
)}
51-
</Toggle>
19+
<Box>
20+
<Toggle>
21+
{({ on, toggle }) => (
22+
<>
23+
<DropdownMenu
24+
options={[
25+
{
26+
onPress: toggle,
27+
children: 'Menu Option 1',
28+
color: 'danger',
29+
appearance: 'minimal',
30+
},
31+
{
32+
onPress: toggle,
33+
children: 'Menu Option 2',
34+
color: 'primary',
35+
appearance: 'minimal',
36+
},
37+
{
38+
onPress: toggle,
39+
children: 'Menu Option 3',
40+
color: 'secondary',
41+
appearance: 'minimal',
42+
},
43+
{
44+
onPress: toggle,
45+
children: 'Menu Option 4',
46+
appearance: 'minimal',
47+
},
48+
]}
49+
isVisible={on}
50+
onClose={toggle}
51+
>
52+
<Button isInline onPress={toggle}>
53+
Open dropdown menu
54+
</Button>
55+
</DropdownMenu>
56+
</>
57+
)}
58+
</Toggle>
59+
</Box>
60+
5261
</Playground>

0 commit comments

Comments
 (0)