@xsolla/xui-toast 0.150.0 → 0.151.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 (2) hide show
  1. package/README.md +185 -405
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,543 +1,323 @@
1
1
  # Toast
2
2
 
3
- A cross-platform React toast notification system for displaying brief, auto-dismissing messages. Built on a provider/context architecture with a hook-based API, the Toast package supports multiple variants, configurable positioning, custom durations, custom icons, and programmatic dismiss on both React (web) and React Native.
3
+ A cross-platform toast notification system built on a provider/context architecture with a hook-based API. Supports multiple variants, configurable position and alignment, custom durations, custom icons, and programmatic dismiss on both web and React Native.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @xsolla/xui-toast @xsolla/xui-core
9
- # or
10
- yarn add @xsolla/xui-toast @xsolla/xui-core
8
+ npm install @xsolla/xui-toast
11
9
  ```
12
10
 
13
- **Peer dependencies:** `react >= 16.8.0`, `styled-components >= 4`
11
+ ## Imports
14
12
 
15
- ## Architecture
16
-
17
- The toast system uses a **Provider → Context → Hook** pattern:
18
-
19
- ```
20
- ┌─────────────────────────────────────────────────┐
21
- ToastProvider │
22
- ┌────────────┐ ┌───────────────────────────┐ │
23
- ToastContext│ │ ToastGroup (portal / abs) │ │
24
- │ - toasts │ │ ┌───────┐ ┌───────┐ │ │
25
- │ - addToast│──▶ │ Toast │ │ Toast │ ... │ │
26
- │ - dismiss │ │ └───────┘ └───────┘ │ │
27
- └────────────┘ └───────────────────────────┘ │
28
- │ ▲ │
29
- │ │ useToast() │
30
- │ ┌─────┴──────┐ │
31
- │ │ Your App │ │
32
- │ └────────────┘ │
33
- └─────────────────────────────────────────────────┘
13
+ ```tsx
14
+ import {
15
+ Toast,
16
+ ToastProvider,
17
+ ToastGroup,
18
+ ToastContext,
19
+ useToast,
20
+ type ToastProps,
21
+ type ToastOptions,
22
+ type ToastVariant,
23
+ type ToastPosition,
24
+ type ToastAlign,
25
+ type UseToastReturn,
26
+ } from '@xsolla/xui-toast';
34
27
  ```
35
28
 
36
- 1. **`ToastProvider`** — Wraps your application. Manages toast state (an array of `ToastData`), auto-dismiss timers, and renders the `ToastGroup` container.
37
- 2. **`ToastContext`** — React context that exposes `addToast`, `dismissToast`, and `dismissAllToasts` to descendants.
38
- 3. **`useToast`** — Consumer hook that provides convenience methods (`success`, `info`, `warning`, `error`, `dismiss`, `dismissAll`).
39
- 4. **`ToastGroup`** — Renders the stack of visible toasts. On web, uses `ReactDOM.createPortal` to escape z-index stacking contexts. On React Native, uses absolute positioning.
40
- 5. **`Toast`** — The individual notification component with icon, message, and optional close button.
41
-
42
- ## Quick Start
43
-
44
- ### 1. Wrap your app with `ToastProvider`
29
+ ## Quick start
45
30
 
46
- **React (Web):**
31
+ Wrap your app with `ToastProvider`, then call `useToast` from any descendant.
47
32
 
48
33
  ```tsx
34
+ import * as React from 'react';
49
35
  import { XUIProvider } from '@xsolla/xui-core';
50
- import { ToastProvider } from '@xsolla/xui-toast';
36
+ import { ToastProvider, useToast } from '@xsolla/xui-toast';
51
37
 
52
- export default function App() {
38
+ function SaveButton() {
39
+ const toast = useToast();
53
40
  return (
54
- <XUIProvider initialMode="dark" initialProductContext="b2b">
55
- <ToastProvider>
56
- <YourApp />
57
- </ToastProvider>
58
- </XUIProvider>
41
+ <button onClick={() => toast.success('Saved successfully')}>Save</button>
59
42
  );
60
43
  }
61
- ```
62
-
63
- **React Native:**
64
-
65
- ```tsx
66
- import React from 'react';
67
- import { View } from 'react-native';
68
- import { XUIProvider } from '@xsolla/xui-core';
69
- import { ToastProvider } from '@xsolla/xui-toast';
70
- import { MainNavigator } from './navigation';
71
44
 
72
45
  export default function App() {
73
46
  return (
74
- <XUIProvider mode="dark">
75
- <ToastProvider position="top">
76
- <View style={{ flex: 1 }}>
77
- <MainNavigator />
78
- </View>
47
+ <XUIProvider initialMode="dark">
48
+ <ToastProvider>
49
+ <SaveButton />
79
50
  </ToastProvider>
80
51
  </XUIProvider>
81
52
  );
82
53
  }
83
54
  ```
