minisnackbar 1.0.1 → 2.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.
@@ -1,389 +1,381 @@
1
- (function (factory) {
2
- typeof define === 'function' && define.amd ? define(factory) :
3
- factory();
4
- })((function () { 'use strict';
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Snackbar = {}));
5
+ })(this, (function (exports) { 'use strict';
5
6
 
6
- /**
7
- * MiniSnackbar - A simple vanilla JavaScript snackbar/toast library
8
- *
9
- * @version 1.0.0
10
- * @author Shanto Islam <shantoislamdev@gmail.com>
11
- * @license MIT
12
- * @description A lightweight, zero-dependency snackbar library with Material Design integration
13
- * @repository https://github.com/shantoislamdev/minisnackbar
14
- * @homepage https://github.com/shantoislamdev/minisnackbar#readme
15
- */
16
-
17
- class Snackbar {
18
- static _queue = []
19
- static _isShowing = false
20
- static _currentTimeout = null
21
- static _state = 'idle' // idle, showing, transitioning
22
- static _currentActionHandler = null
23
- static _transitionDuration = 250
24
- static _initialized = false
25
-
26
- static init(options = {}) {
27
- if (this._initialized) return
28
-
29
- if (typeof document === 'undefined' || !document.body) {
30
- console.error('Snackbar: DOM is not available');
31
- return
32
- }
33
-
34
- if (options.transitionDuration && typeof options.transitionDuration === 'number') {
35
- this._transitionDuration = options.transitionDuration;
36
- }
37
-
38
- if (document.getElementById('mini-snackbar')) {
39
- this._initialized = true;
40
- return
41
- }
42
-
43
- if (!document.getElementById('mini-snackbar-styles')) {
44
- const style = document.createElement('style');
45
- style.id = 'mini-snackbar-styles';
46
- style.textContent = `
47
- .mini-snackbar {
48
- /* Positioning */
49
- position: fixed;
50
- z-index: 1000;
51
- left: 50%;
52
- bottom: 30px;
53
- transform: translateX(-50%) translateY(100%);
54
-
55
- /* Sizing */
56
- min-width: 250px;
57
- max-width: 90%;
58
-
59
- /* Layout */
60
- display: flex;
61
- align-items: center;
62
- justify-content: space-between;
63
- gap: 8px;
64
- padding: 0.875rem 1rem;
65
-
66
- /* Visibility */
67
- visibility: hidden;
68
-
69
- /* Theming */
70
- background-color: var(--mini-snackbar-bg, var(--md-sys-color-inverse-surface, rgba(255, 255, 255, 1)));
71
- color: var(--mini-snackbar-text, var(--md-sys-color-inverse-on-surface, inherit));
72
- border: var(--mini-snackbar-border, none);
73
- font-family: var(--mini-snackbar-font-family, inherit);
74
- font-size: 0.875rem;
75
- text-align: left;
76
- border-radius: var(--mini-snackbar-radius, 1rem);
77
- box-shadow: var(--mini-snackbar-shadow, 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12));
78
-
79
- /* Animation */
80
- transition: var(--mini-snackbar-transition, transform ${this._transitionDuration}ms ease-in-out);
81
- }
82
-
83
- .mini-snackbar.show {
84
- visibility: visible;
85
- transform: translateX(-50%) translateY(0);
86
- }
87
-
88
- /* Material Component Action Button */
89
- .mini-snackbar .mini-snackbar-action {
90
- flex-shrink: 0;
91
- padding: 0.5rem 1rem;
92
- margin: -0.5rem -0.5rem -0.5rem 0;
93
- }
94
-
95
- /* Fallback Action Button (when Material Components unavailable) */
96
- .mini-snackbar md-text-button[data-fallback] {
97
- display: inline-block;
98
- flex-shrink: 0;
99
- padding: 0.5rem 1rem;
100
- margin: -0.5rem -0.5rem -0.5rem 0;
101
- border: none;
102
- background: var(--mini-snackbar-btn-bg, transparent);
103
- font-size: inherit;
104
- font-family: inherit;
105
- font-weight: 500;
106
- letter-spacing: 0.0892857143em;
107
- text-transform: uppercase;
108
- color: var(--mini-snackbar-btn-text, inherit);
109
- cursor: pointer;
110
- user-select: none;
111
- border-radius: var(--mini-snackbar-btn-radius, 1rem);
112
- transition: opacity 0.2s ease;
113
- }
114
-
115
- .mini-snackbar md-text-button[data-fallback]:hover {
116
- opacity: var(--mini-snackbar-btn-hover-opacity, 0.8);
117
- outline: var(--mini-snackbar-btn-hover-outline, 2px solid var(--mini-snackbar-btn-text, inherit));
118
- outline-offset: var(--mini-snackbar-btn-outline-offset, 2px);
119
- background-color: var(--mini-snackbar-btn-hover-bg, transparent);
120
- }
121
-
122
- .mini-snackbar md-text-button[data-fallback]:focus {
123
- outline: var(--mini-snackbar-btn-focus-outline, 2px solid var(--mini-snackbar-btn-text, inherit));
124
- outline-offset: var(--mini-snackbar-btn-outline-offset, 2px);
125
- }
126
-
127
- /* Mobile responsive */
128
- @media (max-width: 600px) {
129
- .mini-snackbar {
130
- bottom: 90px;
131
- }
132
- }
133
-
134
- /* Accessibility: Reduced motion */
135
- @media (prefers-reduced-motion: reduce) {
136
- .mini-snackbar {
137
- transition: opacity 0.15s ease;
138
- }
139
- }
140
- `;
141
- document.head.appendChild(style);
142
- }
143
-
144
- const snackbar = document.createElement('div');
145
- snackbar.id = 'mini-snackbar';
146
- snackbar.className = 'mini-snackbar';
147
- snackbar.setAttribute('role', 'alert');
148
- snackbar.setAttribute('aria-live', 'assertive');
149
- snackbar.setAttribute('aria-atomic', 'true');
150
-
151
- const snackbarText = document.createElement('span');
152
- snackbarText.className = 'mini-snackbar-text';
153
- snackbar.appendChild(snackbarText);
154
-
155
- document.body.appendChild(snackbar);
156
- this._initialized = true;
157
- }
158
-
159
- static destroy() {
160
- this.hideCurrent();
161
- this.clearQueue();
162
-
163
- const snackbar = document.getElementById('mini-snackbar');
164
- if (snackbar) snackbar.remove();
165
-
166
- const styles = document.getElementById('mini-snackbar-styles');
167
- if (styles) styles.remove();
168
-
169
- this._state = 'idle';
170
- this._isShowing = false;
171
- this._currentActionHandler = null;
172
- this._currentTimeout = null;
173
- this._initialized = false;
174
- }
175
-
176
- static getTransitionDuration() {
177
- const snackbar = document.getElementById('mini-snackbar');
178
- if (!snackbar) return this._transitionDuration
179
-
180
- try {
181
- const computedStyle = window.getComputedStyle(snackbar);
182
- const duration = computedStyle.transitionDuration;
183
- if (duration && duration !== '0s') {
184
- const value = parseFloat(duration);
185
- return duration.includes('ms') ? value : value * 1000
186
- }
187
- } catch (e) {
188
- console.warn('Snackbar: Could not read transition duration from CSS', e);
189
- }
190
-
191
- return this._transitionDuration
192
- }
193
-
194
- static add(message, action = null, duration = 3000) {
195
- if (!this._initialized) {
196
- console.warn('Snackbar: Not initialized. Call Snackbar.init() first.');
197
- return
198
- }
199
-
200
- if (typeof message !== 'string' || message.trim() === '') {
201
- console.warn('Snackbar: Message must be a non-empty string');
202
- return
203
- }
204
- if (action !== null && (typeof action !== 'object' || typeof action.text !== 'string' || typeof action.handler !== 'function')) {
205
- console.warn('Snackbar: Action must be an object with "text" (string) and "handler" (function) properties');
206
- return
207
- }
208
- if (typeof duration !== 'number' || duration <= 0) {
209
- console.warn('Snackbar: Duration must be a positive number');
210
- return
211
- }
212
-
213
- this._queue.push({ message, action, duration });
214
- if (this._state === 'idle') this.showNext();
215
- }
216
-
217
- static _cleanupAction() {
218
- const snackbar = document.getElementById('mini-snackbar');
219
- if (!snackbar) return
220
-
221
- const actionButton = snackbar.querySelector('.mini-snackbar-action');
222
- if (actionButton && this._currentActionHandler) {
223
- actionButton.removeEventListener('click', this._currentActionHandler);
224
- this._currentActionHandler = null;
225
- actionButton.remove();
226
- }
227
- }
228
-
229
- static _showSnackbar(message, action, duration, onHide = null) {
230
- const snackbar = document.getElementById('mini-snackbar');
231
- if (!snackbar) {
232
- console.error('Snackbar: Snackbar element not found. Ensure init() has been called.');
233
- return
234
- }
235
-
236
- this._state = 'showing';
237
- this._isShowing = true;
238
- const snackbarText = snackbar.querySelector('.mini-snackbar-text');
239
- snackbarText.textContent = message;
240
-
241
- if (action) {
242
- const actionButton = document.createElement('md-text-button');
243
- actionButton.classList.add('mini-snackbar-action');
244
-
245
- // Fallback for when Material Components are not available
246
- if (customElements.get('md-text-button') === undefined) {
247
- actionButton.setAttribute('data-fallback', '');
248
- }
249
-
250
- actionButton.textContent = action.text;
251
-
252
- this._currentActionHandler = () => {
253
- action.handler();
254
- this._hideSnackbar(onHide);
255
- };
256
-
257
- actionButton.addEventListener('click', this._currentActionHandler);
258
- snackbar.appendChild(actionButton);
259
- }
260
-
261
- snackbar.classList.add('show');
262
-
263
- this._currentTimeout = setTimeout(() => {
264
- this._hideSnackbar(onHide);
265
- }, duration);
266
- }
267
-
268
- static _hideSnackbar(onHide = null) {
269
- if (this._currentTimeout) {
270
- clearTimeout(this._currentTimeout);
271
- this._currentTimeout = null;
272
- }
273
-
274
- this._state = 'transitioning';
275
- const snackbar = document.getElementById('mini-snackbar');
276
- if (snackbar) {
277
- snackbar.classList.remove('show');
278
- }
279
-
280
- this._cleanupAction();
281
-
282
- // Wait for CSS transition to complete
283
- const transitionDuration = this.getTransitionDuration();
284
- setTimeout(() => {
285
- this._isShowing = false;
286
- this._state = 'idle';
287
- if (onHide) onHide();
288
- }, transitionDuration);
289
- }
290
-
291
- static show(message, action = null, duration = 3000) {
292
- if (!this._initialized) {
293
- console.warn('Snackbar: Not initialized. Call Snackbar.init() first.');
294
- return
295
- }
296
-
297
- if (typeof message !== 'string' || message.trim() === '') {
298
- console.warn('Snackbar: Message must be a non-empty string');
299
- return
300
- }
301
- if (action !== null && (typeof action !== 'object' || typeof action.text !== 'string' || typeof action.handler !== 'function')) {
302
- console.warn('Snackbar: Action must be an object with "text" (string) and "handler" (function) properties');
303
- return
304
- }
305
- if (typeof duration !== 'number' || duration <= 0) {
306
- console.warn('Snackbar: Duration must be a positive number');
307
- return
308
- }
309
-
310
- // Queue message if currently transitioning
311
- if (this._state === 'transitioning') {
312
- this.add(message, action, duration);
313
- return
314
- }
315
-
316
- // Interrupt current snackbar if showing
317
- if (this._isShowing) {
318
- this._state = 'transitioning';
319
- if (this._currentTimeout) {
320
- clearTimeout(this._currentTimeout);
321
- this._currentTimeout = null;
322
- }
323
- const snackbar = document.getElementById('mini-snackbar');
324
- if (snackbar) {
325
- snackbar.classList.remove('show');
326
- }
327
- this._cleanupAction();
328
-
329
- const transitionDuration = this.getTransitionDuration();
330
- setTimeout(() => {
331
- this._isShowing = false;
332
- this._state = 'idle';
333
- this._showSnackbar(message, action, duration);
334
- }, transitionDuration);
335
- } else {
336
- this._showSnackbar(message, action, duration);
337
- }
338
- }
339
-
340
- static showNext() {
341
- if (this._queue.length === 0) {
342
- this._isShowing = false;
343
- this._state = 'idle';
344
- return
345
- }
346
-
347
- const { message, action, duration } = this._queue.shift();
348
- this._showSnackbar(message, action, duration, () => {
349
- setTimeout(() => this.showNext(), 200);
350
- });
351
- }
352
-
353
- static clearQueue() {
354
- this._queue = [];
355
- }
356
-
357
- static hideCurrent() {
358
- if (this._isShowing && this._state !== 'transitioning') {
359
- this._hideSnackbar();
360
- }
361
- }
362
-
363
- static isInitialized() {
364
- return this._initialized
365
- }
366
-
367
- // Getters/setters for testing
368
- static get queue() { return this._queue }
369
- static set queue(value) { this._queue = value; }
370
- static get isShowing() { return this._isShowing }
371
- static set isShowing(value) { this._isShowing = value; }
372
- static get currentTimeout() { return this._currentTimeout }
373
- static set currentTimeout(value) { this._currentTimeout = value; }
374
- static get state() { return this._state }
375
- static set state(value) { this._state = value; }
376
- }
377
-
378
- // Module exports
379
- if (typeof module !== 'undefined' && module.exports) {
380
- module.exports = Snackbar;
381
- }
382
-
383
- // Make available globally in browser
384
- if (typeof window !== 'undefined') {
385
- window.Snackbar = Snackbar;
386
- }
7
+ /**
8
+ * MiniSnackbar - A simple vanilla JavaScript snackbar/toast library
9
+ *
10
+ * @version 2.0.0
11
+ * @author Shanto Islam <shantoislamdev@gmail.com>
12
+ * @license MIT
13
+ * @description A lightweight, zero-dependency snackbar library with Material Design integration
14
+ * @repository https://github.com/shantoislamdev/minisnackbar
15
+ * @homepage https://github.com/shantoislamdev/minisnackbar#readme
16
+ */
17
+ // Snackbar class
18
+ class Snackbar {
19
+ static init(options = {}) {
20
+ if (this._initialized)
21
+ return;
22
+ if (typeof document === 'undefined' || !document.body) {
23
+ console.error('Snackbar: DOM is not available');
24
+ return;
25
+ }
26
+ if (options.transitionDuration && typeof options.transitionDuration === 'number') {
27
+ this._transitionDuration = options.transitionDuration;
28
+ }
29
+ if (document.getElementById('mini-snackbar')) {
30
+ this._initialized = true;
31
+ return;
32
+ }
33
+ if (!document.getElementById('mini-snackbar-styles')) {
34
+ const style = document.createElement('style');
35
+ style.id = 'mini-snackbar-styles';
36
+ style.textContent = `
37
+ .mini-snackbar {
38
+ /* Positioning */
39
+ position: fixed;
40
+ z-index: 1000;
41
+ left: 50%;
42
+ bottom: 30px;
43
+ transform: translateX(-50%) translateY(100%);
44
+
45
+ /* Sizing */
46
+ min-width: 250px;
47
+ max-width: 90%;
48
+
49
+ /* Layout */
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: space-between;
53
+ gap: 8px;
54
+ padding: 0.875rem 1rem;
55
+
56
+ /* Visibility */
57
+ visibility: hidden;
58
+
59
+ /* Theming */
60
+ background-color: var(--mini-snackbar-bg, var(--md-sys-color-inverse-surface, rgba(255, 255, 255, 1)));
61
+ color: var(--mini-snackbar-text, var(--md-sys-color-inverse-on-surface, rgba(27, 27, 27, 1)));
62
+ border: var(--mini-snackbar-border, none);
63
+ font-family: var(--mini-snackbar-font-family, inherit);
64
+ font-size: 0.875rem;
65
+ text-align: left;
66
+ border-radius: var(--mini-snackbar-radius, 1rem);
67
+ box-shadow: var(--mini-snackbar-shadow, 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12));
68
+
69
+ /* Animation */
70
+ transition: var(--mini-snackbar-transition, transform ${this._transitionDuration}ms ease-in-out);
71
+ }
72
+
73
+ .mini-snackbar.show {
74
+ visibility: visible;
75
+ transform: translateX(-50%) translateY(0);
76
+ }
77
+
78
+ /* Material Component Action Button */
79
+ .mini-snackbar .mini-snackbar-action {
80
+ flex-shrink: 0;
81
+ padding: 0.5rem 1rem;
82
+ margin: -0.5rem -0.5rem -0.5rem 0;
83
+ }
84
+
85
+ /* Fallback Action Button (when Material Components unavailable) */
86
+ .mini-snackbar md-text-button[data-fallback] {
87
+ display: inline-block;
88
+ flex-shrink: 0;
89
+ padding: 0.5rem 1rem;
90
+ margin: -0.5rem -0.5rem -0.5rem 0;
91
+ border: none;
92
+ background: var(--mini-snackbar-btn-bg, transparent);
93
+ font-size: inherit;
94
+ font-family: inherit;
95
+ font-weight: 500;
96
+ letter-spacing: 0.0892857143em;
97
+ text-transform: uppercase;
98
+ color: var(--mini-snackbar-btn-text, inherit);
99
+ cursor: pointer;
100
+ user-select: none;
101
+ border-radius: var(--mini-snackbar-btn-radius, 1rem);
102
+ transition: opacity 0.2s ease;
103
+ }
104
+
105
+ .mini-snackbar md-text-button[data-fallback]:hover {
106
+ opacity: var(--mini-snackbar-btn-hover-opacity, 0.8);
107
+ outline: var(--mini-snackbar-btn-hover-outline, 2px solid var(--mini-snackbar-btn-text, inherit));
108
+ outline-offset: var(--mini-snackbar-btn-outline-offset, 2px);
109
+ background-color: var(--mini-snackbar-btn-hover-bg, transparent);
110
+ }
111
+
112
+ .mini-snackbar md-text-button[data-fallback]:focus {
113
+ outline: var(--mini-snackbar-btn-focus-outline, 2px solid var(--mini-snackbar-btn-text, inherit));
114
+ outline-offset: var(--mini-snackbar-btn-outline-offset, 2px);
115
+ }
116
+
117
+ /* Mobile responsive */
118
+ @media (max-width: 600px) {
119
+ .mini-snackbar {
120
+ bottom: 90px;
121
+ }
122
+ }
123
+
124
+ /* Accessibility: Reduced motion */
125
+ @media (prefers-reduced-motion: reduce) {
126
+ .mini-snackbar {
127
+ transition: opacity 0.15s ease;
128
+ }
129
+ }
130
+ `;
131
+ document.head.appendChild(style);
132
+ }
133
+ const snackbar = document.createElement('div');
134
+ snackbar.id = 'mini-snackbar';
135
+ snackbar.className = 'mini-snackbar';
136
+ snackbar.setAttribute('role', 'alert');
137
+ snackbar.setAttribute('aria-live', 'assertive');
138
+ snackbar.setAttribute('aria-atomic', 'true');
139
+ const snackbarText = document.createElement('span');
140
+ snackbarText.className = 'mini-snackbar-text';
141
+ snackbar.appendChild(snackbarText);
142
+ document.body.appendChild(snackbar);
143
+ this._initialized = true;
144
+ }
145
+ static destroy() {
146
+ this.hideCurrent();
147
+ this.clearQueue();
148
+ const snackbar = document.getElementById('mini-snackbar');
149
+ if (snackbar)
150
+ snackbar.remove();
151
+ const styles = document.getElementById('mini-snackbar-styles');
152
+ if (styles)
153
+ styles.remove();
154
+ this._state = 'idle';
155
+ this._isShowing = false;
156
+ this._currentActionHandler = null;
157
+ this._currentTimeout = null;
158
+ this._initialized = false;
159
+ }
160
+ static getTransitionDuration() {
161
+ const snackbar = document.getElementById('mini-snackbar');
162
+ if (!snackbar)
163
+ return this._transitionDuration;
164
+ try {
165
+ const computedStyle = window.getComputedStyle(snackbar);
166
+ const duration = computedStyle.transitionDuration;
167
+ if (duration && duration !== '0s') {
168
+ const value = parseFloat(duration);
169
+ return duration.includes('ms') ? value : value * 1000;
170
+ }
171
+ }
172
+ catch (e) {
173
+ console.warn('Snackbar: Could not read transition duration from CSS', e);
174
+ }
175
+ return this._transitionDuration;
176
+ }
177
+ static add(message, action = null, duration = 3000) {
178
+ if (!this._initialized) {
179
+ console.warn('Snackbar: Not initialized. Call Snackbar.init() first.');
180
+ return;
181
+ }
182
+ if (typeof message !== 'string' || message.trim() === '') {
183
+ console.warn('Snackbar: Message must be a non-empty string');
184
+ return;
185
+ }
186
+ if (action !== null &&
187
+ (typeof action !== 'object' ||
188
+ typeof action.text !== 'string' ||
189
+ typeof action.handler !== 'function')) {
190
+ console.warn('Snackbar: Action must be an object with "text" (string) and "handler" (function) properties');
191
+ return;
192
+ }
193
+ if (typeof duration !== 'number' || duration <= 0) {
194
+ console.warn('Snackbar: Duration must be a positive number');
195
+ return;
196
+ }
197
+ this._queue.push({ message, action, duration });
198
+ if (this._state === 'idle')
199
+ this.showNext();
200
+ }
201
+ static _cleanupAction() {
202
+ const snackbar = document.getElementById('mini-snackbar');
203
+ if (!snackbar)
204
+ return;
205
+ const actionButton = snackbar.querySelector('.mini-snackbar-action');
206
+ if (actionButton && this._currentActionHandler) {
207
+ actionButton.removeEventListener('click', this._currentActionHandler);
208
+ this._currentActionHandler = null;
209
+ actionButton.remove();
210
+ }
211
+ }
212
+ static _showSnackbar(message, action, duration, onHide = null) {
213
+ const snackbar = document.getElementById('mini-snackbar');
214
+ if (!snackbar) {
215
+ console.error('Snackbar: Snackbar element not found. Ensure init() has been called.');
216
+ return;
217
+ }
218
+ this._state = 'showing';
219
+ this._isShowing = true;
220
+ const snackbarText = snackbar.querySelector('.mini-snackbar-text');
221
+ if (snackbarText) {
222
+ snackbarText.textContent = message;
223
+ }
224
+ if (action) {
225
+ const actionButton = document.createElement('md-text-button');
226
+ actionButton.classList.add('mini-snackbar-action');
227
+ // Fallback for when Material Components are not available
228
+ if (customElements.get('md-text-button') === undefined) {
229
+ actionButton.setAttribute('data-fallback', '');
230
+ }
231
+ actionButton.textContent = action.text;
232
+ this._currentActionHandler = () => {
233
+ action.handler();
234
+ this._hideSnackbar(onHide);
235
+ };
236
+ actionButton.addEventListener('click', this._currentActionHandler);
237
+ snackbar.appendChild(actionButton);
238
+ }
239
+ snackbar.classList.add('show');
240
+ this._currentTimeout = setTimeout(() => {
241
+ this._hideSnackbar(onHide);
242
+ }, duration);
243
+ }
244
+ static _hideSnackbar(onHide = null) {
245
+ if (this._currentTimeout) {
246
+ clearTimeout(this._currentTimeout);
247
+ this._currentTimeout = null;
248
+ }
249
+ this._state = 'transitioning';
250
+ const snackbar = document.getElementById('mini-snackbar');
251
+ if (snackbar) {
252
+ snackbar.classList.remove('show');
253
+ }
254
+ this._cleanupAction();
255
+ // Wait for CSS transition to complete
256
+ const transitionDuration = this.getTransitionDuration();
257
+ setTimeout(() => {
258
+ this._isShowing = false;
259
+ this._state = 'idle';
260
+ if (onHide)
261
+ onHide();
262
+ }, transitionDuration);
263
+ }
264
+ static show(message, action = null, duration = 3000) {
265
+ if (!this._initialized) {
266
+ console.warn('Snackbar: Not initialized. Call Snackbar.init() first.');
267
+ return;
268
+ }
269
+ if (typeof message !== 'string' || message.trim() === '') {
270
+ console.warn('Snackbar: Message must be a non-empty string');
271
+ return;
272
+ }
273
+ if (action !== null &&
274
+ (typeof action !== 'object' ||
275
+ typeof action.text !== 'string' ||
276
+ typeof action.handler !== 'function')) {
277
+ console.warn('Snackbar: Action must be an object with "text" (string) and "handler" (function) properties');
278
+ return;
279
+ }
280
+ if (typeof duration !== 'number' || duration <= 0) {
281
+ console.warn('Snackbar: Duration must be a positive number');
282
+ return;
283
+ }
284
+ // Queue message if currently transitioning
285
+ if (this._state === 'transitioning') {
286
+ this.add(message, action, duration);
287
+ return;
288
+ }
289
+ // Interrupt current snackbar if showing
290
+ if (this._isShowing) {
291
+ this._state = 'transitioning';
292
+ if (this._currentTimeout) {
293
+ clearTimeout(this._currentTimeout);
294
+ this._currentTimeout = null;
295
+ }
296
+ const snackbar = document.getElementById('mini-snackbar');
297
+ if (snackbar) {
298
+ snackbar.classList.remove('show');
299
+ }
300
+ this._cleanupAction();
301
+ const transitionDuration = this.getTransitionDuration();
302
+ setTimeout(() => {
303
+ this._isShowing = false;
304
+ this._state = 'idle';
305
+ this._showSnackbar(message, action, duration);
306
+ }, transitionDuration);
307
+ }
308
+ else {
309
+ this._showSnackbar(message, action, duration);
310
+ }
311
+ }
312
+ static showNext() {
313
+ if (this._queue.length === 0) {
314
+ this._isShowing = false;
315
+ this._state = 'idle';
316
+ return;
317
+ }
318
+ const item = this._queue.shift();
319
+ if (item) {
320
+ const { message, action, duration } = item;
321
+ this._showSnackbar(message, action, duration, () => {
322
+ setTimeout(() => this.showNext(), 200);
323
+ });
324
+ }
325
+ }
326
+ static clearQueue() {
327
+ this._queue = [];
328
+ }
329
+ static hideCurrent() {
330
+ if (this._isShowing && this._state !== 'transitioning') {
331
+ this._hideSnackbar();
332
+ }
333
+ }
334
+ static isInitialized() {
335
+ return this._initialized;
336
+ }
337
+ // Getters/setters for testing
338
+ static get queue() {
339
+ return this._queue;
340
+ }
341
+ static set queue(value) {
342
+ this._queue = value;
343
+ }
344
+ static get isShowing() {
345
+ return this._isShowing;
346
+ }
347
+ static set isShowing(value) {
348
+ this._isShowing = value;
349
+ }
350
+ static get currentTimeout() {
351
+ return this._currentTimeout;
352
+ }
353
+ static set currentTimeout(value) {
354
+ this._currentTimeout = value;
355
+ }
356
+ static get state() {
357
+ return this._state;
358
+ }
359
+ static set state(value) {
360
+ this._state = value;
361
+ }
362
+ }
363
+ Snackbar._queue = [];
364
+ Snackbar._isShowing = false;
365
+ Snackbar._currentTimeout = null;
366
+ Snackbar._state = 'idle';
367
+ Snackbar._currentActionHandler = null;
368
+ Snackbar._transitionDuration = 250;
369
+ Snackbar._initialized = false;
370
+ // Make available globally in browser for UMD builds
371
+ if (typeof window !== 'undefined') {
372
+ window.Snackbar = Snackbar;
373
+ }
374
+
375
+ exports.Snackbar = Snackbar;
376
+ exports.default = Snackbar;
377
+
378
+ Object.defineProperty(exports, '__esModule', { value: true });
387
379
 
388
380
  }));
389
381
  //# sourceMappingURL=minisnackbar.js.map