Skip to content

Commit

Permalink
feat: Button and IconButton (#359)
Browse files Browse the repository at this point in the history
  • Loading branch information
jordmccord committed Jul 4, 2024
1 parent 636cb9d commit 3b320c2
Show file tree
Hide file tree
Showing 61 changed files with 7,212 additions and 5,218 deletions.
6 changes: 6 additions & 0 deletions .changeset/brown-rules-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@utilitywarehouse/native-ui': minor
---

feat: add `Button` component
feat: add `IconButton` component
2 changes: 1 addition & 1 deletion apps/native-ui-storybook/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const path = require('path');
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
[
'module-resolver',
Expand All @@ -24,5 +23,6 @@ module.exports = function (api) {
'@babel/plugin-proposal-export-namespace-from',
'react-native-reanimated/plugin',
],
presets: ['babel-preset-expo'],
};
};
210 changes: 210 additions & 0 deletions apps/native-ui-storybook/components/Button/Button.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { Meta, Canvas, Story, Primary, Controls } from '@storybook/blocks';
import * as ButtonStories from './Button.stories';
import {
ButtonGroup,
Button,
ButtonIcon,
ButtonSpinner,
ButtonText,
Alert,
Box,
Center,
NativeUIProvider,
} from '@utilitywarehouse/native-ui';
import {
AddSmallIcon,
ChevronLeft01SmallIcon,
ChevronRight01SmallIcon,
} from '@utilitywarehouse/react-native-icons';
import ViewFigmaButton from '../../docs/components/ViewFigmaButton';

<Meta of={ButtonStories} />

<ViewFigmaButton url="https://www.figma.com/design/3RY3OvLA88yZksRjOfjQJm/UW-App-UI?node-id=15-3" />

# Button

The `Button` component is used to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation.

<NativeUIProvider>
<Box mb="$5">
<Alert
title="Note:"
text="This component is not yet available in Figma as of 04/07/24 so may vary slightly from some designs. For any questions related to this please reach out on the DS Slack channel: #help-design-systems"
link="Open Slack channel"
onPressLink={() => window.open('https://utilitywarehouse.slack.com/archives/C04MKBQ34PJ')}
/>
</Box>
</NativeUIProvider>

## Playground

<Primary />

<Controls />

## Usage

> This component should be wrapped in a `NativeUIProvider` component to ensure that the correct theme is applied.
<Canvas>
<NativeUIProvider>
<Center>
<Button colorScheme="green">
<ButtonText>Button</ButtonText>
</Button>
</Center>
</NativeUIProvider>
</Canvas>

```tsx
import { Button, ButtonText } from '@utilitywarehouse/native-ui';

const MyComponent = () => {
const handlePress = () => {
console.log('Button pressed');
};
return (
<Button onPress={handlePress} colorScheme="green">
<ButtonText>Button</ButtonText>
</Button>
);
};
```

## Props

| Property | Type | Description | Default |
| ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------- | -------- |
| `onPress` | `() => void` | Callback function to be called when the button is pressed. | - |
| `variant` | `'solid' \| 'outline' \| 'ghost'` | The variant of the button. | 'solid' |
| `size` | `'small' \| 'medium' \| 'large'` | The size of the button. | 'medium' |
| `colorScheme` | `'cyan' \| 'greeb' \| 'red' \| 'grey' \| 'gold'` | The colour scheme of the button. | 'cyan' |
| `inverted` | `boolean` | Changes the button to an inverted state. (To only be used on `midnight` or `purple` backgrounds). | `false` |
| `isDisabled` | `boolean` | Disables the button. | `false` |
| `isPressed` | `boolean` | Changes the button to a pressed state. | `false` |

### Descendants Styling Props

Props to style the child components.

| Sx Prop | Description |
| ---------- | ------------------------------------- |
| `_text` | Prop to style ButtonText Component |
| `_icon` | Prop to style ButtonIcon Component |
| `_spinner` | Prop to style ButtonSpinner Component |

### Components