84
55
 
85
- > **Important for React Native:** The `ToastProvider` renders toasts using absolute positioning. Ensure your app's root container has `flex: 1` so toasts position correctly relative to the screen.
56
+ > **React Native:** ensure the root container under `ToastProvider` has `flex: 1` so absolute-positioned toasts have a reference height.
86
57
 
87
- ### 2. Show toasts with `useToast`
58
+ ## API Reference
88
59
 
89
- ```tsx
90
- import { useToast } from '@xsolla/xui-toast';
60
+ ### `<ToastProvider>`
91
61
 
92
- function SaveButton() {
93
- const toast = useToast();
62
+ Root provider. Manages toast state, auto-dismiss timers, and renders the `ToastGroup`.
94
63
 
95
- const handleSave = async () => {
96
- try {
97
- await saveData();
98
- toast.success('Changes saved successfully');
99
- } catch {
100
- toast.error('Failed to save changes');
101
- }
102
- };
64
+ | Prop | Type | Default | Description |
65
+ | --- | --- | --- | --- |
66
+ | `children` | `ReactNode` | — | Application content. |
67
+ | `position` | `"top" \| "bottom"` | `"top"` | Vertical anchor of the toast container. |
68
+ | `align` | `"left" \| "center" \| "right"` | `"center"` | Horizontal alignment of toasts within the container. |
69
+ | `defaultDuration` | `number` | `5000` | Default auto-dismiss duration in ms. Set `0` to disable auto-dismiss globally. |
70
+ | `maxWidth` | `number` | — | Maximum width (px) of the toast stack. When unset, toasts stretch to the container width. |
103
71
 
104
- return <button onClick={handleSave}>Save</button>;
105
- }
106
- ```
72
+ ### `<Toast>`
107
73
 
108
- ## Demo
74
+ The individual toast cell. Used internally by `ToastGroup`, but can be rendered standalone for static display.
109
75
 
110
- ### Showing Toast Variants
76
+ | Prop | Type | Default | Description |
77
+ | --- | --- | --- | --- |
78
+ | `id` | `string` | — | Required unique identifier. |
79
+ | `message` | `string` | — | Required message text. |
80
+ | `variant` | `"success" \| "info" \| "warning" \| "error"` | `"info"` | Visual variant; determines the default icon and accent colour. |
81
+ | `icon` | `ReactNode` | — | Custom icon. Overrides the default. |
82
+ | `duration` | `number` | — | Auto-dismiss duration in ms. `0` or omitted = no auto-dismiss. |
83
+ | `onClose` | `() => void` | — | Close handler. Required for the close button to render. |
111
84
 
112
- Each variant conveys a different semantic meaning and displays a corresponding icon:
85
+ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
113
86
 
