Skip to content

Commit

Permalink
feat: Add Actionsheet lab component (#396)
Browse files Browse the repository at this point in the history
  • Loading branch information
jordmccord committed Jul 4, 2024
1 parent 31a1227 commit 4b830eb
Show file tree
Hide file tree
Showing 23 changed files with 552 additions and 145 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-knives-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@utilitywarehouse/native-ui': minor
---

Adds `Actionsheet` to lab components
8 changes: 8 additions & 0 deletions apps/native-ui-storybook/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ module.exports = function (api) {
{
alias: {
'@utilitywarehouse/native-ui': path.join(__dirname, '../../packages/native-ui/src'),
'@utilitywarehouse/native-ui/lab': path.join(
__dirname,
'../../packages/native-ui/src/lab'
),
'@utilitywarehouse/native-ui/unstyled': path.join(
__dirname,
'../../packages/native-ui/src/components/unstyled'
),
},
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import { Meta, Canvas, Story } from '@storybook/blocks';
import * as Stories from './Actionsheet.stories';
import { Center, Text, NativeUIProvider, Alert, Box } from '@utilitywarehouse/native-ui';
import {
Actionsheet,
ActionsheetBackdrop,
ActionsheetContent,
ActionsheetDragIndicator,
ActionsheetDragIndicatorWrapper,
ActionsheetItem,
ActionsheetItemText,
} from '@utilitywarehouse/native-ui/lab';

<Meta of={Stories} />

# Actionsheet

<NativeUIProvider>
<Box mt="$6">
<Alert
colorScheme="warning"
text="These components may potentially change their API and/or design and will be replaced in minor release versions, eventually being integrated into the main library code. Use at your own discretion."
mb="$4"
/>
</Box>
</NativeUIProvider>

The Actionsheet component presents a set of options to the user, overlaid on top of the app's content, allowing them to take quick actions without leaving the current page or view.

## Usage

> This component should be wrapped in a `NativeUIProvider` component to ensure that the correct theme is applied.
**Warning**: Showing the actionsheet in examples disables the ability to interact with the rest of the page. To interact with the rest of the page, close the actionsheet.

<Canvas of={Stories.Basic} />

```tsx
import { Actionsheet } from '@utilitywarehouse/native-ui/lab';

const MyComponent = () => {
const [showActionsheet, setShowActionsheet] = React.useState(false);
const handleClose = () => setShowActionsheet(!showActionsheet);
return (
<Box>
<Button onPress={handleClose}>
<ButtonText>Open</ButtonText>
</Button>
<Actionsheet isOpen={showActionsheet} onClose={handleClose} zIndex={999}>
<ActionsheetBackdrop />
<ActionsheetContent h="$64" zIndex={999}>
<ActionsheetDragIndicatorWrapper>
<ActionsheetDragIndicator />
</ActionsheetDragIndicatorWrapper>
<ActionsheetItem onPress={handleAction}>
<ActionsheetItemText>Delete</ActionsheetItemText>
</ActionsheetItem>
<ActionsheetItem onPress={handleAction}>
<ActionsheetItemText>Share</ActionsheetItemText>
</ActionsheetItem>
<ActionsheetItem onPress={handleAction}>
<ActionsheetItemText>Play</ActionsheetItemText>
</ActionsheetItem>
<ActionsheetItem onPress={handleAction}>
<ActionsheetItemText>Favourite</ActionsheetItemText>
</ActionsheetItem>
<ActionsheetItem onPress={handleAction}>
<ActionsheetItemText>Cancel</ActionsheetItemText>
</ActionsheetItem>
</ActionsheetContent>
</Actionsheet>
);
};
```

## Props

### Actionsheet

It inherits all the properties of React Native's View component.

| Property | Type | Description | Default |
| ----------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `isOpen` | `boolean` | If true, the Actionsheet will open. Useful for controllable state behavior. | - |
| `onClose` | `() => any` | Callback invoked when the Actionsheet is closed. | - |
| `onOpen` | `() => any` | Callback invoked when the Actionsheet is opened. | - |
| `useRNModal` | `boolean` | If true, renders react-native native modal. | false |
| `defaultIsOpen` | `boolean` | Specifies the default open state of the Actionsheet | - |
| `initialFocusRef` | `React.RefObject<any>` | The ref of element to receive focus when the Actionsheet opens. | - |
| `finalFocusRef` | `React.RefObject<any>` | The ref of element to receive focus when the Actionsheet closes | - |
| `closeOnOverlayClick` | `boolean` | If true, the Actionsheet will close when the overlay is clicked. | - |
| `isKeyboardDismissable` | `boolean` | If true, the keyboard can dismiss the Actionsheet | - |
| `trapFocus` | `boolean` | If true, creates a focus scope containing all elements within the Actionsheet content. | true |
| `children` | `any` | The content to display inside the Actionsheet | - |
| `snapPoints` | `Array<number>` | The snap points for the Actionsheet The Actionsheet will snap to the point closest to its current position. The default value is 50% of the screen height. The value should be between 0 and 100. Currently, only one snap point is supported. We plan to support multiple snap points in the future. | [50] |

### ActionsheetBackdrop

It is React Native's Pressable component, created using @legendapp/motion's createMotionAnimatedComponent function to add animation to the component. You can use any declarative animation library you prefer.

### ActionsheetContent

It inherits all the properties of @legendapp/motion's Motion.View component. With this Actionsheet component, you have the flexibility to use any declarative animation library that suits your needs.

#### Descendants Styling Props

Props to style child components.

| Sx Prop | Description |
| -------------------- | ---------------------------------------------------- |
| `_sectionHeaderText` | Prop to style ActionsheetSectionHeaderText Component |

### ActionsheetDragIndicatorWrapper

It inherits all the properties of React Native's View component.

### ActionsheetDragIndicator

It inherits all the properties of React Native's View component.

### ActionsheetItem

It inherits all the properties of React Native's Pressable component.

#### Descendants Styling Props

Props to style child components.

| Sx Prop | Description |
| ------- | ------------------------------------------- |
| `_text` | Prop to style ActionsheetItemText Component |
| `_icon` | Prop to style ActionsheetIcon Component |

### ActionsheetItemText

It inherits all the properties of React Native's Text component.

### ActionsheetIcon

It inherits all the properties of React Native's View component.

### ActionsheetScrollView

It inherits all the properties of React Native's ScrollView component.

### ActionsheetVirtualizedList

It inherits all the properties of React Native's VirtualizedList component.

### ActionsheetFlatList

It inherits all the properties of React Native's FlatList component.

### ActionsheetSectionList

It inherits all the properties of React Native's SectionList component.

### ActionsheetSectionHeaderText

It inherits all the properties of React Native's Text component.

> Note: While our Actionsheet component supports both ActionsheetScrollView and ActionsheetVirtualizedList, we recommend using VirtualizedList for better performance on large lists of items. The ScrollView option may cause performance issues on lists with many items.

## Features

- Actionsheet has aria-modal set to true.
- Actionsheet has role set to dialog.
- When the Actionsheet opens, focus is trapped within it.
- Pressing Esc closes the Actionsheet
- Clicking on the overlay closes the Actionsheet
- Scrolling is blocked on the elements behind the Actionsheet

## Examples

### With ScrollView

<Canvas of={Stories.WithScrollView} />

```tsx
import {
Actionsheet,
ActionsheetBackdrop,
ActionsheetContent,
ActionsheetDragIndicator,
ActionsheetDragIndicatorWrapper,
ActionsheetScrollView,
} from '@utilitywarehouse/native-ui/lab';
import {
Heading,
Text,
Button,
ButtonText
} from '@utilitywarehouse/native-ui';

const MyComponent = () => {
const [showActionsheet, setShowActionsheet] = React.useState(false);
const handleClose = () => setShowActionsheet(!showActionsheet);
return (
<Box h="$96" alignItems="center" justifyContent="center">
<Button onPress={handleClose}>
<ButtonText>Open</ButtonText>
</Button>
<Actionsheet isOpen={showActionsheet} onClose={handleClose}>
<ActionsheetBackdrop />
<ActionsheetContent maxHeight="75%">
<ActionsheetDragIndicatorWrapper>
<ActionsheetDragIndicator />
</ActionsheetDragIndicatorWrapper>
<ActionsheetScrollView>
<Heading textAlign="center" mb="$4">
Out of range reading
</Heading>
<Text mb="$6">
The number that was entered was too high or too low for what we'd expect based on past
readings and your typical energy usage. This normally suggests an error when the
reading was submitted. In some cases, the reading may still be used after
investigation.
</Text>
<Button onPress={handleClose}>
<ButtonText>Close</ButtonText>
</Button>
</ActionsheetScrollView>
</ActionsheetContent>
</ActionsheetContent>
</Box>
);
};
```
Loading

0 comments on commit 4b830eb

Please sign in to comment.