- [ButtonGroup](#buttongroup)
- [ButtonIcon](#buttonicon)
- [ButtonSpinner](#buttonspinner)

### `ButtonGroup`

The `ButtonGroup` component is used to group multiple buttons together.

<Canvas>
<NativeUIProvider>
<Center>
<ButtonGroup flexDirection="column">
<Button colorScheme="cyan">
<ButtonText>Button 1</ButtonText>
</Button>
<Button colorScheme="grey" variant="outline">
<ButtonText>Button 2</ButtonText>
</Button>
<Button colorScheme="red" variant="ghost">
<ButtonText>Button 3</ButtonText>
</Button>
</ButtonGroup>
</Center>
</NativeUIProvider>
</Canvas>

```tsx
import { ButtonGroup, Button, ButtonText } from '@utilitywarehouse/native-ui';

const MyComponent = () => {
return (
<ButtonGroup flexDirection="column">
<Button colorScheme="cyan">
<ButtonText>Button 1</ButtonText>
</Button>
<Button colorScheme="grey" variant="outline">
<ButtonText>Button 2</ButtonText>
</Button>
<Button colorScheme="red" variant="ghost">
<ButtonText>Button 3</ButtonText>
</Button>
</ButtonGroup>
);
};
```

#### Props

| Property | Type | Description | Default |
| --------------- | -------------------------------------------------------- | -------------------------------------------------------------- | ------- |
| `flexDirection` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | Set the direction of Button group to vertical or horizontal | 'row' |
| `isDisabled` | `boolean` | When true, this will disable all the buttons in a ButtonGroup. | `false` |
| `isAttached` | `boolean` | When attached, all buttons will be attached to each other. | `false` |
| `reversed` | `boolean` | To reverse the order of components. | `false` |
| `space` | `string` | It sets the space between different buttons. | 'md' |

### `ButtonIcon`

The `ButtonIcon` component is used to add an icon to the button.

<Canvas>
<NativeUIProvider>
<Center>
<Button colorScheme="cyan">
<ButtonIcon as={AddSmallIcon} />
<ButtonText>Button</ButtonText>
</Button>
</Center>
</NativeUIProvider>
</Canvas>

```tsx
import { Button, ButtonIcon, ButtonText } from '@utilitywarehouse/native-ui';
import { AddSmallIcon } from '@utilitywarehouse/react-native-icons';

const MyComponent = () => {
return (
<Button colorScheme="cyan">
<ButtonIcon as={AddSmallIcon} />
<ButtonText>Button</ButtonText>
</Button>
);
};
```

### `ButtonSpinner`

The `ButtonSpinner` component is used to add a spinner to the button and show loading state.

<Canvas>
<NativeUIProvider>
<Center>
<Button colorScheme="cyan">
<ButtonSpinner />
<ButtonText>Button</ButtonText>
</Button>
</Center>
</NativeUIProvider>
</Canvas>

```tsx
import { Button, ButtonSpinner, ButtonText } from '@utilitywarehouse/native-ui';

const MyComponent = () => {
return (
<Button colorScheme="cyan">
<ButtonSpinner />
<ButtonText>Button</ButtonText>
</Button>
);
};
```
13 changes: 13 additions & 0 deletions apps/native-ui-storybook/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Meta } from '@storybook/react';
import Button from './Button';
import PlaygroundVariants from './PlaygroundVariants';
import Variants from './Variants';

const ButtonMeta: Meta<typeof Button> = {
title: 'Native UI / Components / Button',
component: Button,
};

export default ButtonMeta;

export { Button as Playground, PlaygroundVariants, Variants };
122 changes: 122 additions & 0 deletions apps/native-ui-storybook/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Box, Button, ButtonIcon, ButtonSpinner, ButtonText } from '@utilitywarehouse/native-ui';
import React from 'react';
import { AddSmallIcon } from '@utilitywarehouse/react-native-icons';
import { StoryFn } from '@storybook/react';
import ScrollWrap from '../../docs/components/ScrollWrap';

const ButtonBasic: StoryFn = ({
size,
variant,
colorScheme,
isDisabled,
inverted,
_ButtonText,
_showIcon,
_showLoading,
_loadingPosition,
_iconPosition,
_backgroundColor,
}: any) => {
return (
<Box height={68} width="100%">
<ScrollWrap backgroundColor={_backgroundColor}>
<Button
size={size}
variant={variant}
colorScheme={colorScheme}
isDisabled={isDisabled}
inverted={inverted}
>
{_showIcon && _iconPosition === 'left' && <ButtonIcon as={AddSmallIcon} />}
{_showLoading && _loadingPosition === 'left' && <ButtonSpinner />}
<ButtonText>{_ButtonText}</ButtonText>
{_showLoading && _loadingPosition === 'right' && <ButtonSpinner />}
{_showIcon && _iconPosition === 'right' && <ButtonIcon as={AddSmallIcon} />}
</Button>
</ScrollWrap>
</Box>
);
};

ButtonBasic.argTypes = {
size: {
options: ['small', 'medium', 'large'],
control: 'select',
description: 'The size of the button.',
},
variant: {
options: ['solid', 'outline', 'ghost'],
control: 'select',
description: 'The variant of the button.',
},
colorScheme: {
options: ['cyan', 'red', 'green', 'grey', 'gold'],
control: 'select',
description: 'The color scheme of the button.',
},
inverted: {
type: 'boolean',
control: 'boolean',
description:
'To set the button to be inverted. (To only be used on `midnight` or `purple` backgrounds)',
},
isDisabled: {
type: 'boolean',
control: 'boolean',
description: 'To manually set disable to the button.',
},
_ButtonText: {
type: 'string',
control: 'text',
description:
'The text component for the button.\n _Note: this is not a prop of the `Button` component, just a representation of the `ButtonText` component for the Storybook playground._',
},
_showIcon: {
type: 'boolean',
control: 'boolean',
description:
'To show or hide the icon component for the button.\n _Note: this is not a prop of the `Button` component, just a representation of the `ButtonIcon` component for the Storybook playground._',
},
_iconPosition: {
options: ['left', 'right'],
control: 'select',
description:
'The position of the icon component in the button.\n _Note: this is not a prop of the `Button` component, just a representation of the `ButtonIcon` component for the Storybook playground._',
},
_showLoading: {
type: 'boolean',
control: 'boolean',
description:
'To show or hide the loading spinner component for the button.\n _Note: this is not a prop of the `Button` component, just a representation of the `ButtonSpinner` component for the Storybook playground._',
},
_loadingPosition: {
options: ['left', 'right'],
control: 'select',
description:
'The position of the loading spinner component in the button.\n _Note: this is not a prop of the `Button` component, just a representation of the `ButtonSpinner` component for the Storybook playground._',
},
_backgroundColor: {
options: ['default', 'midnight', 'purple'],
control: 'select',
description:
'The background color the button appears on.\n _Note: this is not a prop of the `Button` component, just a representation of the `Button` component for the Storybook playground._',
},
};

ButtonBasic.args = {
size: 'medium',
variant: 'solid',
colorScheme: 'cyan',
isDisabled: false,
inverted: false,
_ButtonText: 'Example',
_showIcon: true,
_iconPosition: 'left',
_showLoading: false,
_loadingPosition: 'left',
_backgroundColor: 'default',
};

export default ButtonBasic;

export { ButtonText, Button };
Loading

0 comments on commit 3b320c2

Please sign in to comment.