@t007/toast 0.0.2 → 0.0.3

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,6 +1,5 @@
1
- (function (exports) {
2
- 'use strict';
3
-
1
+ "use strict";
2
+ (() => {
4
3
  // ../utils/dist/index.js
5
4
  function clamp(min = 0, val, max = Infinity) {
6
5
  return Math.min(Math.max(val, min), max);
@@ -17,14 +16,20 @@
17
16
  return src1.replace(/\\/g, "/").split("?")[0].trim() === src2.replace(/\\/g, "/").split("?")[0].trim();
18
17
  }
19
18
  }
20
- function createEl(tag, props = {}, dataset = {}, styles = {}) {
21
- return assignEl(tag ? document?.createElement(tag) : void 0, props, dataset, styles) ?? null;
19
+ function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
20
+ return assignEl(el, props, dataset, styles), el;
22
21
  }
23
- function assignEl(el, props = {}, dataset = {}, styles = {}) {
22
+ function assignEl(el, props, dataset, styles) {
24
23
  if (!el) return;
25
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
26
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
27
- for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
24
+ if (props) {
25
+ for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
26
+ }
27
+ if (dataset) {
28
+ for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
29
+ }
30
+ if (styles) {
31
+ for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
32
+ }
28
33
  }
29
34
  function loadResource(src, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
30
35
  w.t007._resourceCache ??= {};
@@ -515,13 +520,4 @@
515
520
  window.Toast ??= t007.toast;
516
521
  console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
517
522
  }
518
-
519
- exports.default = index_default;
520
- exports.toaster = toaster;
521
- exports.toasting = toasting;
522
-
523
- Object.defineProperty(exports, '__esModule', { value: true });
524
-
525
- return exports;
526
-
527
- })({});
523
+ })();
package/dist/index.js CHANGED
@@ -1,80 +1,5 @@
1
- // ../utils/dist/index.js
2
- function clamp(min = 0, val, max = Infinity) {
3
- return Math.min(Math.max(val, min), max);
4
- }
5
- function uid(prefix = "") {
6
- return prefix + Date.now().toString(36) + "_" + performance.now().toString(36).replace(".", "") + "_" + Math.random().toString(36).slice(2);
7
- }
8
- function isSameURL(src1, src2) {
9
- if (typeof src1 !== "string" || typeof src2 !== "string" || !src1 || !src2) return false;
10
- try {
11
- const u1 = new URL(src1, window.location.href), u2 = new URL(src2, window.location.href);
12
- return decodeURIComponent(u1.origin + u1.pathname) === decodeURIComponent(u2.origin + u2.pathname);
13
- } catch {
14
- return src1.replace(/\\/g, "/").split("?")[0].trim() === src2.replace(/\\/g, "/").split("?")[0].trim();
15
- }
16
- }
17
- function createEl(tag, props = {}, dataset = {}, styles = {}) {
18
- return assignEl(tag ? document?.createElement(tag) : void 0, props, dataset, styles) ?? null;
19
- }
20
- function assignEl(el, props = {}, dataset = {}, styles = {}) {
21
- if (!el) return;
22
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
23
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
24
- for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
25
- }
26
- function loadResource(src, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
27
- w.t007._resourceCache ??= {};
28
- if (w.t007._resourceCache[src]) return w.t007._resourceCache[src];
29
- const existing = type === "script" ? Array.prototype.find.call(w.document.scripts, (s) => isSameURL(s.src, src)) : type === "style" ? Array.prototype.find.call(w.document.styleSheets, (s) => isSameURL(s.href, src)) : null;
30
- if (existing) return w.t007._resourceCache[src] = Promise.resolve(existing);
31
- w.t007._resourceCache[src] = new Promise((resolve, reject) => {
32
- (function tryLoad(remaining, el) {
33
- const onerror = () => {
34
- el?.remove?.();
35
- if (remaining > 1) {
36
- setTimeout(tryLoad, 1e3, remaining - 1);
37
- console.warn(`Retrying ${type} load (${attempts - remaining + 1}): ${src}...`);
38
- } else {
39
- delete w.t007._resourceCache[src];
40
- reject(new Error(`${type} load failed after ${attempts} attempts: ${src}`));
41
- }
42
- };
43
- const url = retryKey && remaining < attempts ? `${src}${src.includes("?") ? "&" : "?"}_${retryKey}=${Date.now()}` : src;
44
- if (type === "script") w.document.body.append(el = createEl("script", { src: url, type: module ? "module" : "text/javascript", crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
45
- else if (type === "style") w.document.head.append(el = createEl("link", { rel: "stylesheet", href: url, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
46
- else reject(new Error(`Unsupported resource type: ${type}`));
47
- })(attempts);
48
- });
49
- return w.t007._resourceCache[src];
50
- }
51
- function onAllMethods(owner, callback) {
52
- let proto = owner;
53
- while (proto && proto !== Object.prototype) {
54
- for (const method of Object.getOwnPropertyNames(proto)) {
55
- if (method === "constructor") continue;
56
- if ("function" !== typeof Object.getOwnPropertyDescriptor(proto, method)?.value) continue;
57
- callback(method, owner);
58
- }
59
- proto = Object.getPrototypeOf(proto);
60
- }
61
- }
62
- function bindAllMethods(owner) {
63
- onAllMethods(owner, (method, owner2) => {
64
- owner2[method] = owner2[method].bind(owner2);
65
- });
66
- }
67
- if (typeof window !== "undefined") {
68
- window.t007 ??= {};
69
- window.T007_TOAST_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest`;
70
- window.T007_INPUT_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest`;
71
- window.T007_DIALOG_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest`;
72
- window.T007_TOAST_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest/dist/style.css`;
73
- window.T007_INPUT_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest/dist/style.css`;
74
- window.T007_DIALOG_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest/dist/style.css`;
75
- }
76
-
77
1
  // src/index.js
2
+ import { clamp, uid, bindAllMethods, createEl, loadResource } from "@t007/utils";
78
3
  var T007_Toast = class {
79
4
  #autoCloseInterval;
80
5
  #progressInterval;
@@ -512,5 +437,8 @@ if (typeof window !== "undefined") {
512
437
  window.Toast ??= t007.toast;
513
438
  console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
514
439
  }
515
-
516
- export { index_default as default, toaster, toasting };
440
+ export {
441
+ index_default as default,
442
+ toaster,
443
+ toasting
444
+ };
@@ -0,0 +1,525 @@
1
+ // ../utils/dist/index.js
2
+ function clamp(min = 0, val, max = Infinity) {
3
+ return Math.min(Math.max(val, min), max);
4
+ }
5
+ function uid(prefix = "") {
6
+ return prefix + Date.now().toString(36) + "_" + performance.now().toString(36).replace(".", "") + "_" + Math.random().toString(36).slice(2);
7
+ }
8
+ function isSameURL(src1, src2) {
9
+ if (typeof src1 !== "string" || typeof src2 !== "string" || !src1 || !src2) return false;
10
+ try {
11
+ const u1 = new URL(src1, window.location.href), u2 = new URL(src2, window.location.href);
12
+ return decodeURIComponent(u1.origin + u1.pathname) === decodeURIComponent(u2.origin + u2.pathname);
13
+ } catch {
14
+ return src1.replace(/\\/g, "/").split("?")[0].trim() === src2.replace(/\\/g, "/").split("?")[0].trim();
15
+ }
16
+ }
17
+ function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
18
+ return assignEl(el, props, dataset, styles), el;
19
+ }
20
+ function assignEl(el, props, dataset, styles) {
21
+ if (!el) return;
22
+ if (props) {
23
+ for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
24
+ }
25
+ if (dataset) {
26
+ for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
27
+ }
28
+ if (styles) {
29
+ for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
30
+ }
31
+ }
32
+ function loadResource(src, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
33
+ w.t007._resourceCache ??= {};
34
+ if (w.t007._resourceCache[src]) return w.t007._resourceCache[src];
35
+ const existing = type === "script" ? Array.prototype.find.call(w.document.scripts, (s) => isSameURL(s.src, src)) : type === "style" ? Array.prototype.find.call(w.document.styleSheets, (s) => isSameURL(s.href, src)) : null;
36
+ if (existing) return w.t007._resourceCache[src] = Promise.resolve(existing);
37
+ w.t007._resourceCache[src] = new Promise((resolve, reject) => {
38
+ (function tryLoad(remaining, el) {
39
+ const onerror = () => {
40
+ el?.remove?.();
41
+ if (remaining > 1) {
42
+ setTimeout(tryLoad, 1e3, remaining - 1);
43
+ console.warn(`Retrying ${type} load (${attempts - remaining + 1}): ${src}...`);
44
+ } else {
45
+ delete w.t007._resourceCache[src];
46
+ reject(new Error(`${type} load failed after ${attempts} attempts: ${src}`));
47
+ }
48
+ };
49
+ const url = retryKey && remaining < attempts ? `${src}${src.includes("?") ? "&" : "?"}_${retryKey}=${Date.now()}` : src;
50
+ if (type === "script") w.document.body.append(el = createEl("script", { src: url, type: module ? "module" : "text/javascript", crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
51
+ else if (type === "style") w.document.head.append(el = createEl("link", { rel: "stylesheet", href: url, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
52
+ else reject(new Error(`Unsupported resource type: ${type}`));
53
+ })(attempts);
54
+ });
55
+ return w.t007._resourceCache[src];
56
+ }
57
+ function onAllMethods(owner, callback) {
58
+ let proto = owner;
59
+ while (proto && proto !== Object.prototype) {
60
+ for (const method of Object.getOwnPropertyNames(proto)) {
61
+ if (method === "constructor") continue;
62
+ if ("function" !== typeof Object.getOwnPropertyDescriptor(proto, method)?.value) continue;
63
+ callback(method, owner);
64
+ }
65
+ proto = Object.getPrototypeOf(proto);
66
+ }
67
+ }
68
+ function bindAllMethods(owner) {
69
+ onAllMethods(owner, (method, owner2) => {
70
+ owner2[method] = owner2[method].bind(owner2);
71
+ });
72
+ }
73
+ if (typeof window !== "undefined") {
74
+ window.t007 ??= {};
75
+ window.T007_TOAST_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest`;
76
+ window.T007_INPUT_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest`;
77
+ window.T007_DIALOG_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest`;
78
+ window.T007_TOAST_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest/dist/style.css`;
79
+ window.T007_INPUT_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest/dist/style.css`;
80
+ window.T007_DIALOG_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest/dist/style.css`;
81
+ }
82
+
83
+ // src/index.js
84
+ var T007_Toast = class {
85
+ #autoCloseInterval;
86
+ #progressInterval;
87
+ #timeVisible = 0;
88
+ #isPaused = false;
89
+ #shouldUnPause;
90
+ queue = [];
91
+ destroyed = true;
92
+ #visiblityChange = () => this.#shouldUnPause = document.visibilityState === "visible";
93
+ constructor(options) {
94
+ bindAllMethods(this);
95
+ this.opts = { ...options };
96
+ this.id = this.opts.id ??= uid(this.opts.idPrefix ?? "t007_toast_");
97
+ t007.toasts.set(this.id, this);
98
+ "number" !== typeof this.opts.delay ? this.init() : this.queue.push(setTimeout(this.init, this.opts.delay));
99
+ this.update(this.opts);
100
+ }
101
+ init() {
102
+ this.toastElement = createEl("div", { className: "t007-toast", id: this.id, ariaAtomic: "true" }, { idPrefix: this.opts.idPrefix });
103
+ requestAnimationFrame(() => this.toastElement.classList.add("t007-toast-show"));
104
+ this.destroyed = false;
105
+ }
106
+ update(options) {
107
+ if (!options || typeof options !== "object") return this.opts.id;
108
+ try {
109
+ this.opts = { ...this.opts, ...options };
110
+ const run = () => Object.keys(options).forEach((key) => this[key] = options[key]);
111
+ "number" !== typeof this.opts.delay ? run() : this.queue.push(setTimeout(run, this.opts.delay));
112
+ this.opts.delay = null;
113
+ } catch (err) {
114
+ console.error("toast update failed:", err);
115
+ }
116
+ return this.opts.id;
117
+ }
118
+ play = () => setTimeout(() => this.#isPaused = false);
119
+ pause = () => this.#isPaused = true;
120
+ set rootElement(value) {
121
+ const container = value?.querySelector(`.t007-toast-container[data-position="${this.opts.position}"]`);
122
+ container?.style.setProperty("--t007-toast-container-position", value === document.body ? "fixed" : "absolute");
123
+ container && !value.contains(container) && value.append(container);
124
+ }
125
+ set type(value) {
126
+ this.toastElement.classList.remove("info", "success", "error", "warning");
127
+ value && this.toastElement.classList.add(value);
128
+ this.toastElement.role = value === "error" || value === "warning" ? "alert" : "status";
129
+ this.toastElement.ariaLive = value === "error" || value === "warning" ? "assertive" : "polite";
130
+ if (value) this.icon = this.opts.icon;
131
+ }
132
+ set bodyHTML(value) {
133
+ this.toastElement.querySelectorAll(".t007-toast > *:not(.t007-toast-cancel-button)").forEach((el) => el.remove());
134
+ this.toastElement.insertAdjacentHTML("afterbegin", `${value ? typeof value === "function" ? value() : value : ""}`);
135
+ }
136
+ set render(value) {
137
+ const bodyText = () => this.toastElement.querySelector(".t007-toast-body-text");
138
+ if (value) {
139
+ this._setUpBodyHTML();
140
+ this.toastElement.querySelector(".t007-toast-body").prepend(bodyText() || createEl("p", { className: "t007-toast-body-text" }));
141
+ const text = bodyText();
142
+ text.innerHTML = text.dataset.render = typeof value === "function" ? value() : value;
143
+ } else bodyText()?.remove();
144
+ }
145
+ set actions(value) {
146
+ const actionsWrapper = () => this.toastElement.querySelector(".t007-toast-actions-wrapper"), values = value ? Object.entries(value) : [];
147
+ if (values.length) {
148
+ this._setUpBodyHTML();
149
+ this.toastElement.querySelector(".t007-toast-body").insertAdjacentElement("afterend", actionsWrapper() || createEl("div", { className: "t007-toast-actions-wrapper" }));
150
+ const wrapper = actionsWrapper();
151
+ wrapper.innerHTML = values.map(([label]) => label ? `<button class="t007-toast-action-button" data-action="${label}">${label}</button>` : "").join("");
152
+ wrapper.querySelectorAll(".t007-toast-action-button").forEach((btn, i) => btn.onclick = (e) => values[i][1]?.(e, this));
153
+ } else actionsWrapper()?.remove();
154
+ }
155
+ set image(value) {
156
+ const image = () => this.toastElement.querySelector(".t007-toast-image");
157
+ if (value) {
158
+ this._setUpBodyHTML();
159
+ this.toastElement.querySelector(".t007-toast-image-wrapper").prepend(
160
+ image() || createEl("img", {
161
+ className: "t007-toast-image",
162
+ alt: "toast-image"
163
+ })
164
+ );
165
+ const img = image();
166
+ img.src = value;
167
+ img.onload = img.onerror = () => img.dataset.loaded = img.complete && img.naturalWidth > 0;
168
+ } else image()?.remove();
169
+ }
170
+ get icon() {
171
+ return this.opts.icon === true ? t007.TOAST_ICONS[this.opts.type] || "" : this.opts.icon || "";
172
+ }
173
+ set icon(value) {
174
+ if (this.opts.isLoading) return;
175
+ const icon = () => this.toastElement.querySelector(".t007-toast-icon:not(.t007-toast-loader)");
176
+ if (value) {
177
+ this._setUpBodyHTML();
178
+ this.toastElement.querySelector(".t007-toast-image-wrapper").appendChild(icon() || createEl("span", { className: "t007-toast-icon" }));
179
+ const icn = icon();
180
+ icn.innerHTML = icn.dataset.icon = this.icon;
181
+ } else icon()?.remove();
182
+ }
183
+ set isLoading(value) {
184
+ const loader = () => this.toastElement.querySelector(".t007-toast-loader");
185
+ if (value) {
186
+ this._setUpBodyHTML();
187
+ this.toastElement.querySelectorAll(".t007-toast-icon:not(.t007-toast-loader)").forEach((i) => i.remove());
188
+ this.toastElement.querySelector(".t007-toast-image-wrapper").appendChild(
189
+ loader() || createEl("span", {
190
+ className: "t007-toast-icon t007-toast-loader"
191
+ })
192
+ );
193
+ loader().innerHTML = typeof value === "string" ? value : t007.TOAST_ICONS.loading;
194
+ } else {
195
+ loader()?.remove();
196
+ this.icon = this.opts.icon;
197
+ }
198
+ }
199
+ set closeButton(value) {
200
+ const btn = this.toastElement.querySelector(".t007-toast-cancel-button");
201
+ if (value)
202
+ this.toastElement.appendChild(
203
+ btn || createEl("button", {
204
+ title: "Close",
205
+ ariaLabel: "Close notification",
206
+ className: "t007-toast-cancel-button",
207
+ innerHTML: "&times;",
208
+ onclick: this._remove
209
+ })
210
+ );
211
+ else btn?.remove();
212
+ }
213
+ get animation() {
214
+ if (this.opts.animation === true || this.opts.animation === "slide")
215
+ switch (this.opts.position) {
216
+ case "top-right":
217
+ case "center-right":
218
+ case "bottom-right":
219
+ return "slide-left";
220
+ case "top-center":
221
+ case "center-center":
222
+ case "bottom-center":
223
+ return this.opts.position === "top-center" ? "slide-down" : "slide-up";
224
+ case "top-left":
225
+ case "center-left":
226
+ case "bottom-left":
227
+ default:
228
+ return "slide-right";
229
+ }
230
+ return this.opts.animation;
231
+ }
232
+ set animation(value) {
233
+ this.toastElement.dataset.animation = this.animation;
234
+ }
235
+ get autoClose() {
236
+ return this.opts.autoClose === true ? t007.TOAST_DURATIONS[this.opts.type] || t007.TOAST_DURATIONS.info : this.opts.autoClose;
237
+ }
238
+ set autoClose(value) {
239
+ cancelAnimationFrame(this.#autoCloseInterval);
240
+ this.#timeVisible = 0;
241
+ let lastTime;
242
+ const loop = (time) => {
243
+ if (this.#shouldUnPause) {
244
+ lastTime = null;
245
+ this.#shouldUnPause = false;
246
+ }
247
+ if (lastTime == null) {
248
+ lastTime = time;
249
+ return this.#autoCloseInterval = requestAnimationFrame(loop);
250
+ }
251
+ if (!this.#isPaused) {
252
+ this.#timeVisible += time - lastTime;
253
+ this.onTimeUpdate?.(this.#timeVisible);
254
+ if ("number" == typeof this.autoClose && this.#timeVisible >= this.autoClose) return this._remove("smooth", true);
255
+ }
256
+ lastTime = time;
257
+ this.#autoCloseInterval = requestAnimationFrame(loop);
258
+ };
259
+ if (value) this.#autoCloseInterval = requestAnimationFrame(loop);
260
+ }
261
+ set position(value) {
262
+ const currentContainer = this.toastElement.parentElement;
263
+ const container = this.opts.rootElement?.querySelector(`.t007-toast-container[data-position="${value}"]`) || this._createContainer(value);
264
+ container[this.opts.newestOnTop ? "prepend" : "append"](this.toastElement);
265
+ if (!(currentContainer == null || currentContainer.hasChildNodes())) currentContainer.remove();
266
+ }
267
+ set closeOnClick(value) {
268
+ this.toastElement.onclick = value ? () => this._remove() : null;
269
+ }
270
+ set hideProgressBar(value) {
271
+ this.toastElement.classList.toggle("progress", !value);
272
+ this.nprogress = 0;
273
+ cancelAnimationFrame(this.#progressInterval);
274
+ const loop = () => {
275
+ if ("number" == typeof this.autoClose && !this.#isPaused) this.nprogress = 1 - this.#timeVisible / this.autoClose;
276
+ this.#progressInterval = requestAnimationFrame(loop);
277
+ };
278
+ if (!value) this.#progressInterval = requestAnimationFrame(loop);
279
+ }
280
+ get nprogress() {
281
+ return Number(this.toastElement.style.getProperty("--progress"));
282
+ }
283
+ set nprogress(value) {
284
+ this.toastElement.style.setProperty("--progress", value);
285
+ }
286
+ set pauseOnHover(value) {
287
+ this.toastElement.onmouseover = value ? this.pause : null;
288
+ this.toastElement.onmouseleave = value ? this.play : null;
289
+ this.toastElement[value ? "addEventListener" : "removeEventListener"]("touchend", this.play);
290
+ }
291
+ set pauseOnFocusLoss(value) {
292
+ value ? document.addEventListener("visibilitychange", this.#visiblityChange) : document.removeEventListener("visibilitychange", this.#visiblityChange);
293
+ }
294
+ set tag(value) {
295
+ this.toastElement.dataset.tag = value;
296
+ }
297
+ set renotify(value) {
298
+ value && this.opts.tag && t007.toasts.entries().forEach(([id, toast2]) => id !== this.id && (toast2.opts.tag ?? 1) === (this.opts.tag ?? 0) && toast2._remove("instant"));
299
+ }
300
+ get vibrate() {
301
+ return this.opts.vibrate === true ? t007.TOAST_VIBRATIONS[this.opts.type] || t007.TOAST_VIBRATIONS.info : this.opts.vibrate;
302
+ }
303
+ set vibrate(value) {
304
+ value && navigator?.vibrate?.(this.vibrate);
305
+ }
306
+ set maxToasts(value) {
307
+ const toastsInContainer = [...this.toastElement?.parentElement?.children || []];
308
+ if (!toastsInContainer.length) return;
309
+ for (let i = 0; i < toastsInContainer.length - value; i++) {
310
+ [...t007.toasts.values()].find((t) => t.toastElement === (this.opts.newestOnTop ? toastsInContainer[toastsInContainer.length - 1 - i] : toastsInContainer[i]))?._remove("instant");
311
+ }
312
+ }
313
+ set newestOnTop(value) {
314
+ this.toastElement?.parentElement?.[value ? "prepend" : "append"](this.toastElement);
315
+ }
316
+ set dragToClose(value) {
317
+ this.toastElement.dataset.dragToClose = this._ptrType = value;
318
+ this.toastElement.onpointerdown = value ? this._handleToastPointerStart : null;
319
+ this.toastElement.onpointerup = value ? this._handleToastPointerUp : null;
320
+ }
321
+ _handleToastPointerStart(e) {
322
+ if (typeof this._ptrType === "string" && e.pointerType !== this._ptrType) return;
323
+ if (e.touches?.length > 1) return;
324
+ !e.target?.matches('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])') && this.toastElement.setPointerCapture(e.pointerId);
325
+ this.#isPaused = true;
326
+ this._ptrTicker = this._ptrDirSet = this._ptrDir = false;
327
+ this._ptrStartX = e.clientX ?? e.targetTouches[0]?.clientX;
328
+ this._ptrStartY = e.clientY ?? e.targetTouches[0]?.clientY;
329
+ this.toastElement.addEventListener("pointermove", this._handleToastPointerMove, { passive: false });
330
+ this.toastElement.style.setProperty("transition", "none", "important");
331
+ }
332
+ _handleToastPointerMove(e) {
333
+ e.preventDefault();
334
+ if (this._ptrTicker) return;
335
+ this._ptrRAF = requestAnimationFrame(() => {
336
+ const has = (str) => this.opts.dragToCloseDir.includes(str), x = e.clientX ?? e.targetTouches[0]?.clientX, y = e.clientY ?? e.targetTouches[0]?.clientY;
337
+ this._ptrDir ||= Math.abs(x - this._ptrStartX) >= Math.abs(y - this._ptrStartY) ? "x" : "y";
338
+ this._ptrDeltaX = (has("|") ? this._ptrDir == "x" : has("x")) && !has(x - this._ptrStartX > 0 ? "-" : "+") ? x - this._ptrStartX : 0;
339
+ this._ptrDeltaY = (has("|") ? this._ptrDir == "y" : has("y")) && !has(y - this._ptrStartY > 0 ? "+" : "-") ? y - this._ptrStartY : 0;
340
+ this.toastElement.style.setProperty("transform", `translate(${this._ptrDeltaX}px, ${this._ptrDeltaY}px)`, "important");
341
+ const xR = Math.abs(this._ptrDeltaX) / this.toastElement.offsetWidth, yR = Math.abs(this._ptrDeltaY) / this.toastElement.offsetHeight;
342
+ this.toastElement.style.setProperty("opacity", clamp(0, 1 - (yR > 0.5 ? yR : xR), 1), "important");
343
+ if (!this._ptrDirSet && !xR && !yR) this._ptrDir = false;
344
+ if (this._ptrDir) this._ptrDirSet = has("||");
345
+ this._ptrTicker = false;
346
+ });
347
+ this._ptrTicker = true;
348
+ }
349
+ _handleToastPointerUp(e) {
350
+ if (typeof this._ptrType === "string" && e.pointerType !== this._ptrType) return;
351
+ cancelAnimationFrame(this._ptrRAF);
352
+ if (Math.abs(this._ptrDeltaX) > this.toastElement.offsetWidth * (this.opts.dragToClosePercent.x ?? this.opts.dragToClosePercent / 100) || Math.abs(this._ptrDeltaY) > this.toastElement.offsetHeight * (this.opts.dragToClosePercent.y ?? this.opts.dragToClosePercent / 100)) return this._remove("instant");
353
+ this.#isPaused = this._ptrTicker = this._ptrDirSet = this._ptrDir = false;
354
+ this.toastElement.removeEventListener("pointermove", this._handleToastPointerMove, { passive: false });
355
+ this.toastElement.style.removeProperty("transition");
356
+ this.toastElement.style.removeProperty("transform");
357
+ this.toastElement.style.removeProperty("opacity");
358
+ }
359
+ _remove(manner = "smooth", timeElapsed = false) {
360
+ if (!this.opts.isLoading) t007.toasts.delete(this.id);
361
+ this.queue.forEach(clearTimeout);
362
+ document.removeEventListener("visibilitychange", this.#visiblityChange);
363
+ cancelAnimationFrame(this.#autoCloseInterval);
364
+ cancelAnimationFrame(this.#progressInterval);
365
+ if (this.destroyed || manner === "instant" || !this.animation) this._cleanUpToast();
366
+ else this.toastElement.onanimationend = this._cleanUpToast;
367
+ this.toastElement.classList.remove("t007-toast-show");
368
+ this.onClose?.(timeElapsed);
369
+ }
370
+ _createContainer(position) {
371
+ const container = document.createElement("div");
372
+ container.classList.add("t007-toast-container");
373
+ container.style.setProperty("--t007-toast-container-position", this.opts.rootElement === document.body ? "fixed" : "absolute");
374
+ container.dataset.position = position;
375
+ this.opts.rootElement?.append(container);
376
+ return container;
377
+ }
378
+ _setUpBodyHTML() {
379
+ this.toastElement.querySelectorAll(".t007-toast > *:not(.t007-toast-image-wrapper, .t007-toast-body, .t007-toast-actions-wrapper, .t007-toast-cancel-button)").forEach((el) => el.remove());
380
+ const imageWrapper = () => this.toastElement.querySelector(".t007-toast-image-wrapper");
381
+ if (!imageWrapper()) this.toastElement.prepend(createEl("div", { className: "t007-toast-image-wrapper" }));
382
+ if (!this.toastElement.querySelector(".t007-toast-body")) imageWrapper().insertAdjacentElement("afterend", createEl("div", { className: "t007-toast-body" }));
383
+ }
384
+ _cleanUpToast() {
385
+ const container = this.toastElement.parentElement;
386
+ this.toastElement.remove();
387
+ if (!container?.hasChildNodes()) container?.remove();
388
+ this.destroyed = true;
389
+ }
390
+ };
391
+ var toasting = {
392
+ update(base, id, options) {
393
+ const toast2 = t007.toasts.get(id);
394
+ toast2?.queue.forEach(clearTimeout);
395
+ return !!toast2 && (toast2.destroyed ? base(options.render, { ...toast2.opts, id, ...options }) : toast2.update(options));
396
+ },
397
+ message: (base, defaults, action) => base[action] = (renderOrId, options = {}) => {
398
+ options = { ...options, type: action === "warn" ? "warning" : action };
399
+ if (!t007.toasts.get(renderOrId)) return base(renderOrId, options);
400
+ const { autoClose, closeButton, closeOnClick, dragToClose } = defaults();
401
+ return base.update(renderOrId, {
402
+ ...t007.toasts.get(renderOrId)?.opts.isLoading ? { autoClose, closeButton, closeOnClick, dragToClose } : {},
403
+ ...options,
404
+ isLoading: false
405
+ });
406
+ },
407
+ loading: (base, renderOrId, options = {}) => (t007.toasts.get(renderOrId) ? base.update : base)(renderOrId, {
408
+ autoClose: false,
409
+ closeButton: false,
410
+ closeOnClick: false,
411
+ dragToClose: false,
412
+ ...options,
413
+ isLoading: options.isLoading || true,
414
+ type: ""
415
+ }),
416
+ promise(base, promise = new Promise((res, rej) => setTimeout(Math.round(Math.random()) ? res : rej, 3e3)), { pending, success, error } = {}) {
417
+ if (!promise || typeof promise.then !== "function") return console.error("toast.promise() requires a valid promise");
418
+ const NFC = (input, type) => typeof input === "string" ? { render: input, type } : typeof input === "object" ? { ...input, type } : { type };
419
+ const pendingConfig = NFC(pending);
420
+ const pendingToastId = base.loading(pendingConfig.render || "Promise pending...", { ...pendingConfig });
421
+ promise.then(
422
+ (response) => {
423
+ const successConfig = NFC(success || "Promise resolved", "success");
424
+ const { render, bodyHTML } = successConfig;
425
+ if (typeof render === "function") successConfig.render = (response2) => render(response2);
426
+ if (typeof bodyHTML === "function") successConfig.bodyHTML = (response2) => bodyHTML(response2);
427
+ base.success(pendingToastId, successConfig);
428
+ return response;
429
+ },
430
+ (err) => {
431
+ const errorConfig = NFC(error || "Promise rejected", "error");
432
+ const { render, bodyHTML } = errorConfig;
433
+ if (typeof render === "function") errorConfig.render = (err2) => render(err2);
434
+ if (typeof bodyHTML === "function") errorConfig.bodyHTML = (err2) => bodyHTML(err2);
435
+ base.error(pendingToastId, errorConfig);
436
+ return Promise.reject(err);
437
+ }
438
+ );
439
+ return promise;
440
+ },
441
+ dismiss(base, id, manner, timeElapsed) {
442
+ return !arguments.length ? base.dismissAll() : t007.toasts.get(id)?._remove(manner, timeElapsed);
443
+ },
444
+ dismissAll(base, idPrefix) {
445
+ t007.toasts.values().forEach((toast2) => (!arguments.length ? true : toast2.id.startsWith(idPrefix)) && toast2._remove());
446
+ },
447
+ doForAll(base, action, options, idPrefix) {
448
+ t007.toasts.keys().forEach((id) => (!arguments.length ? true : id.startsWith(idPrefix)) && base[action]?.(id, options));
449
+ },
450
+ getAll(base, idPrefix) {
451
+ return t007.toasts.values().filter((toast2) => !arguments.length ? true : toast2.id.startsWith(idPrefix));
452
+ }
453
+ };
454
+ var toaster = (defOptions = {}, idPrefix = "t007_toast_") => {
455
+ const defaults = () => ({ ...t007.TOAST_DEFAULT_OPTIONS, ...defOptions }), base = (render, options = {}) => new T007_Toast({
456
+ ...defaults(),
457
+ ...options,
458
+ id: render?.startsWith?.(idPrefix) ? render : options.id,
459
+ render: render?.startsWith?.(idPrefix) ? options.render : render,
460
+ idPrefix
461
+ }).id;
462
+ base.update = (id, options) => toasting.update(base, id, options);
463
+ ["info", "success", "warn", "error"].forEach((action) => toasting.message(base, defaults, action));
464
+ base.loading = (render, options) => toasting.loading(base, render, options);
465
+ base.promise = (promise, options) => toasting.promise(base, promise, options);
466
+ base.dismiss = (id, manner, timeElapsed) => toasting.dismiss(base, id, manner, timeElapsed);
467
+ base.dismissAll = (idPrefix2) => toasting.dismissAll(base, idPrefix2);
468
+ base.doForAll = (action, options, idPrefix2) => toasting.doForAll(base, action, options, idPrefix2);
469
+ base.getAll = (idPrefix2) => toasting.getAll(base, idPrefix2);
470
+ return base;
471
+ };
472
+ var toast = toaster();
473
+ var src_default = toast;
474
+ if (typeof window !== "undefined") {
475
+ t007.toast = toast;
476
+ t007.toasting = toasting;
477
+ t007.toaster = toaster;
478
+ t007.toasts = /* @__PURE__ */ new Map();
479
+ t007.TOAST_DEFAULT_OPTIONS ??= {};
480
+ t007.TOAST_DURATIONS ??= {};
481
+ t007.TOAST_VIBRATIONS ??= {};
482
+ t007.TOAST_ICONS ??= {};
483
+ t007.TOAST_DEFAULT_OPTIONS.rootElement ??= document.body;
484
+ t007.TOAST_DEFAULT_OPTIONS.render ??= "";
485
+ t007.TOAST_DEFAULT_OPTIONS.type ??= "";
486
+ t007.TOAST_DEFAULT_OPTIONS.icon ??= true;
487
+ t007.TOAST_DEFAULT_OPTIONS.image ??= false;
488
+ t007.TOAST_DEFAULT_OPTIONS.autoClose ??= true;
489
+ t007.TOAST_DEFAULT_OPTIONS.position ??= "top-right";
490
+ t007.TOAST_DEFAULT_OPTIONS.isLoading ??= false;
491
+ t007.TOAST_DEFAULT_OPTIONS.closeButton ??= !/Mobi|Android|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
492
+ t007.TOAST_DEFAULT_OPTIONS.closeOnClick ??= false;
493
+ t007.TOAST_DEFAULT_OPTIONS.hideProgressBar ??= false;
494
+ t007.TOAST_DEFAULT_OPTIONS.pauseOnHover ??= true;
495
+ t007.TOAST_DEFAULT_OPTIONS.pauseOnFocusLoss ??= true;
496
+ t007.TOAST_DEFAULT_OPTIONS.dragToClose ??= true;
497
+ t007.TOAST_DEFAULT_OPTIONS.dragToClosePercent ??= 40;
498
+ t007.TOAST_DEFAULT_OPTIONS.dragToCloseDir ??= "x";
499
+ t007.TOAST_DEFAULT_OPTIONS.renotify ??= true;
500
+ t007.TOAST_DEFAULT_OPTIONS.vibrate ??= false;
501
+ t007.TOAST_DEFAULT_OPTIONS.animation ??= true;
502
+ t007.TOAST_DEFAULT_OPTIONS.newestOnTop ??= false;
503
+ t007.TOAST_DEFAULT_OPTIONS.maxToasts ??= 1e3;
504
+ t007.TOAST_DURATIONS.success ??= 2500;
505
+ t007.TOAST_DURATIONS.error ??= 4500;
506
+ t007.TOAST_DURATIONS.warning ??= 3500;
507
+ t007.TOAST_DURATIONS.info ??= 4e3;
508
+ t007.TOAST_VIBRATIONS.success ??= [100, 50, 100];
509
+ t007.TOAST_VIBRATIONS.warning ??= [300, 100, 300];
510
+ t007.TOAST_VIBRATIONS.error ??= [500, 200, 500];
511
+ t007.TOAST_VIBRATIONS.info ??= [200];
512
+ t007.TOAST_ICONS.success ??= `<svg class="no-css-fill" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#27ae60"/><path fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 12l3 3l6-6"/></svg>`;
513
+ t007.TOAST_ICONS.error ??= `<svg class="no-css-fill" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#e74c3c"/><path fill="#fff" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M8 8l8 8M16 8l-8 8"/></svg>`;
514
+ t007.TOAST_ICONS.warning ??= `<svg class="no-css-fill" width="24" height="24" viewBox="0 0 24 24"><path fill="#f1c40f" stroke="#f39c12" stroke-width="2" stroke-linejoin="round" d="M12 3L2.5 20.5A2 2 0 0 0 4.5 23h15a2 2 0 0 0 2-2.5L12 3z"/><circle cx="12" cy="17" r="1.5" fill="#fff"/><path fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M12 8v6"/></svg>`;
515
+ t007.TOAST_ICONS.info ??= `<svg class="no-css-fill" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#3498db"/><path fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M12 10v6"/><circle cx="12" cy="7" r="1.5" fill="#fff"/></svg>`;
516
+ t007.TOAST_ICONS.loading ??= `<svg class="no-css-fill" width="24" height="24" viewBox="0 0 16 16" fill="none" style="scale:0.75;"><g fill-rule="evenodd" clip-rule="evenodd"><path fill="whitesmoke" d="M8 1.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8"/><path fill="gray" d="M7.25.75A.75.75 0 0 1 8 0a8 8 0 0 1 8 8 .75.75 0 0 1-1.5 0A6.5 6.5 0 0 0 8 1.5a.75.75 0 0 1-.75-.75"/></g><animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="600ms" repeatCount="indefinite"/></svg>`;
517
+ loadResource(T007_TOAST_CSS_SRC);
518
+ window.Toast ??= t007.toast;
519
+ console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
520
+ }
521
+ export {
522
+ src_default as default,
523
+ toaster,
524
+ toasting
525
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t007/toast",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A lightweight, pure JS toast system.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",
@@ -16,7 +16,8 @@
16
16
  "type": "module",
17
17
  "main": "./dist/index.js",
18
18
  "module": "./dist/index.js",
19
- "browser": "./dist/index.global.js",
19
+ "unpkg": "./dist/index.global.js",
20
+ "jsdelivr": "./dist/index.global.js",
20
21
  "types": "./src/ts/types/index.d.ts",
21
22
  "style": "./src/css/index.css",
22
23
  "sideEffects": [
@@ -26,17 +27,14 @@
26
27
  ".": {
27
28
  "types": "./src/ts/types/index.d.ts",
28
29
  "import": "./dist/index.js",
29
- "default": "./dist/index.global.js"
30
+ "default": "./dist/index.js"
30
31
  },
32
+ "./standalone": "./dist/standalone.js",
33
+ "./global": "./dist/index.global.js",
31
34
  "./style.css": "./src/css/index.css"
32
35
  },
33
36
  "scripts": {
34
- "build": "tsup src/index.js --format esm,iife --clean --treeshake"
35
- },
36
- "tsup": {
37
- "noExternal": [
38
- "@t007/utils"
39
- ]
37
+ "build": "tsup --config ../../tsup.config.ts"
40
38
  },
41
39
  "files": [
42
40
  "dist",