@wello-dev/notifications 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +47 -0
- package/README.md +169 -3
- package/dist/index.cjs +1418 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +323 -0
- package/dist/index.d.ts +323 -0
- package/dist/index.js +1383 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +338 -0
- package/package.json +73 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wello-dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
--------------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
Portions of this package are derived from software under this licence:
|
|
26
|
+
|
|
27
|
+
MIT License
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2021 Vitaly Rtishchev
|
|
30
|
+
|
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
in the Software without restriction, including without limitation the rights
|
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
furnished to do so, subject to the following conditions:
|
|
37
|
+
|
|
38
|
+
The above copyright notice and this permission notice shall be included in all
|
|
39
|
+
copies or substantial portions of the Software.
|
|
40
|
+
|
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,169 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @wello-dev/notifications
|
|
2
|
+
|
|
3
|
+
Toasts for React with a sonner-style API, plus tab title / favicon badges and notification sounds.
|
|
4
|
+
No dependencies besides React. RTL, Arabic labels, light and dark themes built in; the CSS is injected on import.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pnpm add @wello-dev/notifications
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { toast, Toaster } from "@wello-dev/notifications";
|
|
12
|
+
|
|
13
|
+
function App() {
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<Routes />
|
|
17
|
+
<Toaster />
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
toast.success("Product saved");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## `toast`
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
toast("Event created");
|
|
29
|
+
toast.success("Saved");
|
|
30
|
+
toast.error("Upload failed", { description: "The file is larger than 5 MB" });
|
|
31
|
+
toast.warning("Stock is low");
|
|
32
|
+
toast.info("A new version is available", { title: "Update" }); // message becomes the description
|
|
33
|
+
toast.danger("…"); // same as error
|
|
34
|
+
|
|
35
|
+
// Loading, then the result in the same toast
|
|
36
|
+
const id = toast.loading("Sending…");
|
|
37
|
+
toast.success("Sent", { id });
|
|
38
|
+
|
|
39
|
+
// Promise: returns the promise's value (and rethrows its error)
|
|
40
|
+
const order = await toast.promise(saveOrder(), {
|
|
41
|
+
loading: "Saving…",
|
|
42
|
+
success: (order) => `Order #${order.id} saved`,
|
|
43
|
+
error: (error) => (error instanceof Error ? error.message : "Could not save"),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
toast("Order deleted", { action: { label: "Undo", onClick: restore }, cancel: { label: "Dismiss" } });
|
|
47
|
+
toast.custom((t) => <MyCard onClose={() => toast.dismiss(t.id)} />);
|
|
48
|
+
|
|
49
|
+
toast.update(id, { description: "2 of 3 files" });
|
|
50
|
+
toast.dismiss(id); // or toast.close(id); without an id closes all
|
|
51
|
+
toast.clear();
|
|
52
|
+
toast.pauseAll(); // e.g. while a dialog is open
|
|
53
|
+
toast.resumeAll();
|
|
54
|
+
toast.isActive(id);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| Option | Type | Default | |
|
|
58
|
+
| ----------------------------------------------- | ------------------------------------ | ------------------------- | ---------------------------------------------------------- |
|
|
59
|
+
| `id` | `string \| number` | generated | Reusing an id replaces that toast |
|
|
60
|
+
| `title` / `description` | `ReactNode` | message / – | |
|
|
61
|
+
| `duration` | `number \| false` | per type | Alias: `autoClose`. `false` stays until closed |
|
|
62
|
+
| `icon` | `ReactNode \| false` | per type | |
|
|
63
|
+
| `color` | `string` | per type | Tailwind name (`'violet-600'`) or any CSS color |
|
|
64
|
+
| `action` / `cancel` | `{ label, onClick?, closeOnClick? }` | – | Buttons; they close the toast unless `closeOnClick: false` |
|
|
65
|
+
| `dismissible` | `boolean` | `true` (loading: `false`) | Close button, swipe and Esc |
|
|
66
|
+
| `progress` | `boolean` | toaster | Remaining-time bar |
|
|
67
|
+
| `important` | `boolean` | `true` for errors | `role="alert"`, announced right away |
|
|
68
|
+
| `sound` | `boolean \| string` | toaster | `true` for a tone, or a sound URL |
|
|
69
|
+
| `position` | `ToastPosition` | toaster | |
|
|
70
|
+
| `className` / `style` / `classNames` / `styles` | | | See below |
|
|
71
|
+
| `onOpen` / `onClose` / `onAutoClose` | `(toast) => void` | | |
|
|
72
|
+
|
|
73
|
+
## `<Toaster>`
|
|
74
|
+
|
|
75
|
+
Mount one `<Toaster />` near the app root. If multiple instances are mounted, only the first
|
|
76
|
+
displays notifications; another takes over if it unmounts.
|
|
77
|
+
|
|
78
|
+
| Prop | Default | |
|
|
79
|
+
| ------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------- |
|
|
80
|
+
| `position` | `'bottom-start'` | `top-/bottom-` + `start`, `center`, `end` (or `left` / `right`) |
|
|
81
|
+
| `dir` | `'auto'` | `'auto'` follows `<html dir>`, also when it changes |
|
|
82
|
+
| `limit` | `4` | Shown at once per position; newer ones wait |
|
|
83
|
+
| `duration` | `4000` | |
|
|
84
|
+
| `durations` | error 5500, warning 5000, loading `false` | Per type |
|
|
85
|
+
| `colors` | emerald-600, red-600, amber-600, blue-600, slate-500 | Per type |
|
|
86
|
+
| `icons` | built in | Per type; `null` hides one |
|
|
87
|
+
| `closeButton` | `true` | |
|
|
88
|
+
| `progress` | `false` | |
|
|
89
|
+
| `swipe` | `true` | Swipe sideways to dismiss |
|
|
90
|
+
| `pauseOnHover` | `true` | Also while a toast has focus |
|
|
91
|
+
| `pauseWhenPageHidden` | `true` | |
|
|
92
|
+
| `sound` | `false` | For every toast |
|
|
93
|
+
| `theme` | light | Dark under `.dark` / `[data-theme="dark"]`; or `'dark'`, `'system'` |
|
|
94
|
+
| `width` / `gap` / `offset` / `zIndex` | `390` / `12` / `16` / `11000` | |
|
|
95
|
+
| `locale` / `labels` | `'en'` | `'ar'` for Arabic |
|
|
96
|
+
| `classNames` / `styles` | | Parts below, plus `toaster` |
|
|
97
|
+
| `container` | `document.body` | |
|
|
98
|
+
|
|
99
|
+
`start` and `end` follow the direction, so `bottom-start` is bottom-left in English and bottom-right in Arabic.
|
|
100
|
+
|
|
101
|
+
## Styling
|
|
102
|
+
|
|
103
|
+
Parts: `toaster`, `toast`, `icon`, `content`, `title`, `description`, `actions`, `action`, `cancel`, `closeButton`, `progress`.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
<Toaster
|
|
107
|
+
classNames={{ toast: "rounded-xl shadow-lg", title: "text-base", closeButton: "text-gray-400" }}
|
|
108
|
+
/>;
|
|
109
|
+
toast.success("Saved", { classNames: { title: "font-bold" } });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The CSS is in the `components` cascade layer, so Tailwind utilities override it without `!`.
|
|
113
|
+
Theme variables on `.wello-notifications-toaster`: `--wello-notifications-bg`, `--wello-notifications-fg`, `--wello-notifications-muted`, `--wello-notifications-border`, `--wello-notifications-ring`,
|
|
114
|
+
`--wello-notifications-hover`, `--wello-notifications-shadow`, `--wello-notifications-radius`, `--wello-notifications-font`; the accent of each toast is `--wello-notifications-tone`.
|
|
115
|
+
|
|
116
|
+
If your bundler drops the injected CSS, import it yourself: `import "@wello-dev/notifications/styles.css";`.
|
|
117
|
+
|
|
118
|
+
## Tab title and favicon
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { tabNotifications, createTabNotifications } from "@wello-dev/notifications";
|
|
122
|
+
|
|
123
|
+
tabNotifications.setUnreadCount(5); // "(5) My app" and a red dot on the favicon
|
|
124
|
+
tabNotifications.flashTitle("🔴 New order"); // until the user comes back to the tab
|
|
125
|
+
tabNotifications.stopFlashing();
|
|
126
|
+
tabNotifications.reset();
|
|
127
|
+
|
|
128
|
+
const tab = createTabNotifications({
|
|
129
|
+
dotColor: "#2563eb",
|
|
130
|
+
formatTitle: (n, t) => `${n} new · ${t}`,
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Sounds
|
|
135
|
+
|
|
136
|
+
Built-in sounds are synthesized in the browser (no files to host): layered bell / marimba tones
|
|
137
|
+
with a soft attack, a short room reverb and a limiter, balanced to the same loudness.
|
|
138
|
+
|
|
139
|
+
| Name | Sound | Used for toast type |
|
|
140
|
+
| ---------- | -------------------------------- | ------------------- |
|
|
141
|
+
| `success` | rising arpeggio ending on a bell | `success` |
|
|
142
|
+
| `error` | soft falling minor step | `error` |
|
|
143
|
+
| `warning` | two even mallet knocks | `warning` |
|
|
144
|
+
| `info` | single bell with its octave | `info` |
|
|
145
|
+
| `message` | chat-style "ding-dong" | – |
|
|
146
|
+
| `critical` | three quick rising pairs | – |
|
|
147
|
+
| `pop` | short bubble pop | plain `toast()` |
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { playNotificationSound, playSound } from "@wello-dev/notifications";
|
|
151
|
+
|
|
152
|
+
playSound("message");
|
|
153
|
+
playSound("critical", { volume: 1 });
|
|
154
|
+
playNotificationSound("/sounds/notification.mp3"); // a file, or a built-in name
|
|
155
|
+
playNotificationSound("/sounds/alert.mp3", { volume: 0.5, fallback: "critical" }); // if the file can't play
|
|
156
|
+
|
|
157
|
+
toast.success("Order received", { sound: true }); // built-in sound of the type
|
|
158
|
+
toast("New message", { sound: "message" });
|
|
159
|
+
<Toaster sound />; // every toast
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`playTone(priority)` still works: `critical` → `critical`, `high` → `message`, `normal` → `info`, `low` → `pop`.
|
|
163
|
+
`scheduleSound(ctx, name)` renders a sound on any `AudioContext` / `OfflineAudioContext`.
|
|
164
|
+
|
|
165
|
+
Browsers block audio until the user has interacted with the page once.
|
|
166
|
+
|
|
167
|
+
## Your own UI
|
|
168
|
+
|
|
169
|
+
`useToasts()` returns the open toasts (newest first), e.g. for a badge. `toastStore` exposes the raw state.
|