d9-toast 1.1.19 → 1.2.20

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 CHANGED
@@ -1,25 +1,29 @@
1
1
  # D9-Toast
2
2
 
3
- Customizable toast notifications for React.
3
+ ![npm version](https://img.shields.io/npm/v/d9-toast?style=flat-square)
4
+ ![npm bundle size](https://img.shields.io/bundlephobia/min/d9-toast?style=flat-square)
5
+ ![npm downloads](https://img.shields.io/npm/dm/d9-toast?style=flat-square)
6
+ ![License](https://img.shields.io/npm/l/d9-toast?style=flat-square)
7
+ ![React](https://img.shields.io/badge/React-18+-61DAFB?style=flat-square&logo=react&logoColor=black)
4
8
 
9
+ A lightweight, customizable toast notification library for React applications.
5
10
 
6
- **Features:**
11
+ ## ✨ Features
7
12
 
8
- * Lightweight and fully customizable toast notifications.
9
- * Built with React.
10
- * Pure CSS included no additional setup required.
11
- * Easy to import and use in any React project.
12
- * Supports multiple types: success, error, info, warning, loading, submit.
13
- * Fully responsive and modern UI and smooth animation.
14
- * Users can optionally add Tailwind CSS classes via `className` for custom styling.
13
+ * **Lightweight & Customizable** Minimal bundle size with extensive customization options
14
+ * **React Native** – Built specifically for React with hooks support
15
+ * **No External Dependencies** – Pure CSS included, works out of the box
16
+ * **Multiple Toast Types** Success, error, info, warning, loading, and submit states
17
+ * **Responsive Design** Modern UI with smooth animations across all devices
18
+ * **Tailwind CSS Compatible** Optional custom styling via `className` prop
19
+ * **Flexible Positioning** 7 different display positions
20
+ * **Theme Support** – Light, dark, and colored themes
15
21
 
16
- ---
17
-
18
- ## Demo
22
+ ## 📺 Demo
19
23
 
20
- [Click Here](https://codesandbox.io/embed/cqkyzm?view=preview&module=%2Fpublic%2Findex.html)
24
+ [![Live Demo](https://img.shields.io/badge/Live_Demo-CodeSandbox-000000?style=for-the-badge&logo=codesandbox&logoColor=white)](https://codesandbox.io/embed/cqkyzm?view=preview&module=%2Fpublic%2Findex.html)
21
25
 
22
- ## Installation
26
+ ## 📦 Installation
23
27
 
24
28
  ```bash
25
29
  npm install d9-toast
@@ -31,9 +35,7 @@ or
31
35
  yarn add d9-toast
32
36
  ```
33
37
 
34
- ---
35
-
36
- ## Usage
38
+ ## 🚀 Quick Start
37
39
 
38
40
  ### 1. Wrap your app with `ToastProvider`
39
41
 
@@ -53,56 +55,149 @@ function Root() {
53
55
  export default Root;
54
56
  ```
55
57
 
56
- ### 2. Trigger a toast using `useToast`
58
+ ### 2. Use toast notifications anywhere
57
59
 
58
60
  ```jsx
59
61
  import React from "react";
60
62
  import { useToast } from "d9-toast";
61
63
 
62
- function App() {
64
+ function MyComponent() {
65
+ const { showToast } = useToast();
63
66
 
64
- const { showToast, removeToast, removeToastAll } = useToast();
65
-
66
- const Toast = () => {
67
+ const handleClick = () => {
67
68
  showToast({
68
- message: "Hello World!",
69
- type: "success", // success | error | info | warning | loading | submit
69
+ message: "Operation completed successfully!",
70
+ type: "success",
70
71
  position: "top-right",
71
72
  duration: 3000,
72
- actions: [
73
- { text: "Toast ID", callback: (toastId) => console.log(toastId) },
74
- { text: "Submit", callback: () => console.log("Submit clicked") },
75
- ],
76
- className: "bg-green-500 text-white shadow-lg", // optional Tailwind/custom styling
77
73
  });
78
74
  };
79
75
 
80
- return <button onClick={Toast}>Show Toast</button>;
76
+ return <button onClick={handleClick}>Show Toast</button>;
81
77
  }
78
+ ```
79
+
80
+ ## 📖 API Reference
81
+
82
+ ### `useToast()`
83
+
84
+ Returns an object with toast management methods:
85
+
86
+ | Method | Description |
87
+ |--------|-------------|
88
+ | `showToast(options)` | Displays a new toast notification |
89
+ | `removeToast(id)` | Removes a specific toast by ID |
90
+ | `removeToastAll()` | Removes all active toasts |
91
+
92
+
93
+ ### Toast Options
94
+
95
+ | Option | Type | Default | Description |
96
+ |--------|------|---------|-------------|
97
+ | `message` | string \| React.ReactNode | **Required** | Toast content (supports JSX) |
98
+ | `type` | string | `"info"` | Toast type: `success`, `error`, `info`, `warning`, `loading`, `submit` |
99
+ | `position` | string | `"top-right"` | Position: `top-left`, `top-right`, `bottom-left`, `bottom-right`, `center`, `center-top`, `center-bottom` |
100
+ | `theme` | string | `"light"` | Theme: `light`, `dark`, `colored` |
101
+ | `duration` | number | `5000` | Auto-close duration in ms (0 = infinite) |
102
+ | `autoClose` | boolean | `true` | Whether toast auto-closes after duration |
103
+ | `closable` | boolean | `true` | Show close (X) button |
104
+ | `pauseOnHover` | boolean | `true` | Pause timer on hover |
105
+ | `pauseOnFocusLoss` | boolean | `true` | Pause timer when window loses focus |
106
+ | `progress` | boolean | `true` | Show progress bar |
107
+ | `title` | boolean | `true` | Show toast header with type |
108
+ | `actions` | Array | `[]` | Action buttons: `[{ text: string, callback: function }]` |
109
+ | `className` | string | `""` | Additional CSS/Tailwind classes |
82
110
 
83
- export default App;
111
+ ## 💡 Advanced Usage
112
+
113
+ ### Custom Messages with JSX
114
+
115
+ ```jsx
116
+ showToast({
117
+ message: (
118
+ <div>
119
+ <strong>Custom Content</strong>
120
+ <p>With formatted HTML/JSX</p>
121
+ </div>
122
+ ),
123
+ type: "info"
124
+ });
84
125
  ```
85
126
 
86
- ### 3. Toast Options
87
-
88
- | Option | Type | Default | Description |
89
- | ---------- | ------- | ------- | -------------------------------------------------------------------------- |
90
- | `message` | string | - | Main message text of the toast |
91
- | `type` | string | `info` | Type of toast (`success`, `error`, `info`, `warning`, `loading`, `submit`) |
92
- | `duration` | number | 5000 | Auto-close duration in ms (0 for infinite) |
93
- | `position` | string | `top-right` | Position of all toasts (`top-left`, `top-right`, `bottom-left`, `bottom-right`, `center`, `center-top`, `center-bottom` ) |
94
- | `theme` | string | `light` | Default theme for all toasts (`light` or `dark`) |
95
- | `pauseOnHover` | boolean | `true` | Pause timer when hovered |
96
- | `pauseOnFocusLoss` | boolean | `true` | Pause timer when window/tab loses focus |
97
- | `actions` | array | [] | Array of action objects `{ text: string, callback: function }` |
98
- | `closable` | boolean | true | Allow manual close via X button
99
- | `autoClose` | boolean | true | Whether the toast auto-closes after duration button |
100
- | `progress` | boolean | true | Whether to show progress bar |
101
- | `className` | string| " " | Optional extra CSS/Tailwind classes to customize the toast bar |
127
+ ### Action Buttons
102
128
 
103
- ---
129
+ ```jsx
130
+ showToast({
131
+ message: "File uploaded successfully",
132
+ type: "success",
133
+ actions: [
134
+ {
135
+ text: "View",
136
+ callback: () => console.log("View clicked")
137
+ },
138
+ {
139
+ text: "Dismiss",
140
+ callback: ({ id }) => removeToast(id)
141
+ }
142
+ ]
143
+ });
144
+ ```
145
+
146
+ ### Manual Control
147
+
148
+ ```jsx
149
+ const { showToast, removeToast, removeToastAll } = useToast();
150
+
151
+ // Show a persistent toast
152
+ const toastId = showToast({
153
+ message: "Processing...",
154
+ type: "loading",
155
+ duration: 0 // Infinite
156
+ });
157
+
158
+ // Remove it later
159
+ removeToast(toastId);
160
+
161
+ // Clear all toasts
162
+ removeToastAll();
163
+ ```
104
164
 
105
- ## Development
165
+ ## 🎨 Styling
166
+
167
+ ### Default CSS
168
+
169
+ ```jsx
170
+ import "d9-toast/dist/toast.css";
171
+ ```
172
+
173
+ ### Custom Styling
174
+
175
+ ```jsx
176
+ showToast({
177
+ message: "Custom styled toast",
178
+ className: "bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-xl rounded-lg",
179
+ type: "info"
180
+ });
181
+ ```
182
+
183
+ ### Theme Examples
184
+
185
+ ```jsx
186
+ // Light theme (default)
187
+ showToast({ message: "Light", theme: "light" });
188
+
189
+ // Dark theme
190
+ showToast({ message: "Dark", theme: "dark" });
191
+
192
+ // Colored theme (uses type for color)
193
+ showToast({
194
+ message: "Colored",
195
+ theme: "colored",
196
+ type: "success"
197
+ });
198
+ ```
199
+
200
+ ## 🔧 Development
106
201
 
107
202
  ### Build
108
203
 
@@ -110,20 +205,37 @@ export default App;
110
205
  npm run build
111
206
  ```
112
207
 
113
- * Copies JS to `dist/`
114
- * Copies CSS `(toast.css)` to `dist/`
115
-
116
- ### Styling
208
+ Outputs to `dist/` directory:
209
+ - `dist/index.js` JavaScript bundle
210
+ - `dist/toast.css` – Default styles
117
211
 
118
- * Default styling is included in dist/toast.css
119
- * Users can optionally override or extend styles using className
212
+ ### Local Development
120
213
 
121
- ```jsx
122
- import "d9-toast/dist/toast.css";
214
+ ```bash
215
+ npm start
216
+ # or
217
+ npm run dev
123
218
  ```
124
- * Tailwind CSS is optional — you can pass Tailwind classes via className.
219
+
220
+ ## 🤝 Contributing
221
+
222
+ Contributions are welcome! Please feel free to submit a Pull Request.
223
+
224
+ ## 📄 License
225
+
226
+ MIT © [Athul / D9 Coder]
227
+
125
228
  ---
126
229
 
127
- ## License
230
+ ## 🙏 Acknowledgments
231
+
232
+ - Inspired by popular notification libraries
233
+ - Built with React and modern web standards
234
+ - Thanks to all contributors and users
235
+
236
+ ---
128
237
 
129
- MIT
238
+ **Quick Links:**
239
+ - [Report an Issue](https://github.com/psathul073/d9-toast/issues)
240
+ - [View Source](https://github.com/psathul073/d9-toast)
241
+ - [npm Package](https://www.npmjs.com/package/d9-toast)
package/dist/Icons.js CHANGED
@@ -1,12 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  var Icons = function Icons(_ref) {
3
- var name = _ref.name;
3
+ var name = _ref.name,
4
+ className = _ref.className;
4
5
  var icons = {
5
6
  success: /*#__PURE__*/_jsx("svg", {
6
7
  xmlns: "http://www.w3.org/2000/svg",
7
8
  viewBox: "0 0 24 24",
8
9
  width: "1em",
9
10
  height: "1em",
11
+ className: className,
12
+ style: {
13
+ backgroundColor: "transparent",
14
+ fontSize: "22px",
15
+ flexShrink: 0
16
+ },
10
17
  children: /*#__PURE__*/_jsx("path", {
11
18
  fill: "currentColor",
12
19
  fillRule: "evenodd",
@@ -18,6 +25,12 @@ var Icons = function Icons(_ref) {
18
25
  viewBox: "0 0 24 24",
19
26
  width: "1em",
20
27
  height: "1em",
28
+ className: className,
29
+ style: {
30
+ backgroundColor: "transparent",
31
+ fontSize: "22px",
32
+ flexShrink: 0
33
+ },
21
34
  children: /*#__PURE__*/_jsx("path", {
22
35
  d: "M16.707 2.293A.996.996 0 0 0 16 2H8a.996.996 0 0 0-.707.293l-5 5A.996.996 0 0 0 2 8v8c0 .266.105.52.293.707l5 5A.996.996 0 0 0 8 22h8c.266 0 .52-.105.707-.293l5-5A.996.996 0 0 0 22 16V8a.996.996 0 0 0-.293-.707l-5-5zM13 17h-2v-2h2v2zm0-4h-2V7h2v6z",
23
36
  fill: "currentColor"
@@ -28,6 +41,12 @@ var Icons = function Icons(_ref) {
28
41
  viewBox: "0 0 24 24",
29
42
  width: "1em",
30
43
  height: "1em",
44
+ className: className,
45
+ style: {
46
+ backgroundColor: "transparent",
47
+ fontSize: "22px",
48
+ flexShrink: 0
49
+ },
31
50
  children: /*#__PURE__*/_jsx("path", {
32
51
  fill: "currentColor",
33
52
  d: "M12 2c5.523 0 10 4.477 10 10a10 10 0 0 1-19.995.324L2 12l.004-.28C2.152 6.327 6.57 2 12 2m0 9h-1l-.117.007a1 1 0 0 0 0 1.986L11 13v3l.007.117a1 1 0 0 0 .876.876L12 17h1l.117-.007a1 1 0 0 0 .876-.876L14 16l-.007-.117a1 1 0 0 0-.764-.857l-.112-.02L13 15v-3l-.007-.117a1 1 0 0 0-.876-.876zm.01-3l-.127.007a1 1 0 0 0 0 1.986L12 10l.127-.007a1 1 0 0 0 0-1.986z"
@@ -38,6 +57,12 @@ var Icons = function Icons(_ref) {
38
57
  viewBox: "0 0 24 24",
39
58
  width: "1em",
40
59
  height: "1em",
60
+ className: className,
61
+ style: {
62
+ backgroundColor: "transparent",
63
+ fontSize: "22px",
64
+ flexShrink: 0
65
+ },
41
66
  children: /*#__PURE__*/_jsx("path", {
42
67
  fill: "currentColor",
43
68
  d: "m21.171 15.398l-5.912-9.854C14.483 4.251 13.296 3.511 12 3.511s-2.483.74-3.259 2.031l-5.912 9.856c-.786 1.309-.872 2.705-.235 3.83C3.23 20.354 4.472 21 6 21h12c1.528 0 2.77-.646 3.406-1.771s.551-2.521-.235-3.831M12 17.549c-.854 0-1.55-.695-1.55-1.549c0-.855.695-1.551 1.55-1.551s1.55.696 1.55 1.551c0 .854-.696 1.549-1.55 1.549m1.633-7.424c-.011.031-1.401 3.468-1.401 3.468c-.038.094-.13.156-.231.156s-.193-.062-.231-.156l-1.391-3.438a1.8 1.8 0 0 1-.129-.655c0-.965.785-1.75 1.75-1.75a1.752 1.752 0 0 1 1.633 2.375"
@@ -48,6 +73,12 @@ var Icons = function Icons(_ref) {
48
73
  viewBox: "0 0 24 24",
49
74
  width: "1em",
50
75
  height: "1em",
76
+ className: className,
77
+ style: {
78
+ backgroundColor: "transparent",
79
+ fontSize: "22px",
80
+ flexShrink: 0
81
+ },
51
82
  children: /*#__PURE__*/_jsxs("g", {
52
83
  fill: "none",
53
84
  stroke: "currentColor",
@@ -89,6 +120,12 @@ var Icons = function Icons(_ref) {
89
120
  viewBox: "0 0 24 24",
90
121
  width: "1em",
91
122
  height: "1em",
123
+ className: className,
124
+ style: {
125
+ backgroundColor: "transparent",
126
+ fontSize: "22px",
127
+ flexShrink: 0
128
+ },
92
129
  children: /*#__PURE__*/_jsxs("g", {
93
130
  fill: "none",
94
131
  stroke: "currentColor",
@@ -146,6 +183,12 @@ var Icons = function Icons(_ref) {
146
183
  viewBox: "0 0 24 24",
147
184
  width: "1em",
148
185
  height: "1em",
186
+ className: className,
187
+ style: {
188
+ backgroundColor: "transparent",
189
+ fontSize: "22px",
190
+ flexShrink: 0
191
+ },
149
192
  children: /*#__PURE__*/_jsxs("g", {
150
193
  fill: "currentColor",
151
194
  fillRule: "evenodd",
package/dist/Toast.js CHANGED
@@ -4,7 +4,7 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
- import React, { useEffect, useRef, useState } from "react";
7
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
8
  import "./toast.css";
9
9
  import Icons from "./Icons";
10
10
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
@@ -30,6 +30,8 @@ var Toast = function Toast(_ref) {
30
30
  autoClose = _ref$autoClose === void 0 ? true : _ref$autoClose,
31
31
  _ref$closable = _ref.closable,
32
32
  closable = _ref$closable === void 0 ? true : _ref$closable,
33
+ _ref$title = _ref.title,
34
+ title = _ref$title === void 0 ? true : _ref$title,
33
35
  _ref$pauseOnHover = _ref.pauseOnHover,
34
36
  pauseOnHover = _ref$pauseOnHover === void 0 ? true : _ref$pauseOnHover,
35
37
  _ref$pauseOnFocusLoss = _ref.pauseOnFocusLoss,
@@ -51,40 +53,23 @@ var Toast = function Toast(_ref) {
51
53
  setExiting = _useState6[1];
52
54
 
53
55
  // Styles [Animation]
54
- // entry animation [based on position]
55
- var enterAnim = "".concat(position.startsWith("top") && "upToDown" || position.startsWith("bottom") && "downToUp" || position.endsWith("top") && "upToDown" || position.endsWith("bottom") && "downToUp" || "centerEnter", " 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards");
56
+ var _useMemo = useMemo(function () {
57
+ // entry animation [based on position]
58
+ var baseEnter = position.startsWith("top") && "upToDown" || position.startsWith("bottom") && "downToUp" || position.endsWith("top") && "upToDown" || position.endsWith("bottom") && "downToUp" || "centerEnter";
56
59
 
57
- // exit animation [reverse direction]
58
- var exitAnim = "".concat(position.startsWith("top") && "downToUpExit" || position.startsWith("bottom") && "upToDownExit" || position.endsWith("top") && "downToUpExit" || position.endsWith("bottom") && "upToDownExit" || "centerExit", " 0.25s cubic-bezier(0.39, 0.575, 0.565, 1) forwards");
59
-
60
- // Start auto-close timer.
61
- useEffect(function () {
62
- if (duration !== 0 && autoClose) {
63
- startTimer();
64
- }
65
- // pause/resume when window focus changes.
66
- var handleBlur = function handleBlur() {
67
- return pauseOnFocusLoss && pauseTimer();
68
- };
69
- var handleFocus = function handleFocus() {
70
- return pauseOnFocusLoss && resumeTimer();
71
- };
72
- if (pauseOnFocusLoss) {
73
- window.addEventListener("blur", handleBlur);
74
- window.addEventListener("focus", handleFocus);
75
- }
76
- return function () {
77
- clearInterval(intervalRef.current);
78
- if (pauseOnFocusLoss) {
79
- window.removeEventListener("blur", handleBlur);
80
- window.removeEventListener("focus", handleFocus);
81
- }
82
- };
83
- }, [duration, autoClose, pauseOnFocusLoss]);
60
+ // exit animation [reverse direction]
61
+ var baseExit = position.startsWith("top") && "downToUpExit" || position.startsWith("bottom") && "upToDownExit" || position.endsWith("top") && "downToUpExit" || position.endsWith("bottom") && "upToDownExit" || "centerExit";
62
+ return {
63
+ enterAnim: "".concat(baseEnter, " 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards"),
64
+ exitAnim: "".concat(baseExit, " 0.25s cubic-bezier(0.39, 0.575, 0.565, 1) forwards")
65
+ };
66
+ }, [position]),
67
+ enterAnim = _useMemo.enterAnim,
68
+ exitAnim = _useMemo.exitAnim;
84
69
 
85
70
  // --- Helpers Fun ---
86
71
  // for start
87
- var startTimer = function startTimer() {
72
+ var startTimer = useCallback(function () {
88
73
  if (!autoClose) return;
89
74
  intervalRef.current = setInterval(function () {
90
75
  // time to passed...
@@ -100,40 +85,85 @@ var Toast = function Toast(_ref) {
100
85
  triggerExit();
101
86
  }
102
87
  }, 100);
103
- };
88
+ }, [autoClose, duration]);
104
89
 
105
90
  // for pause
106
- var pauseTimer = function pauseTimer() {
91
+ var pauseTimer = useCallback(function () {
107
92
  if (isPaused && !autoClose) return;
108
93
  clearInterval(intervalRef.current);
109
94
  remaining.current = remaining.current - (Date.now() - start.current);
110
95
  setPaused(true);
111
- };
96
+ }, [isPaused, autoClose]);
112
97
 
113
98
  // for resume
114
- var resumeTimer = function resumeTimer() {
99
+ var resumeTimer = useCallback(function () {
115
100
  if (!isPaused && !autoClose) return;
116
101
  start.current = Date.now();
117
102
  setPaused(false);
118
103
  startTimer();
119
- };
104
+ }, [isPaused, autoClose, startTimer]);
120
105
 
121
106
  // for exit
122
- var triggerExit = function triggerExit() {
107
+ var triggerExit = useCallback(function () {
123
108
  setExiting(true);
109
+ clearInterval(intervalRef.current);
124
110
  setTimeout(function () {
125
111
  return remove();
126
112
  }, 250); // Set and match exit animation duration.
127
- };
113
+ }, [remove]);
114
+
115
+ // Toast actions...
116
+ var actionButtons = useMemo(function () {
117
+ if (actions.length === 0) return null;
118
+ return actions.slice(0, 2).map(function (a, idx) {
119
+ return /*#__PURE__*/_jsx("button", {
120
+ onClick: function onClick() {
121
+ var _a$callback;
122
+ return (_a$callback = a.callback) === null || _a$callback === void 0 ? void 0 : _a$callback.call(a, {
123
+ id: id
124
+ });
125
+ },
126
+ className: "action-btn ".concat(actions.length === 1 ? "action-btnA ".concat(type) : idx === 0 ? "action-btnB ".concat(type) : "action-btnA ".concat(type)),
127
+ children: a.text
128
+ }, idx);
129
+ });
130
+ }, [actions, type, id]);
131
+ var handleMouseEnter = pauseOnHover ? pauseTimer : undefined;
132
+ var handleMouseLeave = pauseOnHover ? resumeTimer : undefined;
133
+
134
+ // Start auto-close timer.
135
+ useEffect(function () {
136
+ if (duration !== 0 && autoClose) {
137
+ startTimer();
138
+ }
139
+ // pause/resume when window focus changes.
140
+ var handleBlur = function handleBlur() {
141
+ return pauseOnFocusLoss && pauseTimer();
142
+ };
143
+ var handleFocus = function handleFocus() {
144
+ return pauseOnFocusLoss && resumeTimer();
145
+ };
146
+ if (pauseOnFocusLoss) {
147
+ window.addEventListener("blur", handleBlur);
148
+ window.addEventListener("focus", handleFocus);
149
+ }
150
+ return function () {
151
+ clearInterval(intervalRef.current);
152
+ if (pauseOnFocusLoss) {
153
+ window.removeEventListener("blur", handleBlur);
154
+ window.removeEventListener("focus", handleFocus);
155
+ }
156
+ };
157
+ }, [duration, autoClose, pauseOnFocusLoss]);
128
158
  return /*#__PURE__*/_jsx(_Fragment, {
129
159
  children: /*#__PURE__*/_jsxs("div", {
130
160
  style: {
131
161
  animation: exiting ? exitAnim : enterAnim
132
162
  },
133
- className: "toast ".concat(theme, " ").concat(className),
134
- onMouseEnter: pauseOnHover ? pauseTimer : undefined,
135
- onMouseLeave: pauseOnHover ? resumeTimer : undefined,
136
- children: [/*#__PURE__*/_jsxs("div", {
163
+ className: "toast ".concat(theme === "colored" ? type : theme, " ").concat(className),
164
+ onMouseEnter: handleMouseEnter,
165
+ onMouseLeave: handleMouseLeave,
166
+ children: [title && /*#__PURE__*/_jsxs("div", {
137
167
  className: "toastHeader ".concat(type),
138
168
  children: [/*#__PURE__*/_jsxs("div", {
139
169
  className: "title",
@@ -143,6 +173,7 @@ var Toast = function Toast(_ref) {
143
173
  children: type.toUpperCase()
144
174
  })]
145
175
  }), closable && /*#__PURE__*/_jsx("button", {
176
+ className: "close-button",
146
177
  onClick: function onClick() {
147
178
  return triggerExit();
148
179
  },
@@ -150,27 +181,35 @@ var Toast = function Toast(_ref) {
150
181
  name: "X"
151
182
  })
152
183
  })]
153
- }), /*#__PURE__*/_jsx("p", {
184
+ }), typeof message === "string" ? /*#__PURE__*/_jsx(_Fragment, {
185
+ children: /*#__PURE__*/_jsxs("div", {
186
+ className: "toast-message__container",
187
+ children: [/*#__PURE__*/_jsxs("div", {
188
+ className: "toast-message",
189
+ children: [!title && /*#__PURE__*/_jsx(Icons, {
190
+ name: type,
191
+ className: type
192
+ }), /*#__PURE__*/_jsx("p", {
193
+ children: message
194
+ })]
195
+ }), closable && !title && /*#__PURE__*/_jsx("button", {
196
+ className: "close-button",
197
+ onClick: function onClick() {
198
+ return triggerExit();
199
+ },
200
+ children: /*#__PURE__*/_jsx(Icons, {
201
+ name: "X"
202
+ })
203
+ })]
204
+ })
205
+ }) : /*#__PURE__*/_jsx("div", {
154
206
  style: {
155
207
  padding: "4px"
156
208
  },
157
209
  children: message
158
210
  }), actions.length > 0 && /*#__PURE__*/_jsx("div", {
159
211
  className: "toastActions",
160
- children: actions.map(function (a, idx) {
161
- if (idx < 2) {
162
- return /*#__PURE__*/_jsx("button", {
163
- onClick: function onClick() {
164
- var _a$callback;
165
- return (_a$callback = a.callback) === null || _a$callback === void 0 ? void 0 : _a$callback.call(a, {
166
- id: id
167
- });
168
- },
169
- className: "action-btn ".concat(actions.length === 1 ? "action-btnA ".concat(type) : idx === 0 ? "action-btnB ".concat(type) : "action-btnA ".concat(type)),
170
- children: a.text
171
- }, idx);
172
- }
173
- })
212
+ children: actionButtons
174
213
  }), progress && duration !== 0 && autoClose && /*#__PURE__*/_jsx("div", {
175
214
  className: "progress-container ".concat(type),
176
215
  children: /*#__PURE__*/_jsx("div", {
@@ -183,4 +222,4 @@ var Toast = function Toast(_ref) {
183
222
  })
184
223
  });
185
224
  };
186
- export default Toast;
225
+ export default /*#__PURE__*/React.memo(Toast);
@@ -11,7 +11,7 @@ declare module "d9-toast" {
11
11
  | "submit";
12
12
 
13
13
  /** Theme variants */
14
- export type ToastTheme = "light" | "dark";
14
+ export type ToastTheme = "light" | "dark" | "colored";
15
15
 
16
16
  /** Available toast positions */
17
17
  export type ToastPosition =
@@ -33,8 +33,8 @@ declare module "d9-toast" {
33
33
 
34
34
  /** Toast configuration options */
35
35
  export interface ToastOptions {
36
- /** Main message text of the toast */
37
- message: string;
36
+ /** Main message; can be string or any React node (you render non-strings as-is) */
37
+ message: string | React.ReactNode;
38
38
  /** Visual type (color/icon) */
39
39
  type?: ToastType;
40
40
  /** Duration in ms before auto-close (0 = persistent) */
@@ -43,6 +43,8 @@ declare module "d9-toast" {
43
43
  actions?: ToastAction[];
44
44
  /** Visual theme */
45
45
  theme?: ToastTheme;
46
+ /** Weather to show toast title */
47
+ title?: boolean;
46
48
  /** Whether to show progress bar */
47
49
  progress?: boolean;
48
50
  /** Allow manual close via X button */
@@ -57,6 +59,7 @@ declare module "d9-toast" {
57
59
  position?: ToastPosition;
58
60
  /** Whether the toast auto-closes after duration */
59
61
  autoClose?: boolean;
62
+
60
63
  }
61
64
 
62
65
  /** Toast provider props for context setup */
@@ -65,6 +68,10 @@ declare module "d9-toast" {
65
68
  children: React.ReactNode;
66
69
  }
67
70
 
71
+ export interface ToastData extends ToastOptions {
72
+ id: number;
73
+ }
74
+
68
75
  /** Context value shape */
69
76
  export interface ToastContextValue {
70
77
  /** Show a toast with given options */
@@ -80,4 +87,10 @@ declare module "d9-toast" {
80
87
 
81
88
  /** Hook to trigger and manage toasts */
82
89
  export const useToast: () => ToastContextValue;
90
+
91
+ /** Export the Toast component props/type for advanced consumers */
92
+ export interface ToastProps extends ToastData {
93
+ remove: () => void;
94
+ }
95
+ export const Toast: React.FC<ToastProps>;
83
96
  }
package/dist/toast.css CHANGED
@@ -57,25 +57,28 @@
57
57
 
58
58
  .toast {
59
59
  position: relative;
60
- width: 320px;
60
+ min-width: 310px;
61
+ max-width: 425px;
61
62
  display: flex;
62
63
  flex-direction: column;
63
64
  gap: 8px;
64
65
  padding: 6px;
65
- margin: 6px 0;
66
+ margin: 8px;
66
67
  border-radius: 8px;
67
68
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
68
69
  font-family: cursive;
69
70
  transition: all 0.3s ease-in;
71
+ will-change: transform, opacity;
70
72
  }
73
+
71
74
  .light {
72
- background-color: #f9fafb;
73
- color: #111827;
75
+ background-color: #ffffff;
76
+ color: #1e2939;
74
77
  }
75
78
 
76
79
  .dark {
77
- background-color: #030712;
78
- color: #f3f4f6;
80
+ background-color: #1e2939;
81
+ color: #ffffff;
79
82
  }
80
83
 
81
84
  .toastHeader {
@@ -84,49 +87,44 @@
84
87
  align-items: center;
85
88
  padding: 2px 4px;
86
89
  border-radius: 6px;
87
- box-shadow: inset 0 1px rgb(0 0 0 / 0.05);
90
+ box-shadow: inset 0 1px rgb(0 0 0 / 0.06);
88
91
  }
92
+
89
93
  .toastHeader .title {
90
94
  display: inline-flex;
91
95
  align-items: center;
92
96
  gap: 8px;
93
- font-size: 1rem;
97
+ font-size: 0.9rem;
94
98
  font-weight: 500;
95
99
  }
96
100
 
97
- .toastHeader button {
101
+ .close-button {
98
102
  display: flex;
99
103
  align-items: center;
100
104
  justify-content: center;
101
- font-size: 1.3em;
102
105
  cursor: pointer;
103
106
  }
104
107
 
105
- .toastHeader button:hover {
108
+ .close-button:hover {
106
109
  color: oklch(57.7% 0.245 27.325);
107
110
  }
108
111
 
109
- .toastHeader.success {
110
- color: oklch(62.7% 0.194 149.214);
111
- background-color: oklch(63.187% 0.18673 147.227 / 0.2);
112
- }
113
- .toastHeader.error {
114
- color: oklch(57.7% 0.245 27.325);
115
- background-color: oklch(58.305% 0.23863 28.392 / 0.2);
116
- }
117
- .toastHeader.info {
118
- color: oklch(54.6% 0.245 262.881);
119
- background-color: oklch(54.6% 0.245 262.881 / 0.2);
120
- }
121
- .toastHeader.warning {
122
- color: oklch(68.1% 0.162 75.834);
123
- background-color: oklch(68.1% 0.162 75.834 / 0.2);
112
+ .toast-message__container {
113
+ display: inline-flex;
114
+ justify-content: space-between;
115
+ align-items: center;
116
+ padding: 8px;
117
+ gap: 8px;
124
118
  }
125
- .toastHeader.loading,
126
- .toastHeader.submit {
127
- color: oklab(54.13400000000001% 0.09644 -0.22706);
128
- background-color: oklab(54.13400000000001% 0.09644 -0.22706 / 0.2);
119
+
120
+ .toast-message__container .toast-message{
121
+ display: inline-flex;
122
+ align-items: center;
123
+ text-wrap: wrap;
124
+ gap: 8px;
125
+ overflow: hidden;
129
126
  }
127
+
130
128
  .toastActions {
131
129
  display: flex;
132
130
  justify-content: flex-end;
@@ -139,6 +137,7 @@
139
137
  font-size: 14px;
140
138
  border-radius: 6px;
141
139
  border: 1px solid;
140
+ box-shadow: inset 0 0 1px #0b0b0b;
142
141
  cursor: pointer;
143
142
  }
144
143
  .toastActions .action-btn:hover {
@@ -146,54 +145,54 @@
146
145
  }
147
146
 
148
147
  /* Action button 1 */
149
- .action-btnA.success {
150
- color: oklab(98.193% -0.01648 0.00729);
151
- border-color: oklch(63.187% 0.18673 147.227);
152
- background-color: oklch(63.187% 0.18673 147.227);
148
+ .action-btnA.success,.colored.success {
149
+ color: #ffffff;
150
+ border-color: #00c950;
151
+ background-color: #00c950;
153
152
  }
154
153
  .action-btnA.error {
155
- color: oklab(93.56400000000001% 0.02943 0.0093);
156
- border-color: oklch(58.305% 0.23863 28.392);
157
- background-color: oklch(58.305% 0.23863 28.392);
154
+ color: #ffffff;
155
+ border-color: #fb2c36;
156
+ background-color: #fb2c36;
158
157
  }
159
158
  .action-btnA.info {
160
- color: oklab(93.192% -0.00786 -0.03071);
161
- border-color: oklch(54.742% 0.24331 262.725);
162
- background-color: oklch(54.742% 0.24331 262.725);
159
+ color: #ffffff;
160
+ border-color: #0088ff;
161
+ background-color: #0088ff;
163
162
  }
164
163
  .action-btnA.warning {
165
- color: oklab(97.962% 0.00443 0.01503);
166
- border-color: oklch(68.215% 0.14645 71.468);
167
- background-color: oklch(68.215% 0.14645 71.468);
164
+ color: #ffffff;
165
+ border-color: #f0b100;
166
+ background-color: #f0b100;
168
167
  }
169
168
  .action-btnA.loading,
170
169
  .action-btnA.submit {
171
- color: oklab(94.33500000000001% 0.01183 -0.02594);
172
- border-color: oklab(54.13400000000001% 0.09644 -0.22706);
173
- background-color: oklab(54.13400000000001% 0.09644 -0.22706);
170
+ color: #ffffff;
171
+ border-color: #aa44ff;
172
+ background-color: #aa44ff;
174
173
  }
175
174
  /* Action button 2 */
176
175
  .action-btnB.success {
177
- color: oklch(63.187% 0.18673 147.227);
178
- border-color: oklch(63.187% 0.18673 147.227);
176
+ color: #00c950;
177
+ border-color: currentColor;
179
178
  }
180
179
 
181
180
  .action-btnB.error {
182
- color: oklch(58.305% 0.23863 28.392);
183
- border-color: oklch(58.305% 0.23863 28.392);
181
+ color: #fb2c36;
182
+ border-color: currentColor;
184
183
  }
185
184
  .action-btnB.info {
186
- color: oklch(54.742% 0.24331 262.725);
187
- border-color: oklch(54.742% 0.24331 262.725);
185
+ color: #0088ff;
186
+ border-color: currentColor;
188
187
  }
189
188
  .action-btnB.warning {
190
- color: oklch(68.215% 0.14645 71.468);
191
- border-color: oklch(68.215% 0.14645 71.468);
189
+ color: #f0b100;
190
+ border-color: currentColor;
192
191
  }
193
192
  .action-btnB.loading,
194
193
  .action-btnB.submit {
195
- color: oklab(54.13400000000001% 0.09644 -0.22706);
196
- border-color: oklab(54.13400000000001% 0.09644 -0.22706);
194
+ color: #aa44ff;
195
+ border-color: currentColor;
197
196
  }
198
197
 
199
198
  .progress-container {
@@ -203,49 +202,54 @@
203
202
  width: 100%;
204
203
  height: 0.25rem;
205
204
  border-radius: 0 0 0.25rem 0.25rem;
206
- background-color: rgba(220, 220, 220, 0.715);
207
205
  overflow: hidden;
208
206
  }
209
207
 
210
- .progress-container.success {
211
- background-color: oklch(62.7% 0.194 149.214 / 0.25);
212
- }
213
- .progress-container.error {
214
- background-color: oklch(57.7% 0.245 27.325 / 0.25);
215
- }
216
- .progress-container.info {
217
- background-color: oklch(54.6% 0.245 262.881 / 0.25);
218
- }
219
- .progress-container.warning {
220
- background-color: oklch(68.1% 0.162 75.834 / 0.25);
221
- }
222
- .progress-container.loading,
223
- .progress-container.submit {
224
- background-color: oklab(54.13400000000001% 0.09644 -0.22706 / 0.25);
225
- }
226
-
227
208
  .toast-progress {
228
209
  height: 0.25rem;
229
210
  transition: width 0.1s linear;
230
211
  }
231
212
 
232
213
  .toast-progress.success {
233
- background-color: oklch(62.7% 0.194 149.214);
214
+ background-color: #00c950;
234
215
  }
235
216
  .toast-progress.error {
236
- background-color: oklch(57.7% 0.245 27.325);
217
+ background-color: #fb2c36;
237
218
  }
238
219
  .toast-progress.info {
239
- background-color: oklch(54.6% 0.245 262.881);
220
+ background-color: #0088ff;
240
221
  }
241
222
  .toast-progress.warning {
242
- background-color: oklch(68.1% 0.162 75.834);
223
+ background-color: #f0b100;
243
224
  }
244
225
  .toast-progress.loading,
245
226
  .toast-progress.submit {
246
- background-color: oklab(54.13400000000001% 0.09644 -0.22706);
227
+ background-color: #aa44ff;
247
228
  }
248
229
 
230
+ .success {
231
+ color: #00c950;
232
+ background-color: rgba(0, 166, 61, 0.1);
233
+ }
234
+ .error {
235
+ color: #fb2c36;
236
+ background-color: rgba(231, 0, 12, 0.1);
237
+ }
238
+ .info {
239
+ color: #0088ff;
240
+ background-color: rgba(21, 93, 251, 0.1);
241
+ }
242
+ .warning {
243
+ color: #f0b100;
244
+ background-color: rgba(208, 135, 0, 0.1);
245
+ }
246
+ .loading,.submit {
247
+ color: #aa44ff;
248
+ background-color: rgba(124, 58, 237, 0.1);
249
+ }
250
+
251
+
252
+ /* Zoom animation */
249
253
  /* Enter animate keyframes */
250
254
  @keyframes upToDown {
251
255
  from {
@@ -269,6 +273,17 @@
269
273
  }
270
274
  }
271
275
 
276
+ @keyframes centerEnter {
277
+ from {
278
+ opacity: 0;
279
+ transform: scale(0.6);
280
+ }
281
+ to {
282
+ opacity: 1;
283
+ transform: scale(1);
284
+ }
285
+ }
286
+
272
287
  /* Exit animate keyframes */
273
288
  @keyframes upToDownExit {
274
289
  from {
@@ -292,17 +307,6 @@
292
307
  }
293
308
  }
294
309
 
295
- @keyframes centerEnter {
296
- from {
297
- opacity: 0;
298
- transform: scale(0.6);
299
- }
300
- to {
301
- opacity: 1;
302
- transform: scale(1);
303
- }
304
- }
305
-
306
310
  @keyframes centerExit {
307
311
  from {
308
312
  opacity: 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "d9-toast",
3
- "version": "1.1.19",
3
+ "version": "1.2.20",
4
4
  "description": "Customizable toast notifications for React",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",