@pushwoosh/dumb-components 1.1.39 → 1.1.41

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.
@@ -0,0 +1,475 @@
1
+ # Tabs Component System - @pushwoosh/dumb-components
2
+
3
+ ## Overview
4
+
5
+ - **Component Name**: Tabs (System)
6
+ - **Import Path**: `@pushwoosh/dumb-components`
7
+ - **Files**:
8
+ - `/src/Tabs/index.tsx` - Main exports
9
+ - `/src/Tabs/types.ts` - Core type definitions
10
+ - `/src/Tabs/context.tsx` - React context for tab state
11
+ - `/src/Tabs/helpers.tsx` - Helper utilities
12
+ - `/src/Tabs/components/Tabs/` - Main Tabs container
13
+ - `/src/Tabs/components/Tab/` - Individual Tab component
14
+ - `/src/Tabs/components/TabBar/` - Tab navigation bar
15
+ - `/src/Tabs/components/TabPanel/` - Tab content panel
16
+ - `/src/Tabs/components/TabBase/` - Base tab styling
17
+ - `/src/Tabs/components/TabBarScrollableFrame/` - Scrollable tab container
18
+ - **Type**: Navigation/Layout
19
+ - **Description**: A complete tab system with multiple components for creating tabbed interfaces. Supports controlled state management, custom containers, icons, disabled states, and new item indicators.
20
+
21
+ ## TypeScript Interfaces
22
+
23
+ ```typescript
24
+ export type TabCode = string | number;
25
+
26
+ export type TabContextType = {
27
+ activeTabCode: TabCode;
28
+ setActiveTabCode: (code: TabCode) => void;
29
+ };
30
+
31
+ // Main Tabs container
32
+ export type TabsProps = PropsWithChildren<Readonly<{
33
+ activeCode: TabCode;
34
+ onChange: (code: TabCode) => void;
35
+ container?: ElementType;
36
+ }>>;
37
+
38
+ // Individual Tab
39
+ export type TabProps = Omit<JSX.IntrinsicElements['div'], 'ref' | 'onClick'> & Readonly<{
40
+ code: TabCode;
41
+ onActivate?: (code: TabCode) => void;
42
+ isDisabled?: boolean;
43
+ isNew?: boolean;
44
+ icon?: ReactNode;
45
+ }>;
46
+
47
+ // Tab Bar (navigation container)
48
+ export type TabBarProps = Omit<JSX.IntrinsicElements['div'], 'ref'> & Readonly<{
49
+ title?: ReactNode;
50
+ }>;
51
+
52
+ // Tab Panel (content container)
53
+ export type TabPanelProps = PropsWithChildren<Readonly<{
54
+ code: TabCode;
55
+ container?: ElementType;
56
+ }>>;
57
+ ```
58
+
59
+ ## Import & Usage
60
+
61
+ ```typescript
62
+ import { Tabs, Tab, TabBar, TabPanel } from '@pushwoosh/dumb-components';
63
+
64
+ // Basic usage
65
+ function MyTabs() {
66
+ const [activeTab, setActiveTab] = useState('tab1');
67
+
68
+ return (
69
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
70
+ <TabBar>
71
+ <Tab code="tab1">First Tab</Tab>
72
+ <Tab code="tab2">Second Tab</Tab>
73
+ <Tab code="tab3">Third Tab</Tab>
74
+ </TabBar>
75
+
76
+ <TabPanel code="tab1">
77
+ <h3>First Panel</h3>
78
+ <p>Content for the first tab</p>
79
+ </TabPanel>
80
+
81
+ <TabPanel code="tab2">
82
+ <h3>Second Panel</h3>
83
+ <p>Content for the second tab</p>
84
+ </TabPanel>
85
+
86
+ <TabPanel code="tab3">
87
+ <h3>Third Panel</h3>
88
+ <p>Content for the third tab</p>
89
+ </TabPanel>
90
+ </Tabs>
91
+ );
92
+ }
93
+
94
+ // With tab bar title
95
+ function TitledTabs() {
96
+ const [activeTab, setActiveTab] = useState('overview');
97
+
98
+ return (
99
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
100
+ <TabBar title="Dashboard Settings">
101
+ <Tab code="overview">Overview</Tab>
102
+ <Tab code="users">Users</Tab>
103
+ <Tab code="billing">Billing</Tab>
104
+ </TabBar>
105
+
106
+ <TabPanel code="overview">Overview content</TabPanel>
107
+ <TabPanel code="users">User management</TabPanel>
108
+ <TabPanel code="billing">Billing information</TabPanel>
109
+ </Tabs>
110
+ );
111
+ }
112
+ ```
113
+
114
+ ## Advanced Examples
115
+
116
+ ```typescript
117
+ // Tabs with icons and states
118
+ function AdvancedTabs() {
119
+ const [activeTab, setActiveTab] = useState('dashboard');
120
+
121
+ return (
122
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
123
+ <TabBar title="Application">
124
+ <Tab
125
+ code="dashboard"
126
+ icon={<DashboardIcon />}
127
+ >
128
+ Dashboard
129
+ </Tab>
130
+
131
+ <Tab
132
+ code="notifications"
133
+ icon={<BellIcon />}
134
+ isNew={true}
135
+ >
136
+ Notifications
137
+ </Tab>
138
+
139
+ <Tab
140
+ code="settings"
141
+ icon={<SettingsIcon />}
142
+ >
143
+ Settings
144
+ </Tab>
145
+
146
+ <Tab
147
+ code="archive"
148
+ icon={<ArchiveIcon />}
149
+ isDisabled={true}
150
+ >
151
+ Archive
152
+ </Tab>
153
+ </TabBar>
154
+
155
+ <TabPanel code="dashboard">
156
+ <div>Dashboard content with charts and metrics</div>
157
+ </TabPanel>
158
+
159
+ <TabPanel code="notifications">
160
+ <div>New notification system</div>
161
+ </TabPanel>
162
+
163
+ <TabPanel code="settings">
164
+ <div>Application settings</div>
165
+ </TabPanel>
166
+
167
+ <TabPanel code="archive">
168
+ <div>Archived items (disabled)</div>
169
+ </TabPanel>
170
+ </Tabs>
171
+ );
172
+ }
173
+
174
+ // Dynamic tabs with add/remove functionality
175
+ function DynamicTabs() {
176
+ const [tabs, setTabs] = useState([
177
+ { code: 'tab-1', title: 'Tab 1', content: 'Content 1' },
178
+ { code: 'tab-2', title: 'Tab 2', content: 'Content 2' },
179
+ ]);
180
+ const [activeTab, setActiveTab] = useState('tab-1');
181
+ const [counter, setCounter] = useState(3);
182
+
183
+ const addTab = () => {
184
+ const newTab = {
185
+ code: `tab-${counter}`,
186
+ title: `Tab ${counter}`,
187
+ content: `Content for tab ${counter}`,
188
+ };
189
+ setTabs(prev => [...prev, newTab]);
190
+ setActiveTab(newTab.code);
191
+ setCounter(prev => prev + 1);
192
+ };
193
+
194
+ const removeTab = (codeToRemove: string) => {
195
+ setTabs(prev => prev.filter(tab => tab.code !== codeToRemove));
196
+
197
+ // Switch to first tab if active tab is removed
198
+ if (activeTab === codeToRemove && tabs.length > 1) {
199
+ const remainingTabs = tabs.filter(tab => tab.code !== codeToRemove);
200
+ setActiveTab(remainingTabs[0].code);
201
+ }
202
+ };
203
+
204
+ return (
205
+ <div>
206
+ <button onClick={addTab}>Add Tab</button>
207
+
208
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
209
+ <TabBar>
210
+ {tabs.map(tab => (
211
+ <Tab
212
+ key={tab.code}
213
+ code={tab.code}
214
+ style={{ display: 'flex', alignItems: 'center', gap: '8px' }}
215
+ >
216
+ {tab.title}
217
+ {tabs.length > 1 && (
218
+ <button
219
+ onClick={(e) => {
220
+ e.stopPropagation();
221
+ removeTab(tab.code);
222
+ }}
223
+ style={{
224
+ marginLeft: '8px',
225
+ padding: '2px 4px',
226
+ fontSize: '12px'
227
+ }}
228
+ >
229
+ ×
230
+ </button>
231
+ )}
232
+ </Tab>
233
+ ))}
234
+ </TabBar>
235
+
236
+ {tabs.map(tab => (
237
+ <TabPanel key={tab.code} code={tab.code}>
238
+ <div>{tab.content}</div>
239
+ </TabPanel>
240
+ ))}
241
+ </Tabs>
242
+ </div>
243
+ );
244
+ }
245
+
246
+ // Form tabs with validation states
247
+ function FormTabs() {
248
+ const [activeTab, setActiveTab] = useState('personal');
249
+ const [formErrors, setFormErrors] = useState<{[key: string]: boolean}>({});
250
+
251
+ const hasErrors = (tabCode: string) => formErrors[tabCode];
252
+
253
+ return (
254
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
255
+ <TabBar title="User Profile">
256
+ <Tab
257
+ code="personal"
258
+ style={{
259
+ color: hasErrors('personal') ? '#dc3545' : undefined
260
+ }}
261
+ >
262
+ Personal Info
263
+ {hasErrors('personal') && <span style={{color: '#dc3545'}}>*</span>}
264
+ </Tab>
265
+
266
+ <Tab
267
+ code="contact"
268
+ style={{
269
+ color: hasErrors('contact') ? '#dc3545' : undefined
270
+ }}
271
+ >
272
+ Contact Details
273
+ {hasErrors('contact') && <span style={{color: '#dc3545'}}>*</span>}
274
+ </Tab>
275
+
276
+ <Tab code="preferences">
277
+ Preferences
278
+ </Tab>
279
+ </TabBar>
280
+
281
+ <TabPanel code="personal">
282
+ <form>
283
+ <input placeholder="First Name" required />
284
+ <input placeholder="Last Name" required />
285
+ <input placeholder="Date of Birth" type="date" />
286
+ </form>
287
+ </TabPanel>
288
+
289
+ <TabPanel code="contact">
290
+ <form>
291
+ <input placeholder="Email" type="email" required />
292
+ <input placeholder="Phone" type="tel" />
293
+ <textarea placeholder="Address"></textarea>
294
+ </form>
295
+ </TabPanel>
296
+
297
+ <TabPanel code="preferences">
298
+ <form>
299
+ <label>
300
+ <input type="checkbox" /> Email notifications
301
+ </label>
302
+ <label>
303
+ <input type="checkbox" /> SMS notifications
304
+ </label>
305
+ </form>
306
+ </TabPanel>
307
+ </Tabs>
308
+ );
309
+ }
310
+
311
+ // Custom containers and styling
312
+ function CustomStyledTabs() {
313
+ const [activeTab, setActiveTab] = useState('code');
314
+
315
+ const CustomTabsContainer = styled.div`
316
+ background: #f8f9fa;
317
+ border-radius: 8px;
318
+ padding: 16px;
319
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
320
+ `;
321
+
322
+ const CustomPanelContainer = styled.div`
323
+ background: white;
324
+ padding: 24px;
325
+ border-radius: 4px;
326
+ min-height: 200px;
327
+ `;
328
+
329
+ return (
330
+ <Tabs
331
+ activeCode={activeTab}
332
+ onChange={setActiveTab}
333
+ container={CustomTabsContainer}
334
+ >
335
+ <TabBar title="Code Editor">
336
+ <Tab code="code" icon={<CodeIcon />}>Code</Tab>
337
+ <Tab code="preview" icon={<EyeIcon />}>Preview</Tab>
338
+ <Tab code="console" icon={<TerminalIcon />}>Console</Tab>
339
+ </TabBar>
340
+
341
+ <TabPanel code="code" container={CustomPanelContainer}>
342
+ <pre><code>function hello() {`\n`} console.log('Hello World!');{`\n`}}</code></pre>
343
+ </TabPanel>
344
+
345
+ <TabPanel code="preview" container={CustomPanelContainer}>
346
+ <iframe src="/preview" style={{width: '100%', height: '300px'}}></iframe>
347
+ </TabPanel>
348
+
349
+ <TabPanel code="console" container={CustomPanelContainer}>
350
+ <div style={{fontFamily: 'monospace', background: '#000', color: '#fff', padding: '12px'}}>
351
+ > Hello World!
352
+ </div>
353
+ </TabPanel>
354
+ </Tabs>
355
+ );
356
+ }
357
+ ```
358
+
359
+ ## Props Reference
360
+
361
+ ### Tabs (Main Container)
362
+
363
+ | Prop | Type | Default | Required | Description |
364
+ |------|------|---------|----------|-------------|
365
+ | `activeCode` | `TabCode` | - | Yes | Currently active tab code |
366
+ | `onChange` | `(code: TabCode) => void` | - | Yes | Callback when active tab changes |
367
+ | `container` | `ElementType` | `TabsContainer` | No | Custom container component |
368
+ | `children` | `ReactNode` | - | Yes | Tab bar and panels |
369
+
370
+ ### Tab (Individual Tab)
371
+
372
+ | Prop | Type | Default | Required | Description |
373
+ |------|------|---------|----------|-------------|
374
+ | `code` | `TabCode` | - | Yes | Unique identifier for the tab |
375
+ | `onActivate` | `(code: TabCode) => void` | `undefined` | No | Callback when tab is activated |
376
+ | `isDisabled` | `boolean` | `false` | No | Whether the tab is disabled |
377
+ | `isNew` | `boolean` | `false` | No | Whether to show "new" indicator |
378
+ | `icon` | `ReactNode` | `undefined` | No | Icon to display in the tab |
379
+ | `children` | `ReactNode` | - | Yes | Tab label content |
380
+
381
+ ### TabBar (Navigation Container)
382
+
383
+ | Prop | Type | Default | Required | Description |
384
+ |------|------|---------|----------|-------------|
385
+ | `title` | `ReactNode` | `undefined` | No | Optional title above tabs |
386
+ | `children` | `ReactNode` | - | Yes | Tab components |
387
+
388
+ ### TabPanel (Content Panel)
389
+
390
+ | Prop | Type | Default | Required | Description |
391
+ |------|------|---------|----------|-------------|
392
+ | `code` | `TabCode` | - | Yes | Tab code this panel belongs to |
393
+ | `container` | `ElementType` | `TabPanelContainer` | No | Custom container component |
394
+ | `children` | `ReactNode` | - | Yes | Panel content |
395
+
396
+ ## AI Agent Guidelines
397
+
398
+ ### Recommended Patterns
399
+
400
+ 1. **Controlled State**: Always use controlled tab state
401
+ ```typescript
402
+ const [activeTab, setActiveTab] = useState('defaultTab');
403
+
404
+ <Tabs activeCode={activeTab} onChange={setActiveTab}>
405
+ {/* tabs and panels */}
406
+ </Tabs>
407
+ ```
408
+
409
+ 2. **Consistent Codes**: Use consistent, meaningful tab codes
410
+ ```typescript
411
+ // Good - descriptive codes
412
+ <Tab code="user-profile">Profile</Tab>
413
+ <Tab code="account-settings">Settings</Tab>
414
+
415
+ // Avoid - generic or unclear codes
416
+ <Tab code="1">Profile</Tab>
417
+ <Tab code="tab2">Settings</Tab>
418
+ ```
419
+
420
+ 3. **Panel Matching**: Ensure every Tab has a matching TabPanel
421
+ ```typescript
422
+ <TabBar>
423
+ <Tab code="overview">Overview</Tab>
424
+ <Tab code="details">Details</Tab>
425
+ </TabBar>
426
+
427
+ <TabPanel code="overview">...</TabPanel>
428
+ <TabPanel code="details">...</TabPanel>
429
+ ```
430
+
431
+ ### Common Mistakes to Avoid
432
+
433
+ 1. **Missing TabBar**: Don't put Tab components directly in Tabs without TabBar
434
+ 2. **Mismatched Codes**: Ensure Tab and TabPanel codes match exactly
435
+ 3. **Missing onChange**: Always provide an onChange handler
436
+ 4. **Uncontrolled State**: Don't mix controlled and uncontrolled patterns
437
+ 5. **Invalid HTML**: Tab content should be properly structured HTML
438
+
439
+ ### Integration Tips
440
+
441
+ 1. **State Management**: Works well with global state management
442
+ ```typescript
443
+ // Redux integration
444
+ const activeTab = useSelector(state => state.ui.activeTab);
445
+ const dispatch = useDispatch();
446
+
447
+ <Tabs
448
+ activeCode={activeTab}
449
+ onChange={(code) => dispatch(setActiveTab(code))}
450
+ >
451
+ ```
452
+
453
+ 2. **Routing Integration**: Sync tabs with URL routing
454
+ ```typescript
455
+ const navigate = useNavigate();
456
+ const location = useLocation();
457
+
458
+ const activeTab = location.pathname.split('/').pop() || 'overview';
459
+
460
+ <Tabs
461
+ activeCode={activeTab}
462
+ onChange={(code) => navigate(`/dashboard/${code}`)}
463
+ >
464
+ ```
465
+
466
+ 3. **Form Integration**: Use tabs for multi-step forms
467
+ 4. **Accessibility**: Components handle ARIA attributes and keyboard navigation automatically
468
+ 5. **Performance**: TabPanels only render when active (conditional rendering)
469
+
470
+ ## Related Components
471
+
472
+ - **Button**: For tab-like button groups
473
+ - **Modal**: For modal dialogs with tabbed content
474
+ - **Accordion**: Alternative for collapsible content sections
475
+ - **Drawer**: For side navigation with tab-like behavior
@@ -0,0 +1,230 @@
1
+ # Toast Component Documentation
2
+
3
+ ## Component Overview
4
+
5
+ The Toast component provides a notification system with provider/context pattern for global toast management. It displays temporary messages to users with different types (info, success, warning, error) and supports custom content.
6
+
7
+ ## Component Structure
8
+
9
+ - `Toast.tsx` - Main toast component with portal rendering
10
+ - `ToastProvider.tsx` - Context provider for global toast management
11
+ - `hooks.ts` - useToast hook for consuming toast context
12
+ - `types.ts` - TypeScript interfaces and type definitions
13
+ - `constants.ts` - Default values and type color mappings
14
+ - `styles.ts` - Styled components for toast styling
15
+
16
+ ## TypeScript Interfaces
17
+
18
+ ```typescript
19
+ export type ToastType = 'info' | 'success' | 'warning' | 'error';
20
+
21
+ export type ToastParams = {
22
+ title: string;
23
+ description?: string;
24
+ duration: number;
25
+ type: ToastType;
26
+ additionalContent?: ReactNode;
27
+ };
28
+
29
+ export type OpenToastParams = {
30
+ title: string;
31
+ description?: string;
32
+ duration?: number;
33
+ type?: ToastType;
34
+ additionalContent?: ReactNode;
35
+ };
36
+
37
+ export interface ToastContextProps {
38
+ openToast: (params: OpenToastParams) => void;
39
+ closeToast: () => void;
40
+ }
41
+
42
+ export interface ToastProviderProps {
43
+ children: ReactNode;
44
+ }
45
+
46
+ export interface ToastProps {
47
+ open: boolean;
48
+ toast: ToastParams;
49
+ onClose: () => void;
50
+ }
51
+ ```
52
+
53
+ ## Usage Examples
54
+
55
+ ### Basic Setup with Provider
56
+
57
+ ```tsx
58
+ import { ToastProvider } from '@pushwoosh/dumb-components';
59
+
60
+ function App() {
61
+ return (
62
+ <ToastProvider>
63
+ <YourAppContent />
64
+ </ToastProvider>
65
+ );
66
+ }
67
+ ```
68
+
69
+ ### Using Toast Hook
70
+
71
+ ```tsx
72
+ import { useToast } from '@pushwoosh/dumb-components';
73
+
74
+ function MyComponent() {
75
+ const { openToast, closeToast } = useToast();
76
+
77
+ const handleSuccess = () => {
78
+ openToast({
79
+ title: 'Success!',
80
+ description: 'Your action was completed successfully.',
81
+ type: 'success',
82
+ duration: 3000,
83
+ });
84
+ };
85
+
86
+ const handleError = () => {
87
+ openToast({
88
+ title: 'Error occurred',
89
+ description: 'Please try again later.',
90
+ type: 'error',
91
+ duration: 5000,
92
+ });
93
+ };
94
+
95
+ return (
96
+ <div>
97
+ <button onClick={handleSuccess}>Show Success</button>
98
+ <button onClick={handleError}>Show Error</button>
99
+ <button onClick={closeToast}>Close Toast</button>
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ### Toast with Custom Content
106
+
107
+ ```tsx
108
+ import { useToast } from '@pushwoosh/dumb-components';
109
+
110
+ function ComponentWithCustomToast() {
111
+ const { openToast } = useToast();
112
+
113
+ const handleCustomToast = () => {
114
+ openToast({
115
+ title: 'Custom Toast',
116
+ description: 'This toast has additional content.',
117
+ type: 'info',
118
+ additionalContent: (
119
+ <div style={{ marginTop: 8 }}>
120
+ <button>Action 1</button>
121
+ <button>Action 2</button>
122
+ </div>
123
+ ),
124
+ });
125
+ };
126
+
127
+ return <button onClick={handleCustomToast}>Show Custom Toast</button>;
128
+ }
129
+ ```
130
+
131
+ ## Props Reference
132
+
133
+ ### ToastProvider Props
134
+
135
+ | Prop | Type | Required | Description |
136
+ |------|------|----------|-------------|
137
+ | children | ReactNode | Yes | Child components that can access toast context |
138
+
139
+ ### useToast Hook Returns
140
+
141
+ | Property | Type | Description |
142
+ |----------|------|-------------|
143
+ | openToast | (params: OpenToastParams) => void | Function to open a new toast |
144
+ | closeToast | () => void | Function to close current toast |
145
+
146
+ ### OpenToastParams
147
+
148
+ | Prop | Type | Required | Default | Description |
149
+ |------|------|----------|---------|-------------|
150
+ | title | string | Yes | - | Main toast title |
151
+ | description | string | No | - | Optional description text |
152
+ | duration | number | No | 3000 | Toast display duration in milliseconds |
153
+ | type | ToastType | No | 'info' | Toast type affecting icon and color |
154
+ | additionalContent | ReactNode | No | - | Custom content to display below description |
155
+
156
+ ### Toast Types
157
+
158
+ - `'info'` - Blue info icon with bright color
159
+ - `'success'` - Green checkmark icon
160
+ - `'warning'` - Orange warning icon
161
+ - `'error'` - Red danger triangle icon
162
+
163
+ ## Features
164
+
165
+ ### Auto-dismissal
166
+ Toasts automatically close after the specified duration (default 3000ms).
167
+
168
+ ### Manual Dismissal
169
+ Users can manually close toasts using the close button or the closeToast function.
170
+
171
+ ### Portal Rendering
172
+ Toasts are rendered using React portals to document.body for proper z-index layering.
173
+
174
+ ### Global State Management
175
+ Single toast instance managed through React Context for application-wide access.
176
+
177
+ ### Type-based Styling
178
+ Different toast types have distinct icons and border colors for visual differentiation.
179
+
180
+ ## Constants
181
+
182
+ ```typescript
183
+ export const DEFAULT_DURATION = 3000;
184
+
185
+ export const TypeColorMap = {
186
+ info: Color.BRIGHT,
187
+ success: Color.SUCCESS,
188
+ warning: Color.WARNING,
189
+ error: Color.DANGER,
190
+ };
191
+ ```
192
+
193
+ ## Styling
194
+
195
+ The toast uses a fixed positioning system:
196
+ - Positioned at top center of the viewport (50px from top when open)
197
+ - 380px width with responsive design
198
+ - Slide animation from top (-250px when closed)
199
+ - High z-index (999999999) for overlay display
200
+ - Border color matches toast type
201
+ - Large shadow for elevation
202
+
203
+ ## AI Agent Guidelines
204
+
205
+ When working with the Toast component:
206
+
207
+ 1. **Provider Setup**: Always ensure ToastProvider wraps the application root for global access
208
+ 2. **Hook Usage**: Use useToast hook only within components wrapped by ToastProvider
209
+ 3. **Error Handling**: The hook throws an error if used outside of provider context
210
+ 4. **Duration Management**: Consider appropriate duration based on toast importance and content length
211
+ 5. **Type Selection**: Choose appropriate toast type based on user action outcome
212
+ 6. **Custom Content**: Use additionalContent for action buttons or extra information
213
+ 7. **Accessibility**: Toast messages should be descriptive for screen readers
214
+ 8. **Portal Rendering**: Remember that toasts render to document.body, not inline
215
+ 9. **Single Instance**: Only one toast displays at a time; new toasts replace current ones
216
+ 10. **Manual Control**: Provide manual close options for important messages or longer durations
217
+
218
+ ### Common Use Cases
219
+ - Success confirmations after form submissions
220
+ - Error messages for failed operations
221
+ - Information notices about system changes
222
+ - Warning messages before destructive actions
223
+ - Progress notifications with custom action buttons
224
+
225
+ ### Best Practices
226
+ - Keep titles concise and descriptive
227
+ - Use descriptions for additional context
228
+ - Choose appropriate durations (3s for success, 5s+ for errors)
229
+ - Provide manual close for critical messages
230
+ - Test toast behavior in different viewport sizes