@r01al/simple-toast 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.
@@ -0,0 +1,394 @@
1
+ const defaultConfig = {
2
+ position: 'tr',
3
+ duration: 3000,
4
+ theme: 'l',
5
+ dismissible: true,
6
+ maxToasts: 10
7
+ };
8
+
9
+ let globalConfig = { ...defaultConfig };
10
+
11
+ function configure(config) {
12
+ globalConfig = { ...globalConfig, ...config };
13
+ }
14
+
15
+ function getConfig() {
16
+ return globalConfig;
17
+ }
18
+
19
+ let stylesInjected = false;
20
+
21
+ function injectStyles() {
22
+ if (stylesInjected) return;
23
+
24
+ const style = document.createElement('style');
25
+ style.setAttribute('data-r01st', '');
26
+ style.textContent = `
27
+ .r01st-container {
28
+ position: fixed;
29
+ z-index: 9999;
30
+ pointer-events: none;
31
+ padding: 16px;
32
+ }
33
+ .r01st-container[data-position="tl"] {
34
+ top: 0;
35
+ left: 0;
36
+ }
37
+
38
+ .r01st-container[data-position="tc"] {
39
+ top: 0;
40
+ left: 50%;
41
+ margin-left: -210px;
42
+ }
43
+
44
+ .r01st-container[data-position="tr"] {
45
+ top: 0;
46
+ right: 0;
47
+ }
48
+ .r01st-container[data-position="ml"] {
49
+ top: 50%;
50
+ left: 0;
51
+ margin-top: -50px;
52
+ }
53
+
54
+ .r01st-container[data-position="mc"] {
55
+ top: 50%;
56
+ left: 50%;
57
+ margin-left: -210px;
58
+ margin-top: -50px;
59
+ }
60
+
61
+ .r01st-container[data-position="mr"] {
62
+ top: 50%;
63
+ right: 0;
64
+ margin-top: -50px;
65
+ }
66
+ .r01st-container[data-position="bl"] {
67
+ bottom: 0;
68
+ left: 0;
69
+ }
70
+
71
+ .r01st-container[data-position="bc"] {
72
+ bottom: 0;
73
+ left: 50%;
74
+ margin-left: -210px;
75
+ }
76
+
77
+ .r01st-container[data-position="br"] {
78
+ bottom: 0;
79
+ right: 0;
80
+ }
81
+ .r01st {
82
+ pointer-events: auto;
83
+ position: relative;
84
+ min-width: 280px;
85
+ max-width: 420px;
86
+ padding: 16px;
87
+ margin-bottom: 16px;
88
+ border-radius: 8px;
89
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
90
+ font-size: 14px;
91
+ line-height: 1.5;
92
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
93
+ color: #ffffff;
94
+ opacity: 0;
95
+ transition: opacity 0.3s ease, margin-top 0.3s ease;
96
+ margin-top: -20px;
97
+ }
98
+ .r01st-show {
99
+ opacity: 1;
100
+ margin-top: 0;
101
+ }
102
+ .r01st-container[data-theme="l"] .r01st-success {
103
+ background-color: #10b981;
104
+ }
105
+
106
+ .r01st-container[data-theme="l"] .r01st-error {
107
+ background-color: #ef4444;
108
+ }
109
+
110
+ .r01st-container[data-theme="l"] .r01st-info {
111
+ background-color: #3b82f6;
112
+ }
113
+
114
+ .r01st-container[data-theme="l"] .r01st-warning {
115
+ background-color: #f59e0b;
116
+ }
117
+ .r01st-container[data-theme="d"] .r01st-success {
118
+ background-color: #059669;
119
+ }
120
+
121
+ .r01st-container[data-theme="d"] .r01st-error {
122
+ background-color: #dc2626;
123
+ }
124
+
125
+ .r01st-container[data-theme="d"] .r01st-info {
126
+ background-color: #2563eb;
127
+ }
128
+
129
+ .r01st-container[data-theme="d"] .r01st-warning {
130
+ background-color: #d97706;
131
+ }
132
+ .r01st-content {
133
+ display: inline-block;
134
+ width: 100%;
135
+ vertical-align: top;
136
+ padding-right: 30px;
137
+ }
138
+ .r01st-icon {
139
+ display: inline-block;
140
+ width: 20px;
141
+ height: 20px;
142
+ vertical-align: middle;
143
+ margin-right: 12px;
144
+ }
145
+
146
+ .r01st-icon svg {
147
+ width: 100%;
148
+ height: 100%;
149
+ display: block;
150
+ }
151
+ .r01st-message {
152
+ display: inline-block;
153
+ vertical-align: middle;
154
+ word-wrap: break-word;
155
+ max-width: calc(100% - 32px);
156
+ }
157
+ .r01st-close {
158
+ position: absolute;
159
+ top: 16px;
160
+ right: 16px;
161
+ background: transparent;
162
+ border: none;
163
+ color: #ffffff;
164
+ font-size: 24px;
165
+ line-height: 1;
166
+ cursor: pointer;
167
+ padding: 0;
168
+ width: 24px;
169
+ height: 24px;
170
+ text-align: center;
171
+ border-radius: 4px;
172
+ opacity: 0.8;
173
+ }
174
+
175
+ .r01st-close:hover {
176
+ background-color: rgba(255, 255, 255, 0.2);
177
+ opacity: 1;
178
+ }
179
+
180
+ .r01st-close:focus {
181
+ outline: 2px solid #ffffff;
182
+ outline-offset: 2px;
183
+ }
184
+ .r01st-container[data-position^="b"] .r01st {
185
+ margin-top: 0;
186
+ margin-bottom: -20px;
187
+ }
188
+
189
+ .r01st-container[data-position^="b"] .r01st-show {
190
+ margin-bottom: 16px;
191
+ }
192
+ @media (max-width: 480px) {
193
+ .r01st-container {
194
+ left: 0 !important;
195
+ right: 0 !important;
196
+ margin-left: 0 !important;
197
+ padding: 8px;
198
+ }
199
+
200
+ .r01st {
201
+ min-width: auto;
202
+ max-width: none;
203
+ }
204
+ }
205
+ @media (prefers-reduced-motion: reduce) {
206
+ .r01st {
207
+ transition: opacity 0.2s;
208
+ margin-top: 0;
209
+ }
210
+ }
211
+ @media print {
212
+ .r01st-container {
213
+ display: none;
214
+ }
215
+ }
216
+ `;
217
+
218
+ document.head.appendChild(style);
219
+ stylesInjected = true;
220
+ }
221
+
222
+ let container = null;
223
+
224
+ function getContainer(position, theme) {
225
+ injectStyles();
226
+
227
+ if (container && (container.getAttribute('data-position') !== position || container.getAttribute('data-theme') !== theme)) {
228
+ container.parentNode.removeChild(container);
229
+ container = null;
230
+ }
231
+
232
+ if (!container) {
233
+ container = document.createElement('div');
234
+ container.className = 'r01st-container';
235
+ container.setAttribute('role', 'region');
236
+ container.setAttribute('aria-label', 'Notifications');
237
+ container.setAttribute('aria-live', 'polite');
238
+ container.setAttribute('data-position', position);
239
+ container.setAttribute('data-theme', theme);
240
+ document.body.appendChild(container);
241
+ }
242
+
243
+ return container;
244
+ }
245
+
246
+ function cleanupContainer(activeCount) {
247
+ if (container && activeCount === 0) {
248
+ container.parentNode.removeChild(container);
249
+ container = null;
250
+ }
251
+ }
252
+
253
+ function getIcon(type) {
254
+ const icons = {
255
+ success: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>',
256
+ error: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg>',
257
+ info: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg>',
258
+ warning: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg>'
259
+ };
260
+ return icons[type] || icons.info;
261
+ }
262
+
263
+ function createToastElement(message, type, dismissible, className, id, onClose) {
264
+ const toastEl = document.createElement('div');
265
+ toastEl.className = 'r01st r01st-' + type + (className ? ' ' + className : '');
266
+ toastEl.setAttribute('role', 'alert');
267
+ toastEl.setAttribute('data-toast-id', id);
268
+
269
+ const content = document.createElement('div');
270
+ content.className = 'r01st-content';
271
+
272
+ const icon = document.createElement('span');
273
+ icon.className = 'r01st-icon';
274
+ icon.innerHTML = getIcon(type);
275
+ icon.setAttribute('aria-hidden', 'true');
276
+ content.appendChild(icon);
277
+
278
+ const messageEl = document.createElement('span');
279
+ messageEl.className = 'r01st-message';
280
+ messageEl.textContent = message;
281
+ content.appendChild(messageEl);
282
+
283
+ toastEl.appendChild(content);
284
+
285
+ if (dismissible) {
286
+ const closeBtn = document.createElement('button');
287
+ closeBtn.className = 'r01st-close';
288
+ closeBtn.innerHTML = '&times;';
289
+ closeBtn.setAttribute('aria-label', 'Close notification');
290
+ closeBtn.onclick = onClose;
291
+ toastEl.appendChild(closeBtn);
292
+ }
293
+
294
+ return toastEl;
295
+ }
296
+
297
+ function showToast(element) {
298
+ requestAnimationFrame(() => {
299
+ element.className = element.className + ' r01st-show';
300
+ });
301
+ }
302
+
303
+ function hideToast(element, callback) {
304
+ element.className = element.className.replace(' r01st-show', '');
305
+
306
+ setTimeout(() => {
307
+ if (element.parentNode) {
308
+ element.parentNode.removeChild(element);
309
+ }
310
+ if (callback) callback();
311
+ }, 300);
312
+ }
313
+
314
+ let toastCounter = 0;
315
+ const activeToasts = new Map();
316
+
317
+ function createToast(message, options = {}) {
318
+ const config = { ...getConfig(), ...options };
319
+ const { position, duration, dismissible, theme, className, type = 'info' } = config;
320
+
321
+ const id = ++toastCounter;
322
+
323
+ if (activeToasts.size >= getConfig().maxToasts) {
324
+ const firstToast = activeToasts.keys().next().value;
325
+ dismissToast(firstToast);
326
+ }
327
+
328
+ const container = getContainer(position, theme);
329
+
330
+ const handleClose = () => dismissToast(id);
331
+
332
+ const toastEl = createToastElement(message, type, dismissible, className, id, handleClose);
333
+
334
+ container.appendChild(toastEl);
335
+
336
+ showToast(toastEl);
337
+
338
+ const toastData = {
339
+ element: toastEl,
340
+ timeoutId: null
341
+ };
342
+
343
+ if (duration > 0) {
344
+ toastData.timeoutId = setTimeout(() => dismissToast(id), duration);
345
+ }
346
+
347
+ activeToasts.set(id, toastData);
348
+
349
+ return id;
350
+ }
351
+
352
+ function dismissToast(id) {
353
+ const toastData = activeToasts.get(id);
354
+ if (!toastData) return;
355
+
356
+ const { element, timeoutId } = toastData;
357
+
358
+ if (timeoutId) {
359
+ clearTimeout(timeoutId);
360
+ }
361
+
362
+ activeToasts.delete(id);
363
+
364
+ hideToast(element, () => {
365
+ cleanupContainer(activeToasts.size);
366
+ });
367
+ }
368
+
369
+ function dismissAllToasts() {
370
+ const ids = Array.from(activeToasts.keys());
371
+ ids.forEach(id => dismissToast(id));
372
+ }
373
+
374
+ /**
375
+ * Display a toast notification
376
+ * @param {string} message - The message to display
377
+ * @param {Object} options - Toast options
378
+ * @returns {number} Toast ID
379
+ */
380
+ function toast(message, options = {}) {
381
+ return createToast(message, options);
382
+ }
383
+
384
+ // Shorthand methods
385
+ toast.success = (message, options = {}) => toast(message, { ...options, type: 'success' });
386
+ toast.error = (message, options = {}) => toast(message, { ...options, type: 'error' });
387
+ toast.info = (message, options = {}) => toast(message, { ...options, type: 'info' });
388
+ toast.warning = (message, options = {}) => toast(message, { ...options, type: 'warning' });
389
+
390
+ // Export dismiss methods
391
+ toast.dismiss = dismissToast;
392
+ toast.dismissAll = dismissAllToasts;
393
+
394
+ export { configure, toast as default, toast };
@@ -0,0 +1 @@
1
+ !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((n="undefined"!=typeof globalThis?globalThis:n||self).SimpleToast={})}(this,function(n){"use strict";let t={position:"tr",duration:3e3,theme:"l",dismissible:!0,maxToasts:10};function e(){return t}let o=!1;let i=null;function r(n,t){return function(){if(o)return;const n=document.createElement("style");n.setAttribute("data-r01st",""),n.textContent='\n.r01st-container {\n position: fixed;\n z-index: 9999;\n pointer-events: none;\n padding: 16px;\n}\n.r01st-container[data-position="tl"] {\n top: 0;\n left: 0;\n}\n\n.r01st-container[data-position="tc"] {\n top: 0;\n left: 50%;\n margin-left: -210px;\n}\n\n.r01st-container[data-position="tr"] {\n top: 0;\n right: 0;\n}\n.r01st-container[data-position="ml"] {\n top: 50%;\n left: 0;\n margin-top: -50px;\n}\n\n.r01st-container[data-position="mc"] {\n top: 50%;\n left: 50%;\n margin-left: -210px;\n margin-top: -50px;\n}\n\n.r01st-container[data-position="mr"] {\n top: 50%;\n right: 0;\n margin-top: -50px;\n}\n.r01st-container[data-position="bl"] {\n bottom: 0;\n left: 0;\n}\n\n.r01st-container[data-position="bc"] {\n bottom: 0;\n left: 50%;\n margin-left: -210px;\n}\n\n.r01st-container[data-position="br"] {\n bottom: 0;\n right: 0;\n}\n.r01st {\n pointer-events: auto;\n position: relative;\n min-width: 280px;\n max-width: 420px;\n padding: 16px;\n margin-bottom: 16px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n font-size: 14px;\n line-height: 1.5;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n color: #ffffff;\n opacity: 0;\n transition: opacity 0.3s ease, margin-top 0.3s ease;\n margin-top: -20px;\n}\n.r01st-show {\n opacity: 1;\n margin-top: 0;\n}\n.r01st-container[data-theme="l"] .r01st-success {\n background-color: #10b981;\n}\n\n.r01st-container[data-theme="l"] .r01st-error {\n background-color: #ef4444;\n}\n\n.r01st-container[data-theme="l"] .r01st-info {\n background-color: #3b82f6;\n}\n\n.r01st-container[data-theme="l"] .r01st-warning {\n background-color: #f59e0b;\n}\n.r01st-container[data-theme="d"] .r01st-success {\n background-color: #059669;\n}\n\n.r01st-container[data-theme="d"] .r01st-error {\n background-color: #dc2626;\n}\n\n.r01st-container[data-theme="d"] .r01st-info {\n background-color: #2563eb;\n}\n\n.r01st-container[data-theme="d"] .r01st-warning {\n background-color: #d97706;\n}\n.r01st-content {\n display: inline-block;\n width: 100%;\n vertical-align: top;\n padding-right: 30px;\n}\n.r01st-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n vertical-align: middle;\n margin-right: 12px;\n}\n\n.r01st-icon svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.r01st-message {\n display: inline-block;\n vertical-align: middle;\n word-wrap: break-word;\n max-width: calc(100% - 32px);\n}\n.r01st-close {\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n color: #ffffff;\n font-size: 24px;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n text-align: center;\n border-radius: 4px;\n opacity: 0.8;\n}\n\n.r01st-close:hover {\n background-color: rgba(255, 255, 255, 0.2);\n opacity: 1;\n}\n\n.r01st-close:focus {\n outline: 2px solid #ffffff;\n outline-offset: 2px;\n}\n.r01st-container[data-position^="b"] .r01st {\n margin-top: 0;\n margin-bottom: -20px;\n}\n\n.r01st-container[data-position^="b"] .r01st-show {\n margin-bottom: 16px;\n}\n@media (max-width: 480px) {\n .r01st-container {\n left: 0 !important;\n right: 0 !important;\n margin-left: 0 !important;\n padding: 8px;\n }\n\n .r01st {\n min-width: auto;\n max-width: none;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .r01st {\n transition: opacity 0.2s;\n margin-top: 0;\n }\n}\n@media print {\n .r01st-container {\n display: none;\n }\n}\n',document.head.appendChild(n),o=!0}(),!i||i.getAttribute("data-position")===n&&i.getAttribute("data-theme")===t||(i.parentNode.removeChild(i),i=null),i||(i=document.createElement("div"),i.className="r01st-container",i.setAttribute("role","region"),i.setAttribute("aria-label","Notifications"),i.setAttribute("aria-live","polite"),i.setAttribute("data-position",n),i.setAttribute("data-theme",t),document.body.appendChild(i)),i}let a=0;const s=new Map;function l(n,t={}){const o={...e(),...t},{position:i,duration:l,dismissible:c,theme:p,className:m,type:u="info"}=o,f=++a;if(s.size>=e().maxToasts){d(s.keys().next().value)}const g=r(i,p),h=function(n,t,e,o,i,r){const a=document.createElement("div");a.className="r01st r01st-"+t+(o?" "+o:""),a.setAttribute("role","alert"),a.setAttribute("data-toast-id",i);const s=document.createElement("div");s.className="r01st-content";const l=document.createElement("span");l.className="r01st-icon",l.innerHTML=function(n){const t={success:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>',error:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg>',info:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg>',warning:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg>'};return t[n]||t.info}(t),l.setAttribute("aria-hidden","true"),s.appendChild(l);const d=document.createElement("span");if(d.className="r01st-message",d.textContent=n,s.appendChild(d),a.appendChild(s),e){const n=document.createElement("button");n.className="r01st-close",n.innerHTML="&times;",n.setAttribute("aria-label","Close notification"),n.onclick=r,a.appendChild(n)}return a}(n,u,c,m,f,()=>d(f));var b;g.appendChild(h),b=h,requestAnimationFrame(()=>{b.className=b.className+" r01st-show"});const x={element:h,timeoutId:null};return l>0&&(x.timeoutId=setTimeout(()=>d(f),l)),s.set(f,x),f}function d(n){const t=s.get(n);if(!t)return;const{element:e,timeoutId:o}=t;o&&clearTimeout(o),s.delete(n),function(n,t){n.className=n.className.replace(" r01st-show",""),setTimeout(()=>{n.parentNode&&n.parentNode.removeChild(n),t&&t()},300)}(e,()=>{var n;n=s.size,i&&0===n&&(i.parentNode.removeChild(i),i=null)})}function c(n,t={}){return l(n,t)}c.success=(n,t={})=>c(n,{...t,type:"success"}),c.error=(n,t={})=>c(n,{...t,type:"error"}),c.info=(n,t={})=>c(n,{...t,type:"info"}),c.warning=(n,t={})=>c(n,{...t,type:"warning"}),c.dismiss=d,c.dismissAll=function(){Array.from(s.keys()).forEach(n=>d(n))},n.configure=function(n){t={...t,...n}},n.default=c,n.toast=c,Object.defineProperty(n,"__esModule",{value:!0})});