114
- ```tsx
115
- import { useToast } from '@xsolla/xui-toast';
87
+ ### `<ToastGroup>`
116
88
 
117
- export default function ToastExample() {
118
- const toast = useToast();
89
+ Renders the stack of visible toasts. On web uses `ReactDOM.createPortal` to escape stacking contexts; on React Native uses absolute positioning.
119
90
 
120
- return (
121
- <div style={{ display: 'flex', gap: 8 }}>
122
- <button onClick={() => toast.success('Quest has been activated')}>
123
- Success
124
- </button>
125
- <button onClick={() => toast.info('You received 50 Xsolla Points')}>
126
- Info
127
- </button>
128
- <button onClick={() => toast.warning('Your session is about to expire')}>
129
- Warning
130
- </button>
131
- <button onClick={() => toast.error('Failed to save changes')}>
132
- Error
133
- </button>
134
- </div>
135
- );
91
+ | Prop | Type | Default | Description |
92
+ | --- | --- | --- | --- |
93
+ | `toasts` | `ToastData[]` | | Toasts to render. |
94
+ | `position` | `"top" \| "bottom"` | `"top"` | Vertical anchor. |
95
+ | `align` | `"left" \| "center" \| "right"` | `"center"` | Horizontal alignment. |
96
+ | `maxWidth` | `number` | | Maximum width (px). |
97
+ | `onDismiss` | `(id: string) => void` | — | Dismiss callback per toast. |
98
+
99
+ Inherits `ThemeOverrideProps`.
100
+
101
+ ### `useToast()`
102
+
103
+ Hook that returns toast helpers. Throws if called outside a `ToastProvider`.
104
+
105
+ | Method | Signature | Description |
106
+ | --- | --- | --- |
107
+ | `toast` | `(options: ToastOptions) => string` | Show a toast with full options. Returns the toast ID. |
108
+ | `success` | `(message: string, options?) => string` | Show a success toast. |
109
+ | `info` | `(message: string, options?) => string` | Show an info toast. |
110
+ | `warning` | `(message: string, options?) => string` | Show a warning toast. |
111
+ | `error` | `(message: string, options?) => string` | Show an error toast. |
112
+ | `dismiss` | `(id: string) => void` | Dismiss a specific toast by ID. |
113
+ | `dismissAll` | `() => void` | Dismiss all visible toasts. |
114
+
115
+ ### `ToastOptions`
116
+
117
+ | Property | Type | Default | Description |
118
+ | --- | --- | --- | --- |
119
+ | `message` | `string` | — | Required message text. |
120
+ | `variant` | `"success" \| "info" \| "warning" \| "error"` | `"info"` | Visual variant. |
121
+ | `icon` | `ReactNode` | — | Custom icon. |
122
+ | `duration` | `number` | provider's `defaultDuration` | Auto-dismiss duration. `0` keeps the toast until dismissed manually. |
123
+
124
+ ### `ToastData`
125
+
126
+ Internal shape exposed via `ToastContext.toasts`.
127
+
128
+ | Property | Type | Description |
129
+ | --- | --- | --- |
130
+ | `id` | `string` | Unique identifier generated by the provider. |
131
+ | `variant` | `ToastVariant` | Toast variant. |
132
+ | `message` | `string` | Message text. |
133
+ | `icon` | `ReactNode \| undefined` | Custom icon, if any. |
134
+ | `duration` | `number \| undefined` | Auto-dismiss duration. |
135
+
136
+ ### `ToastContext`
137
+
138
+ React context with `{ toasts, addToast, dismissToast, dismissAllToasts }`. Typically consumed via `useToast`; available for advanced use cases:
139
+
140
+ ```tsx
141
+ import { useContext } from 'react';
142
+ import { ToastContext } from '@xsolla/xui-toast';
143
+
144
+ function ActiveCount() {
145
+ const ctx = useContext(ToastContext);
146
+ if (!ctx) throw new Error('Must be within ToastProvider');
147
+ return <span>Active toasts: {ctx.toasts.length}</span>;
136
148
  }
137
149
  ```
138
150
 
139
- ### Showing Toasts (React Native)
151
+ ## Examples
140
152
 
141
- The `useToast` hook works identically in React Native. Use `onPress` instead of `onClick`:
153
+ ### Variants
142
154
 
143
155
  ```tsx
144
- import React from 'react';
145
- import { View } from 'react-native';
146
- import { Button } from '@xsolla/xui-button';
156
+ import * as React from 'react';
147
157
  import { useToast } from '@xsolla/xui-toast';
148
158
 
