@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/dist/index.d.ts
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, MouseEvent, CSSProperties, SVGProps } from 'react';
|
|
3
|
+
|
|
4
|
+
/** `'blue-600'`, `'blue'` (= 500), or any CSS color. */
|
|
5
|
+
type ToastColor = string;
|
|
6
|
+
/** Resolves a Tailwind name (`'blue-600'`) to its hex value; any other CSS color is returned as is. */
|
|
7
|
+
declare function resolveColor(color: ToastColor): string;
|
|
8
|
+
|
|
9
|
+
type ToastType = "default" | "success" | "error" | "warning" | "info" | "loading";
|
|
10
|
+
type ToastId = string | number;
|
|
11
|
+
/** `start` / `end` follow the toaster direction: `bottom-start` is bottom-left in LTR, bottom-right in RTL. */
|
|
12
|
+
type ToastPosition = "top-start" | "top-center" | "top-end" | "bottom-start" | "bottom-center" | "bottom-end" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
13
|
+
type ToastStylesNames = "toast" | "icon" | "content" | "title" | "description" | "actions" | "action" | "cancel" | "closeButton" | "progress";
|
|
14
|
+
type ToastClassNames = Partial<Record<ToastStylesNames, string>>;
|
|
15
|
+
type ToastStyles = Partial<Record<ToastStylesNames, CSSProperties>>;
|
|
16
|
+
interface ToastAction {
|
|
17
|
+
label: ReactNode;
|
|
18
|
+
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
19
|
+
/** Close the toast after the click. Default: true */
|
|
20
|
+
closeOnClick?: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface ToastOptions {
|
|
23
|
+
/** Pass an existing id to replace that toast in place */
|
|
24
|
+
id?: ToastId;
|
|
25
|
+
/** Bold first line; defaults to the message */
|
|
26
|
+
title?: ReactNode;
|
|
27
|
+
/** Second line under the title */
|
|
28
|
+
description?: ReactNode;
|
|
29
|
+
/** Milliseconds before it closes, or `false` to stay until closed. Default: per type (toaster `duration`) */
|
|
30
|
+
duration?: number | false;
|
|
31
|
+
/** Alias of `duration` */
|
|
32
|
+
autoClose?: number | false;
|
|
33
|
+
/** Custom icon, or `false` for none */
|
|
34
|
+
icon?: ReactNode | false;
|
|
35
|
+
/** Accent color: Tailwind name (`'violet-600'`) or any CSS color. Default: per type */
|
|
36
|
+
color?: ToastColor;
|
|
37
|
+
/** Main button, e.g. Undo */
|
|
38
|
+
action?: ToastAction;
|
|
39
|
+
/** Secondary button */
|
|
40
|
+
cancel?: ToastAction;
|
|
41
|
+
/** Close button and swipe to dismiss. Default: true (false for loading toasts) */
|
|
42
|
+
dismissible?: boolean;
|
|
43
|
+
/** Shows the remaining time as a bar. Default: toaster `progress` */
|
|
44
|
+
progress?: boolean;
|
|
45
|
+
/** Announced right away by screen readers (`role="alert"`). Default: true for errors */
|
|
46
|
+
important?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Plays a sound when shown (and when a loading toast settles): `true` for the built-in sound
|
|
49
|
+
* of its type, a built-in name (`'message'`, `'critical'`, …) or a sound file URL
|
|
50
|
+
*/
|
|
51
|
+
sound?: boolean | string;
|
|
52
|
+
/** Overrides the toaster position for this toast */
|
|
53
|
+
position?: ToastPosition;
|
|
54
|
+
className?: string;
|
|
55
|
+
style?: CSSProperties;
|
|
56
|
+
classNames?: ToastClassNames;
|
|
57
|
+
styles?: ToastStyles;
|
|
58
|
+
/** Called when it closes for any reason */
|
|
59
|
+
onClose?: (toast: ToastRecord) => void;
|
|
60
|
+
/** Called when it closes because its time ran out */
|
|
61
|
+
onAutoClose?: (toast: ToastRecord) => void;
|
|
62
|
+
/** Called when it appears */
|
|
63
|
+
onOpen?: (toast: ToastRecord) => void;
|
|
64
|
+
}
|
|
65
|
+
interface ToastRecord extends Omit<ToastOptions, "id" | "autoClose"> {
|
|
66
|
+
id: ToastId;
|
|
67
|
+
type: ToastType;
|
|
68
|
+
/** Fully custom content (`toast.custom`); replaces the built-in layout */
|
|
69
|
+
render?: (toast: ToastRecord) => ReactNode;
|
|
70
|
+
/** Changes on every update, so timers restart */
|
|
71
|
+
version: number;
|
|
72
|
+
createdAt: number;
|
|
73
|
+
/** `false` while it animates out */
|
|
74
|
+
open: boolean;
|
|
75
|
+
}
|
|
76
|
+
type ToastContent = ReactNode;
|
|
77
|
+
|
|
78
|
+
/** A promise, or a function that starts one (so it runs only when the toast is shown). */
|
|
79
|
+
type PromiseSource<T> = Promise<T> | (() => Promise<T>);
|
|
80
|
+
interface PromiseMessages<T> {
|
|
81
|
+
loading: ToastContent;
|
|
82
|
+
success: ToastContent | ((data: T) => ToastContent);
|
|
83
|
+
error: ToastContent | ((error: unknown) => ToastContent);
|
|
84
|
+
/** Called after success or error */
|
|
85
|
+
finally?: () => void;
|
|
86
|
+
}
|
|
87
|
+
declare function promise<T>(source: PromiseSource<T>, messages: PromiseMessages<T>, options?: ToastOptions): Promise<T>;
|
|
88
|
+
/**
|
|
89
|
+
* Changes an open toast. Pass a message to replace its text, options to change anything else
|
|
90
|
+
* (including `type` through `toast.success(…, { id })`). Returns false when it is already gone.
|
|
91
|
+
*/
|
|
92
|
+
declare function update(id: ToastId, changes: ToastContent | (ToastOptions & {
|
|
93
|
+
type?: ToastType;
|
|
94
|
+
})): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Shows a toast. Needs one `<Toaster />` somewhere in the app.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* toast.success("Saved");
|
|
100
|
+
* toast.error("Upload failed", { description: "The file is too large" });
|
|
101
|
+
* const id = toast.loading("Sending…"); toast.success("Sent", { id });
|
|
102
|
+
* await toast.promise(save(), { loading: "Saving…", success: "Saved", error: "Could not save" });
|
|
103
|
+
*/
|
|
104
|
+
declare const toast: ((message: ToastContent, options?: ToastOptions) => ToastId) & {
|
|
105
|
+
success: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
106
|
+
error: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
107
|
+
/** Same as `error` */
|
|
108
|
+
danger: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
109
|
+
warning: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
110
|
+
info: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
111
|
+
loading: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
112
|
+
/** Same as `toast()` */
|
|
113
|
+
message: (message: ToastContent, options?: ToastOptions) => ToastId;
|
|
114
|
+
/** Fully custom content; `render` gets the toast (use `toast.dismiss(t.id)` to close it). */
|
|
115
|
+
custom: (render: (toast: ToastRecord) => ReactNode, options?: ToastOptions) => ToastId;
|
|
116
|
+
promise: typeof promise;
|
|
117
|
+
update: typeof update;
|
|
118
|
+
/** Closes one toast, or all of them without an id */
|
|
119
|
+
dismiss: (id?: ToastId) => void;
|
|
120
|
+
/** Same as `dismiss` */
|
|
121
|
+
close: (id?: ToastId) => void;
|
|
122
|
+
/** Closes every toast */
|
|
123
|
+
clear: () => void;
|
|
124
|
+
/** Stops every timer, e.g. while a dialog is open */
|
|
125
|
+
pauseAll: () => void;
|
|
126
|
+
resumeAll: () => void;
|
|
127
|
+
/** `true` while the toast is open */
|
|
128
|
+
isActive: (id: ToastId) => boolean;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
type Listener = () => void;
|
|
132
|
+
interface ToastState {
|
|
133
|
+
/** Newest first; closed toasts stay until their exit animation ends */
|
|
134
|
+
toasts: ToastRecord[];
|
|
135
|
+
/** Set by `toast.pauseAll()` */
|
|
136
|
+
paused: boolean;
|
|
137
|
+
}
|
|
138
|
+
/** Shared toast state, readable with `useSyncExternalStore`. */
|
|
139
|
+
declare const toastStore: {
|
|
140
|
+
getState: () => ToastState;
|
|
141
|
+
subscribe(listener: Listener): () => void;
|
|
142
|
+
/** `true` when at least one `<Toaster>` is mounted */
|
|
143
|
+
hasToaster: () => boolean;
|
|
144
|
+
nextId: () => string;
|
|
145
|
+
/** Adds a toast, or replaces the open one with the same id. */
|
|
146
|
+
upsert(record: Omit<ToastRecord, "version" | "createdAt" | "open">): ToastId;
|
|
147
|
+
/** Merges changes into an open toast. Returns false when there is none with this id. */
|
|
148
|
+
patch(id: ToastId, changes: Partial<ToastRecord>): boolean;
|
|
149
|
+
/** Starts closing one toast, or all of them. */
|
|
150
|
+
dismiss(id?: ToastId, reason?: "close" | "auto"): void;
|
|
151
|
+
/** Removes a toast right away (after its exit animation). */
|
|
152
|
+
remove(id: ToastId): void;
|
|
153
|
+
setPaused(paused: boolean): void;
|
|
154
|
+
/** Test helper: forget every toast. */
|
|
155
|
+
reset(): void;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/** Open toasts, newest first; for badges or your own notification UI. */
|
|
159
|
+
declare function useToasts(): ToastRecord[];
|
|
160
|
+
|
|
161
|
+
interface ToasterLabels {
|
|
162
|
+
/** Name of the notifications region for screen readers */
|
|
163
|
+
region: string;
|
|
164
|
+
close: string;
|
|
165
|
+
}
|
|
166
|
+
type ToasterLocale = "en" | "ar";
|
|
167
|
+
declare function resolveLabels(locale?: ToasterLocale, overrides?: Partial<ToasterLabels>): ToasterLabels;
|
|
168
|
+
|
|
169
|
+
type ToasterTheme = "light" | "dark" | "system";
|
|
170
|
+
interface ToasterProps {
|
|
171
|
+
/** Default: 'bottom-start' (bottom-left in LTR, bottom-right in RTL) */
|
|
172
|
+
position?: ToastPosition;
|
|
173
|
+
/** `'auto'` follows `<html dir>`. Default: 'auto' */
|
|
174
|
+
dir?: "ltr" | "rtl" | "auto";
|
|
175
|
+
/** Toasts shown at once per position; the rest wait their turn. Default: 4 */
|
|
176
|
+
limit?: number;
|
|
177
|
+
/** Default time on screen in ms. Default: 4000 */
|
|
178
|
+
duration?: number;
|
|
179
|
+
/** Per-type time on screen. Default: error 5500, warning 5000, loading until closed */
|
|
180
|
+
durations?: Partial<Record<ToastType, number | false>>;
|
|
181
|
+
/** Per-type accent colors: Tailwind names (`'emerald-600'`) or CSS colors */
|
|
182
|
+
colors?: Partial<Record<ToastType, ToastColor>>;
|
|
183
|
+
/** Per-type icons; `null` hides one */
|
|
184
|
+
icons?: Partial<Record<ToastType, ReactNode>>;
|
|
185
|
+
/** Close button on dismissible toasts. Default: true */
|
|
186
|
+
closeButton?: boolean;
|
|
187
|
+
/** Remaining-time bar on every toast. Default: false */
|
|
188
|
+
progress?: boolean;
|
|
189
|
+
/** Swipe sideways to dismiss. Default: true */
|
|
190
|
+
swipe?: boolean;
|
|
191
|
+
/** Stop timers while hovered or focused. Default: true */
|
|
192
|
+
pauseOnHover?: boolean;
|
|
193
|
+
/** Stop timers while the tab is hidden. Default: true */
|
|
194
|
+
pauseWhenPageHidden?: boolean;
|
|
195
|
+
/** Sound for every toast: `true` for the built-in sound of each type, a built-in name or a URL. Default: false */
|
|
196
|
+
sound?: boolean | string;
|
|
197
|
+
/**
|
|
198
|
+
* Default: light, switching to dark under a `.dark` / `[data-theme="dark"]` ancestor.
|
|
199
|
+
* `'system'` follows the OS setting
|
|
200
|
+
*/
|
|
201
|
+
theme?: ToasterTheme;
|
|
202
|
+
/** Toast width. Default: 390 */
|
|
203
|
+
width?: number | string;
|
|
204
|
+
/** Space between toasts. Default: 12 */
|
|
205
|
+
gap?: number;
|
|
206
|
+
/** Distance from the screen edges. Default: 16 */
|
|
207
|
+
offset?: number | string;
|
|
208
|
+
/** Default: 11000 */
|
|
209
|
+
zIndex?: number;
|
|
210
|
+
/** Built-in texts. Default: 'en' */
|
|
211
|
+
locale?: ToasterLocale;
|
|
212
|
+
labels?: Partial<ToasterLabels>;
|
|
213
|
+
/** Classes and styles for the parts of every toast */
|
|
214
|
+
classNames?: ToastClassNames & {
|
|
215
|
+
toaster?: string;
|
|
216
|
+
};
|
|
217
|
+
styles?: ToastStyles & {
|
|
218
|
+
toaster?: CSSProperties;
|
|
219
|
+
};
|
|
220
|
+
/** Class on each list of toasts */
|
|
221
|
+
className?: string;
|
|
222
|
+
style?: CSSProperties;
|
|
223
|
+
/** Where to render. Default: document.body */
|
|
224
|
+
container?: Element | null;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Renders the toasts. Mount it once, near the root of the app.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* <Toaster />
|
|
231
|
+
* <Toaster position="top-center" locale="ar" progress />
|
|
232
|
+
*/
|
|
233
|
+
declare function Toaster(props: ToasterProps): react.ReactPortal | null;
|
|
234
|
+
|
|
235
|
+
type IconProps = SVGProps<SVGSVGElement>;
|
|
236
|
+
declare const SuccessIcon: (props: IconProps) => react.JSX.Element;
|
|
237
|
+
declare const ErrorIcon: (props: IconProps) => react.JSX.Element;
|
|
238
|
+
declare const WarningIcon: (props: IconProps) => react.JSX.Element;
|
|
239
|
+
declare const InfoIcon: (props: IconProps) => react.JSX.Element;
|
|
240
|
+
declare const LoadingIcon: (props: IconProps) => react.JSX.Element;
|
|
241
|
+
declare const CloseIcon: (props: IconProps) => react.JSX.Element;
|
|
242
|
+
|
|
243
|
+
interface TabNotificationsOptions {
|
|
244
|
+
/** Title with unread items. Default: `(count) title`, `(99+) title` above 99 */
|
|
245
|
+
formatTitle?: (count: number, title: string) => string;
|
|
246
|
+
/** Color of the favicon dot. Default: red-500 */
|
|
247
|
+
dotColor?: string;
|
|
248
|
+
/** Add the dot to the favicon while there are unread items. Default: true */
|
|
249
|
+
favicon?: boolean;
|
|
250
|
+
}
|
|
251
|
+
interface FlashTitleOptions {
|
|
252
|
+
/** Milliseconds between swaps. Default: 1500 */
|
|
253
|
+
interval?: number;
|
|
254
|
+
/** Stop when the user comes back to the tab. Default: true */
|
|
255
|
+
stopOnFocus?: boolean;
|
|
256
|
+
}
|
|
257
|
+
interface TabNotifications {
|
|
258
|
+
/** Shows the count in the title and a dot on the favicon; 0 clears both */
|
|
259
|
+
setUnreadCount(count: number): void;
|
|
260
|
+
getUnreadCount(): number;
|
|
261
|
+
/** Alternates the title with a message until `stopFlashing` (or the tab is focused) */
|
|
262
|
+
flashTitle(message: string, options?: FlashTitleOptions | number): void;
|
|
263
|
+
stopFlashing(): void;
|
|
264
|
+
isFlashing(): boolean;
|
|
265
|
+
/** Restores the original title and favicon */
|
|
266
|
+
reset(): void;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Unread count in the tab title, a dot on the favicon, and a flashing title for urgent alerts.
|
|
270
|
+
* Safe to create on the server; it touches `document` only when used.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* const tab = createTabNotifications();
|
|
274
|
+
* tab.setUnreadCount(5); // "(5) My app" + red dot
|
|
275
|
+
* tab.flashTitle("🔴 New order"); // until the user looks at the tab
|
|
276
|
+
*/
|
|
277
|
+
declare function createTabNotifications(options?: TabNotificationsOptions): TabNotifications;
|
|
278
|
+
/** Shared instance with the default options. */
|
|
279
|
+
declare const tabNotifications: TabNotifications;
|
|
280
|
+
|
|
281
|
+
type NotificationPriority = "critical" | "high" | "normal" | "low";
|
|
282
|
+
/** Built-in sounds, synthesized in the browser (no files to host). */
|
|
283
|
+
type NotificationSoundName = "success" | "error" | "warning" | "info" | "message" | "critical" | "pop";
|
|
284
|
+
interface PlaySoundOptions {
|
|
285
|
+
/** 0–1. Default: 0.7 */
|
|
286
|
+
volume?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Built-in sound played when there is no URL or it can't play (missing file, autoplay
|
|
289
|
+
* blocked before the first click). `false` for silence. Default: 'info'
|
|
290
|
+
*/
|
|
291
|
+
fallback?: NotificationSoundName | NotificationPriority | false;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Schedules a built-in sound on any audio context (also an `OfflineAudioContext`, to render it).
|
|
295
|
+
* Returns its length in seconds.
|
|
296
|
+
*/
|
|
297
|
+
declare function scheduleSound(ctx: BaseAudioContext, name: NotificationSoundName | NotificationPriority, volume?: number, when?: number): number;
|
|
298
|
+
/**
|
|
299
|
+
* Plays a built-in sound. Silent where audio isn't available.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* playSound("success");
|
|
303
|
+
* playSound("critical", { volume: 1 });
|
|
304
|
+
*/
|
|
305
|
+
declare function playSound(name?: NotificationSoundName | NotificationPriority, options?: {
|
|
306
|
+
volume?: number;
|
|
307
|
+
}): void;
|
|
308
|
+
/** Plays the built-in sound for a priority (`critical`, `high`, `normal`, `low`) or a sound name. */
|
|
309
|
+
declare function playTone(priority?: NotificationPriority | NotificationSoundName, volume?: number): void;
|
|
310
|
+
/** Names of the built-in sounds. */
|
|
311
|
+
declare const NOTIFICATION_SOUNDS: NotificationSoundName[];
|
|
312
|
+
/**
|
|
313
|
+
* Plays a sound file (decoded once, then cached) or a built-in sound by name, falling back
|
|
314
|
+
* to a built-in sound. Never throws.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* playNotificationSound("/sounds/notification.mp3");
|
|
318
|
+
* playNotificationSound("message");
|
|
319
|
+
* playNotificationSound(undefined, { fallback: "critical" }); // built-in only
|
|
320
|
+
*/
|
|
321
|
+
declare function playNotificationSound(url?: string, options?: PlaySoundOptions): Promise<void>;
|
|
322
|
+
|
|
323
|
+
export { CloseIcon, ErrorIcon, type FlashTitleOptions, InfoIcon, LoadingIcon, NOTIFICATION_SOUNDS, type NotificationPriority, type NotificationSoundName, type PlaySoundOptions, type PromiseMessages, type PromiseSource, SuccessIcon, type TabNotifications, type TabNotificationsOptions, type ToastAction, type ToastClassNames, type ToastColor, type ToastContent, type ToastId, type ToastOptions, type ToastPosition, type ToastRecord, type ToastState, type ToastStyles, type ToastStylesNames, type ToastType, Toaster, type ToasterLabels, type ToasterLocale, type ToasterProps, type ToasterTheme, WarningIcon, createTabNotifications, playNotificationSound, playSound, playTone, resolveColor, resolveLabels, scheduleSound, tabNotifications, toast, toastStore, useToasts };
|