├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── publish-beta.yml │ ├── publish.yml │ ├── quality.yml │ ├── tag.yml │ └── tests.yml ├── .gitignore ├── .npmignore ├── .prettierrc.js ├── LICENSE ├── README.md ├── babel.config.js ├── docs ├── api.md ├── custom-layouts.md ├── jest-testing.md ├── modal-usage.md ├── navigation-usage.md ├── quick-start.md └── toast.gif ├── index.ts ├── jest.config.js ├── jest.setup.js ├── package.json ├── scripts └── dispatch-publish-beta.sh ├── src ├── Toast.tsx ├── ToastUI.tsx ├── __helpers__ │ └── PanResponder.ts ├── __tests__ │ ├── Toast.test.tsx │ ├── ToastUI.test.tsx │ └── useToast.test.ts ├── components │ ├── AnimatedContainer.styles.tsx │ ├── AnimatedContainer.tsx │ ├── BaseToast.styles.ts │ ├── BaseToast.tsx │ ├── ErrorToast.tsx │ ├── InfoToast.tsx │ ├── SuccessToast.tsx │ └── __tests__ │ │ ├── AnimatedContainer.test.tsx │ │ ├── BaseToast.test.tsx │ │ ├── ErrorToast.test.tsx │ │ ├── InfoToast.test.tsx │ │ └── SuccessToast.test.tsx ├── contexts │ ├── LoggerContext.tsx │ ├── __tests__ │ │ └── LoggerContext.test.tsx │ └── index.ts ├── hooks │ ├── __tests__ │ │ ├── useKeyboard.test.ts │ │ ├── usePanResponder.test.ts │ │ ├── useSlideAnimation.test.ts │ │ ├── useTimeout.test.ts │ │ └── useViewDimensions.test.ts │ ├── index.ts │ ├── useKeyboard.ts │ ├── usePanResponder.ts │ ├── useSlideAnimation.ts │ ├── useTimeout.ts │ └── useViewDimensions.ts ├── types │ └── index.ts ├── useToast.ts └── utils │ ├── __tests__ │ ├── number.test.ts │ └── obj.test.ts │ ├── array.ts │ ├── func.ts │ ├── number.ts │ ├── obj.ts │ ├── platform.ts │ └── test-id.ts ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | babel.config.js 2 | .eslintrc.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['backpacker-react-ts'], 4 | rules: { 5 | 'import/no-extraneous-dependencies': 'off', 6 | '@typescript-eslint/explicit-module-boundary-types': 'off' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Tap on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Code sample** 27 | To help debugging, please add a code sample that reproduces the issue. 28 | 29 | **Environment (please complete the following information):** 30 | - OS: [iOS, Android, Web] 31 | - react-native-toast-message version: [e.g. v2.0.0] 32 | - react-native version [e.g. v0.65.0] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: '/' 5 | schedule: 6 | interval: monthly 7 | time: '03:00' 8 | open-pull-requests-limit: 10 9 | reviewers: 10 | - calintamas 11 | -------------------------------------------------------------------------------- /.github/workflows/publish-beta.yml: -------------------------------------------------------------------------------- 1 | name: Publish a new beta version 2 | 3 | on: 4 | repository_dispatch: 5 | types: [publish-beta] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | ref: ${{ github.event.client_payload.ref }} 14 | 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: 16 19 | 20 | - name: Get yarn cache directory path 21 | id: yarn-cache-dir-path 22 | run: echo "::set-output name=dir::$(yarn cache dir)" 23 | 24 | - name: Restore yarn cache 25 | uses: actions/cache@v4 26 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 27 | with: 28 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 29 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 30 | restore-keys: | 31 | ${{ runner.os }}-yarn- 32 | 33 | - name: Install dependencies 34 | run: yarn --prefer-offline 35 | 36 | - name: Setup React Native environment 37 | run: | 38 | yarn add react@17.0.2 39 | yarn add react-native@0.64.2 40 | 41 | - name: Run tests 42 | run: yarn test --coverage 43 | 44 | publish-beta: 45 | runs-on: ubuntu-latest 46 | needs: test 47 | steps: 48 | - uses: actions/checkout@v2 49 | with: 50 | ref: ${{ github.event.client_payload.ref }} 51 | 52 | - name: Setup Node.js 53 | uses: actions/setup-node@v1 54 | with: 55 | node-version: 16 56 | 57 | - name: Install dependencies 58 | run: yarn 59 | 60 | - name: Build 61 | run: yarn build 62 | 63 | - id: publish 64 | uses: JS-DevTools/npm-publish@v1 65 | with: 66 | token: ${{ secrets.NPM_TOKEN }} 67 | tag: 'beta' 68 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v1 14 | 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: 14 19 | 20 | - name: Get yarn cache directory path 21 | id: yarn-cache-dir-path 22 | run: echo "::set-output name=dir::$(yarn cache dir)" 23 | 24 | - name: Restore yarn cache 25 | uses: actions/cache@v4 26 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 27 | with: 28 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 29 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 30 | restore-keys: | 31 | ${{ runner.os }}-yarn- 32 | 33 | - name: Install dependencies 34 | run: yarn --prefer-offline 35 | 36 | - name: Setup React Native environment 37 | run: | 38 | yarn add react@17.0.2 39 | yarn add react-native@0.64.2 40 | 41 | - name: Run tests 42 | run: yarn test --coverage 43 | 44 | publish: 45 | runs-on: ubuntu-latest 46 | needs: test 47 | steps: 48 | - uses: actions/checkout@v1 49 | 50 | - uses: actions/setup-node@v1 51 | with: 52 | node-version: 14 53 | 54 | - name: Install dependencies 55 | run: yarn 56 | 57 | - name: Build 58 | run: yarn build 59 | 60 | - id: publish 61 | uses: JS-DevTools/npm-publish@v1 62 | with: 63 | token: ${{ secrets.NPM_TOKEN }} 64 | -------------------------------------------------------------------------------- /.github/workflows/quality.yml: -------------------------------------------------------------------------------- 1 | name: Run code quality checks 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | quality: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 14 22 | 23 | - name: Get yarn cache directory path 24 | id: yarn-cache-dir-path 25 | run: echo "::set-output name=dir::$(yarn cache dir)" 26 | 27 | - name: Restore yarn cache 28 | uses: actions/cache@v4 29 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 30 | with: 31 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 32 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 33 | restore-keys: | 34 | ${{ runner.os }}-yarn- 35 | 36 | - name: Install dependencies 37 | run: yarn --prefer-offline 38 | 39 | - name: Setup React Native environment 40 | run: | 41 | yarn add react@17.0.2 42 | yarn add react-native@0.64.2 43 | 44 | - name: Run code quality checks 45 | run: yarn quality 46 | -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | name: Create Tag 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: Klemensas/action-autotag@stable 14 | with: 15 | GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' 16 | tag_prefix: 'v' 17 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 14 22 | 23 | - name: Get yarn cache directory path 24 | id: yarn-cache-dir-path 25 | run: echo "::set-output name=dir::$(yarn cache dir)" 26 | 27 | - name: Restore yarn cache 28 | uses: actions/cache@v4 29 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 30 | with: 31 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 32 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 33 | restore-keys: | 34 | ${{ runner.os }}-yarn- 35 | 36 | - name: Install dependencies 37 | run: yarn --prefer-offline 38 | 39 | - name: Setup React Native environment 40 | run: | 41 | yarn add react@17.0.2 42 | yarn add react-native@0.64.2 43 | 44 | - name: Run tests 45 | run: yarn test --coverage 46 | 47 | - name: Coveralls 48 | uses: coverallsapp/github-action@master 49 | with: 50 | github-token: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .git 3 | node_modules 4 | .idea 5 | coverage 6 | lib 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/__tests__/* -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSameLine: true, 3 | jsxSingleQuote: true, 4 | singleQuote: true, 5 | trailingComma: 'none' 6 | }; 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Calin Tamas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-toast-message 2 | 3 | [![npm version](https://img.shields.io/npm/v/react-native-toast-message)](https://www.npmjs.com/package/react-native-toast-message) 4 | [![npm downloads](https://img.shields.io/npm/dw/react-native-toast-message)](https://www.npmjs.com/package/react-native-toast-message) 5 | [![Build](https://github.com/calintamas/react-native-toast-message/actions/workflows/publish.yml/badge.svg)](https://github.com/calintamas/react-native-toast-message/actions/workflows/publish.yml?query=workflow%3Abuild) 6 | [![Coverage Status](https://coveralls.io/repos/github/calintamas/react-native-toast-message/badge.svg?branch=master)](https://coveralls.io/github/calintamas/react-native-toast-message?branch=main) 7 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 8 | 9 | Animated toast message component for React Native. 10 | 11 | ![toast gif](./docs/toast.gif) 12 | 13 | ## Features 14 | 15 | - 🚀 Imperative API 16 | - 📦 Very lightweight (~40 kB) 17 | - ⌨️ Keyboard-aware 18 | - 🎨 Customizable layouts 19 | - 🔧 Flexible config 20 | 21 | ## Documentation 22 | 23 | > This is the documentation for `react-native-toast-message@v2`, which has a similar API to v1, but contains a few important changes. [Read the complete changelog](https://github.com/calintamas/react-native-toast-message/releases/tag/v2.0.0). 24 | 25 | - [Quick start](./docs/quick-start.md) 26 | - [API](./docs/api.md) 27 | - [Create custom layouts](./docs/custom-layouts.md) 28 | - FAQ 29 | - [How to show the Toast inside a Modal?](./docs/modal-usage.md) 30 | - [How to render the Toast when using a Navigation library?](./docs/navigation-usage.md) 31 | - [How to mock the library for testing with jest?](./docs/jest-testing.md) 32 | 33 | ## License 34 | 35 | MIT 36 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'] 3 | }; 4 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | The `Toast` API consists of: 4 | 5 | 1. [methods](#methods) that can be called directly on the `Toast` object (in an _imperative_ way) 6 | 1. [props](#props) that can be passed to the `Toast` component instance; they act as defaults for all Toasts that are shown 7 | 8 | ## methods 9 | 10 | ### `show(options = {})` 11 | 12 | To show a Toast, call the `show()` method and pass the `options` that suit your needs. Everything is optional, unless specified otherwise: 13 | 14 | ```js 15 | import Toast from 'react-native-toast-message' 16 | 17 | Toast.show({ 18 | type: 'info', 19 | text1: 'This is an info message' 20 | }); 21 | ``` 22 | 23 | The complete set of **options** is described below: 24 | 25 | | option | description | type | default value | 26 | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ------------- | 27 | | `type` | Toast type. Default available values: `success`, `error`, `info`. [Learn how to extend / overwrite Toast types](./custom-layouts.md) | `string` | `success` | 28 | | `text1` | First line of text | `string` | | 29 | | `text2` | Second line of text | `string` | | 30 | | `position` | Toast position | `top` or `bottom` | `top` | 31 | | `visibilityTime` | Number of milliseconds after which Toast automatically hides. Has effect only in conjunction with `autoHide` prop set to `true` | `number` | `4000` | 32 | | `autoHide` | When `true`, the visible Toast automatically hides after a certain number of milliseconds, specified by the `visibilityTime` prop | `boolean` | `true` | 33 | | `topOffset` | Offset from the top of the screen (in px). Has effect only when `position` is `top` | `number` | `40` | 34 | | `bottomOffset` | Offset from the bottom of the screen (in px). Has effect only when `position` is `bottom` | `number` | `40` | 35 | | `keyboardOffset` | Offset from the Keyboard (in px). Has effect only when `position` is `bottom` and Keyboard is visible (iOS only) | `number` | `10` | 36 | | `onShow` | Called when the Toast is shown | `() => void` | | 37 | | `onHide` | Called when the Toast hides | `() => void` | | 38 | | `onPress` | Called on Toast press | `() => void` | | 39 | | `props` | Any custom props passed to the specified Toast type. Has effect only when there is a custom Toast type (configured via the `config` prop on the Toast instance) that uses the `props` parameter | `any` | | 40 | 41 | ### `hide()` 42 | 43 | To hide the current visible Toast, call the `hide()` method: 44 | 45 | ```js 46 | Toast.hide(); 47 | ``` 48 | 49 | If an `onHide` callback was set (via `show()`, or as a default `prop` on the Toast component instance), it will be called now. 50 | 51 | ## props 52 | 53 | The following set of `props` can be passed to the `Toast` component instance to specify certain **defaults for all Toasts that are shown**: 54 | 55 | | prop | description | type | default value | 56 | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------- | 57 | | `config` | Layout configuration for custom Toast types | [`ToastConfig`](../src/types/index.ts) | | 58 | | `type` | Default Toast type | `string` | `success` | 59 | | `position` | Default Toast position | `top` or `bottom` | `top` | 60 | | `visibilityTime` | Number of milliseconds after which Toast automatically hides. Has effect only in conjunction with `autoHide` prop set to `true` | `number` | `4000` | 61 | | `autoHide` | When `true`, the visible Toast automatically hides after a certain number of milliseconds, specified by the `visibilityTime` prop | `boolean` | `true` | 62 | | `swipeable` | When `true`, the Toast can be swiped to dismiss | `boolean` | `true` | 63 | | `topOffset` | Offset from the top of the screen (in px). Has effect only when `position` is `top` | `number` | `40` | 64 | | `bottomOffset` | Offset from the bottom of the screen (in px). Has effect only when `position` is `bottom` | `number` | `40` | 65 | | `keyboardOffset` | Offset from the Keyboard (in px). Has effect only when `position` is `bottom` and Keyboard is visible (iOS only) | `number` | `10` | 66 | | `onShow` | Called when any Toast is shown | `() => void` | | 67 | | `onHide` | Called when any Toast hides | `() => void` | | 68 | | `onPress` | Called on any Toast press | `() => void` | | 69 | 70 | For example, to make sure all your Toasts are displayed at the bottom of the screen: 71 | 72 | ```js 73 | // App.jsx 74 | import Toast from 'react-native-toast-message'; 75 | 76 | export function App(props) { 77 | return ( 78 | <> 79 | {/* ... */} 80 | 84 | 85 | ); 86 | } 87 | ``` 88 | -------------------------------------------------------------------------------- /docs/custom-layouts.md: -------------------------------------------------------------------------------- 1 | # Create custom layouts 2 | 3 | If you want to add custom Toast types - or overwrite the existing ones - you can add a [`config` prop](./api.md#props) when rendering the `Toast` component in your app's entry point. 4 | 5 | When creating the `config`, you can either: 6 | 7 | 1. Use any of the default `BaseToast`, `SuccessToast`, `ErrorToast` or `InfoToast` components and adjust their layout 8 | 1. Create Toast layouts from scratch 9 | 10 | ```js 11 | // App.jsx 12 | import Toast, { BaseToast, ErrorToast } from 'react-native-toast-message'; 13 | 14 | /* 15 | 1. Create the config 16 | */ 17 | const toastConfig = { 18 | /* 19 | Overwrite 'success' type, 20 | by modifying the existing `BaseToast` component 21 | */ 22 | success: (props) => ( 23 | 32 | ), 33 | /* 34 | Overwrite 'error' type, 35 | by modifying the existing `ErrorToast` component 36 | */ 37 | error: (props) => ( 38 | 47 | ), 48 | /* 49 | Or create a completely new type - `tomatoToast`, 50 | building the layout from scratch. 51 | 52 | I can consume any custom `props` I want. 53 | They will be passed when calling the `show` method (see below) 54 | */ 55 | tomatoToast: ({ text1, props }) => ( 56 | 57 | {text1} 58 | {props.uuid} 59 | 60 | ) 61 | }; 62 | 63 | /* 64 | 2. Pass the config as prop to the Toast component instance 65 | */ 66 | export function App(props) { 67 | return ( 68 | <> 69 | {...} 70 | 71 | 72 | ); 73 | } 74 | ``` 75 | 76 | Then just use the library as before. 77 | 78 | For example, if I want to show the new `tomatoToast` type I just created above: 79 | 80 | ```js 81 | Toast.show({ 82 | type: 'tomatoToast', 83 | // And I can pass any custom props I want 84 | props: { uuid: 'bba1a7d0-6ab2-4a0a-a76e-ebbe05ae6d70' } 85 | }); 86 | ``` 87 | 88 | All the available props on `BaseToast`, `SuccessToast`, `ErrorToast` or `InfoToast` components can be found here: [BaseToastProps](../src/types/index.ts#L86-L103). 89 | -------------------------------------------------------------------------------- /docs/jest-testing.md: -------------------------------------------------------------------------------- 1 | # How to mock the library for testing with [jest](https://jestjs.io)? 2 | 3 | ```js 4 | jest.mock('react-native-toast-message', () => ({ 5 | show: jest.fn(), 6 | hide: jest.fn() 7 | })); 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/modal-usage.md: -------------------------------------------------------------------------------- 1 | # How to show the Toast inside a Modal? 2 | 3 | ## How are `refs` tracked 4 | 5 | By default, when you render a `` instance in your App's entry point (root), a `ref` is created and tracked internally. 6 | 7 | ```js 8 | // App.jsx 9 | import Toast from 'react-native-toast-message' 10 | 11 | export function App(props) { 12 | return ( 13 | <> 14 | {/* ... */} 15 | {/* A `ref` pointing to this Toast instance is created */} 16 | 17 | 18 | ); 19 | } 20 | ``` 21 | 22 | Under the hood, this `ref` is used when you imperatively call `Toast.show()` or `Toast.hide()`. 23 | 24 | ## Showing a Toast inside a Modal 25 | 26 | When you have a [Modal](https://reactnative.dev/docs/modal), things get different. This `Modal` component is [_above_ React's root `View`](https://stackoverflow.com/questions/39766350/bring-view-on-top-of-modal-using-zindex-style-with-react-native), so the only way to show something _on top of the modal_ is to render it inside the `Modal` itself. 27 | 28 | This means **you need a new instance** of `` rendered inside your `Modal` (as well as keeping the existing `` instance outside, in your App's entry point). 29 | 30 | ```diff 31 | // App.jsx 32 | import { Modal } from 'react-native' 33 | import Toast from 'react-native-toast-message' 34 | 35 | export function App(props) { 36 | const [isModalVisible, setIsModalVisible] = React.useState(false); 37 | 38 | return ( 39 | <> 40 | {/* ... */} 41 | 42 | 43 | + 44 | 45 | 46 | ); 47 | } 48 | ``` 49 | 50 | Everything else works as usual; you can show and hide Toasts using the imperative API: `Toast.show()` or `Toast.hide()`. When the `Modal` is visible, the `ref` from inside the `Modal` will be used, otherwise the one outside. 51 | 52 | > The `ref` is tracked automatically; whichever `` instance last had its `ref` set will be used when showing/hiding. 53 | 54 | ### Notes regarding `react-native-modal` or `NativeStackNavigator` 55 | 56 | The same requirements as above apply when using [react-native-modal](https://github.com/react-native-modal/react-native-modal) or a [NativeStackNavigator](https://reactnavigation.org/docs/native-stack-navigator#presentation) with `presentation: 'modal'`: 57 | 58 | ```js 59 | <> 60 | {/* This `Toast` will show when neither the native stack screen nor `Modal` are presented */} 61 | 62 | 63 | 64 | {/* This `Toast` will show when the `NativeStackNavigator.Screen` is visible, but the `Modal` is NOT visible. */} 65 | 66 | 67 | 68 | {/* This `Toast` will show when both the `NativeStackNavigator.Screen` and the `Modal` are visible. */} 69 | 70 | 71 | 72 | 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/navigation-usage.md: -------------------------------------------------------------------------------- 1 | # How to render the Toast when using a Navigation library? 2 | 3 | 1. Usage with [react-navigation](https://reactnavigation.org) 4 | 5 | ## Usage with [react-navigation](https://reactnavigation.org) 6 | 7 | To have the Toast visible on top of the navigation `View` hierarchy, render it as the **last child** in the `View` hierarchy (along the root Navigation component): 8 | 9 | ```js 10 | import Toast from 'react-native-toast-message' 11 | import { NavigationContainer } from '@react-navigation/native'; 12 | 13 | export function App() { 14 | return ( 15 | <> 16 | 17 | {...} 18 | 19 | 20 | 21 | ); 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/quick-start.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | ## Install 4 | 5 | ```sh 6 | yarn add react-native-toast-message 7 | # or 8 | npm install --save react-native-toast-message 9 | ``` 10 | 11 | ## Usage 12 | 13 | Render the `Toast` component in your app's entry file, as the **LAST CHILD** in the `View` hierarchy (along with any other components that might be rendered there): 14 | 15 | ```js 16 | // App.jsx 17 | import Toast from 'react-native-toast-message'; 18 | 19 | export function App(props) { 20 | return ( 21 | <> 22 | {/* ... */} 23 | 24 | 25 | ); 26 | } 27 | ``` 28 | 29 | Then use it anywhere in your app (even outside React components), by calling [any `Toast` method](./api.md#methods) directly: 30 | 31 | ```js 32 | // Foo.jsx 33 | import Toast from 'react-native-toast-message'; 34 | import { Button } from 'react-native' 35 | 36 | export function Foo(props) { 37 | const showToast = () => { 38 | Toast.show({ 39 | type: 'success', 40 | text1: 'Hello', 41 | text2: 'This is some something 👋' 42 | }); 43 | } 44 | 45 | return ( 46 |