torch-glare 2.5.5 → 2.6.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.
- package/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -338
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -317
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -383
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -84
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -63
- package/apps/lib/components/DataViews/states.tsx +0 -38
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -420
- package/apps/lib/components/DropdownMenu.tsx +0 -540
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -73
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -163
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -91
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -47
- package/apps/lib/components/FormBuilder/types.ts +0 -311
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -128
- package/apps/lib/components/FormRenderer/detail.tsx +0 -207
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -297
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -15
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -339
- package/apps/lib/components/FormRenderer/types.ts +0 -78
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -147
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -253
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -610
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -58
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -214
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1201
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -712
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1495
- package/docs/components/data-views/migration.md +0 -79
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -276
- package/docs/components/form-renderer.md +0 -326
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -477
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -54
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1500
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -704
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
package/docs/components/toast.md
DELETED
|
@@ -1,773 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Toast
|
|
3
|
-
description: Customizable toast notification system built on react-hot-toast with themed variants and flexible positioning
|
|
4
|
-
group: Feedback & Status
|
|
5
|
-
keywords: [toast, notification, message, alert, feedback, react-hot-toast]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Toast
|
|
9
|
-
|
|
10
|
-
> A customizable toast notification system built on react-hot-toast, providing temporary notifications with multiple variants (success, error, loading, info), automatic theming, and flexible positioning options.
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
15
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npx torch-glare@latest init
|
|
19
|
-
npx torch-glare@latest add Toast
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `Toast` depends on.
|
|
23
|
-
|
|
24
|
-
## Import
|
|
25
|
-
|
|
26
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import { Toast } from "@/components/Toast";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Setup
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { Toaster, toast } from "@/components/Toast";
|
|
38
|
-
import { Button } from "@/components/Button";
|
|
39
|
-
|
|
40
|
-
function App() {
|
|
41
|
-
return (
|
|
42
|
-
<div>
|
|
43
|
-
<Toaster />
|
|
44
|
-
<Button onClick={() => toast('Hello World!')}>
|
|
45
|
-
Show Toast
|
|
46
|
-
</Button>
|
|
47
|
-
</div>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Success Toast
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
import { toast } from "@/components/Toast";
|
|
56
|
-
import { Button } from "@/components/Button";
|
|
57
|
-
|
|
58
|
-
function SuccessExample() {
|
|
59
|
-
const handleSuccess = () => {
|
|
60
|
-
toast.success('Operation completed successfully!')
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<Button onClick={handleSuccess}>
|
|
65
|
-
Save Changes
|
|
66
|
-
</Button>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Error Toast
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { toast } from "@/components/Toast";
|
|
75
|
-
import { Button } from "@/components/Button";
|
|
76
|
-
|
|
77
|
-
function ErrorExample() {
|
|
78
|
-
const handleError = () => {
|
|
79
|
-
toast.error('Failed to save changes. Please try again.')
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<Button onClick={handleError}>
|
|
84
|
-
Trigger Error
|
|
85
|
-
</Button>
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Loading Toast
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { toast } from "@/components/Toast";
|
|
94
|
-
import { Button } from "@/components/Button";
|
|
95
|
-
|
|
96
|
-
function LoadingExample() {
|
|
97
|
-
const handleAsync = async () => {
|
|
98
|
-
const toastId = toast.loading('Uploading file...')
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
await uploadFile()
|
|
102
|
-
toast.success('File uploaded successfully!', { id: toastId })
|
|
103
|
-
} catch (error) {
|
|
104
|
-
toast.error('Upload failed', { id: toastId })
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<Button onClick={handleAsync}>
|
|
110
|
-
Upload File
|
|
111
|
-
</Button>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Promise Toast
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { toast } from "@/components/Toast";
|
|
120
|
-
|
|
121
|
-
function PromiseExample() {
|
|
122
|
-
const saveData = async () => {
|
|
123
|
-
const myPromise = fetch('/api/data').then(res => res.json())
|
|
124
|
-
|
|
125
|
-
toast.promise(myPromise, {
|
|
126
|
-
loading: 'Saving...',
|
|
127
|
-
success: (data) => `Successfully saved ${data.name}`,
|
|
128
|
-
error: 'Failed to save data',
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return (
|
|
133
|
-
<Button onClick={saveData}>
|
|
134
|
-
Save Data
|
|
135
|
-
</Button>
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Custom Duration
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import { toast } from "@/components/Toast";
|
|
144
|
-
|
|
145
|
-
function CustomDuration() {
|
|
146
|
-
return (
|
|
147
|
-
<div className="space-x-2">
|
|
148
|
-
<Button onClick={() => toast('Quick message', { duration: 1000 })}>
|
|
149
|
-
1 Second
|
|
150
|
-
</Button>
|
|
151
|
-
|
|
152
|
-
<Button onClick={() => toast.success('Success!', { duration: 5000 })}>
|
|
153
|
-
5 Seconds
|
|
154
|
-
</Button>
|
|
155
|
-
|
|
156
|
-
<Button onClick={() => toast('Permanent', { duration: Infinity })}>
|
|
157
|
-
Never Dismiss
|
|
158
|
-
</Button>
|
|
159
|
-
</div>
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Custom Position
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
import { Toaster, toast } from "@/components/Toast";
|
|
168
|
-
|
|
169
|
-
function PositionExample() {
|
|
170
|
-
return (
|
|
171
|
-
<div>
|
|
172
|
-
<Toaster position="top-right" />
|
|
173
|
-
|
|
174
|
-
<div className="space-x-2">
|
|
175
|
-
<Button onClick={() => toast('Top Left')}>
|
|
176
|
-
Default (Top Left)
|
|
177
|
-
</Button>
|
|
178
|
-
<Button onClick={() => toast('Custom position')}>
|
|
179
|
-
Show Toast
|
|
180
|
-
</Button>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Dismissible Toast
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
import { toast } from "@/components/Toast";
|
|
191
|
-
import { Button } from "@/components/Button";
|
|
192
|
-
|
|
193
|
-
function DismissibleExample() {
|
|
194
|
-
const showDismissible = () => {
|
|
195
|
-
const toastId = toast('Click X to dismiss', {
|
|
196
|
-
duration: Infinity,
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
// Or programmatically dismiss
|
|
200
|
-
setTimeout(() => toast.dismiss(toastId), 5000)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<div className="space-x-2">
|
|
205
|
-
<Button onClick={showDismissible}>
|
|
206
|
-
Show Dismissible
|
|
207
|
-
</Button>
|
|
208
|
-
|
|
209
|
-
<Button onClick={() => toast.dismiss()}>
|
|
210
|
-
Dismiss All
|
|
211
|
-
</Button>
|
|
212
|
-
</div>
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Custom Styling
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
import { toast } from "@/components/Toast";
|
|
221
|
-
|
|
222
|
-
function CustomStyleExample() {
|
|
223
|
-
const showCustom = () => {
|
|
224
|
-
toast.success('Custom styled toast!', {
|
|
225
|
-
style: {
|
|
226
|
-
background: '#10b981',
|
|
227
|
-
color: '#ffffff',
|
|
228
|
-
padding: '16px',
|
|
229
|
-
borderRadius: '8px',
|
|
230
|
-
},
|
|
231
|
-
iconTheme: {
|
|
232
|
-
primary: '#ffffff',
|
|
233
|
-
secondary: '#10b981',
|
|
234
|
-
},
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return (
|
|
239
|
-
<Button onClick={showCustom}>
|
|
240
|
-
Show Custom Toast
|
|
241
|
-
</Button>
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### With Icon
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
import { toast } from "@/components/Toast";
|
|
250
|
-
|
|
251
|
-
function IconExample() {
|
|
252
|
-
return (
|
|
253
|
-
<div className="space-x-2">
|
|
254
|
-
<Button onClick={() => toast('⚠️ Warning message')}>
|
|
255
|
-
With Emoji
|
|
256
|
-
</Button>
|
|
257
|
-
|
|
258
|
-
<Button onClick={() => toast.custom(
|
|
259
|
-
<div className="flex items-center gap-2">
|
|
260
|
-
<i className="ri-rocket-fill text-2xl" />
|
|
261
|
-
<span>Launching rocket!</span>
|
|
262
|
-
</div>
|
|
263
|
-
)}>
|
|
264
|
-
Custom Icon
|
|
265
|
-
</Button>
|
|
266
|
-
</div>
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Form Validation
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
import { toast } from "@/components/Toast";
|
|
275
|
-
import { Button } from "@/components/Button";
|
|
276
|
-
import { InputField } from "@/components/InputField";
|
|
277
|
-
import { useState } from 'react'
|
|
278
|
-
|
|
279
|
-
function FormValidation() {
|
|
280
|
-
const [email, setEmail] = useState('')
|
|
281
|
-
|
|
282
|
-
const handleSubmit = (e: React.FormEvent) => {
|
|
283
|
-
e.preventDefault()
|
|
284
|
-
|
|
285
|
-
if (!email) {
|
|
286
|
-
toast.error('Email is required')
|
|
287
|
-
return
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (!email.includes('@')) {
|
|
291
|
-
toast.error('Please enter a valid email address')
|
|
292
|
-
return
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
toast.success('Form submitted successfully!')
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return (
|
|
299
|
-
<form onSubmit={handleSubmit} className="space-y-4">
|
|
300
|
-
<InputField
|
|
301
|
-
label="Email"
|
|
302
|
-
value={email}
|
|
303
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
304
|
-
/>
|
|
305
|
-
<Button type="submit">Submit</Button>
|
|
306
|
-
</form>
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## API Reference
|
|
312
|
-
|
|
313
|
-
### Toaster Props
|
|
314
|
-
|
|
315
|
-
| Prop | Type | Default | Description |
|
|
316
|
-
|------|------|---------|-------------|
|
|
317
|
-
| `position` | `'top-left' \| 'top-center' \| 'top-right' \| 'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'top-left'` | Toast position on screen |
|
|
318
|
-
| `reverseOrder` | `boolean` | `false` | Reverse toast display order |
|
|
319
|
-
| `gutter` | `number` | `8` | Gap between toasts (px) |
|
|
320
|
-
| `containerClassName` | `string` | - | Container CSS class |
|
|
321
|
-
| `containerStyle` | `CSSProperties` | - | Container inline styles |
|
|
322
|
-
| `toastOptions` | `ToastOptions` | - | Default toast options |
|
|
323
|
-
|
|
324
|
-
### Toast Function Methods
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
// Basic toast
|
|
328
|
-
toast(message: string, options?: ToastOptions)
|
|
329
|
-
|
|
330
|
-
// Variant toasts
|
|
331
|
-
toast.success(message: string, options?: ToastOptions)
|
|
332
|
-
toast.error(message: string, options?: ToastOptions)
|
|
333
|
-
toast.loading(message: string, options?: ToastOptions)
|
|
334
|
-
toast.custom(element: ReactNode, options?: ToastOptions)
|
|
335
|
-
|
|
336
|
-
// Promise toast
|
|
337
|
-
toast.promise(promise: Promise, messages: PromiseMessages, options?: ToastOptions)
|
|
338
|
-
|
|
339
|
-
// Control toasts
|
|
340
|
-
toast.dismiss(toastId?: string) // Dismiss one or all
|
|
341
|
-
toast.remove(toastId?: string) // Remove from DOM
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### ToastOptions
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
interface ToastOptions {
|
|
348
|
-
id?: string
|
|
349
|
-
duration?: number // Milliseconds (default varies by type)
|
|
350
|
-
position?: ToastPosition
|
|
351
|
-
style?: CSSProperties
|
|
352
|
-
className?: string
|
|
353
|
-
iconTheme?: {
|
|
354
|
-
primary: string
|
|
355
|
-
secondary: string
|
|
356
|
-
}
|
|
357
|
-
ariaProps?: {
|
|
358
|
-
role?: string
|
|
359
|
-
'aria-live'?: string
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Default Durations
|
|
365
|
-
|
|
366
|
-
| Type | Duration |
|
|
367
|
-
|------|----------|
|
|
368
|
-
| Default | 8000ms (8s) |
|
|
369
|
-
| Success | 3000ms (3s) |
|
|
370
|
-
| Error | 5000ms (5s) |
|
|
371
|
-
| Loading | 4000ms (4s) |
|
|
372
|
-
| Blank | 4000ms (4s) |
|
|
373
|
-
|
|
374
|
-
## TypeScript
|
|
375
|
-
|
|
376
|
-
### Full Type Definitions
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
import { ComponentPropsWithoutRef } from 'react'
|
|
380
|
-
import { Toaster as ToasterComponent, toast } from 'react-hot-toast'
|
|
381
|
-
|
|
382
|
-
type ToasterProps = ComponentPropsWithoutRef<typeof ToasterComponent>
|
|
383
|
-
|
|
384
|
-
interface CustomToasterProps extends ToasterProps {
|
|
385
|
-
position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
|
|
386
|
-
reverseOrder?: boolean
|
|
387
|
-
gutter?: number
|
|
388
|
-
containerClassName?: string
|
|
389
|
-
containerStyle?: React.CSSProperties
|
|
390
|
-
toastOptions?: {
|
|
391
|
-
className?: string
|
|
392
|
-
duration?: number
|
|
393
|
-
style?: React.CSSProperties
|
|
394
|
-
success?: ToastOptions
|
|
395
|
-
error?: ToastOptions
|
|
396
|
-
loading?: ToastOptions
|
|
397
|
-
blank?: ToastOptions
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Usage
|
|
402
|
-
const showToast = (message: string): string => {
|
|
403
|
-
return toast(message) // Returns toast ID
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const dismissToast = (id: string): void => {
|
|
407
|
-
toast.dismiss(id)
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## Common Patterns
|
|
412
|
-
|
|
413
|
-
### API Error Handling
|
|
414
|
-
|
|
415
|
-
```typescript
|
|
416
|
-
import { toast } from "@/components/Toast";
|
|
417
|
-
|
|
418
|
-
async function fetchData() {
|
|
419
|
-
try {
|
|
420
|
-
const response = await fetch('/api/data')
|
|
421
|
-
|
|
422
|
-
if (!response.ok) {
|
|
423
|
-
if (response.status === 401) {
|
|
424
|
-
toast.error('Unauthorized. Please login again.')
|
|
425
|
-
} else if (response.status === 404) {
|
|
426
|
-
toast.error('Resource not found')
|
|
427
|
-
} else if (response.status >= 500) {
|
|
428
|
-
toast.error('Server error. Please try again later.')
|
|
429
|
-
} else {
|
|
430
|
-
toast.error('Something went wrong')
|
|
431
|
-
}
|
|
432
|
-
return
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const data = await response.json()
|
|
436
|
-
toast.success('Data loaded successfully')
|
|
437
|
-
return data
|
|
438
|
-
} catch (error) {
|
|
439
|
-
toast.error('Network error. Check your connection.')
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
### Multi-Step Process
|
|
445
|
-
|
|
446
|
-
```typescript
|
|
447
|
-
import { toast } from "@/components/Toast";
|
|
448
|
-
|
|
449
|
-
async function multiStepProcess() {
|
|
450
|
-
const toastId = toast.loading('Step 1: Validating data...')
|
|
451
|
-
|
|
452
|
-
try {
|
|
453
|
-
await validateData()
|
|
454
|
-
toast.loading('Step 2: Processing...', { id: toastId })
|
|
455
|
-
|
|
456
|
-
await processData()
|
|
457
|
-
toast.loading('Step 3: Saving...', { id: toastId })
|
|
458
|
-
|
|
459
|
-
await saveData()
|
|
460
|
-
toast.success('All steps completed!', { id: toastId })
|
|
461
|
-
} catch (error) {
|
|
462
|
-
toast.error('Process failed', { id: toastId })
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
### Undo Action
|
|
468
|
-
|
|
469
|
-
```typescript
|
|
470
|
-
import { toast } from "@/components/Toast";
|
|
471
|
-
import { Button } from "@/components/Button";
|
|
472
|
-
|
|
473
|
-
function UndoExample() {
|
|
474
|
-
const handleDelete = (item: Item) => {
|
|
475
|
-
// Store deleted item
|
|
476
|
-
const deleted = { ...item }
|
|
477
|
-
|
|
478
|
-
toast.custom(
|
|
479
|
-
(t) => (
|
|
480
|
-
<div className="flex items-center gap-4">
|
|
481
|
-
<span>Item deleted</span>
|
|
482
|
-
<Button
|
|
483
|
-
size="S"
|
|
484
|
-
onClick={() => {
|
|
485
|
-
restoreItem(deleted)
|
|
486
|
-
toast.dismiss(t.id)
|
|
487
|
-
toast.success('Item restored')
|
|
488
|
-
}}
|
|
489
|
-
>
|
|
490
|
-
Undo
|
|
491
|
-
</Button>
|
|
492
|
-
</div>
|
|
493
|
-
),
|
|
494
|
-
{ duration: 5000 }
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
// Actually delete after timeout
|
|
498
|
-
setTimeout(() => permanentlyDelete(item.id), 5000)
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return <Button onClick={() => handleDelete(item)}>Delete</Button>
|
|
502
|
-
}
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### Rate Limited Actions
|
|
506
|
-
|
|
507
|
-
```typescript
|
|
508
|
-
import { toast } from "@/components/Toast";
|
|
509
|
-
|
|
510
|
-
let lastToastTime = 0
|
|
511
|
-
const TOAST_COOLDOWN = 2000 // 2 seconds
|
|
512
|
-
|
|
513
|
-
function showRateLimitedToast(message: string) {
|
|
514
|
-
const now = Date.now()
|
|
515
|
-
|
|
516
|
-
if (now - lastToastTime < TOAST_COOLDOWN) {
|
|
517
|
-
return // Ignore if within cooldown
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
lastToastTime = now
|
|
521
|
-
toast(message)
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// Usage
|
|
525
|
-
function SpamProtectedButton() {
|
|
526
|
-
return (
|
|
527
|
-
<Button onClick={() => showRateLimitedToast('Action triggered')}>
|
|
528
|
-
Click Me (Rate Limited)
|
|
529
|
-
</Button>
|
|
530
|
-
)
|
|
531
|
-
}
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
## Testing
|
|
535
|
-
|
|
536
|
-
### Unit Test Examples
|
|
537
|
-
|
|
538
|
-
```typescript
|
|
539
|
-
import { render, screen, waitFor } from '@testing-library/react'
|
|
540
|
-
import { Toaster, toast } from "@/components/Toast";
|
|
541
|
-
import userEvent from '@testing-library/user-event'
|
|
542
|
-
|
|
543
|
-
describe('Toast', () => {
|
|
544
|
-
it('renders toaster component', () => {
|
|
545
|
-
render(<Toaster />)
|
|
546
|
-
// Toaster container should be in document
|
|
547
|
-
expect(document.querySelector('[data-react-hot-toast]')).toBeInTheDocument()
|
|
548
|
-
})
|
|
549
|
-
|
|
550
|
-
it('shows toast message', async () => {
|
|
551
|
-
render(
|
|
552
|
-
<div>
|
|
553
|
-
<Toaster />
|
|
554
|
-
<button onClick={() => toast('Test message')}>Show</button>
|
|
555
|
-
</div>
|
|
556
|
-
)
|
|
557
|
-
|
|
558
|
-
await userEvent.click(screen.getByText('Show'))
|
|
559
|
-
|
|
560
|
-
await waitFor(() => {
|
|
561
|
-
expect(screen.getByText('Test message')).toBeInTheDocument()
|
|
562
|
-
})
|
|
563
|
-
})
|
|
564
|
-
|
|
565
|
-
it('shows success toast', async () => {
|
|
566
|
-
render(
|
|
567
|
-
<div>
|
|
568
|
-
<Toaster />
|
|
569
|
-
<button onClick={() => toast.success('Success!')}>Success</button>
|
|
570
|
-
</div>
|
|
571
|
-
)
|
|
572
|
-
|
|
573
|
-
await userEvent.click(screen.getByText('Success'))
|
|
574
|
-
|
|
575
|
-
await waitFor(() => {
|
|
576
|
-
expect(screen.getByText('Success!')).toBeInTheDocument()
|
|
577
|
-
})
|
|
578
|
-
})
|
|
579
|
-
|
|
580
|
-
it('dismisses toast', async () => {
|
|
581
|
-
render(
|
|
582
|
-
<div>
|
|
583
|
-
<Toaster />
|
|
584
|
-
<button onClick={() => {
|
|
585
|
-
const id = toast('Dismissible')
|
|
586
|
-
setTimeout(() => toast.dismiss(id), 100)
|
|
587
|
-
}}>
|
|
588
|
-
Show & Dismiss
|
|
589
|
-
</button>
|
|
590
|
-
</div>
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
await userEvent.click(screen.getByText('Show & Dismiss'))
|
|
594
|
-
|
|
595
|
-
await waitFor(() => {
|
|
596
|
-
expect(screen.getByText('Dismissible')).toBeInTheDocument()
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
await waitFor(() => {
|
|
600
|
-
expect(screen.queryByText('Dismissible')).not.toBeInTheDocument()
|
|
601
|
-
}, { timeout: 200 })
|
|
602
|
-
})
|
|
603
|
-
|
|
604
|
-
it('handles promise toast', async () => {
|
|
605
|
-
const mockPromise = Promise.resolve({ name: 'Test' })
|
|
606
|
-
|
|
607
|
-
render(
|
|
608
|
-
<div>
|
|
609
|
-
<Toaster />
|
|
610
|
-
<button onClick={() => {
|
|
611
|
-
toast.promise(mockPromise, {
|
|
612
|
-
loading: 'Loading...',
|
|
613
|
-
success: (data) => `Got ${data.name}`,
|
|
614
|
-
error: 'Error',
|
|
615
|
-
})
|
|
616
|
-
}}>
|
|
617
|
-
Promise Toast
|
|
618
|
-
</button>
|
|
619
|
-
</div>
|
|
620
|
-
)
|
|
621
|
-
|
|
622
|
-
await userEvent.click(screen.getByText('Promise Toast'))
|
|
623
|
-
|
|
624
|
-
await waitFor(() => {
|
|
625
|
-
expect(screen.getByText('Loading...')).toBeInTheDocument()
|
|
626
|
-
})
|
|
627
|
-
|
|
628
|
-
await waitFor(() => {
|
|
629
|
-
expect(screen.getByText('Got Test')).toBeInTheDocument()
|
|
630
|
-
})
|
|
631
|
-
})
|
|
632
|
-
})
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
## Accessibility
|
|
636
|
-
|
|
637
|
-
- **ARIA Attributes**: `role="status"` and `aria-live="polite"` for screen readers
|
|
638
|
-
- **Keyboard Navigation**: Toasts are announced but don't trap focus
|
|
639
|
-
- **Focus Management**: Does not steal focus from active elements
|
|
640
|
-
- **Color Contrast**: Uses CSS variables with WCAG AA compliant colors
|
|
641
|
-
- **Duration**: Success toasts shorter (3s), errors longer (5s) for readability
|
|
642
|
-
|
|
643
|
-
### Accessibility Best Practices
|
|
644
|
-
|
|
645
|
-
```typescript
|
|
646
|
-
// Use appropriate toast types
|
|
647
|
-
toast.error('Form validation failed') // Error states
|
|
648
|
-
toast.success('Settings saved') // Success confirmations
|
|
649
|
-
|
|
650
|
-
// Provide clear, concise messages
|
|
651
|
-
toast('File uploaded successfully') // ✅ Clear
|
|
652
|
-
toast('Operation complete') // ❌ Too vague
|
|
653
|
-
|
|
654
|
-
// Don't rely solely on color
|
|
655
|
-
toast.error('❌ Failed to save') // Icon + text
|
|
656
|
-
toast.success('✅ Saved successfully') // Icon + text
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
## Performance
|
|
660
|
-
|
|
661
|
-
| Metric | Value |
|
|
662
|
-
|--------|-------|
|
|
663
|
-
| Bundle size (minified) | ~8kb |
|
|
664
|
-
| Bundle size (gzipped) | ~3kb |
|
|
665
|
-
| Dependencies | react-hot-toast (~8kb) |
|
|
666
|
-
| Max simultaneous toasts | 20 (configurable) |
|
|
667
|
-
| Animation performance | 60fps |
|
|
668
|
-
| Tree-shakeable | ✅ |
|
|
669
|
-
|
|
670
|
-
### Performance Tips
|
|
671
|
-
|
|
672
|
-
1. **Limit simultaneous toasts**: Use `visibleToasts` option
|
|
673
|
-
```typescript
|
|
674
|
-
<Toaster toastOptions={{ visibleToasts: 3 }} />
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
2. **Reuse toast IDs**: Update existing instead of creating new
|
|
678
|
-
```typescript
|
|
679
|
-
const toastId = 'unique-id'
|
|
680
|
-
toast.loading('Loading...', { id: toastId })
|
|
681
|
-
toast.success('Done!', { id: toastId })
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
3. **Dismiss old toasts**: Clean up before showing new ones
|
|
685
|
-
```typescript
|
|
686
|
-
toast.dismiss() // Clear all
|
|
687
|
-
toast.success('New message')
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
## Styling
|
|
691
|
-
|
|
692
|
-
### Custom Theme
|
|
693
|
-
|
|
694
|
-
```typescript
|
|
695
|
-
<Toaster
|
|
696
|
-
toastOptions={{
|
|
697
|
-
style: {
|
|
698
|
-
background: '#363636',
|
|
699
|
-
color: '#fff',
|
|
700
|
-
borderRadius: '8px',
|
|
701
|
-
padding: '16px',
|
|
702
|
-
},
|
|
703
|
-
success: {
|
|
704
|
-
style: {
|
|
705
|
-
background: '#10b981',
|
|
706
|
-
},
|
|
707
|
-
iconTheme: {
|
|
708
|
-
primary: '#fff',
|
|
709
|
-
secondary: '#10b981',
|
|
710
|
-
},
|
|
711
|
-
},
|
|
712
|
-
error: {
|
|
713
|
-
style: {
|
|
714
|
-
background: '#ef4444',
|
|
715
|
-
},
|
|
716
|
-
},
|
|
717
|
-
}}
|
|
718
|
-
/>
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
### Default Styling
|
|
722
|
-
|
|
723
|
-
- Background: Uses CSS variables (`--background-presentation-state-*`)
|
|
724
|
-
- Border radius: 16px
|
|
725
|
-
- Colors: Theme-aware (success: green, error: red, warning: yellow)
|
|
726
|
-
- Icons: Matching color scheme with themed backgrounds
|
|
727
|
-
- Animations: Slide-in from position
|
|
728
|
-
|
|
729
|
-
## Best Practices
|
|
730
|
-
|
|
731
|
-
1. **Use appropriate variants**: Match toast type to action result
|
|
732
|
-
```typescript
|
|
733
|
-
toast.success('Saved!') // Successful actions
|
|
734
|
-
toast.error('Failed') // Errors
|
|
735
|
-
toast.loading('Processing...') // Ongoing operations
|
|
736
|
-
```
|
|
737
|
-
|
|
738
|
-
2. **Keep messages concise**: One line when possible
|
|
739
|
-
```typescript
|
|
740
|
-
toast('Email sent') // ✅
|
|
741
|
-
toast('Your email has been successfully sent to the recipient') // ❌
|
|
742
|
-
```
|
|
743
|
-
|
|
744
|
-
3. **Update loading toasts**: Use same ID to update progress
|
|
745
|
-
```typescript
|
|
746
|
-
const id = toast.loading('Uploading...')
|
|
747
|
-
toast.success('Uploaded!', { id })
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
4. **Handle errors gracefully**: Provide actionable feedback
|
|
751
|
-
```typescript
|
|
752
|
-
toast.error('Failed to save. Please check your connection.')
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
5. **Avoid toast spam**: Rate limit or dismiss previous toasts
|
|
756
|
-
```typescript
|
|
757
|
-
toast.dismiss() // Clear old toasts
|
|
758
|
-
toast('New message')
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
6. **Test with screen readers**: Ensure messages are announced
|
|
762
|
-
|
|
763
|
-
7. **Use promises for async operations**: Automatic state handling
|
|
764
|
-
```typescript
|
|
765
|
-
toast.promise(apiCall(), { loading: '...', success: '✅', error: '❌' })
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
## Related Components
|
|
769
|
-
|
|
770
|
-
- [FieldHint](./field-hint.md) - Inline form field hints and alerts
|
|
771
|
-
- [SpinLoading](./spin-loading.md) - Loading spinner component
|
|
772
|
-
- [Dialog](./dialog.md) - Modal dialogs for blocking interactions
|
|
773
|
-
- [AlertDialog](./alert-dialog.md) - Alert dialogs for confirmations
|