@t007/toast 0.0.32 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
- import "@t007/utils";
2
-
3
1
  /** Toast severity level. */
4
- export type ToastType = "info" | "success" | "error" | "warning";
2
+ type ToastType = undefined | "info" | "success" | "error" | "warning";
5
3
  /** Screen anchor for toast placement. */
6
- export type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "center-left" | "center-center" | "center-right";
4
+ type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "center-left" | "center-center" | "center-right";
7
5
  /** Motion preset used when a toast enters or leaves the screen. */
8
- export type ToastAnimation = "fade" | "zoom" | "slide" | "slide-left" | "slide-right" | "slide-up" | "slide-down" | boolean;
6
+ type ToastAnimation = "fade" | "zoom" | "slide" | "slide-left" | "slide-right" | "slide-up" | "slide-down" | boolean;
7
+ /** Allowed pointer types for drag-to-dismiss gestures. */
8
+ type ToastDragOption = boolean | "mouse" | "touch" | "pen";
9
9
  /** Allowed drag directions for dismiss gestures. `|` combines axes where it can be `a` or `b` and can change anytime while `||` does not change after a pick is determined. */
10
- export type ToastDragDir = "x" | "y" | "xy" | "x|y" | "x||y" | "x+" | "x-" | "y+" | "y-" | "xy+" | "xy-" | "x|y+" | "x|y-" | "x||y+" | "x||y-";
10
+ type ToastDragDirection = "x" | "y" | "xy" | "x|y" | "x||y" | "x+" | "x-" | "y+" | "y-" | "xy+" | "xy-" | "x|y+" | "x|y-" | "x||y+" | "x||y-";
11
11
 
12
12
  /** Configuration object for creating and updating a toast. */
