Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
module.exports = {
parser: 'babel-eslint',
extends: 'airbnb',
plugins: ['react', 'react-native'],
rules: {
'react/jsx-filename-extension': 0,
'no-use-before-define': 0,
'import/no-unresolved': ['error', { ignore: ['^react'] }],
'import/extensions': ['error', { ignore: ['^react'] }]
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"airbnb",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint",
"prettier/react"
],
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
};
"rules": {
"react/jsx-filename-extension": ["error", { "extensions": [".ts", ".tsx", ".js", ".jsx"] }],
"import/prefer-default-export": 0,
"import/no-default-export": 2,
"prettier/prettier": "error",
"react/destructuring-assignment": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
package-lock.json
lib
238 changes: 68 additions & 170 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,180 +1,78 @@
## React Native Modal Controller
## React Native Modal Controller 🕹

Modals can be fiddly in React Native. Lets say for example you have a mostly-fullscreen modal with a form in it and you want to show an error modal after an incorrect submission - you'd have to close the form modal and once `onDismiss` is called open the error modal.
A more ergonomic interface for opening and managing modals in your react native
app.

React Native Modal Controller aims to solve this by providing a control component that manages your one or many modals. It does this by opening a single React Native Modal with a single backdrop.
- 🎣 Uses React hooks
- 🍆 Written in TypeScript
- 💥 Open multiple modals at once (tray and an alert, or whatever)
- 🎩 Fancy animations using `react-native-animatable`

For example, you might want to have a modal and a tray with a picker in it:
For example, you might want to have a modal and a tray:

<img src="https://i.imgur.com/6JhOGID.gif" width="200" />

The code for the above looks like:

```js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import showModal, { PRIORITIES, ModalController } from 'react-native-modal-controller';
import AlertModal from './components/alert';
import TrayModal from './components/tray';

export default class App extends React.Component {
handleShowtray = () => {
showModal({
name: 'TRAY',
priority: PRIORITIES.OVERRIDE,
modalProps: {
message: 'Hey tray.',
onOpenAlert: () => this.handleOpen(PRIORITIES.STANDARD),
},
});
};
handleOpen = (priority) => {
showModal({
name: 'ALERT',
priority: priority || PRIORITIES.OVERRIDE,
modalProps: {
message: 'Hello, modal.',
onOpenAnother: this.handleOpen,
onOpenTray: this.handleShowtray
},
});
};

render() {
return (
<View style={styles.container}>
<Button title="Open Modal" onPress={this.handleOpen} />
<ModalController
customAnimations={{
slideTrayUp: {
from: { bottom: -300 },
to: { bottom: 0 }
},
slideTrayDown: {
from: { bottom: 0 },
to: { bottom: -300 }
}
}}
modals={{
ALERT: {
animationIn: 'zoomInDown',
animationOut: 'lightSpeedOut',
Component: AlertModal
},
TRAY: {
animationIn: 'slideTrayUp',
animationOut: 'slideTrayDown',
Component: TrayModal,
absolutePositioning: {
bottom: 0,
left: 0,
right: 0,
},
},
}}
/>
</View>
);
}
}

```

Modal Control is implemented in a very similar way to [react-native-modal](https://github.com/react-native-community/react-native-modal), by using [react-native-animatable](https://github.com/oblador/react-native-animatable). So you'll notice in the above example that you can use any of the animatable animations - or implement your own.

### Priorities

**`PRIORITIES.STANDARD`** - Open the modal alongside (on-top-of) the existing modals - if any.

**`PRIORITIES.OVERRIDE`** - Open the modal and close all existing modals.

### `ModalController`

`ModalController` should be mounted at the route of your app and only mounted once, similar to how you'd set up routing.

#### Props

##### `modals` - required
---

```js
type ModalsPropType = {
[name: string]: {
Component: React.Component, // required
animationIn?: string,
animationOut?: string,
animationInDuration?: number,
animationOutDuration?: number,
absolutePositioning?: Object, // Position the modal absolutely with given styles
}
## Example Usage:

```tsx
// Your basic popup component
const MyModal = (props: ModalComponentProps<any>) => (
<View style={{height: 300, width: 300, backgroundColor: 'white'}}>
{/* Opens another modal from within */}
<TouchableOpacity onPress={() => props.onShowModal({name: 'myModal'})}>
<Text>Open another</Text>
</TouchableOpacity>
</View>
);

const MyScreen = () => {
// The Hook!
const modal = useModalController();
return (
<View style={{flex: 1}}>
<TouchableOpacity
onPress={() =>
// Show the `myModal` popup declared in the the provider
modal.onShowModal({
name: 'myModal',
priority: Priority.Override,
})
}>
<Text>Show Modal</Text>
</TouchableOpacity>
</View>
);
};
```

##### `customAnimations` - optional
---

```js
type CustomAnimationsProp = ?{
[name: string]: {
from: Object,
to: Object,
}
// Your app entry point - define your Modals and pass into the Context Provider
const App = () => {
return (
<ModalControllerProvider
modals={[
{
// Your unique name/key for this modal to be opened
name: 'myModal',
// Define whether, when opened, this modal should override or exist in parallel
priority: Priority.Override,
animation: {
inDuration: 500,
outDuration: 500,
// Using react-native-animatable animations or your own
in: 'fadeInDown' as Animation,
out: 'fadeOutUp' as Animation,
},
Component: MyModal,
},
]}
// Customise the backdrop
backdrop={{
activeOpacity: 0.5,
transitionInTiming: 500,
transitionOutTiming: 500,
}}>
<MyScreen />
</ModalControllerProvider>
);
};
```

##### `activeBackdropOpacity` - optional
---

```js
type ActiveBackdropOpacityProp = ?number;
```


##### `backdropTransitionInTiming` - optional
---

```js
type BackdropTransitionInTimingProp = ?number;
```

##### `backdropTransitionOutTiming` - optional
---

```js
type BackdropTransitionOutTimingProp = ?number;
```

### `showModal`

`showModal` is the default export and can be used to show one of your modals based on the config you pass it.

#### Args

##### `name` - required
---

```js
type name = string; // The key used in your modals prop of ModalController
```

##### `modalProps` - optional
---

```js
type modalProps = Object; // Props passed to your Component
```

##### `priority` - optional
---

```js
type priority = $Keys<typeof PRIORITIES>;
```

#### Overrides

You can also pass in any of the `ModalsPropType`s apart from Component to override your defaults.




```
21 changes: 0 additions & 21 deletions index.js

This file was deleted.

Loading