Skip to content

Commit

Permalink
Create ButtonGroup component
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepinho committed Jul 16, 2024
1 parent fb36e86 commit f62fa14
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 2 deletions.
2 changes: 1 addition & 1 deletion packages/ui/src/Button/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DefaultTheme } from 'styled-components';
import { Variant, ActionType } from './types';
import { Variant, ActionType } from '../utils/button';

export const getBackgroundColor = (
actionType: ActionType,
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MouseEventHandler } from 'react';
import styled, { css, DefaultTheme } from 'styled-components';
import { asTransientProps } from '../utils/asTransientProps';
import { Size, Variant, ActionType } from './types';
import { Size, Variant, ActionType } from '../utils/button';
import { getBackgroundColor } from './helpers';
import { button } from '../utils/typography';
import { LucideIcon } from 'lucide-react';
Expand Down
36 changes: 36 additions & 0 deletions packages/ui/src/ButtonGroup/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Meta, StoryObj } from '@storybook/react';

import { ButtonGroup } from '.';
import { Ban, HandCoins, Send } from 'lucide-react';

const meta: Meta<typeof ButtonGroup> = {
component: ButtonGroup,
tags: ['autodocs', '!dev'],
argTypes: {
buttons: { control: false },
},
};
export default meta;

type Story = StoryObj<typeof ButtonGroup>;

export const Basic: Story = {
args: {
actionType: 'default',
size: 'sparse',
buttons: [
{
label: 'Delegate',
icon: Send,
},
{
label: 'Undelegate',
icon: HandCoins,
},
{
label: 'Cancel',
icon: Ban,
},
],
},
};
76 changes: 76 additions & 0 deletions packages/ui/src/ButtonGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { LucideIcon } from 'lucide-react';
import { MouseEventHandler } from 'react';
import { ActionType, Size } from '../utils/button';
import { Button } from '../Button';
import styled from 'styled-components';
import { media } from '../utils/media';

const Root = styled.div<{ $size: Size }>`
display: flex;
flex-direction: ${props => (props.$size === 'sparse' ? 'column' : 'row')};
gap: ${props => props.theme.spacing(2)};
${props => media.tablet`
flex-direction: row;
gap: ${props.theme.spacing(props.$size === 'sparse' ? 4 : 2)};
`}
`;

const ButtonWrapper = styled.div<{ $size: Size }>`
flex-grow: ${props => (props.$size === 'sparse' ? 1 : 0)};
flex-shrink: ${props => (props.$size === 'sparse' ? 1 : 0)};
`;

interface ButtonDescription {
label: string;
icon?: LucideIcon;
onClick?: MouseEventHandler<HTMLButtonElement>;
}

export interface ButtonGroupProps {
/**
* An array of objects, each describing a button to render. The first will be
* rendered with the `primary` variant, the rest with the `secondary` variant.
*
* Minimum length: 1. Maximum length: 3.
*/
buttons:
| [ButtonDescription]
| [ButtonDescription, ButtonDescription]
| [ButtonDescription, ButtonDescription, ButtonDescription];
/**
* The action type of the button group. Will be used for all buttons in the
* group.
*/
actionType?: ActionType;
/** Will be used for all buttons in the group. */
size?: Size;
}

/**
* Use a `<ButtonGroup />` to render multiple buttons in a group with the same
* `actionType` and `size`.
*
* When rendering multiple Penumbra UI buttons together, always use a `<ButtonGroup />` rather than individual `<Button />`s. This ensures that they always meet Penumbra UI guidelines. (For example, all buttons in a group should have the same `actionType`; and the first button in a group should be the `primary` variant, while subsequent buttons are the `secondary` variant.)
*/
export const ButtonGroup = ({
buttons,
actionType = 'default',
size = 'sparse',
}: ButtonGroupProps) => (
<Root $size={size}>
{buttons.map((action, index) => (
<ButtonWrapper key={index} $size={size}>
<Button
icon={action.icon}
actionType={actionType}
onClick={action.onClick}
variant={index === 0 ? 'primary' : 'secondary'}
size={size}
>
{action.label}
</Button>
</ButtonWrapper>
))}
</Root>
);
File renamed without changes.

0 comments on commit f62fa14

Please sign in to comment.