react-native-toast-message-library 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +585 -156
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,9 +4,40 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
- ## [0.1.0] - Unreleased
7
+ ## [1.0.0] - 2026-10-24
8
+
9
+ First stable release. The public API (`ToastProvider`, `useToast`, `Toast`, `createTheme`,
10
+ toast options and provider props) follows semantic versioning from now on.
11
+
12
+ ### Added
13
+
14
+ - `description` option: an alias of `message` (use one of them, not both).
15
+ - `titles` provider prop: change or hide the default title per toast type, e.g.
16
+ `titles={{ success: 'Done', error: '' }}`.
17
+ - Validation of `<ToastProvider>` props (`position`, `animation`, `duration`, `maxVisible`, `offset`, `titles`, ...).
18
+ - Unit and render tests for the manager, option handling, offsets, insets and titles.
19
+ - Demo app sections for title/description and offsets.
20
+ - Rewritten README: title and description, top/bottom positions, safe-area insets and offsets, full option tables and copy-paste recipes.
21
+
22
+ ### Fixed
23
+
24
+ - Per-toast `offsetX` / `offsetY` were documented and validated but never applied.
25
+ - An invalid provider `position` / `animation` made toasts "visible" but never drawn; it now throws a clear `TypeError`.
26
+ - `insets={{ top: undefined }}` produced `NaN` positions; undefined / non-numeric insets are now ignored.
27
+ - The progress bar did not restart when a toast was updated in place by re-using its `id`.
28
+ - A toast that had been swiped away and was then shown again with the same `id` stayed off screen.
29
+ - A toast with an empty title and an empty message rendered as an empty box; it now throws a `TypeError`.
30
+ - `ToastApi.success/error/warning/info` types now accept numbers and the full options object.
31
+ - Toast width can no longer become negative with very large offsets.
32
+
33
+ ### Changed
34
+
35
+ - Removed the `engines.node` field. It described the demo app's toolchain and produced warnings for library users on older Node versions.
36
+
37
+ ## [0.1.0] - 2026-10-24
8
38
 
9
39
  ### Added
40
+
10
41
  - `ToastProvider`, `useToast()` and an opt-in global `Toast` API.
11
42
  - Toast types: success, error, warning, info, custom.
12
43
  - Seven positions, safe-area aware, with provider and per-toast offsets.
package/README.md CHANGED
@@ -1,165 +1,452 @@
1
1
  # react-native-toast-message-library
2
2
 
