@t007/toast 0.0.1 → 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.
@@ -16,17 +16,23 @@
16
16
  return src1.replace(/\\/g, "/").split("?")[0].trim() === src2.replace(/\\/g, "/").split("?")[0].trim();
17
17
  }
18
18
  }
19
- function createEl(tag, props = {}, dataset = {}, styles = {}) {
20
- 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;
21
21
  }
22
- function assignEl(el, props = {}, dataset = {}, styles = {}) {
22
+ function assignEl(el, props, dataset, styles) {
23
23
  if (!el) return;
24
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
25
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
26
- 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
+ }
27
33
  }
28
34
  function loadResource(src, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
29
- w.t007 ??= {}, w.t007._resourceCache ??= {};
35
+ w.t007._resourceCache ??= {};
30
36
  if (w.t007._resourceCache[src]) return w.t007._resourceCache[src];
31
37
  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;
32
38
  if (existing) return w.t007._resourceCache[src] = Promise.resolve(existing);
@@ -66,17 +72,15 @@
66
72
  owner2[method] = owner2[method].bind(owner2);
67
73
  });
68
74
  }
69
- var _SCROLLERS = /* @__PURE__ */ new WeakMap();
70
- var _SCROLLER_R_OBSERVER = typeof window !== "undefined" ? new ResizeObserver((entries) => entries.forEach(({ target }) => _SCROLLERS.get(target)?.update())) : null;
71
- var _SCROLLER_M_OBSERVER = typeof window !== "undefined" ? new MutationObserver((entries) => {
72
- const els = /* @__PURE__ */ new Set();
73
- for (const entry of entries) {
74
- let node = entry.target instanceof Element ? entry.target : null;
75
- while (node && !_SCROLLERS.has(node)) node = node.parentElement;
76
- if (node) els.add(node);
77
- }
78
- for (const el of els) _SCROLLERS.get(el)?.update();
79
- }) : null;
75
+ if (typeof window !== "undefined") {
76
+ window.t007 ??= {};
77
+ window.T007_TOAST_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest`;
78
+ window.T007_INPUT_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest`;
79
+ window.T007_DIALOG_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest`;
80
+ window.T007_TOAST_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest/dist/style.css`;
81
+ window.T007_INPUT_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest/dist/style.css`;
82
+ window.T007_DIALOG_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest/dist/style.css`;
83
+ }
80
84
 
81
85
  // src/index.js
82
86
  var T007_Toast = class {
@@ -470,7 +474,6 @@
470
474
  var toast = toaster();
471
475
  var index_default = toast;
472
476
  if (typeof window !== "undefined") {
473
- window.t007 ??= {};
474
477
  t007.toast = toast;
475
478
  t007.toasting = toasting;
476
479
  t007.toaster = toaster;
@@ -513,7 +516,6 @@
513
516
  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>`;
514
517
  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>`;
515
518
  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>`;
516
- window.T007_TOAST_CSS_SRC ??= `https://unpkg.com/@t007/toast@latest/style.css`;
517
519
  loadResource(T007_TOAST_CSS_SRC);
518
520
  window.Toast ??= t007.toast;
519
521
  console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
package/dist/index.js CHANGED
@@ -391,7 +391,6 @@ var toaster = (defOptions = {}, idPrefix = "t007_toast_") => {
391
391
  var toast = toaster();
392
392
  var index_default = toast;
393
393
  if (typeof window !== "undefined") {
394
- window.t007 ??= {};
395
394
  t007.toast = toast;
396
395
  t007.toasting = toasting;
397
396
  t007.toaster = toaster;
@@ -434,7 +433,6 @@ if (typeof window !== "undefined") {
434
433
  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>`;
435
434
  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>`;
436
435
  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>`;
437
- window.T007_TOAST_CSS_SRC ??= `https://unpkg.com/@t007/toast@latest/style.css`;
438
436
  loadResource(T007_TOAST_CSS_SRC);
439
437
  window.Toast ??= t007.toast;
440
438
  console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
@@ -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.1",
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,8 +16,8 @@
16
16
  "type": "module",
17
17
  "main": "./dist/index.js",
18
18
  "module": "./dist/index.js",
19
- "browser": "./dist/index.global.js",
20
19
  "unpkg": "./dist/index.global.js",
20
+ "jsdelivr": "./dist/index.global.js",
21
21
  "types": "./src/ts/types/index.d.ts",
22
22
  "style": "./src/css/index.css",
23
23
  "sideEffects": [
@@ -27,12 +27,14 @@
27
27
  ".": {
28
28
  "types": "./src/ts/types/index.d.ts",
29
29
  "import": "./dist/index.js",
30
- "default": "./dist/index.global.js"
30
+ "default": "./dist/index.js"
31
31
  },
32
+ "./standalone": "./dist/standalone.js",
33
+ "./global": "./dist/index.global.js",
32
34
  "./style.css": "./src/css/index.css"
33
35
  },
34
36
  "scripts": {
35
- "build": "tsup src/index.js --format esm,iife --clean"
37
+ "build": "tsup --config ../../tsup.config.ts"
36
38
  },
37
39
  "files": [
38
40
  "dist",
@@ -139,9 +139,6 @@ declare global {
139
139
  }
140
140
 
141
141
  interface Window {
142
- T007_TOAST_CSS_SRC?: string;
143
- T007_TOAST_JS_SRC?: string;
144
-
145
142
  Toast?: Toast;
146
143
  }
147
144
  }