149
- export default function ToastExample() {
159
+ export default function Variants() {
150
160
  const toast = useToast();
151
-
152
161
  return (
153
- <View style={{ gap: 8 }}>
154
- <Button onPress={() => toast.success('Quest has been activated')}>
155
- Success
156
- </Button>
157
- <Button onPress={() => toast.info('You received 50 Xsolla Points')}>
158
- Info
159
- </Button>
160
- <Button onPress={() => toast.warning('Your session is about to expire')}>
161
- Warning
162
- </Button>
163
- <Button onPress={() => toast.error('Failed to save changes')}>
164
- Error
165
- </Button>
166
- </View>
162
+ <div style={{ display: 'flex', gap: 8 }}>
163
+ <button onClick={() => toast.success('Quest activated')}>Success</button>
164
+ <button onClick={() => toast.info('You received 50 points')}>Info</button>
165
+ <button onClick={() => toast.warning('Session about to expire')}>Warning</button>
166
+ <button onClick={() => toast.error('Failed to save')}>Error</button>
167
+ </div>
167
168
  );
168
169
  }
169
170
  ```
170
171
 
171
- ### Toast Variants (Standalone `Toast` Component)
172
-
173
- The `Toast` component can be used standalone outside the provider for static display or custom layouts:
172
+ ### Standalone Toast (no provider)
174
173
 
175
174
  ```tsx
175
+ import * as React from 'react';
176
176
  import { Toast } from '@xsolla/xui-toast';
177
177
 
178
- export default function ToastVariants() {
178
+ export default function Standalone() {
179
179
  return (
180
180
  <div style={{ display: 'flex', flexDirection: 'column', gap: 8, maxWidth: 400 }}>
181
- <Toast id="1" variant="success" message="Quest has been activated" onClose={() => {}} />
182
- <Toast id="2" variant="info" message="You received 50 Xsolla Points" onClose={() => {}} />
183
- <Toast id="3" variant="warning" message="Your session is about to expire" onClose={() => {}} />
184
- <Toast id="4" variant="error" message="Failed to save changes" onClose={() => {}} />
181
+ <Toast id="1" variant="success" message="Quest activated" onClose={() => {}} />
182
+ <Toast id="2" variant="info" message="You received 50 points" onClose={() => {}} />
183
+ <Toast id="3" variant="warning" message="Session about to expire" onClose={() => {}} />
184
+ <Toast id="4" variant="error" message="Failed to save" onClose={() => {}} />
185
185
  </div>
186
186
  );
187
187
  }
188
188
  ```
189
189
 
190
- ### Custom Duration
191
-
192
- Control how long toasts remain visible. The default is 5000ms. Set `duration: 0` to disable auto-dismiss entirely:
190
+ ### Custom duration
193
191
 
194
192
  ```tsx
193
+ import * as React from 'react';
195
194
  import { useToast } from '@xsolla/xui-toast';
196
195
 
197
- export default function CustomDuration() {
196
+ export default function Duration() {
198
197
  const toast = useToast();
199
-
200
198
  return (
201
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
202
- <button onClick={() => toast.toast({ message: 'Stays for 10 seconds', duration: 10000 })}>
203
- Long Duration (10s)
204
- </button>
205
- <button onClick={() => toast.toast({ message: 'Stays for 2 seconds', duration: 2000 })}>
206
- Short Duration (2s)
207
- </button>
208
- <button onClick={() => toast.toast({ message: 'Dismiss me manually', duration: 0 })}>
209
- No Auto-Dismiss
210
- </button>
199
+ <div style={{ display: 'flex', gap: 8 }}>
200
+ <button onClick={() => toast.toast({ message: 'Stays 10s', duration: 10000 })}>10s</button>
201
+ <button onClick={() => toast.toast({ message: 'Stays 2s', duration: 2000 })}>2s</button>
202
+ <button onClick={() => toast.toast({ message: 'Manual dismiss', duration: 0 })}>No auto-dismiss</button>
211
203
  </div>
212
204
  );
213
205
  }
214
206
  ```
215
207
 
216
- You can also set a global default duration on the provider:
217
-
218
- ```tsx
219
- <ToastProvider defaultDuration={3000}>
220
- <App />
221
- </ToastProvider>
222
- ```
223
-
224
- ### Custom Icons
225
-
226
- Override the default variant icon by passing a `ReactNode` via the `icon` option:
208
+ ### Custom icon
227
209
 
228
210
  ```tsx
211
+ import * as React from 'react';
229
212
  import { useToast } from '@xsolla/xui-toast';
230
- import { Star } from '@xsolla/xui-icons';
213
+ import { Star } from '@xsolla/xui-icons-base';
231
214
 
232
- function CustomIconExample() {
215
+ export default function CustomIcon() {
233
216
  const toast = useToast();
234
-
235
217
  return (
236
218
  <button
237
219
  onClick={() =>
238
- toast.toast({
239
- message: 'You earned a gold star!',
240
- variant: 'success',
241
- icon: <Star />,
242
- })
220
+ toast.toast({ message: 'You earned a gold star', variant: 'success', icon: <Star /> })
243
221
  }
244
222
  >
245
- Show Custom Icon Toast
223
+ Show
246
224
  </button>
247
225
  );
248
226
  }
249
227
  ```
250
228
 
251
- ### Dismissing Toasts Programmatically
252
-
253
- Every `toast.*()` call returns a unique ID. Use it to dismiss a specific toast:
229
+ ### Programmatic dismiss
254
230
 
255
231
  ```tsx
256
232
  import * as React from 'react';
257
233
  import { useToast } from '@xsolla/xui-toast';
258
234
 
259
- export default function DismissExample() {
235
+ export default function Dismiss() {
260
236
  const toast = useToast();
261
- const [lastToastId, setLastToastId] = React.useState<string | null>(null);
262
-
263
- const showToast = () => {
264
- const id = toast.info('New notification');
265
- setLastToastId(id);
266
- };
237
+ const [lastId, setLastId] = React.useState<string | null>(null);
267
238
 
268
239
  return (
269
240
  <div style={{ display: 'flex', gap: 8 }}>
270
- <button onClick={showToast}>Show Toast</button>
271
- <button onClick={() => lastToastId && toast.dismiss(lastToastId)}>
272
- Dismiss Last
273
- </button>
274
- <button onClick={() => toast.dismissAll()}>Dismiss All</button>
241
+ <button onClick={() => setLastId(toast.info('New notification'))}>Show</button>
242
+ <button onClick={() => lastId && toast.dismiss(lastId)}>Dismiss last</button>
243
+ <button onClick={() => toast.dismissAll()}>Dismiss all</button>
275
244
  </div>
276
245
  );
277
246
  }
278
247
  ```
279
248
 
280
- ### Position Configuration
281
-
282
- Toasts can be anchored to the top or bottom of the viewport:
249
+ ### Position and alignment
283
250
 
284
251
  ```tsx
252
+ import * as React from 'react';
285
253
  import { ToastProvider, useToast } from '@xsolla/xui-toast';
286
254
 
287
- function ToastTrigger() {
255
+ function Trigger() {
288
256
  const toast = useToast();
289
- return <button onClick={() => toast.info('Toast at the bottom!')}>Show Toast</button>;
257
+ return <button onClick={() => toast.info('Bottom-right toast')}>Show</button>;
290
258
  }
291
259
 
292
- export default function BottomPosition() {
260
+ export default function BottomRight() {
293
261
  return (
294
- <ToastProvider position="bottom">
295
- <ToastTrigger />
262
+ <ToastProvider position="bottom" align="right" maxWidth={400}>
263
+ <Trigger />
296
264
  </ToastProvider>
297
265
  );
298
266
  }
299
267
  ```
300
268
 
301
- ### Multiple Toasts
269
+ ### React Native
302
270
 
303
- Multiple toasts stack vertically in the order they are created:
271
+ The `useToast` hook is identical on React Native; use `onPress` instead of `onClick`.
304
272
 
305
273
  ```tsx
306
- import { useToast } from '@xsolla/xui-toast';
274
+ import * as React from 'react';
275
+ import { View } from 'react-native';
276
+ import { Button } from '@xsolla/xui-button';
277
+ import { XUIProvider } from '@xsolla/xui-core';
278
+ import { ToastProvider, useToast } from '@xsolla/xui-toast';
307
279
 
308
- function MultipleToastsExample() {
280
+ function Trigger() {
309
281
  const toast = useToast();
310
-
311
- const showMultiple = () => {
312
- toast.success('First toast - Success');
313
- setTimeout(() => toast.info('Second toast - Info'), 200);
314
- setTimeout(() => toast.warning('Third toast - Warning'), 400);
315
- };
316
-
317
- return <button onClick={showMultiple}>Show Multiple Toasts</button>;
282
+ return <Button onPress={() => toast.success('Saved')}>Save</Button>;
318
283
  }
319
- ```
320
-
321
- ## API Reference
322
-
323
- ### ToastProvider
324
-
325
- The root provider component that manages toast state and renders the toast container.
326
-
327
- | Prop | Type | Default | Description |
328
- | :--- | :--- | :------ | :---------- |
329
- | `children` | `ReactNode` | — | Application content. |
330
- | `position` | `"top" \| "bottom"` | `"top"` | Position of the toast container on screen. |
331
- | `defaultDuration` | `number` | `5000` | Default auto-dismiss duration in milliseconds. Set to `0` to disable auto-dismiss globally. |
332
- | `maxWidth` | `number` | `100%` | Maximum width of the toast container in pixels. If not set, toasts stretch to full viewport width. |
333
-
334
- ### useToast
335
-
336
- A hook that returns methods to show and dismiss toasts. Must be called within a `ToastProvider` — throws an error otherwise.
337
-
338
- **Return type: `UseToastReturn`**
339
-
340
- | Method | Signature | Description |
341
- | :----- | :-------- | :---------- |
342
- | `toast` | `(options: ToastOptions) => string` | Show a toast with full control over options. Returns the toast ID. |
343
- | `success` | `(message: string, options?) => string` | Show a success toast with a check icon. |
344
- | `info` | `(message: string, options?) => string` | Show an info toast with an info icon. |
345
- | `warning` | `(message: string, options?) => string` | Show a warning toast with an alert icon. |
346
- | `error` | `(message: string, options?) => string` | Show an error toast with an alert icon. |
347
- | `dismiss` | `(id: string) => void` | Dismiss a specific toast by its ID. |
348
- | `dismissAll` | `() => void` | Dismiss all visible toasts at once. |
349
-
350
- ### Toast
351
-
352
- The individual toast notification component. Used internally by `ToastGroup`, but can be rendered standalone for static display.
353
-
354
- | Prop | Type | Default | Description |
355
- | :--- | :--- | :------ | :---------- |
356
- | `id` | `string` | — | Unique identifier for the toast (required). |
357
- | `message` | `string` | — | Toast message text (required). |
358
- | `variant` | `"success" \| "info" \| "warning" \| "error"` | `"info"` | Visual variant that determines the icon color. |
359
- | `icon` | `ReactNode` | — | Custom icon element. When omitted, a default icon for the variant is used. |
360
- | `onClose` | `() => void` | — | Callback fired when the close button is clicked. If omitted, the close button is hidden. |
361
-
362
- ### ToastOptions
363
-
364
- Options object passed to the `toast()` method or as the second argument to shorthand methods.
365
-
366
- | Property | Type | Default | Description |
367
- | :------- | :--- | :------ | :---------- |
368
- | `message` | `string` | — | Toast message text (required). |
369
- | `variant` | `"success" \| "info" \| "warning" \| "error"` | `"info"` | Toast variant. |
370
- | `icon` | `ReactNode` | — | Custom icon element. |
371
- | `duration` | `number` | Provider's `defaultDuration` | Auto-dismiss duration in ms. Use `0` to keep the toast until manually dismissed. |
372
-
373
- ### ToastData
374
-
375
- Internal data structure for a toast instance (available via `ToastContext`).
376
-
377
- | Property | Type | Description |
378
- | :------- | :--- | :---------- |
379
- | `id` | `string` | Unique identifier generated by the provider. |
380
- | `variant` | `ToastVariant` | The toast variant. |
381
- | `message` | `string` | Toast message text. |
382
- | `icon` | `ReactNode \| undefined` | Custom icon, if provided. |
383
- | `duration` | `number \| undefined` | Auto-dismiss duration. |
384
-
385
- ### ToastContext
386
284
 
387
- The React context object. Typically consumed via `useToast`, but available for advanced use cases:
388
-
389
- ```tsx
390
- import { useContext } from 'react';
391
- import { ToastContext } from '@xsolla/xui-toast';
392
-
393
- function CustomToastConsumer() {
394
- const ctx = useContext(ToastContext);
395
- if (!ctx) throw new Error('Must be within ToastProvider');
396
-
397
- return <span>Active toasts: {ctx.toasts.length}</span>;
285
+ export default function App() {
286
+ return (
287
+ <XUIProvider initialMode="dark">
288
+ <ToastProvider position="top">
289
+ <View style={{ flex: 1 }}>
290
+ <Trigger />
291
+ </View>
292
+ </ToastProvider>
293
+ </XUIProvider>
294
+ );
398
295
  }
399
296
  ```
400
297
 
401
- ### Variant Reference
402
-
403
- | Variant | Use Case | Default Icon | Icon Color Theme Path |
404
- | :------ | :------- | :----------- | :-------------------- |
405
- | `success` | Positive outcomes, confirmations | `<Check />` | `theme.colors.content.success.primary` |
406
- | `info` | General information, neutral messages | `<AlertCircle />` | `theme.colors.content.inverse` |
407
- | `warning` | Caution, requires user attention | `<AlertCircle />` | `theme.colors.content.warning.primary` |
408
- | `error` | Errors, failures, critical issues | `<AlertCircle />` | `theme.colors.content.alert.primary` |
409
-
410
- ## Theming
411
-
412
- Toast uses the **inverse** color scheme (dark background with light text) to stand out from the application content:
413
-
414
- ### Colors
415
-
416
- ```typescript
417
- theme.colors.background.inverse // Toast background
418
- theme.colors.content.inverse // Toast text and info icon color
419
-
420
- theme.colors.content.success.primary // Success icon color
421
- theme.colors.content.warning.primary // Warning icon color
422
- theme.colors.content.alert.primary // Error icon color
423
- ```
424
-
425
- ### Sizing
426
-
427
- Toast dimensions come from `theme.sizing.toast()`:
428
-
429
- | Token | Value | Description |
430
- | :---- | :---- | :---------- |
431
- | `minHeight` | `64` | Minimum toast height |
432
- | `paddingHorizontal` | `12` | Left/right padding |
433
- | `paddingVertical` | `8` | Top/bottom padding |
434
- | `borderRadius` | `4` | Corner radius |
435
- | `gap` | `12` | Space between icon, text, and close button |
436
- | `iconSize` | `24` | Icon dimensions |
437
- | `closeButtonSize` | `24` | Close button tap target |
438
- | `closeIconSize` | `20` | Close icon dimensions |
439
- | `fontSize` | `16` | Message text size |
440
- | `lineHeight` | `20` | Message line height |
441
- | `maxWidth` | `400` | Maximum toast width (theme default; overridden by `ToastProvider maxWidth` prop) |
442
- | `containerPadding` | `12` | Padding between toast container and screen edges |
443
- | `groupGap` | `4` | Vertical gap between stacked toasts |
444
-
445
- ## Platform Support
446
-
447
- This package supports both React (web) and React Native with an identical API.
448
-
449
- ### React (Web)
450
-
451
- - Uses `ReactDOM.createPortal` to render toasts at the document body level
452
- - Toasts appear above all other content regardless of z-index stacking contexts
453
- - Works with any React web framework (Next.js, Vite, Create React App, Remix, etc.)
454
-
455
- ### React Native
456
-
457
- - Uses absolute positioning within the app container
458
- - Toasts render within the component tree (no portal equivalent in RN)
459
- - Works with React Navigation, Expo, and bare React Native projects
298
+ ## Platform support
460
299
 
461
- ### Cross-Platform Comparison
462
-
463
- | Feature | Web | React Native |
464
- | :------ | :-- | :----------- |
465
- | Provider setup | `ToastProvider` | `XUIProvider` + `ToastProvider` |
466
- | Hook API | `useToast()` | `useToast()` (identical) |
300
+ | Aspect | Web | React Native |
301
+ | --- | --- | --- |
302
+ | Rendering | `ReactDOM.createPortal` to `document.body` | Absolute-positioned `Box` in tree |
467
303
  | Event handlers | `onClick` | `onPress` |
468
304
  | Root container | Any element | Must have `flex: 1` |
469
- | Position: top | Fixed to viewport top | Absolute to container top |
470
- | Position: bottom | Fixed to viewport bottom | Absolute to container bottom |
471
- | Rendering | `ReactDOM.createPortal` into `document.body` | Absolute-positioned `Box` in tree |
472
-
473
- ### React Native Example with Navigation
474
-
475
- ```tsx
476
- import React from 'react';
477
- import { NavigationContainer } from '@react-navigation/native';
478
- import { SafeAreaProvider } from 'react-native-safe-area-context';
479
- import { XUIProvider } from '@xsolla/xui-core';
480
- import { ToastProvider } from '@xsolla/xui-toast';
481
- import { RootNavigator } from './navigation';
482
-
483
- export default function App() {
484
- return (
485
- <SafeAreaProvider>
486
- <XUIProvider mode="dark">
487
- <ToastProvider position="top">
488
- <NavigationContainer>
489
- <RootNavigator />
490
- </NavigationContainer>
491
- </ToastProvider>
492
- </XUIProvider>
493
- </SafeAreaProvider>
494
- );
495
- }
496
- ```
497
305
 
498
306
  ## Accessibility
499
307
 
500
- - Each toast renders with `role="alert"` and `aria-live="polite"` for screen reader announcements
501
- - The close button includes `aria-label="Dismiss toast"` for assistive technology
502
- - Icons are decorative and do not interfere with accessibility
503
- - Keyboard users can Tab to the close button and press Enter to dismiss
504
- - Toast messages are limited to 2 lines (`numberOfLines={2}`) for readability
308
+ - Each toast renders with `role="alert"` and `aria-live="polite"` for assistive technology.
309
+ - The close button has `aria-label="Dismiss toast"` and is keyboard-focusable.
310
+ - Default icons are decorative.
311
+ - Messages clamp to 2 lines for readability.
505
312
 
506
313
  ## Troubleshooting
507
314
 
508
- ### "useToast must be used within a ToastProvider"
509
-
510
- The `useToast` hook was called in a component that is not a descendant of `ToastProvider`. Ensure your component tree has a `ToastProvider` ancestor:
511
-
512
- ```tsx
513
- // Correct — hook is inside the provider tree
514
- <ToastProvider>
515
- <ComponentThatCallsUseToast />
516
- </ToastProvider>
517
-
518
- // Wrong — hook is outside the provider
519
- <ComponentThatCallsUseToast />
520
- <ToastProvider>
521
- <OtherContent />
522
- </ToastProvider>
523
- ```
524
-
525
- ### Toasts not visible on React Native
526
-
527
- Make sure the container inside `ToastProvider` has `flex: 1`. Without this, the absolute-positioned toast group has no reference height:
528
-
529
- ```tsx
530
- <ToastProvider>
531
- <View style={{ flex: 1 }}> {/* Required */}
532
- <App />
533
- </View>
534
- </ToastProvider>
535
- ```
536
-
537
- ### Toasts appear behind a modal or overlay
538
-
539
- On web, `ToastGroup` uses `z-index: 9999`. If your modal or overlay uses a higher z-index, the toasts may be hidden. Consider placing the `ToastProvider` above your modal provider in the tree, or adjusting z-index values.
315
+ - **"useToast must be used within a ToastProvider"** — ensure the calling component is a descendant of `ToastProvider`.
316
+ - **Toasts hidden on React Native** — wrap content in `<View style={{ flex: 1 }}>` inside `ToastProvider`.
317
+ - **Toasts appear behind a modal (web)** `ToastGroup` uses `z-index: 9999`. Place `ToastProvider` above the modal in the tree, or adjust z-index.
318
+ - **Auto-dismiss not working** — `duration: 0` disables auto-dismiss; check both per-toast and provider defaults.
540
319
 
541
- ### Auto-dismiss not working
320
+ ## Related
542
321
 
543
- Ensure `duration` is not set to `0`. A duration of `0` disables auto-dismiss. Check both the per-toast `duration` option and the provider's `defaultDuration` prop.
322
+ - [Notification](./notification.md) declarative toast/inline notification.
323
+ - [NotificationPanel](./notification-panel.md) — full-width inline banner.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-toast",
3
- "version": "0.150.0",
3
+ "version": "0.151.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -14,9 +14,9 @@
14
14
  "test:coverage": "vitest run --coverage"
15
15
  },
16
16
  "dependencies": {
17
- "@xsolla/xui-core": "0.150.0",
18
- "@xsolla/xui-icons": "0.150.0",
19
- "@xsolla/xui-primitives-core": "0.150.0"
17
+ "@xsolla/xui-core": "0.151.0",
18
+ "@xsolla/xui-icons": "0.151.0",
19
+ "@xsolla/xui-primitives-core": "0.151.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "react": ">=16.8.0",