3
- Lightweight, customizable toast notifications for React Native. Pure JavaScript (no native modules, no
4
- required dependencies), built on the `Animated` API, with a FIFO queue, themes, actions, swipe-to-dismiss
5
- and accessibility support. TypeScript declarations included.
6
-
7
- > **Publishing note:** `react-native-toast-message-library` was not registered on npm when checked (2026-10-24). Re-check with `npm view react-native-toast-message-library` right before publishing.
3
+ Lightweight, customizable toast notifications for React Native.
4
+
5
+ - Pure JavaScript: no native modules, no linking, no required dependencies.
6
+ - Built on the `Animated` API, with a FIFO queue, themes, action buttons, swipe-to-dismiss and accessibility support.
7
+ - TypeScript declarations included.
8
+
9
+ ---
10
+
11
+ ## Table of contents
12
+
13
+ 1. [Features](#features)
14
+ 2. [Compatibility](#compatibility)
15
+ 3. [Installation](#installation)
16
+ 4. [Quick start](#quick-start)
17
+ 5. [Showing toasts](#showing-toasts)
18
+ 6. [Title and description](#title-and-description)
19
+ 7. [Positions: top, bottom and more](#positions-top-bottom-and-more)
20
+ 8. [Safe-area insets and offsets](#safe-area-insets-and-offsets)
21
+ 9. [Options reference (per toast)](#options-reference-per-toast)
22
+ 10. [Provider props reference](#provider-props-reference)
23
+ 11. [Callbacks](#callbacks)
24
+ 12. [Queue behaviour](#queue-behaviour)
25
+ 13. [Themes](#themes)
26
+ 14. [Custom icons and content](#custom-icons-and-content)
27
+ 15. [Action buttons](#action-buttons)
28
+ 16. [Animations and reduced motion](#animations-and-reduced-motion)
29
+ 17. [Accessibility](#accessibility)
30
+ 18. [TypeScript](#typescript)
31
+ 19. [Recipes (copy and paste examples)](#recipes-copy-and-paste-examples)
32
+ 20. [Troubleshooting](#troubleshooting)
33
+ 21. [Limitations](#limitations)
34
+ 22. [Development](#development)
35
+ 23. [Publishing](#publishing)
36
+ 24. [Contributing](#contributing) · [License](#license)
37
+
38
+ ---
8
39
 
9
40
  ## Features
10
41
 
11
42
  - Types: `success`, `error`, `warning`, `info`, `custom`
12
- - Seven positions: `top`, `bottom`, `center`, `top-left`, `top-right`, `bottom-left`, `bottom-right` (per toast)
13
- - Animations: `fade`, `slide`, `zoom`, `none` (native driver; reduced-motion aware)
14
- - Auto-dismiss, persistent toasts (`duration: 0`), timer pauses while the user touches or swipes a toast
43
+ - Seven positions: `top`, `bottom`, `center`, `top-left`, `top-right`, `bottom-left`, `bottom-right` (chosen per toast)
44
+ - Custom **title** and **description**, or remove either one (per toast or for every toast of a type)
45
+ - Safe-area aware, with extra `insets`, provider `offset` and per-toast `offsetX` / `offsetY`
46
+ - Animations: `fade`, `slide`, `zoom`, `none` (native driver, reduced-motion aware)
47
+ - Auto-dismiss, persistent toasts (`duration: 0`); the timer pauses while the user touches or swipes a toast
15
48
  - FIFO queue with `maxVisible`; dismiss by id, `hideAll()`, `isVisible()`
16
49
  - Close button, leading icon, action button, progress bar, swipe-to-dismiss, tap handler
50
+ - Update a toast in place by re-using its `id` (for example "Uploading…" → "Done")
17
51
  - `onShow`, `onPress`, `onAction`, `onDismiss(reason)` callbacks
18
- - Light / dark / system themes, `createTheme()`, per-toast style overrides, custom icons and content
19
- - Safe-area aware (optional `react-native-safe-area-context`)
52
+ - Light / dark / system themes, `createTheme()`, per-toast style overrides, custom icons and fully custom content
20
53
  - Accessibility roles and labels, Android live region, throttled iOS announcements
21
54
  - Optional vibration feedback (`haptics`)
22
55
 
23
56
  ## Compatibility
24
57
 
25
- | What | Status |
26
- | --- | --- |
27
- | React Native 0.88.0 / React 19.3.0 | **Verified**: unit tests (Jest) and Metro bundling for Android and iOS |
28
- | Real devices / emulators | **Not verified in this repository's CI environment** (no Android SDK or macOS available when it was built). Run the demo app before relying on visuals. |
29
- | Other RN / React versions | **Not verified.** Peer ranges (`react >=18`, `react-native >=0.72`) reflect the APIs used (`useSyncExternalStore` needs React 18) and are lower bounds, not test results. |
30
- | New Architecture / Old Architecture | Not separately tested. No native code is involved. |
58
+ | What | Status |
59
+ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
+ | React Native 0.88.0 / React 19.3.0 | **Verified**: unit tests (Jest) and Metro bundling for Android and iOS |
61
+ | Real devices / emulators | **Not verified in this repository's CI environment.** Run the demo app before relying on visuals. |
62
+ | Other RN / React versions | **Not verified.** Peer ranges (`react >=18`, `react-native >=0.72`) are lower bounds based on the APIs used (`useSyncExternalStore` needs React 18), not test results. |
63
+ | New / Old Architecture | Not separately tested. No native code is involved. |
31
64
 
32
65
  ## Installation
33
66
 
34
67
  ```sh
35
68
  npm install react-native-toast-message-library
36
- # optional, recommended: exact safe-area insets
69
+
70
+ # optional but recommended: exact safe-area insets (notch, status bar, home indicator)
37
71
  npm install react-native-safe-area-context
38
72
  ```
39
73
 
40
- No pods, no linking, no Gradle changes. If you use `react-native-safe-area-context`, wrap your app in its
41
- `SafeAreaProvider`; without it the library falls back to the Android status-bar height and conservative
42
- iOS notch values (47 top / 34 bottom).
74
+ No pods, no linking, no Gradle changes.
43
75
 
44
76
  ## Quick start
45
77
 
78
+ **Step 1 – wrap your app once, near the root.** If you use `react-native-safe-area-context`, put `SafeAreaProvider` outside `ToastProvider`.
79
+
46
80
  ```jsx
47
- import { ToastProvider, useToast } from 'react-native-toast-message-library';
81
+ // App.js
82
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
83
+ import { ToastProvider } from 'react-native-toast-message-library';
48
84
 
49
85
  export default function App() {
50
86
  return (
51
- <ToastProvider position="top" duration={3000} animation="slide" maxVisible={3}>
52
- <Home />
53
- </ToastProvider>
87
+ <SafeAreaProvider>
88
+ <ToastProvider
89
+ position="top"
90
+ duration={3000}
91
+ animation="slide"
92
+ maxVisible={3}
93
+ >
94
+ <Home />
95
+ </ToastProvider>
96
+ </SafeAreaProvider>
54
97
  );
55
98
  }
99
+ ```
100
+
101
+ **Step 2 – show a toast from any component below the provider.**
102
+
103
+ ```jsx
104
+ import { Button } from 'react-native';
105
+ import { useToast } from 'react-native-toast-message-library';
56
106
 
57
107
  function Home() {
58
108
  const toast = useToast();
59
109
  return (
60
110
  <Button
61
111
  title="Save"
62
- onPress={() => toast.success('Your changes have been saved.')}
112
+ onPress={() =>
113
+ toast.success({
114
+ title: 'Saved',
115
+ description: 'Your changes have been saved.',
116
+ })
117
+ }
63
118
  />
64
119
  );
65
120
  }
66
121
  ```
67
122
 
68
- The provider renders its children followed by the toast overlay in a wrapper `View` with `flex: 1`
69
- (change with the `style` prop). Place it near the root, inside `SafeAreaProvider` if you use one.
123
+ The provider renders its children followed by the toast overlay inside a wrapper `View` with `flex: 1` (change it with the `style` prop).
70
124
 
71
- ## Toast methods
125
+ ## Showing toasts
72
126
 
73
127
  ```js
74
128
  const toast = useToast();
75
129
 
76
- toast.show(options | 'message'); // -> id
77
- toast.success(message, options); // -> id (also error / warning / info)
78
- toast.hide(id); // -> boolean (true if a visible or queued toast was dismissed)
79
- toast.hideAll(); // -> number of toasts dismissed
80
- toast.isVisible(id?); // -> boolean (no id: is any toast visible?)
130
+ toast.show(options | 'message'); // -> id
131
+ toast.success(message, options); // -> id (also: error / warning / info)
132
+ toast.hide(id); // -> boolean (true if a visible or queued toast was dismissed)
133
+ toast.hideAll(); // -> number of toasts dismissed
134
+ toast.isVisible(id?); // -> boolean (without an id: is any toast visible?)
81
135
  ```
82
136
 
83
- - `success/error/warning/info` accept a string **or** an options object as the first argument; the type is
84
- always forced to the method's type. By default they show a title ("Success", "Error", …); pass
85
- `title: ''` to hide it.
86
- - Invalid options **throw a `TypeError`** with an explanation (unknown `position`, negative `duration`,
87
- non-function callbacks, no `message`/`title`/`render`, …). Nothing is silently ignored.
137
+ - `success`, `error`, `warning` and `info` accept a string, a number **or** an options object as the first argument. The type is always forced to the method's type.
138
+ - Invalid options **throw a `TypeError`** that explains the problem (unknown `position`, negative `duration`, non-function callbacks, nothing to show, …). Nothing is silently ignored.
88
139
  - `useToast()` outside a `ToastProvider` throws an error telling you to add one.
89
- - The returned object is stable: components using `useToast()` do not re-render when toasts change.
140
+ - The returned object is stable: components that call `useToast()` do not re-render when toasts change.
90
141
 
91
- ### Global API (opt-in)
142
+ ### Global API (opt-in, for code outside React)
92
143
 
93
144
  ```jsx
94
145
  import { ToastProvider, Toast } from 'react-native-toast-message-library';
95
146
 
96
- <ToastProvider global>…</ToastProvider>
147
+ <ToastProvider global>…</ToastProvider>;
97
148
 
98
- Toast.error('Network request failed'); // usable from services, outside React
99
- ```
100
-
101
- `global` registers that provider when it mounts and unregisters on unmount. If no global provider is
102
- mounted, `Toast.*` **throws** (it never fails silently). With several global providers the most recently
103
- mounted one wins. Prefer the hook inside components.
104
-
105
- ## Options (per toast)
106
-
107
- | Option | Type | Default | Description |
108
- | --- | --- | --- | --- |
109
- | `id` | string \| number | generated | Reusing the id of a visible/queued toast **updates it in place** and restarts its timer |
110
- | `type` | `'success' \| 'error' \| 'warning' \| 'info' \| 'custom'` | `'custom'` | Controls colours, icon and default title |
111
- | `title` | string \| null | type label | `''`/`null` hides the title |
112
- | `message` | string | – | At least one of `message`, `title`, `render` is required |
113
- | `duration` | number (ms) | `3000` | `0` = persistent |
114
- | `position` | see Positions | `'top'` | |
115
- | `animation` | `'fade' \| 'slide' \| 'zoom' \| 'none'` | `'slide'` | |
116
- | `animationDuration` | number (ms) | `250` | |
117
- | `offsetX`, `offsetY` | number | – | Extra margin on top of the provider `offset` |
118
- | `icon` | `false` \| element \| `({type,color,size}) => node` | built-in glyph | |
119
- | `render` | `({id,type,hide,colors,theme}) => node` | – | Replaces icon + title + message |
120
- | `closeButton` | boolean | `false` | Accessible "Dismiss notification" button |
121
- | `swipeToDismiss` | boolean | `true` | Horizontal swipe |
122
- | `progress` | boolean | `false` | Remaining-time bar (only when `duration > 0`) |
123
- | `haptics` | boolean | `false` | Vibration, see Limitations |
124
- | `action` | `{ label, accessibilityLabel? }` | – | Action button |
125
- | `dismissOnAction` | boolean | `true` | |
126
- | `dismissOnPress` | boolean | `false` | |
127
- | `backgroundColor`, `textColor`, `borderColor`, `iconColor` | string | theme | |
128
- | `borderRadius`, `padding` | number | theme | |
129
- | `shadow` | `false` \| `{color,opacity,radius,offsetY,elevation}` | theme | |
130
- | `containerStyle`, `titleStyle`, `messageStyle` | style | – | |
131
- | `accessibilityLabel`, `closeAccessibilityLabel` | string | generated | |
132
- | `onShow(id)` | function | – | Called when the toast becomes visible (after any time in the queue) |
133
- | `onPress({id,type,hide})` | function | – | Toast body pressed |
134
- | `onAction({id,type,hide})` | function | – | Action button pressed |
135
- | `onDismiss(reason, id)` | function | – | See below |
136
-
137
- Provider props: `theme`, `position`, `duration`, `animation`, `animationDuration`, `maxVisible` (3),
138
- `closeButton`, `swipeToDismiss`, `progress`, `haptics`, `spacing`, `offset={{x,y}}`, `insets`, `global`, `style`.
139
- Defaults set on the provider apply to every toast that does not override them; changing a provider prop
140
- affects toasts shown afterwards.
141
-
142
- ### Callbacks
143
-
144
- - `onDismiss(reason, id)` is called **exactly once**, at the moment dismissal starts (before the exit
145
- animation), for visible toasts and for toasts cancelled while still queued. `reason` is one of
146
- `'timeout' | 'manual' | 'swipe' | 'close' | 'action' | 'press' | 'hideAll'`.
147
- - `onAction` fires once when `dismissOnAction` is true (default) even if the button is tapped repeatedly;
148
- with `dismissOnAction: false` it fires on every press.
149
- - Exceptions thrown inside callbacks are caught and logged with `console.error`; they cannot corrupt the queue.
149
+ // anywhere: services, API clients, interceptors
150
+ Toast.error('Network request failed');
151
+ ```
152
+
153
+ `global` registers that provider when it mounts and unregisters it on unmount. If no global provider is mounted, `Toast.*` **throws** (it never fails silently). With several global providers the most recently mounted one wins. Prefer the hook inside components.
154
+
155
+ ---
156
+
157
+ ## Title and description
158
+
159
+ Every toast has two optional text parts:
160
+
161
+ | Part | Option | Default |
162
+ | --------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------- |
163
+ | **Title** (bold heading) | `title` | The type name: `Success`, `Error`, `Warning`, `Info` (no title for `custom`) |
164
+ | **Description** (body text) | `message` or `description` (identical; use one of them) | none |
165
+
166
+ ### Change them
167
+
168
+ ```js
169
+ // 1) Custom title + custom description
170
+ toast.success({
171
+ title: 'Profile saved',
172
+ description: 'Everyone can see your new photo.',
173
+ });
174
+
175
+ // 2) Shortcut form: first argument is the description, the title comes from the options
176
+ toast.error('Card declined.', { title: 'Payment failed' });
177
+
178
+ // 3) `message` and `description` are the same thing
179
+ toast.info({ title: 'Update', message: 'Version 2.0 is available.' });
180
+ ```
181
+
182
+ ### Remove them
183
+
184
+ ```js
185
+ // Remove the title: pass '' or null. Only the description is shown.
186
+ toast.error('Could not reach the server.', { title: '' });
187
+
188
+ // Remove the description: just leave it out. Only the title is shown.
189
+ toast.info({ title: 'Sync finished' });
190
+ ```
191
+
192
+ A toast must show something. A toast with an empty title **and** an empty description (and no `render`) throws a `TypeError`.
193
+
194
+ ### Change the default title of every toast of a type
195
+
196
+ Use the `titles` prop on the provider. This is also the way to translate the default titles.
197
+
198
+ ```jsx
199
+ <ToastProvider
200
+ titles={{
201
+ success: 'Done',
202
+ error: 'Something went wrong',
203
+ warning: 'Heads up',
204
+ info: 'FYI',
205
+ }}
206
+ />
207
+ ```
208
+
209
+ Hide the default title for all toasts (a per-toast `title` still works):
210
+
211
+ ```jsx
212
+ <ToastProvider titles={{ success: '', error: '', warning: '', info: '' }} />
213
+ ```
214
+
215
+ Order of priority for the title: **per-toast `title`** → **provider `titles[type]`** → **built-in type name**.
216
+
217
+ ### Style the title and description
218
+
219
+ ```js
220
+ toast.success({
221
+ title: 'Saved',
222
+ description: 'All changes are synced.',
223
+ titleStyle: { fontSize: 18, letterSpacing: 0.5 },
224
+ messageStyle: { fontStyle: 'italic' },
225
+ textColor: '#0B3D2E', // colour of both
226
+ });
227
+ ```
228
+
229
+ Global sizes, weights and fonts are set in the theme: `typography: { titleSize, titleWeight, messageSize, messageWeight, fontFamily }` (see [Themes](#themes)).
230
+
231
+ ### Change the text of a toast that is already visible
232
+
233
+ Re-use the `id`. The toast is updated in place and its timer (and progress bar) restarts.
234
+
235
+ ```js
236
+ const id = toast.show({
237
+ id: 'upload',
238
+ type: 'info',
239
+ title: 'Uploading',
240
+ description: '0%',
241
+ duration: 0,
242
+ });
243
+ // later
244
+ toast.show({
245
+ id: 'upload',
246
+ type: 'success',
247
+ title: 'Uploaded',
248
+ description: 'Your file is ready.',
249
+ duration: 3000,
250
+ });
251
+ ```
252
+
253
+ > Screen readers: the accessibility label is built as `"<type>. <title>. <description>"`. If you hide the title, the type is still announced. Set `accessibilityLabel` to override it completely.
254
+
255
+ ---
256
+
257
+ ## Positions: top, bottom and more
258
+
259
+ `position` is chosen per toast (default `'top'`, or the provider's `position`):
260
+
261
+ | Position | Where it appears |
262
+ | ----------------------------- | --------------------------------- |
263
+ | `top` | Top edge, centred |
264
+ | `bottom` | Bottom edge, centred |
265
+ | `center` | Middle of the screen |
266
+ | `top-left`, `top-right` | Top edge, aligned left / right |
267
+ | `bottom-left`, `bottom-right` | Bottom edge, aligned left / right |
268
+
269
+ ```js
270
+ toast.success('Saved', { position: 'top' });
271
+ toast.error('Failed', { position: 'bottom' });
272
+ toast.info('Hello', { position: 'bottom-right' });
273
+ ```
274
+
275
+ Set a default for all toasts on the provider and override it when needed:
276
+
277
+ ```jsx
278
+ <ToastProvider position="bottom">…</ToastProvider>;
279
+ toast.info('This one is on top', { position: 'top' });
280
+ ```
281
+
282
+ How toasts stack:
283
+
284
+ - Toasts that share a position stack in the order they were shown (oldest first, newest last). The gap between them is `spacing` (provider prop, default `10`).
285
+ - At most `maxVisible` toasts are on screen in total; the rest wait in the [queue](#queue-behaviour).
286
+ - Toasts are at most **480 dp** wide and always keep a **16 dp** margin from the screen sides.
287
+ - Each position is its own stack, so a `top` toast and a `bottom` toast can be visible at the same time.
288
+
289
+ ---
290
+
291
+ ## Safe-area insets and offsets
292
+
293
+ Three things control the distance between a toast and the screen edges. They add up.
294
+
295
+ | Setting | Where | What it does |
296
+ | ------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
297
+ | **`insets`** | `<ToastProvider insets={{ top, bottom, left, right }}>` | The "unsafe" areas of the screen: status bar / notch at the top, home indicator at the bottom. |
298
+ | **`offset`** | `<ToastProvider offset={{ x, y }}>` | Extra distance for **every** toast: `y` away from the top or bottom edge, `x` away from the left and right sides. |
299
+ | **`offsetX` / `offsetY`** | per toast option | Extra distance for **one** toast, added on top of the provider `offset`. |
300
+
301
+ Resulting distance from the edge:
302
+
303
+ ```
304
+ top toasts: insets.top + offset.y + toast.offsetY
305
+ bottom toasts: insets.bottom + offset.y + toast.offsetY
306
+ left side: 16 + insets.left + offset.x (+ toast.offsetX for *-left positions)
307
+ right side: 16 + insets.right + offset.x (+ toast.offsetX for *-right positions)
308
+ ```
309
+
310
+ Notes: `center` toasts ignore `offsetY` and `offset.y`. For centred positions (`top`, `bottom`, `center`) a per-toast `offsetX` makes the toast narrower on both sides. All offsets must be numbers `>= 0`.
311
+
312
+ ### Where do the insets come from?
313
+
314
+ In this order:
315
+
316
+ 1. The `insets` prop of `ToastProvider` (any side you pass wins; sides you leave out are taken from the next source).
317
+ 2. `react-native-safe-area-context`, if it is installed **and** your app is wrapped in `SafeAreaProvider`. This is exact and recommended.
318
+ 3. A built-in fallback: Android `top` = status-bar height, `bottom` = 0; iOS `top` = 47, `bottom` = 34 (conservative notch values).
319
+
320
+ ### Examples
321
+
322
+ **Recommended: let safe-area-context do it.** Nothing else is needed.
323
+
324
+ ```jsx
325
+ <SafeAreaProvider>
326
+ <ToastProvider>
327
+ <App />
328
+ </ToastProvider>
329
+ </SafeAreaProvider>
330
+ ```
331
+
332
+ **Set the insets yourself** (no safe-area library):
333
+
334
+ ```jsx
335
+ <ToastProvider insets={{ top: 44, bottom: 34 }}>
336
+ ```
150
337
 
151
- ## Positions
338
+ Only one side is fine; the other sides use the automatic value:
152
339
 
153
- `top`, `bottom`, `center`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. Each toast can choose its
154
- own; toasts sharing a position stack (oldest first). Toasts are at most 480 dp wide and always keep a
155
- 16 dp side margin. Insets come from the `insets` prop, else `react-native-safe-area-context`, else the
156
- fallback described above.
340
+ ```jsx
341
+ <ToastProvider insets={{ bottom: 24 }}>
342
+ ```
343
+
344
+ **Keep toasts below your own header** (56 dp tall):
345
+
346
+ ```jsx
347
+ <ToastProvider offset={{ y: 56 }} position="top">
348
+ ```
349
+
350
+ **Keep bottom toasts above a bottom tab bar** (React Navigation example):
351
+
352
+ ```jsx
353
+ import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
354
+
355
+ function Screen() {
356
+ const toast = useToast();
357
+ const tabBarHeight = useBottomTabBarHeight();
358
+ const saved = () =>
359
+ toast.success('Saved', { position: 'bottom', offsetY: tabBarHeight });
360
+ // ...
361
+ }
362
+ ```
363
+
364
+ …or for the whole app, if the tab bar is always visible:
365
+
366
+ ```jsx
367
+ <ToastProvider position="bottom" offset={{ y: 64 }}>
368
+ ```
369
+
370
+ **Move one toast** away from the edge or side:
371
+
372
+ ```js
373
+ toast.info('A bit lower', { position: 'top', offsetY: 24 });
374
+ toast.info('Narrower', { position: 'top-right', offsetX: 20 });
375
+ ```
376
+
377
+ **More space at the sides for every toast:**
378
+
379
+ ```jsx
380
+ <ToastProvider offset={{ x: 8 }}> // 16 + 8 = 24 dp from each side
381
+ ```
382
+
383
+ > The keyboard is not handled automatically. A `bottom` toast can be covered by the keyboard; use `offsetY` (for example the keyboard height from `Keyboard.addListener`) or show the toast at `top`.
384
+
385
+ ---
386
+
387
+ ## Options reference (per toast)
388
+
389
+ | Option | Type | Default | Description |
390
+ | ---------------------------------------------------------- | --------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------- |
391
+ | `id` | string \| number | generated | Re-using the id of a visible or queued toast **updates it in place** and restarts its timer |
392
+ | `type` | `'success' \| 'error' \| 'warning' \| 'info' \| 'custom'` | `'custom'` | Controls colours, icon and default title |
393
+ | `title` | string \| number \| null | type name (or provider `titles[type]`) | `''` or `null` hides the title |
394
+ | `message` | string \| number | – | The description. At least a title, a message or `render` is needed |
395
+ | `description` | string \| number | – | Alias of `message`. Do not pass both |
396
+ | `duration` | number (ms) | `3000` | `0` = persistent |
397
+ | `position` | see [Positions](#positions-top-bottom-and-more) | `'top'` | |
398
+ | `animation` | `'fade' \| 'slide' \| 'zoom' \| 'none'` | `'slide'` | |
399
+ | `animationDuration` | number (ms) | `250` | |
400
+ | `offsetX`, `offsetY` | number (>= 0) | – | Extra distance on top of the provider `offset` ([details](#safe-area-insets-and-offsets)) |
401
+ | `icon` | `false` \| element \| `({type,color,size}) => node` | built-in glyph | |
402
+ | `render` | `({id,type,hide,colors,theme}) => node` | – | Replaces icon + title + message |
403
+ | `closeButton` | boolean | `false` | Accessible "Dismiss notification" button |
404
+ | `swipeToDismiss` | boolean | `true` | Horizontal swipe |
405
+ | `progress` | boolean | `false` | Remaining-time bar (only when `duration > 0`) |
406
+ | `haptics` | boolean | `false` | Vibration, see [Limitations](#limitations) |
407
+ | `action` | `{ label, accessibilityLabel? }` | – | Action button |
408
+ | `dismissOnAction` | boolean | `true` | |
409
+ | `dismissOnPress` | boolean | `false` | |
410
+ | `backgroundColor`, `textColor`, `borderColor`, `iconColor` | string | theme | |
411
+ | `borderRadius`, `padding` | number | theme | |
412
+ | `shadow` | `false` \| `{color,opacity,radius,offsetY,elevation}` | theme | |
413
+ | `containerStyle`, `titleStyle`, `messageStyle` | style | – | |
414
+ | `accessibilityLabel`, `closeAccessibilityLabel` | string | generated | |
415
+ | `onShow(id)` | function | – | Called when the toast becomes visible (after any time in the queue) |
416
+ | `onPress({id,type,hide})` | function | – | Toast body pressed |
417
+ | `onAction({id,type,hide})` | function | – | Action button pressed |
418
+ | `onDismiss(reason, id)` | function | – | See [Callbacks](#callbacks) |
419
+
420
+ ## Provider props reference
421
+
422
+ Defaults set on the provider apply to every toast that does not override them. Changing a provider prop affects toasts shown afterwards. Invalid values throw a `TypeError`.
423
+
424
+ | Prop | Type | Default | Description |
425
+ | ------------------------------------------------------ | ------------------------------------------------ | -------------------- | --------------------------------------------- |
426
+ | `theme` | `'light' \| 'dark' \| 'system' \| object` | `'light'` | See [Themes](#themes) |
427
+ | `position` | position | `'top'` | Default position |
428
+ | `duration` | number (ms) | `3000` | Default duration |
429
+ | `animation` | animation | `'slide'` | |
430
+ | `animationDuration` | number (ms) | `250` | |
431
+ | `maxVisible` | integer >= 1 | `3` | Toasts on screen at once; the rest are queued |
432
+ | `closeButton`, `swipeToDismiss`, `progress`, `haptics` | boolean | see options | Defaults for every toast |
433
+ | `titles` | `{ success?, error?, warning?, info?, custom? }` | – | Default title per type; `''` hides it |
434
+ | `spacing` | number | theme `spacing` (10) | Gap between stacked toasts |
435
+ | `offset` | `{ x?, y? }` | `{ x: 0, y: 0 }` | Extra distance from the screen edges |
436
+ | `insets` | `{ top?, bottom?, left?, right? }` | automatic | Overrides the detected safe-area insets |
437
+ | `global` | boolean | `false` | Registers this provider for the `Toast` API |
438
+ | `style` | style | `{ flex: 1 }` | Style of the wrapper `View` |
439
+
440
+ ## Callbacks
441
+
442
+ - `onDismiss(reason, id)` is called **exactly once**, at the moment dismissal starts (before the exit animation), for visible toasts and for toasts cancelled while still queued. `reason` is one of `'timeout' | 'manual' | 'swipe' | 'close' | 'action' | 'press' | 'hideAll'`.
443
+ - `onAction` fires once when `dismissOnAction` is `true` (default) even if the button is tapped repeatedly; with `dismissOnAction: false` it fires on every press.
444
+ - Exceptions thrown inside callbacks are caught and logged with `console.error`; they cannot corrupt the queue.
157
445
 
158
446
  ## Queue behaviour
159
447
 
160
448
  - At most `maxVisible` toasts are on screen; further requests wait in a **FIFO** queue.
161
- - A toast occupies its slot until its **exit animation has finished**, then the oldest queued toast is promoted.
162
- Its timer starts when it becomes visible, not when it was requested.
449
+ - A toast occupies its slot until its **exit animation has finished**, then the oldest queued toast is promoted. Its timer starts when it becomes visible, not when it was requested.
163
450
  - `hide(id)` also cancels a queued toast; `hideAll()` clears the queue and dismisses visible toasts.
164
451
  - Raising `maxVisible` at runtime promotes queued toasts immediately.
165
452
  - Generated ids are unique and never collide with ids you pass.
@@ -174,17 +461,15 @@ import { ToastProvider, createTheme } from 'react-native-toast-message-library';
174
461
  <ToastProvider
175
462
  theme={createTheme('dark', {
176
463
  borderRadius: 4,
177
- typography: { fontFamily: 'Inter' },
464
+ typography: { fontFamily: 'Inter', titleSize: 16 },
178
465
  colors: { success: { background: '#052E1B', text: '#fff' } },
179
466
  })}
180
467
  />
181
468
 
182
- <ToastProvider theme={{ extends: 'dark', padding: 20 }} /> // plain object also works
469
+ <ToastProvider theme={{ extends: 'dark', padding: 20 }} /> // a plain object also works
183
470
  ```
184
471
 
185
- A theme object is deep-merged over the light theme (or the one named by `extends`). See `src/themes/light.js`
186
- for every key (`colors.<type>.{background,text,border,icon,iconText}`, `borderRadius`, `borderWidth`,
187
- `padding`, `spacing`, `iconSize`, `typography`, `shadow`, `actionColor`, `closeColor`, `progressTrack`).
472
+ A theme object is deep-merged over the light theme (or the one named by `extends`). Every key (`colors.<type>.{background,text,border,icon,iconText}`, `borderRadius`, `borderWidth`, `padding`, `spacing`, `iconSize`, `typography`, `shadow`, `actionColor`, `closeColor`, `progressTrack`) is listed in `src/themes/light.js`.
188
473
 
189
474
  ## Custom icons and content
190
475
 
@@ -195,10 +480,14 @@ toast.show({
195
480
  icon: ({ color, size }) => <RocketIcon color={color} size={size} />,
196
481
  });
197
482
 
483
+ toast.success('No icon here', { icon: false });
484
+
198
485
  toast.show({
199
486
  type: 'custom',
200
487
  render: ({ hide, colors }) => (
201
- <Text style={{ color: colors.text }} onPress={hide}>Fully custom — tap to close</Text>
488
+ <Text style={{ color: colors.text }} onPress={hide}>
489
+ Fully custom: tap to close
490
+ </Text>
202
491
  ),
203
492
  });
204
493
  ```
@@ -208,7 +497,7 @@ toast.show({
208
497
  ```jsx
209
498
  toast.show({
210
499
  type: 'success',
211
- message: 'Message deleted',
500
+ title: 'Message deleted',
212
501
  duration: 6000,
213
502
  action: { label: 'Undo' },
214
503
  onAction: () => restoreMessage(),
@@ -218,63 +507,199 @@ toast.show({
218
507
 
219
508
  ## Animations and reduced motion
220
509
 
221
- All animations animate only `opacity` and `transform`, so they use the native driver. The progress bar
222
- animates `width` (a layout property) and therefore runs on the JS thread; it is a 3 dp element. When the
223
- system "reduce motion" setting is on, `slide` and `zoom` are replaced by `fade`; `none` stays `none`.
224
- After a toast exits, toasts stacked below it move into place without animation.
510
+ All animations animate only `opacity` and `transform`, so they use the native driver. The progress bar animates `width` (a layout property) and therefore runs on the JS thread; it is a 3 dp element. When the system "reduce motion" setting is on, `slide` and `zoom` are replaced by `fade`; `none` stays `none`. After a toast exits, toasts stacked next to it move into place without animation.
225
511
 
226
512
  ## Accessibility
227
513
 
228
- - Each toast is an `alert` (or a `button` when `onPress` is set) with a label such as
229
- `"Error. Disk full"`, so the type is available to screen readers and not only conveyed by colour/icon.
230
- The decorative icon glyph is hidden from assistive technology.
231
- - Android: `accessibilityLiveRegion="polite"`. iOS: announcements via `announceForAccessibility`, throttled
232
- to one per 1.5 s so a burst of queued toasts does not interrupt VoiceOver repeatedly.
233
- - Close and action buttons are labelled and have ≥ 44 dp touch targets (including `hitSlop`).
514
+ - Each toast is an `alert` (or a `button` when `onPress` is set) with a label such as `"Error. Disk full"`, so the type is available to screen readers and not only conveyed by colour or icon. The decorative icon glyph is hidden from assistive technology.
515
+ - Android: `accessibilityLiveRegion="polite"`. iOS: announcements via `announceForAccessibility`, throttled to one per 1.5 s so a burst of queued toasts does not interrupt VoiceOver repeatedly.
516
+ - Close and action buttons are labelled and have touch targets of at least 44 dp (including `hitSlop`).
234
517
  - Text scales with the system font size up to 1.6×.
235
518
 
236
- **Not covered:** the screen-reader behaviour has been implemented following platform guidelines but has not
237
- been tested on real TalkBack/VoiceOver. Toasts that disappear on a timer can be missed by assistive
238
- technology users; use `duration: 0` plus a close button for important messages.
519
+ **Not covered:** the screen-reader behaviour follows platform guidelines but has not been tested on real TalkBack / VoiceOver. Toasts that disappear on a timer can be missed by assistive-technology users; use `duration: 0` plus a close button for important messages.
239
520
 
240
521
  ## TypeScript
241
522
 
242
523
  Declarations ship in `types/index.d.ts` (checked by `npm run typecheck`).
243
524
 
244
525
  ```ts
245
- import { useToast, type ToastOptions } from 'react-native-toast-message-library';
246
-
247
- const opts: ToastOptions = { type: 'info', message: 'Hi', position: 'bottom-right' };
526
+ import {
527
+ useToast,
528
+ type ToastOptions,
529
+ } from 'react-native-toast-message-library';
530
+
531
+ const opts: ToastOptions = {
532
+ type: 'info',
533
+ title: 'Hello',
534
+ description: 'World',
535
+ position: 'bottom-right',
536
+ offsetY: 12,
537
+ };
248
538
  useToast().show(opts);
249
539
  ```
250
540
 
541
+ Exported types include `ToastOptions`, `ToastApi`, `ToastProviderProps`, `ToastTitles`, `ToastTheme`, `ToastThemeOverrides`, `ToastType`, `ToastPosition`, `ToastAnimation`, `ToastDismissReason` and `Insets`.
542
+
543
+ ---
544
+
545
+ ## Recipes (copy and paste examples)
546
+
547
+ ### 1. Result of an API call
548
+
549
+ ```js
550
+ async function save() {
551
+ try {
552
+ await api.save();
553
+ toast.success({ title: 'Saved', description: 'Your changes are live.' });
554
+ } catch (error) {
555
+ toast.error(error.message, { title: 'Could not save', duration: 5000 });
556
+ }
557
+ }
558
+ ```
559
+
560
+ ### 2. Loading → success / error with one toast
561
+
562
+ ```js
563
+ const ID = 'upload';
564
+ toast.show({
565
+ id: ID,
566
+ type: 'info',
567
+ title: 'Uploading…',
568
+ duration: 0,
569
+ closeButton: false,
570
+ });
571
+ try {
572
+ await upload();
573
+ toast.show({
574
+ id: ID,
575
+ type: 'success',
576
+ title: 'Uploaded',
577
+ description: 'Your file is ready.',
578
+ });
579
+ } catch {
580
+ toast.show({
581
+ id: ID,
582
+ type: 'error',
583
+ title: 'Upload failed',
584
+ duration: 0,
585
+ closeButton: true,
586
+ });
587
+ }
588
+ ```
589
+
590
+ ### 3. Undo
591
+
592
+ ```js
593
+ toast.show({
594
+ type: 'success',
595
+ title: 'Item deleted',
596
+ action: { label: 'Undo' },
597
+ duration: 6000,
598
+ onAction: restoreItem,
599
+ onDismiss: reason => reason === 'timeout' && deleteForever(),
600
+ });
601
+ ```
602
+
603
+ ### 4. Toast from an API client or Redux middleware (outside React)
604
+
605
+ ```jsx
606
+ <ToastProvider global>…</ToastProvider>
607
+ ```
608
+
609
+ ```js
610
+ // api.js
611
+ import { Toast } from 'react-native-toast-message-library';
612
+
613
+ axios.interceptors.response.use(undefined, error => {
614
+ Toast.error(error.message, { title: 'Network error' });
615
+ return Promise.reject(error);
616
+ });
617
+ ```
618
+
619
+ ### 5. Translate or remove all default titles
620
+
621
+ ```jsx
622
+ <ToastProvider titles={{ success: 'સફળ', error: 'ભૂલ', warning: 'ચેતવણી', info: 'માહિતી' }} />
623
+ <ToastProvider titles={{ success: '', error: '', warning: '', info: '' }} /> {/* no titles */}
624
+ ```
625
+
626
+ ### 6. Bottom toasts that avoid the home indicator and a tab bar
627
+
628
+ ```jsx
629
+ <SafeAreaProvider>
630
+ <ToastProvider position="bottom" offset={{ y: 56 }}>
631
+ …
632
+ </ToastProvider>
633
+ </SafeAreaProvider>
634
+ ```
635
+
636
+ ### 7. Persistent error with a close button and a retry action
637
+
638
+ ```js
639
+ toast.error('The server is not reachable.', {
640
+ title: 'Offline',
641
+ duration: 0,
642
+ closeButton: true,
643
+ action: { label: 'Retry' },
644
+ dismissOnAction: false,
645
+ onAction: ({ hide }) => retry().then(hide),
646
+ });
647
+ ```
648
+
649
+ ### 8. Brand-coloured toast
650
+
651
+ ```js
652
+ toast.show({
653
+ type: 'custom',
654
+ title: 'Welcome back',
655
+ description: 'Good to see you again.',
656
+ backgroundColor: '#1E1B4B',
657
+ textColor: '#EEF2FF',
658
+ borderColor: '#818CF8',
659
+ iconColor: '#C7D2FE',
660
+ icon: ({ color }) => <Text style={{ color, fontSize: 22 }}>👋</Text>,
661
+ });
662
+ ```
663
+
664
+ ### 9. Theme follows the device
665
+
666
+ ```jsx
667
+ <ToastProvider theme="system">…</ToastProvider>
668
+ ```
669
+
670
+ ---
671
+
251
672
  ## Troubleshooting
252
673
 
253
- | Symptom | Cause / fix |
254
- | --- | --- |
255
- | `useToast() was called outside of a <ToastProvider>` | Render the component below the provider (usually in `App.js`). |
256
- | `Toast.* was called but no <ToastProvider global> is mounted` | Add the `global` prop, or use `useToast()`. |
257
- | `Invalid position "…"` / other `TypeError` | Fix the option; the message lists the allowed values. |
258
- | Toast hidden behind a modal / native screen | See Limitations. |
259
- | Toast under the notch / status bar | Install `react-native-safe-area-context` and use `SafeAreaProvider`, or pass `insets`. |
260
- | Nothing vibrates with `haptics` | Android needs `<uses-permission android:name="android.permission.VIBRATE" />`. |
261
- | Layout broken because of the wrapper View | Pass `style` to the provider. |
674
+ | Symptom | Cause / fix |
675
+ | ------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
676
+ | `useToast() was called outside of a <ToastProvider>` | Render the component below the provider (usually in `App.js`). |
677
+ | `Toast.* was called but no <ToastProvider global> is mounted` | Add the `global` prop, or use `useToast()`. |
678
+ | `Invalid position "…"` or another `TypeError` | Fix the option or prop; the message lists the allowed values. |
679
+ | `the toast would be empty` | Give the toast a `message`/`description`, a non-empty `title` or a `render` function. |
680
+ | `use either "message" or "description"` | Pass only one of them. |
681
+ | Toast hidden behind a modal / native screen | See [Limitations](#limitations). |
682
+ | Toast under the notch / status bar | Install `react-native-safe-area-context` and use `SafeAreaProvider`, or pass `insets`. |
683
+ | Toast too close to the header or tab bar | Use `offset={{ y }}` on the provider or `offsetY` on the toast. |
684
+ | Bottom toast hidden by the keyboard | Use `offsetY` or show it at `top`. |
685
+ | Nothing vibrates with `haptics` | Android needs `<uses-permission android:name="android.permission.VIBRATE" />`. |
686
+ | Layout broken because of the wrapper View | Pass `style` to the provider. |
262
687
 
263
688
  ## Limitations
264
689
 
265
- - Toasts render inside the React tree. They appear **under** React Native `Modal`s and native-presented
266
- screens (e.g. native-stack modal presentations). Render another `ToastProvider` inside such a modal.
267
- - `haptics` uses the built-in `Vibration` API: Android honours short vibrations (needs the `VIBRATE`
268
- permission), iOS ignores the duration and vibrates for a fixed ~0.4 s. It is not a Taptic Engine integration.
269
- - Swipe-to-dismiss uses `PanResponder` (horizontal swipes only). It is implemented but **not covered by
270
- automated tests** (gesture simulation is not available in the Jest setup); verify it on a device.
271
- - Visual rendering, animation smoothness, and screen-reader behaviour have not been verified on a device or emulator.
272
- - Toasts below a removed toast jump into position (no layout animation).
690
+ - Toasts render inside the React tree. They appear **under** React Native `Modal`s and native-presented screens (for example native-stack modal presentations). Render another `ToastProvider` inside such a modal.
691
+ - The fallback insets (used without `react-native-safe-area-context`) are approximations. Install the library for exact values.
692
+ - The keyboard is not tracked automatically (see the offsets section).
693
+ - `center` toasts ignore `offsetY`.
694
+ - `haptics` uses the built-in `Vibration` API: Android honours short vibrations (needs the `VIBRATE` permission), iOS ignores the duration and vibrates for a fixed ~0.4 s. It is not a Taptic Engine integration.
695
+ - Swipe-to-dismiss uses `PanResponder` (horizontal swipes only). It is implemented but **not covered by automated tests** (gesture simulation is not available in the Jest setup); verify it on a device.
696
+ - Visual rendering, animation smoothness and screen-reader behaviour have not been verified on a device or emulator.
697
+ - Toasts next to a removed toast jump into position (no layout animation).
273
698
  - `onDismiss` fires when dismissal starts, not when the exit animation ends.
274
699
 
275
700
  ## Development
276
701
 
277
- The repository root is both the library and a React Native CLI demo app (no Expo).
702
+ The repository root is both the library and a React Native CLI demo app (no Expo). Node.js 22.11 or newer is needed for the demo app's toolchain (React Native 0.88); the published library itself has no Node requirement.
278
703
 
279
704
  ```sh
280
705
  npm install
@@ -288,40 +713,44 @@ npm run android # terminal 2; needs Android SDK + JDK
288
713
  npm run ios # macOS + Xcode; cd ios && bundle exec pod install first
289
714
  ```
290
715
 
291
- Layout: `src/` (the library: `manager` = queue + timers, `components`, `animations`, `themes`, `utils`),
292
- `types/` (TypeScript declarations), `__tests__/`, and `App.js` + `demo/` (the demo app).
716
+ Layout: `src/` (the library: `manager` = queue + timers, `components`, `animations`, `themes`, `utils`), `types/` (TypeScript declarations), `__tests__/`, and `App.js` + `demo/` (the demo app).
293
717
 
294
718
  ## Publishing
295
719
 
720
+ Current release: **1.0.0**. Before the first publish of a new version:
721
+
296
722
  ```sh
297
- # 0. one-time: set repository/bugs/homepage in package.json
723
+ # 1. Update CHANGELOG.md (new version heading + date) and the "version" in package.json
298
724
  npm ci
299
- npm run validate # lint + typecheck + tests + npm pack --dry-run
300
- npm pack --dry-run # should list only src/, types/, README.md, CHANGELOG.md, LICENSE, package.json
725
+ npm run validate # lint + typecheck + tests + npm pack --dry-run
726
+ npm pack --dry-run # should list only src/, types/index.d.ts, README.md, CHANGELOG.md, LICENSE, package.json
301
727
 
302
- npm login # interactive; never commit tokens
303
- npm publish # scoped public packages: npm publish --access public (already set in publishConfig)
728
+ # 2. Publish
729
+ npm login # interactive; never commit tokens
730
+ npm publish # publishConfig.access is already "public"
304
731
 
305
- npm view <your-package-name> version # verify
306
- git tag v0.1.0 && git push origin v0.1.0
732
+ # 3. Verify, tag and push
733
+ npm view react-native-toast-message-library version
734
+ git tag v1.0.0 && git push origin v1.0.0
307
735
  ```
308
736
 
309
- Future releases (semantic versioning: patch = fixes, minor = backwards-compatible features, major = breaking):
737
+ For every later release (semantic versioning: patch = fixes, minor = backwards-compatible features, major = breaking changes):
310
738
 
311
739
  ```sh
312
740
  # update CHANGELOG.md first
313
- npm version patch # or minor / major — bumps package.json and creates the git tag
741
+ npm version patch # or minor / major; bumps package.json and package-lock.json and creates the git tag
314
742
  npm publish
315
743
  git push --follow-tags
316
744
  ```
317
745
 
746
+ > An already published version can never be published again. If `npm publish` says "cannot publish over the previously published versions", bump the version first.
747
+
318
748
  ### Release checklist
319
749
 
320
- - [ ] `npm view react-native-toast-message-library` still returns 404 (name free)
321
750
  - [ ] `npm run validate` passes
322
- - [ ] Example app run on an Android device/emulator **and** an iOS simulator (swipe, queue, themes, a11y spot check)
323
- - [ ] `CHANGELOG.md` entry dated; version bumped
324
- - [ ] `repository`, `bugs`, `homepage` fields filled in `package.json`
751
+ - [ ] `CHANGELOG.md` entry added and dated; `version` bumped in `package.json` (and `package-lock.json`)
752
+ - [ ] Demo app run on an Android device/emulator **and** an iOS simulator (swipe, queue, themes, insets, a11y spot check)
753
+ - [ ] `repository`, `bugs` and `homepage` fields are filled in `package.json` (they make the npm page link to your GitHub)
325
754
  - [ ] `npm pack --dry-run` file list reviewed
326
755
  - [ ] Published, verified with `npm view`, tag pushed
327
756
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-toast-message-library",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Lightweight, customizable toast notifications for React Native: queue, themes, animations, actions, swipe-to-dismiss and accessibility. Pure JavaScript, no native modules.",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",