13
- export interface ToastOptions {
13
+ interface ToastOptions {
14
14
  /** Explicit toast id. Reusing an active id updates that toast in place (upsert-style), preserving position/animation state. */
15
15
  id?: string;
16
16
  /** Prefix used when ids are generated automatically. */
@@ -48,11 +48,11 @@ export interface ToastOptions {
48
48
  /** Pause auto-close while the document is hidden. */
49
49
  pauseOnFocusLoss?: boolean;
50
50
  /** Enable drag-to-dismiss gestures and optionally limit pointer types. */
51
- dragToClose?: boolean | "mouse" | "pen" | "touch";
51
+ dragToClose?: ToastDragOption;
52
52
  /** Percentage threshold needed to dismiss by drag. */
53
53
  dragToClosePercent?: number | { x?: number; y?: number };
54
54
  /** Axis or direction filter used by the drag gesture system. */
55
- dragToCloseDir?: ToastDragDir;
55
+ dragToCloseDir?: ToastDragDirection;
56
56
  /** When true and `tag` is provided, any other active toast with the same tag is removed before this toast renders. */
57
57
  renotify?: boolean;
58
58
  /** Arbitrary tag used for grouping and renotify matching. Does not update by itself; pair with `renotify` to enforce one-toast-per-tag behavior. */
@@ -71,11 +71,13 @@ export interface ToastOptions {
71
71
  onClose?: (timeElapsed?: boolean | false) => void;
72
72
  /** Callback fired as the toast auto-close timer advances. */
73
73
  onTimeUpdate?: (timeVisible: number) => void;
74
+ /** Abort signal to control the toast's lifecycle and timeout aborts. */
75
+ signal?: AbortSignal;
74
76
  // [key: string]: any; // To allow arbitrary overrides internally if needed
75
77
  }
76
78
 
77
79
  /** Live toast instance returned by the runtime. */
78
- export interface ToastInstance {
80
+ interface ToastInstance {
79
81
  /** Current option bag applied to the instance. */
80
82
  opts: ToastOptions;
81
83
  /** Pending timeouts waiting to apply queued updates. */
@@ -103,17 +105,19 @@ export interface ToastInstance {
103
105
  * @param timeElapsed Whether the auto-close timer already elapsed.
104
106
  */
105
107
  remove(manner?: "smooth" | "instant", timeElapsed?: boolean): void;
108
+ /** Dismiss the toast immediately without any exit animation. */
109
+ abort(): void;
106
110
  }
107
111
 
108
112
  /** Promise state configuration used by toast.promise. */
109
- export interface ToastPromiseState<T = any> extends Omit<ToastOptions, "render" | "bodyHTML"> {
113
+ interface ToastPromiseState<T = any> extends Omit<ToastOptions, "render" | "bodyHTML"> {
110
114
  /** Render text for the promise state. */
111
115
  render?: string | ((response: T) => string);
112
116
  /** Render HTML for the promise state. */
113
117
  bodyHTML?: string | ((response: T) => string);
114
118
  }
115
119
  /** Configuration object accepted by toast.promise. */
116
- export interface ToastPromiseConfig<T = any> {
120
+ interface ToastPromiseConfig<T = any> {
117
121
  /** Pending-state text or options. */
118
122
  pending?: string | ToastOptions;
119
123
  /** Success-state text or options. */
@@ -123,7 +127,7 @@ export interface ToastPromiseConfig<T = any> {
123
127
  }
124
128
 
125
129
  /** Public toast API exposed to consumers. */
126
- export interface Toast {
130
+ interface Toast {
127
131
  /** Create a default toast.
128
132
  * @param render Body text for the toast.
129
133
  * @param options Toast configuration.
@@ -201,7 +205,7 @@ export interface Toast {
201
205
  }
202
206
 
203
207
  /** Helper methods used internally by toaster() and promise flows. */
204
- export interface Toasting {
208
+ interface Toasting {
205
209
  isActive(base: Toast, id: string): boolean;
206
210
  update(base: Toast, id: string, options: ToastOptions): boolean | string;
207
211
  message(base: Toast, getDefaults: () => ToastOptions, action: string, renderOrId: string, options?: ToastOptions): string;
@@ -216,16 +220,22 @@ export interface Toasting {
216
220
  // BUNDLE EXPORTS & GLOBAL DECLARATIONS
217
221
 
218
222
  /** Internal helper methods used by the toast factory. */
219
- export const toasting: Toasting;
223
+ declare const toasting: Toasting;
220
224
  /** Create a toast factory with custom defaults and a group id.
221
225
  * @param defOptions Default options merged into every toast.
222
226
  * @param groupId Prefix applied to generated ids.
223
227
  * @returns Toast factory.
224
228
  */
225
- export function toaster(defOptions?: ToastOptions, groupId?: string): Toast;
229
+ declare function toaster(defOptions?: ToastOptions, groupId?: string): Toast;
226
230
  /** Default toast factory instance attached by the bundle. */
227
231
  declare const toast: Toast;
228
- export default toast;
232
+
233
+
234
+ declare const TOAST_UI_POSITIONS: { value: ToastPosition; display: string }[];
235
+ declare const TOAST_UI_ANIMATIONS: { value: ToastAnimation; display: string }[];
236
+ declare const TOAST_UI_TYPES: { value: ToastType; display: string }[];
237
+ declare const TOAST_UI_DRAG_OPTIONS: { value: ToastDragOption; display: string }[];
238
+ declare const TOAST_UI_DRAG_DIRECTIONS: { value: ToastDragDirection; display: string }[];
229
239
 
230
240
  declare global {
231
241
  interface T007Namespace {
@@ -245,8 +255,15 @@ declare global {
245
255
  TOAST_VIBRATIONS: Record<ToastType, number[]>;
246
256
  /** Default SVG icons by toast type. */
247
257
  TOAST_ICONS: Record<ToastType | "loading", string>;
258
+ TOAST_UI_POSITIONS: typeof TOAST_UI_POSITIONS;
259
+ TOAST_UI_ANIMATIONS: typeof TOAST_UI_ANIMATIONS;
260
+ TOAST_UI_TYPES: typeof TOAST_UI_TYPES;
261
+ TOAST_UI_DRAG_OPTS: typeof TOAST_UI_DRAG_OPTIONS;
262
+ TOAST_UI_DRAG_DIRS: typeof TOAST_UI_DRAG_DIRECTIONS;
248
263
  }
249
264
  interface Window {
250
265
  toast?: Toast;
251
266
  }
252
267
  }
268
+
269
+ export { TOAST_UI_ANIMATIONS, TOAST_UI_DRAG_DIRECTIONS, TOAST_UI_DRAG_OPTIONS, TOAST_UI_POSITIONS, TOAST_UI_TYPES, type Toast, type ToastAnimation, type ToastDragDirection, type ToastDragOption, type ToastInstance, type ToastOptions, type ToastPosition, type ToastPromiseConfig, type ToastPromiseState, type ToastType, type Toasting, toast as default, toaster, toasting };
@@ -4,8 +4,16 @@
4
4
  function clamp(min = 0, val, max = Infinity) {
5
5
  return Math.min(Math.max(val, min), max);
6
6
  }
7
+ function setTimeout2(handler, timeout, ...args) {
8
+ const sig = args[0] instanceof AbortSignal ? args.shift() : void 0;
9
+ if (sig?.aborted) return -1;
10
+ const win = args[0] instanceof Window ? args.shift() : window;
11
+ if (!sig) return win.setTimeout(handler, timeout, ...args);
12
+ const id = win.setTimeout(() => (sig.removeEventListener("abort", kill), "string" === typeof handler ? new Function(handler) : handler(...args)), timeout), kill = () => win.clearTimeout(id);
13
+ return sig.addEventListener("abort", kill, { once: true }), id;
14
+ }
7
15
 
8
- // ../../../sia-reactor/dist/chunk-243U74PP.js
16
+ // ../../../sia-reactor/dist/chunk-ORK3EGB6.js
9
17
  function onAllMethods(owner, callback, skipOwn = true, nested = false) {
10
18
  let proto = owner;
11
19
  while (proto && proto !== Object.prototype) {
@@ -25,50 +33,40 @@
25
33
  function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
26
34
  return assignEl(el, props, dataset, styles);
27
35
  }
28
- function assignEl(el, props, dataset, styles) {
36
+ function assignEl(el, props, dataset, styles, nodiff = true) {
29
37
  if (!el) return null;
30
38
  if (props) {
31
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
39
+ for (const k of Object.keys(props)) if (props[k] !== void 0) {
40
+ if (nodiff || el[k] !== props[k]) el[k] = props[k];
41
+ }
32
42
  }
33
43
  if (dataset) {
34
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
44
+ for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) {
45
+ if (nodiff || el.dataset[k] !== dataset[k]) el.dataset[k] = String(dataset[k]);
46
+ }
35
47
  }
36
48
  if (styles) {
37
- for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
49
+ for (const k of Object.keys(styles)) if (styles[k] !== void 0) {
50
+ if (nodiff || el.style[k] !== styles[k]) el.style[k] = styles[k];
51
+ }
38
52
  }
39
53
  return el;
40
54
  }
41
55
 
42
- // ../../../sia-reactor/dist/chunk-2ZYYYSZ4.js
56
+ // ../../../sia-reactor/dist/chunk-SHWIAQD2.js
43
57
  var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
44
58
  var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
45
59
  var NIL = Object.freeze({});
46
- var CTX = {
47
- /** Flag indicating whether the application is running in development mode. */
48
- isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
49
- /** Flag indicating whether an operation is bypassing checks so reactors can allow all writes. */
50
- usingForce: false,
51
- /** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
52
- autotracker: null,
53
- /** Extensible meta context for payloads and cross-cutting concerns. */
54
- meta: null,
55
- /** Default configuration for new `Reactor` instances and also fallback for utils that need and are called without these options. */
56
- defaults: {
57
- crossRealms: false,
58
- smartCloning: false,
59
- eventBubbling: true,
60
- eventCapturing: "auto",
61
- lineageTracing: false,
62
- preserveContext: false,
63
- equalityFunction: Object.is,
64
- batchingFunction: RTR_BATCH
65
- }
66
- };
60
+ var isDevEnv = false;
61
+ try {
62
+ isDevEnv = process.env.NODE_ENV !== "production";
63
+ } catch (e) {
64
+ }
67
65
  function isObj(obj, arraycheck = true) {
68
66
  return "object" === typeof obj && obj !== null && (arraycheck ? !Array.isArray(obj) : true);
69
67
  }
70
68
 
71
- // ../utils/dist/chunk-HGUYOV3P.js
69
+ // ../utils/dist/chunk-ZALPHCSJ.js
72
70
  var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
73
71
  var isInteractive = (target) => target instanceof HTMLElement && target.matches(INTERACTIVE_SELECTOR);
74
72
  var VIRTUAL_RESOURCE = /* @__PURE__ */ Symbol.for("T007_VIRTUAL_RESOURCE");
@@ -133,6 +131,11 @@
133
131
  if (!isStr(url1) || !isStr(url2) || !url1 || !url2) return false;
134
132
  return cleanURL(url1) === cleanURL(url2);
135
133
  }
134
+ function bindCleanupToSignal(cleanup, signal) {
135
+ signal?.aborted ? cleanup() : signal?.addEventListener("abort", cleanup, { once: true });
136
+ if (signal && !signal.aborted) cleanup = (() => (signal.removeEventListener("abort", cleanup), cleanup()));
137
+ return cleanup;
138
+ }
136
139
  if ("undefined" !== typeof window) {
137
140
  (window.t007 ??= {}).VIRTUAL_RESOURCE = VIRTUAL_RESOURCE;
138
141
  window.T007_TOAST_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest`;
@@ -156,10 +159,10 @@
156
159
  inactive = true;
157
160
  #visiblityChange = () => this.#shouldUnPause = document.visibilityState === "visible";
158
161
  constructor(options) {
159
- bindAllMethods(this);
162
+ bindAllMethods(this), bindCleanupToSignal(this.abort, options.signal);
160
163
  this.opts = options;
161
164
  t007.toasts.set(this.opts.id ??= uid(this.opts.groupId ??= "t007_toast_"), this);
162
- !isNum(this.opts.delay) ? this.activate() : this.queue.push(setTimeout(this.activate, this.opts.delay));
165
+ !isNum(this.opts.delay) ? this.activate() : this.queue.push(setTimeout2(this.activate, this.opts.delay, this.opts.signal));
163
166
  this.update(this.opts);
164
167
  }
165
168
  activate() {
@@ -170,16 +173,17 @@
170
173
  update(options, constructed = this.#constructed) {
171
174
  if (!options || !isObj(options) || constructed && this.inactive) return this.opts.id;
172
175
  try {
176
+ if (constructed) options.signal !== this.opts.signal && (this.opts.signal.removeEventListener("abort", this.abort), bindCleanupToSignal(this.abort, this.opts.signal));
173
177
  this.opts = { ...this.opts, ...options };
174
178
  const run = () => (Object.keys(options).forEach((key) => this[key] = options[key]), this.#constructed = true, !constructed && (this.position = this.opts.position));
175
- !isNum(this.opts.delay) ? run() : this.queue.push(setTimeout(run, this.opts.delay));
179
+ !isNum(this.opts.delay) ? run() : this.queue.push(setTimeout2(run, this.opts.delay, this.opts.signal));
176
180
  this.opts.delay = null;
177
181
  } catch (err) {
178
182
  console.error("t007 toast update failed:", err);
179
183
  }
180
184
  return this.opts.id;
181
185
  }
182
- play = () => setTimeout(() => this.#isPaused = false);
186
+ play = () => setTimeout2(() => this.#isPaused = false, 0, this.opts.signal);
183
187
  pause = () => this.#isPaused = true;
184
188
  get rootElement() {
185
189
  return this.opts.rootElement ?? document.body;
@@ -301,7 +305,7 @@
301
305
  set position(value) {
302
306
  if (!this.#constructed) return;
303
307
  const currContainer = this.toastElement.parentElement, container = this.rootElement.querySelector(`:scope > .t007-toast-container[data-position="${value}"]`) || this._createContainer(value);
304
- container[this.opts.newestOnTop ? "prepend" : "append"](this.toastElement);
308
+ !container.contains(this.toastElement) && container[this.opts.newestOnTop ? "prepend" : "append"](this.toastElement);
305
309
  this.toastElement.classList.toggle("t007-toast-scoped", this.scoped);
306
310
  if (!(currContainer == null || currContainer.hasChildNodes())) currContainer.remove();
307
311
  }
@@ -337,7 +341,7 @@
337
341
  }
338
342
  set renotify(value) {
339
343
  if (value && this.opts.tag) {
340
- for (const toast2 of t007.toasts.values()) if (toast2.opts.tag === this.opts.tag && toast2.opts.id !== this.opts.id) toast2.remove("instant");
344
+ for (const toast2 of t007.toasts.values()) if (toast2.opts.tag === this.opts.tag && toast2.opts.id !== this.opts.id) toast2.abort();
341
345
  }
342
346
  }
343
347
  get vibrate() {
@@ -349,7 +353,7 @@
349
353
  set limit(value) {
350
354
  const toastsInContainer = [...this.toastElement?.parentElement?.children || []];
351
355
  if (!toastsInContainer.length) return;
352
- for (let i = 0; i < toastsInContainer.length - value; i++) [...t007.toasts.values()].find((t) => t.toastElement === (this.opts.newestOnTop ? toastsInContainer[toastsInContainer.length - 1 - i] : toastsInContainer[i]))?.remove("instant");
356
+ for (let i = 0; i < toastsInContainer.length - value; i++) [...t007.toasts.values()].find((t) => t.toastElement === (this.opts.newestOnTop ? toastsInContainer[toastsInContainer.length - 1 - i] : toastsInContainer[i]))?.abort();
353
357
  }
354
358
  set newestOnTop(value) {
355
359
  this.toastElement?.parentElement?.[value ? "prepend" : "append"](this.toastElement);
@@ -392,7 +396,7 @@
392
396
  _handleToastPointerUp(e) {
393
397
  if (isStr(this._ptrType) && e.pointerType !== this._ptrType) return;
394
398
  cancelAnimationFrame(this._ptrRAF);
395
- 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");
399
+ 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.abort();
396
400
  this.#isPaused = this._ptrTicker = this._ptrDirSet = this._ptrDir = false;
397
401
  this.toastElement.removeEventListener("pointermove", this._handleToastPointerMove, { passive: false });
398
402
  for (const prop of ["transition", "transform", "opacity"]) this.toastElement.style.removeProperty(prop);
@@ -407,6 +411,7 @@
407
411
  this.toastElement.classList.remove("t007-toast-show");
408
412
  this.onClose?.(timeElapsed);
409
413
  }
414
+ abort = () => this.remove("instant", false);
410
415
  _createContainer(position) {
411
416
  const container = createEl("div", { className: "t007-toast-container" }, { position });
412
417
  container.style.setProperty("--t007-toast-container-position", !this.scoped ? "fixed" : "absolute");
@@ -432,7 +437,8 @@
432
437
  update(base, id, options, _toast) {
433
438
  const toast2 = _toast ?? t007.toasts.get(id);
434
439
  if (toast2?.queue) for (const tid of toast2.queue) clearTimeout(tid);
435
- return toast2 && (toast2.inactive ? base(options.render, { ...toast2.opts, id, ...options }) : toast2.update(options));
440
+ if (toast2 && toast2.inactive) return t007.toasts.delete(id), base(options.render, { ...toast2.opts, id, ...options });
441
+ return toast2 && toast2.update(options);
436
442
  },
437
443
  message: (base, getDefaults, action, renderOrId, options = {}) => {
438
444
  options = { ...options, type: action === "warn" ? "warning" : action };
@@ -445,7 +451,7 @@
445
451
  const id = options.id ?? renderOrId, toast2 = t007.toasts.get(id);
446
452
  return (toast2 ? base.update : base)(id, { closeButton: false, closeOnClick: false, dragToClose: false, ...options.id ? { render: renderOrId } : null, autoClose: false, ...options, isLoading: options.isLoading || true, type: "" }, toast2 || void 0);
447
453
  },
448
- promise(base, promise = new Promise((res, rej) => setTimeout(Math.round(Math.random()) ? res : rej, 3e3)), { pending, success, error } = {}) {
454
+ promise(base, promise = new Promise((res, rej) => setTimeout2(Math.round(Math.random()) ? res : rej, 3e3)), { pending, success, error } = {}) {
449
455
  if (!promise || !isFunc(promise.then)) return console.error("toast.promise() requires a valid promise");
450
456
  const NFC = (input, type) => isStr(input) ? { render: input, type } : isObj(input) ? { ...input, type } : { type };
451
457
  const pendingCfg = NFC(pending);
@@ -484,7 +490,7 @@
484
490
  }
485
491
  };
486
492
  var toaster = (defOptions = {}, groupId = "t007_toast_") => {
487
- const getDefaults = () => ({ ...t007.TOAST_DEFAULT_OPTIONS, ...defOptions }), base = (render, options = {}, mayBeId = render?.startsWith?.(groupId)) => new T007_Toast({ ...getDefaults(), ...options, id: mayBeId ? render : options.id, render: mayBeId ? options.render : render, groupId }).opts.id;
493
+ const getDefaults = () => ({ ...t007.TOAST_DEFAULT_OPTIONS, ...defOptions }), base = (renderOrId, options = {}, mayBeId = renderOrId?.startsWith?.(groupId), render = mayBeId ? options.render : renderOrId, id = mayBeId ? renderOrId : options.id, toast2 = t007.toasts.get(id)) => toast2 ? toasting.update(base, id, { ...options, render }, toast2) : new T007_Toast({ ...getDefaults(), ...options, id, render, groupId }).opts.id;
488
494
  base.isActive = (id) => toasting.isActive(base, id);
489
495
  base.update = (id, options, _toast) => toasting.update(base, id, options, _toast);
490
496
  for (const action of ["info", "success", "warn", "error"]) base[action] = (renderOrId, options) => toasting.message(base, getDefaults, action, renderOrId, options);
@@ -498,10 +504,15 @@
498
504
  };
499
505
  var toast = toaster();
500
506
  var index_default = toast;
507
+ var TOAST_UI_POSITIONS = [{ value: "top-left", display: "Top Left" }, { value: "top-center", display: "Top Center" }, { value: "top-right", display: "Top Right" }, { value: "center-left", display: "Center Left" }, { value: "center-center", display: "Center Center" }, { value: "center-right", display: "Center Right" }, { value: "bottom-left", display: "Bottom Left" }, { value: "bottom-center", display: "Bottom Center" }, { value: "bottom-right", display: "Bottom Right" }];
508
+ var TOAST_UI_ANIMATIONS = [{ value: "fade", display: "Fade" }, { value: "zoom", display: "Zoom" }, { value: "slide", display: "Slide" }, { value: "slide-left", display: "Slide Left" }, { value: "slide-right", display: "Slide Right" }, { value: "slide-up", display: "Slide Up" }, { value: "slide-down", display: "Slide Down" }];
509
+ var TOAST_UI_TYPES = [{ value: void 0, display: "None" }, { value: "info", display: "Info" }, { value: "success", display: "Success" }, { value: "warning", display: "Warning" }, { value: "error", display: "Error" }];
510
+ var TOAST_UI_DRAG_OPTIONS = [{ value: true, display: "On" }, { value: "mouse", display: "Mouse" }, { value: "touch", display: "Touch" }, { value: "pen", display: "Pen" }, { value: false, display: "Off" }];
511
+ var TOAST_UI_DRAG_DIRECTIONS = [{ value: "x", display: "Horizontal" }, { value: "y", display: "Vertical" }, { value: "xy", display: "Horizontal and Vertical" }, { value: "x|y", display: "Horizontal or Vertical" }, { value: "x||y", display: "Horizontal or Vertical (Locked)" }, { value: "x+", display: "Right" }, { value: "x-", display: "Left" }, { value: "y+", display: "Down" }, { value: "y-", display: "Up" }, { value: "xy+", display: "Right and Down" }, { value: "xy-", display: "Left and Up" }, { value: "x|y+", display: "Right or Down" }, { value: "x|y-", display: "Left or Up" }, { value: "x||y+", display: "Right or Down (Locked)" }, { value: "x||y-", display: "Left or Up (Locked)" }];
501
512
  if ("undefined" !== typeof window) {
502
513
  t007.toast = toast, t007.toasting = toasting, t007.toaster = toaster;
503
514
  t007.toasts = /* @__PURE__ */ new Map();
504
- t007.TOAST_DEFAULT_OPTIONS ??= {}, t007.TOAST_DURATIONS ??= {}, t007.TOAST_VIBRATIONS ??= {}, t007.TOAST_ICONS ??= {};
515
+ t007.TOAST_DEFAULT_OPTIONS ??= {}, t007.TOAST_DURATIONS ??= {}, t007.TOAST_VIBRATIONS ??= {}, t007.TOAST_ICONS ??= {}, t007.T0AST_UI_POSITIONS = TOAST_UI_POSITIONS, t007.TOAST_UI_ANIMATIONS = TOAST_UI_ANIMATIONS, t007.TOAST_UI_TYPES = TOAST_UI_TYPES, t007.TOAST_UI_DRAG_OPTIONS = TOAST_UI_DRAG_OPTIONS, t007.TOAST_UI_DRAG_DIRECTIONS = TOAST_UI_DRAG_DIRECTIONS;
505
516
  t007.TOAST_DEFAULT_OPTIONS.render ??= "";
506
517
  t007.TOAST_DEFAULT_OPTIONS.type ??= "";
507
518
  t007.TOAST_DEFAULT_OPTIONS.icon ??= true;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/js/index.js
2
- import { isStr, isNum, isObj, isFunc, clamp, uid, bindAllMethods, isInteractive, createEl, loadResource, isDef } from "@t007/utils";
2
+ import { isStr, isNum, isObj, isFunc, clamp, uid, bindAllMethods, isInteractive, createEl, loadResource, isDef, setTimeout, bindCleanupToSignal } from "@t007/utils";
3
3
  var T007_Toast = class {
4
4
  #constructed = false;
5
5
  // to minimize updates
@@ -12,10 +12,10 @@ var T007_Toast = class {
12
12
  inactive = true;
13
13
  #visiblityChange = () => this.#shouldUnPause = document.visibilityState === "visible";
14
14
  constructor(options) {
15
- bindAllMethods(this);
15
+ bindAllMethods(this), bindCleanupToSignal(this.abort, options.signal);
16
16
  this.opts = options;
17
17
  t007.toasts.set(this.opts.id ??= uid(this.opts.groupId ??= "t007_toast_"), this);
18
- !isNum(this.opts.delay) ? this.activate() : this.queue.push(setTimeout(this.activate, this.opts.delay));
18
+ !isNum(this.opts.delay) ? this.activate() : this.queue.push(setTimeout(this.activate, this.opts.delay, this.opts.signal));
19
19
  this.update(this.opts);
20
20
  }
21
21
  activate() {
@@ -26,16 +26,17 @@ var T007_Toast = class {
26
26
  update(options, constructed = this.#constructed) {
27
27
  if (!options || !isObj(options) || constructed && this.inactive) return this.opts.id;
28
28
  try {
29
+ if (constructed) options.signal !== this.opts.signal && (this.opts.signal.removeEventListener("abort", this.abort), bindCleanupToSignal(this.abort, this.opts.signal));
29
30
  this.opts = { ...this.opts, ...options };
30
31
  const run = () => (Object.keys(options).forEach((key) => this[key] = options[key]), this.#constructed = true, !constructed && (this.position = this.opts.position));
31
- !isNum(this.opts.delay) ? run() : this.queue.push(setTimeout(run, this.opts.delay));
32
+ !isNum(this.opts.delay) ? run() : this.queue.push(setTimeout(run, this.opts.delay, this.opts.signal));
32
33
  this.opts.delay = null;
33
34
  } catch (err) {
34
35
  console.error("t007 toast update failed:", err);
35
36
  }
36
37
  return this.opts.id;
37
38
  }
38
- play = () => setTimeout(() => this.#isPaused = false);
39
+ play = () => setTimeout(() => this.#isPaused = false, 0, this.opts.signal);
39
40
  pause = () => this.#isPaused = true;
40
41
  get rootElement() {
41
42
  return this.opts.rootElement ?? document.body;
@@ -157,7 +158,7 @@ var T007_Toast = class {
157
158
  set position(value) {
158
159
  if (!this.#constructed) return;
159
160
  const currContainer = this.toastElement.parentElement, container = this.rootElement.querySelector(`:scope > .t007-toast-container[data-position="${value}"]`) || this._createContainer(value);
160
- container[this.opts.newestOnTop ? "prepend" : "append"](this.toastElement);
161
+ !container.contains(this.toastElement) && container[this.opts.newestOnTop ? "prepend" : "append"](this.toastElement);
161
162
  this.toastElement.classList.toggle("t007-toast-scoped", this.scoped);
162
163
  if (!(currContainer == null || currContainer.hasChildNodes())) currContainer.remove();
163
164
  }
@@ -193,7 +194,7 @@ var T007_Toast = class {
193
194
  }
194
195
  set renotify(value) {
195
196
  if (value && this.opts.tag) {
196
- for (const toast2 of t007.toasts.values()) if (toast2.opts.tag === this.opts.tag && toast2.opts.id !== this.opts.id) toast2.remove("instant");
197
+ for (const toast2 of t007.toasts.values()) if (toast2.opts.tag === this.opts.tag && toast2.opts.id !== this.opts.id) toast2.abort();
197
198
  }
198
199
  }
199
200
  get vibrate() {
@@ -205,7 +206,7 @@ var T007_Toast = class {
205
206
  set limit(value) {
206
207
  const toastsInContainer = [...this.toastElement?.parentElement?.children || []];
207
208
  if (!toastsInContainer.length) return;
208
- for (let i = 0; i < toastsInContainer.length - value; i++) [...t007.toasts.values()].find((t) => t.toastElement === (this.opts.newestOnTop ? toastsInContainer[toastsInContainer.length - 1 - i] : toastsInContainer[i]))?.remove("instant");
209
+ for (let i = 0; i < toastsInContainer.length - value; i++) [...t007.toasts.values()].find((t) => t.toastElement === (this.opts.newestOnTop ? toastsInContainer[toastsInContainer.length - 1 - i] : toastsInContainer[i]))?.abort();
209
210
  }
210
211
  set newestOnTop(value) {
211
212
  this.toastElement?.parentElement?.[value ? "prepend" : "append"](this.toastElement);
@@ -248,7 +249,7 @@ var T007_Toast = class {
248
249
  _handleToastPointerUp(e) {
249
250
  if (isStr(this._ptrType) && e.pointerType !== this._ptrType) return;
250
251
  cancelAnimationFrame(this._ptrRAF);
251
- 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");
252
+ 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.abort();
252
253
  this.#isPaused = this._ptrTicker = this._ptrDirSet = this._ptrDir = false;
253
254
  this.toastElement.removeEventListener("pointermove", this._handleToastPointerMove, { passive: false });
254
255
  for (const prop of ["transition", "transform", "opacity"]) this.toastElement.style.removeProperty(prop);
@@ -263,6 +264,7 @@ var T007_Toast = class {
263
264
  this.toastElement.classList.remove("t007-toast-show");
264
265
  this.onClose?.(timeElapsed);
265
266
  }
267
+ abort = () => this.remove("instant", false);
266
268
  _createContainer(position) {
267
269
  const container = createEl("div", { className: "t007-toast-container" }, { position });
268
270
  container.style.setProperty("--t007-toast-container-position", !this.scoped ? "fixed" : "absolute");
@@ -288,7 +290,8 @@ var toasting = {
288
290
  update(base, id, options, _toast) {
289
291
  const toast2 = _toast ?? t007.toasts.get(id);
290
292
  if (toast2?.queue) for (const tid of toast2.queue) clearTimeout(tid);
291
- return toast2 && (toast2.inactive ? base(options.render, { ...toast2.opts, id, ...options }) : toast2.update(options));
293
+ if (toast2 && toast2.inactive) return t007.toasts.delete(id), base(options.render, { ...toast2.opts, id, ...options });
294
+ return toast2 && toast2.update(options);
292
295
  },
293
296
  message: (base, getDefaults, action, renderOrId, options = {}) => {
294
297
  options = { ...options, type: action === "warn" ? "warning" : action };
@@ -340,7 +343,7 @@ var toasting = {
340
343
  }
341
344
  };
342
345
  var toaster = (defOptions = {}, groupId = "t007_toast_") => {
343
- const getDefaults = () => ({ ...t007.TOAST_DEFAULT_OPTIONS, ...defOptions }), base = (render, options = {}, mayBeId = render?.startsWith?.(groupId)) => new T007_Toast({ ...getDefaults(), ...options, id: mayBeId ? render : options.id, render: mayBeId ? options.render : render, groupId }).opts.id;
346
+ const getDefaults = () => ({ ...t007.TOAST_DEFAULT_OPTIONS, ...defOptions }), base = (renderOrId, options = {}, mayBeId = renderOrId?.startsWith?.(groupId), render = mayBeId ? options.render : renderOrId, id = mayBeId ? renderOrId : options.id, toast2 = t007.toasts.get(id)) => toast2 ? toasting.update(base, id, { ...options, render }, toast2) : new T007_Toast({ ...getDefaults(), ...options, id, render, groupId }).opts.id;
344
347
  base.isActive = (id) => toasting.isActive(base, id);
345
348
  base.update = (id, options, _toast) => toasting.update(base, id, options, _toast);
346
349
  for (const action of ["info", "success", "warn", "error"]) base[action] = (renderOrId, options) => toasting.message(base, getDefaults, action, renderOrId, options);
@@ -354,10 +357,15 @@ var toaster = (defOptions = {}, groupId = "t007_toast_") => {
354
357
  };
355
358
  var toast = toaster();
356
359
  var index_default = toast;
360
+ var TOAST_UI_POSITIONS = [{ value: "top-left", display: "Top Left" }, { value: "top-center", display: "Top Center" }, { value: "top-right", display: "Top Right" }, { value: "center-left", display: "Center Left" }, { value: "center-center", display: "Center Center" }, { value: "center-right", display: "Center Right" }, { value: "bottom-left", display: "Bottom Left" }, { value: "bottom-center", display: "Bottom Center" }, { value: "bottom-right", display: "Bottom Right" }];
361
+ var TOAST_UI_ANIMATIONS = [{ value: "fade", display: "Fade" }, { value: "zoom", display: "Zoom" }, { value: "slide", display: "Slide" }, { value: "slide-left", display: "Slide Left" }, { value: "slide-right", display: "Slide Right" }, { value: "slide-up", display: "Slide Up" }, { value: "slide-down", display: "Slide Down" }];
362
+ var TOAST_UI_TYPES = [{ value: void 0, display: "None" }, { value: "info", display: "Info" }, { value: "success", display: "Success" }, { value: "warning", display: "Warning" }, { value: "error", display: "Error" }];
363
+ var TOAST_UI_DRAG_OPTIONS = [{ value: true, display: "On" }, { value: "mouse", display: "Mouse" }, { value: "touch", display: "Touch" }, { value: "pen", display: "Pen" }, { value: false, display: "Off" }];
364
+ var TOAST_UI_DRAG_DIRECTIONS = [{ value: "x", display: "Horizontal" }, { value: "y", display: "Vertical" }, { value: "xy", display: "Horizontal and Vertical" }, { value: "x|y", display: "Horizontal or Vertical" }, { value: "x||y", display: "Horizontal or Vertical (Locked)" }, { value: "x+", display: "Right" }, { value: "x-", display: "Left" }, { value: "y+", display: "Down" }, { value: "y-", display: "Up" }, { value: "xy+", display: "Right and Down" }, { value: "xy-", display: "Left and Up" }, { value: "x|y+", display: "Right or Down" }, { value: "x|y-", display: "Left or Up" }, { value: "x||y+", display: "Right or Down (Locked)" }, { value: "x||y-", display: "Left or Up (Locked)" }];
357
365
  if ("undefined" !== typeof window) {
358
366
  t007.toast = toast, t007.toasting = toasting, t007.toaster = toaster;
359
367
  t007.toasts = /* @__PURE__ */ new Map();
360
- t007.TOAST_DEFAULT_OPTIONS ??= {}, t007.TOAST_DURATIONS ??= {}, t007.TOAST_VIBRATIONS ??= {}, t007.TOAST_ICONS ??= {};
368
+ t007.TOAST_DEFAULT_OPTIONS ??= {}, t007.TOAST_DURATIONS ??= {}, t007.TOAST_VIBRATIONS ??= {}, t007.TOAST_ICONS ??= {}, t007.T0AST_UI_POSITIONS = TOAST_UI_POSITIONS, t007.TOAST_UI_ANIMATIONS = TOAST_UI_ANIMATIONS, t007.TOAST_UI_TYPES = TOAST_UI_TYPES, t007.TOAST_UI_DRAG_OPTIONS = TOAST_UI_DRAG_OPTIONS, t007.TOAST_UI_DRAG_DIRECTIONS = TOAST_UI_DRAG_DIRECTIONS;
361
369
  t007.TOAST_DEFAULT_OPTIONS.render ??= "";
362
370
  t007.TOAST_DEFAULT_OPTIONS.type ??= "";
363
371
  t007.TOAST_DEFAULT_OPTIONS.icon ??= true;
@@ -390,6 +398,11 @@ if ("undefined" !== typeof window) {
390
398
  console.log("%cT007 Toasts attached to window!", "color: darkturquoise");
391
399
  }
392
400
  export {
401
+ TOAST_UI_ANIMATIONS,
402
+ TOAST_UI_DRAG_DIRECTIONS,
403
+ TOAST_UI_DRAG_OPTIONS,
404
+ TOAST_UI_POSITIONS,
405
+ TOAST_UI_TYPES,
393
406
  index_default as default,
394
407
  toaster,
395
408
  toasting
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t007/toast",
3
- "version": "0.0.32",
3
+ "version": "0.0.33",
4
4
  "description": "A lightweight, pure JS toast system.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",
@@ -55,7 +55,7 @@
55
55
  "promise"
56
56
  ],
57
57
  "dependencies": {
58
- "@t007/utils": "^0.0.34"
58
+ "@t007/utils": "^0.0.35"
59
59
  },
60
60
  "devDependencies": {
61
61
  "esbuild-sass-plugin": "^3.7.0"