ga-toasts 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +327 -554
- package/dist/ga-toasts.css +608 -0
- package/dist/ga-toasts.global.js +2 -0
- package/dist/index.cjs +1242 -0
- package/dist/index.d.cts +247 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +1235 -0
- package/package.json +85 -23
- package/.htaccess +0 -75
- package/REDIRECT_SETUP.md +0 -149
- package/ga-toasts.d.ts +0 -99
- package/images/gennie_logo.png +0 -0
- package/index.html +0 -1034
- package/robots.txt +0 -54
- package/sitemap.xml +0 -47
- package/src/demo.css +0 -698
- package/src/demo.js +0 -467
- package/src/toasts.css +0 -1644
- package/src/toasts.js +0 -1005
- package/src/variables.css +0 -480
- package/vercel.json +0 -50
package/dist/index.js
ADDED
|
@@ -0,0 +1,1235 @@
|
|
|
1
|
+
// src/styles.generated.ts
|
|
2
|
+
var css = '.ga-toast-container{--gat-width: 380px;--gat-radius: 14px;--gat-gap: 14px;--gat-edge: 22px;--gat-pad-y: 12px;--gat-pad-x: 16px;--gat-font-size: .875rem;--gat-accent-edge: 0px;--gat-font: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--gat-surface: rgba(255, 255, 255, .82);--gat-surface-solid: #ffffff;--gat-border: rgba(15, 23, 42, .07);--gat-ring: rgba(15, 23, 42, .05);--gat-highlight: rgba(255, 255, 255, .75);--gat-text: #0f172a;--gat-text-soft: #475569;--gat-text-muted: #64748b;--gat-shadow: 0 1px 2px rgba(15, 23, 42, .05), 0 8px 20px -12px rgba(15, 23, 42, .16);--gat-shadow-hover: 0 2px 4px -2px rgba(15, 23, 42, .12), 0 14px 32px -12px rgba(15, 23, 42, .26);--gat-chip: rgba(15, 23, 42, .05);--gat-success: #16a34a;--gat-error: #e11d48;--gat-warning: #d97706;--gat-info: #2563eb;--gat-primary: #6366f1;--gat-secondary: #64748b;--gat-loading: #2563eb;--gat-ease: cubic-bezier(.22, 1, .36, 1)}[data-ga-theme=dark] .ga-toast-container,.ga-theme-dark .ga-toast-container,.ga-toast-container.ga-theme-dark{--gat-surface: rgba(30, 34, 44, .72);--gat-surface-solid: #22262f;--gat-border: rgba(255, 255, 255, .09);--gat-ring: rgba(255, 255, 255, .06);--gat-highlight: rgba(255, 255, 255, .07);--gat-text: #f8fafc;--gat-text-soft: #cbd5e1;--gat-text-muted: #9aa7ba;--gat-shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 10px 28px -14px rgba(0, 0, 0, .5);--gat-shadow-hover: 0 2px 6px -2px rgba(0, 0, 0, .5), 0 16px 38px -12px rgba(0, 0, 0, .64);--gat-chip: rgba(255, 255, 255, .08)}@media(prefers-color-scheme:dark){:root:not([data-ga-theme]):not(.ga-theme-light):not(.ga-theme-dark) .ga-toast-container{--gat-surface: rgba(24, 27, 34, .82);--gat-surface-solid: #191c22;--gat-border: rgba(255, 255, 255, .09);--gat-ring: rgba(255, 255, 255, .06);--gat-highlight: rgba(255, 255, 255, .07);--gat-text: #f8fafc;--gat-text-soft: #cbd5e1;--gat-text-muted: #9aa7ba;--gat-shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 10px 28px -14px rgba(0, 0, 0, .5);--gat-chip: rgba(255, 255, 255, .08)}}.ga-toast-backdrop{position:fixed;inset:0;z-index:2147482990;background:#0a0c146b;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);opacity:0;transition:opacity .22s ease}.ga-toast-backdrop-show{opacity:1}@media(prefers-reduced-transparency:reduce){.ga-toast-backdrop{backdrop-filter:none;-webkit-backdrop-filter:none}}.ga-toast-container{position:fixed;z-index:2147483000;width:var(--gat-width);max-width:calc(100vw - 2 * var(--gat-edge));pointer-events:none;font-family:var(--gat-font)}.ga-toast-container-top-start{inset-block-start:var(--gat-edge);inset-inline-start:var(--gat-edge)}.ga-toast-container-top-end{inset-block-start:var(--gat-edge);inset-inline-end:var(--gat-edge)}.ga-toast-container-top-center{inset-block-start:var(--gat-edge);left:50%;transform:translate(-50%)}.ga-toast-container-bottom-start{inset-block-end:var(--gat-edge);inset-inline-start:var(--gat-edge)}.ga-toast-container-bottom-end{inset-block-end:var(--gat-edge);inset-inline-end:var(--gat-edge)}.ga-toast-container-bottom-center{inset-block-end:var(--gat-edge);left:50%;transform:translate(-50%)}.ga-toast-container-middle-start{top:50%;inset-inline-start:var(--gat-edge)}.ga-toast-container-middle-end{top:50%;inset-inline-end:var(--gat-edge)}.ga-toast-container-middle-center{top:50%;left:50%;transform:translate(-50%)}.ga-toast{position:absolute;inset-inline:0;width:100%;box-sizing:border-box;display:flex;flex-direction:row;align-items:flex-start;gap:11px;padding:var(--gat-pad-y, 12px) var(--gat-pad-x, 16px);color:var(--gat-text);background:var(--gat-surface-solid);border:none;border-radius:var(--gat-radius);box-shadow:var(--gat-shadow),inset 0 1px 0 var(--gat-highlight);pointer-events:auto;opacity:0;transform:translateY(-140%);transition:transform .5s var(--gat-ease),opacity .35s ease,box-shadow .2s ease;will-change:transform,opacity;overflow:hidden;font-size:var(--gat-font-size, .875rem);line-height:1.5;-webkit-font-smoothing:antialiased;text-align:start;touch-action:pan-y;overscroll-behavior:contain}@media(hover:hover){.ga-toast:hover{box-shadow:var(--gat-shadow-hover),inset 0 1px 0 var(--gat-highlight)}}[data-ga-position^=top] .ga-toast,[data-ga-position^=middle] .ga-toast{top:0;transform-origin:top center}[data-ga-position^=bottom] .ga-toast{bottom:0;transform-origin:bottom center}.ga-toast-glass{background:var(--gat-surface);backdrop-filter:blur(16px) saturate(160%);-webkit-backdrop-filter:blur(16px) saturate(160%)}.ga-toast-outline{background:transparent;border:1px solid var(--gat-border);box-shadow:var(--gat-shadow);backdrop-filter:none;-webkit-backdrop-filter:none}.ga-toast:before{content:"";position:absolute;inset-block:0;inset-inline-start:0;width:var(--gat-accent-edge, 0px);background:var(--gat-accent, var(--gat-info));pointer-events:none}.ga-toast-hide{pointer-events:none}.ga-toast-swiping,.ga-toast-swiping *{user-select:none;-webkit-user-select:none;cursor:grabbing}.ga-toast-success{--gat-accent: var(--gat-success)}.ga-toast-error{--gat-accent: var(--gat-error)}.ga-toast-warning{--gat-accent: var(--gat-warning)}.ga-toast-info{--gat-accent: var(--gat-info)}.ga-toast-primary{--gat-accent: var(--gat-primary)}.ga-toast-secondary{--gat-accent: var(--gat-secondary)}.ga-toast-loading{--gat-accent: var(--gat-loading)}.ga-toast-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.ga-toast-header{display:flex;align-items:center;gap:8px;min-width:0}.ga-toast-icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;margin-top:1px;color:var(--gat-accent, var(--gat-info))}.ga-toast-icon svg{width:1.25rem;height:1.25rem;display:block;overflow:visible}.ga-toast-spinner{animation:ga-toast-spin .8s linear infinite}.ga-toast-icon-ring{position:relative;width:2rem;height:2rem;margin-top:0}.ga-toast-icon-ring>svg:not(.ga-toast-ring){width:1.1rem;height:1.1rem}.ga-toast-ring{position:absolute;inset:0;width:100%!important;height:100%!important;transform:rotate(-90deg);overflow:visible}.ga-toast-ring-track{fill:none;stroke:var(--gat-chip);stroke-width:2.4}.ga-toast-ring-bar{fill:none;stroke:var(--gat-accent, var(--gat-info));stroke-width:2.4;stroke-linecap:round}@media(prefers-reduced-motion:no-preference){.ga-toast-icon .ga-ic-ring{stroke-dasharray:64;stroke-dashoffset:64;animation:ga-toast-ic-draw .5s var(--gat-ease) .02s forwards}.ga-toast-icon .ga-ic-draw{stroke-dasharray:28;stroke-dashoffset:28;animation:ga-toast-ic-draw .4s var(--gat-ease) .16s forwards}}@keyframes ga-toast-ic-draw{to{stroke-dashoffset:0}}.ga-toast-avatar{flex-shrink:0;width:34px;height:34px;border-radius:50%;object-fit:cover;border:1px solid var(--gat-border)}.ga-toast-unread-dot{flex-shrink:0;width:8px;height:8px;border-radius:50%;background:var(--gat-accent, var(--gat-info))}.ga-toast-title{font-weight:600;font-size:.9rem;color:var(--gat-text);flex:1;min-width:0;letter-spacing:-.011em}.ga-toast-title-truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ga-toast-status{flex-shrink:0;padding:2px 9px;border-radius:999px;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--gat-accent, var(--gat-info));color:color-mix(in srgb,var(--gat-accent, var(--gat-info)) 58%,var(--gat-text));background:var(--gat-chip);background:color-mix(in srgb,var(--gat-accent, var(--gat-info)) 18%,transparent)}.ga-toast-close{flex-shrink:0;align-self:flex-start;margin-top:-1px;margin-inline-end:-4px;display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;padding:0;border:none;border-radius:7px;color:var(--gat-text-muted);background:transparent;cursor:pointer;opacity:.9;transition:background .15s ease,color .15s ease,opacity .15s ease}.ga-toast:hover .ga-toast-close,.ga-toast:focus-within .ga-toast-close{opacity:1}.ga-toast-close svg{width:15px;height:15px;display:block}.ga-toast-close:hover{background:var(--gat-chip);color:var(--gat-text)}.ga-toast-close:focus-visible{outline:2px solid currentColor;outline-offset:2px}.ga-toast-body{min-width:0}.ga-toast-meta{font-size:.75rem;color:var(--gat-text-muted);margin-bottom:2px}.ga-toast-message{color:var(--gat-text-soft);font-size:.85rem;word-break:break-word;max-height:40vh;overflow-y:auto;overscroll-behavior:contain}.ga-toast-message a{color:var(--gat-accent, var(--gat-info));font-weight:500;text-decoration:underline}.ga-toast:not([class*=-filled]) .ga-toast-content>.ga-toast-body:only-child .ga-toast-message{color:var(--gat-text)}.ga-toast-actions{display:flex;gap:8px;margin-top:2px}.ga-toast-btn{flex:1;padding:8px 14px;font:inherit;font-size:.8125rem;font-weight:600;border-radius:9px;border:1px solid var(--gat-border);background:var(--gat-chip);color:var(--gat-text);cursor:pointer;transition:filter .15s ease,background .15s ease}.ga-toast-btn:hover{filter:brightness(.97)}.ga-toast-btn:focus-visible{outline:2px solid currentColor;outline-offset:2px}.ga-toast-btn-primary{background:var(--gat-accent, var(--gat-primary));border-color:transparent;color:#fff}.ga-toast-btn-primary:hover{filter:brightness(1.06)}.ga-toast-progress{position:absolute;left:0;bottom:0;height:2px;width:100%;transform:scaleX(1);transform-origin:left center;background:var(--gat-accent, var(--gat-info));opacity:.4}.ga-toast-progress-top{top:0;bottom:auto}.ga-toast-steps{display:flex;gap:4px;margin-top:4px}.ga-toast-step{flex:1;height:3px;border-radius:999px;background:var(--gat-chip)}.ga-toast-step-active{background:var(--gat-accent, var(--gat-info))}.ga-toast[class*=-filled]{background:var(--gat-accent, var(--gat-info));border-color:transparent;color:#fff}.ga-toast-success[class*=-filled]{background:#15803d}.ga-toast-primary[class*=-filled]{background:#4f46e5}.ga-toast[class*=-filled] .ga-toast-title,.ga-toast[class*=-filled] .ga-toast-message,.ga-toast[class*=-filled] .ga-toast-meta,.ga-toast[class*=-filled] .ga-toast-icon,.ga-toast[class*=-filled] .ga-toast-close{color:#fff}.ga-toast[class*=-filled] .ga-toast-close:hover{background:#fff3}.ga-toast[class*=-filled] .ga-toast-progress{background:#fff;opacity:.55}.ga-toast[class*=-filled] .ga-toast-step{background:#ffffff47}.ga-toast[class*=-filled] .ga-toast-step-active{background:#fff}.ga-toast[class*=-filled] .ga-toast-status{color:#fff;background:#ffffff38}.ga-toast[class*=-filled] .ga-toast-message a{color:#fff;text-decoration:underline}.ga-toast-warning[class*=-filled],.ga-toast-warning[class*=-filled] .ga-toast-title,.ga-toast-warning[class*=-filled] .ga-toast-message,.ga-toast-warning[class*=-filled] .ga-toast-meta,.ga-toast-warning[class*=-filled] .ga-toast-icon,.ga-toast-warning[class*=-filled] .ga-toast-close,.ga-toast-warning[class*=-filled] .ga-toast-message a{color:#2e2100}.ga-toast-warning[class*=-filled] .ga-toast-progress{background:#2e2100;opacity:.6}.ga-toast-warning[class*=-filled] .ga-toast-step{background:#0000002e}.ga-toast-warning[class*=-filled] .ga-toast-step-active{background:#2e2100}.ga-toast-warning[class*=-filled] .ga-toast-status{color:#2e2100;background:#00000029}.ga-toast-warning[class*=-filled] .ga-toast-close:hover{background:#00000024}.ga-toast[class*=-light]{background:var(--gat-surface);background-image:linear-gradient(0deg,color-mix(in srgb,var(--gat-accent, var(--gat-info)) 14%,transparent),color-mix(in srgb,var(--gat-accent, var(--gat-info)) 14%,transparent));border-color:color-mix(in srgb,var(--gat-accent, var(--gat-info)) 38%,var(--gat-border))}.ga-toast[class*=-light] .ga-toast-meta{color:var(--gat-text-soft)}.ga-toast[class*=-light] .ga-toast-message a{color:color-mix(in srgb,var(--gat-accent, var(--gat-info)) 55%,var(--gat-text));text-decoration:underline}.ga-toast-xs{padding:10px 13px;font-size:.78rem}.ga-toast-xs .ga-toast-icon svg{width:1.05rem;height:1.05rem}.ga-toast-xs .ga-toast-message{font-size:.78rem}.ga-toast-sm{padding:11px 14px;gap:9px}.ga-toast-lg{padding:18px 20px}.ga-toast-lg .ga-toast-title{font-size:1rem}.ga-toast-lg .ga-toast-message{font-size:.95rem}.ga-toast-lg .ga-toast-icon svg{width:1.4rem;height:1.4rem}.ga-toast-xl{padding:22px 24px}.ga-toast-xl .ga-toast-title{font-size:1.125rem}.ga-toast-xl .ga-toast-message{font-size:1.05rem}.ga-toast-xl .ga-toast-icon svg{width:1.6rem;height:1.6rem}.ga-toast-compact{align-items:center;gap:10px;padding:10px 14px}.ga-toast-compact .ga-toast-content{gap:2px}.ga-toast-compact .ga-toast-icon{margin-top:0}.ga-toast-compact .ga-toast-close{align-self:center;margin-top:0}.ga-toast-compact .ga-toast-steps{display:none}.ga-toast-compact .ga-toast-icon svg{width:1.05rem;height:1.05rem}.ga-toast-live-region{position:fixed;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}@media(max-width:520px){.ga-toast-container{--gat-width: auto;left:var(--gat-edge);right:var(--gat-edge);transform:none}.ga-toast-container-top-center,.ga-toast-container-bottom-center,.ga-toast-container-middle-center{transform:none}}[dir=rtl] .ga-toast-progress{transform-origin:right center}@media(prefers-reduced-motion:reduce){.ga-toast{transition:opacity .15s ease}.ga-toast-spinner{animation-duration:1.4s}}@media(prefers-reduced-transparency:reduce){.ga-toast-glass{background:var(--gat-surface-solid);backdrop-filter:none;-webkit-backdrop-filter:none}}.ga-toast-custom{min-width:0}.ga-toast-has-custom{padding:0}.ga-toast-has-custom .ga-toast-close{position:absolute;inset-block-start:8px;inset-inline-end:8px;z-index:1}@keyframes ga-toast-spin{to{transform:rotate(360deg)}}';
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
|
|
6
|
+
var PREFIX = "ga-toast";
|
|
7
|
+
var STYLE_ID = "ga-toasts-styles";
|
|
8
|
+
var REMOVE_FALLBACK = 450;
|
|
9
|
+
var COLLAPSE_DELAY = 140;
|
|
10
|
+
var DEFAULT_MAX_VISIBLE = 3;
|
|
11
|
+
var DEFAULT_PEEK = 14;
|
|
12
|
+
var DEFAULT_STACK_GAP = 14;
|
|
13
|
+
var DEFAULT_SCALE_STEP = 0.05;
|
|
14
|
+
var S = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">';
|
|
15
|
+
var DEFAULT_ICONS = {
|
|
16
|
+
success: `${S}<circle cx="12" cy="12" r="9" class="ga-ic-ring"/><path d="M7.75 12.5l2.75 2.75L16.5 9" class="ga-ic-draw"/></svg>`,
|
|
17
|
+
error: `${S}<circle cx="12" cy="12" r="9" class="ga-ic-ring"/><path d="M15 9l-6 6M9 9l6 6" class="ga-ic-draw"/></svg>`,
|
|
18
|
+
warning: `${S}<path d="M12 3.6 2.4 20.4h19.2L12 3.6z" class="ga-ic-ring"/><path d="M12 10v4" class="ga-ic-draw"/><path d="M12 17.4v.01"/></svg>`,
|
|
19
|
+
info: `${S}<circle cx="12" cy="12" r="9" class="ga-ic-ring"/><path d="M12 11v5" class="ga-ic-draw"/><path d="M12 7.6v.01"/></svg>`,
|
|
20
|
+
primary: `${S}<path d="M12 3.5l2.6 5.27 5.82.85-4.21 4.1.99 5.79L12 16.77 6.8 19.5l.99-5.79-4.21-4.1 5.82-.85L12 3.5z" class="ga-ic-draw"/></svg>`,
|
|
21
|
+
secondary: `${S}<path d="M6 9a6 6 0 0112 0c0 4.5 1.8 5.6 1.8 5.6H4.2S6 13.5 6 9z" class="ga-ic-draw"/><path d="M10 19a2 2 0 004 0"/></svg>`,
|
|
22
|
+
loading: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true" class="ga-toast-spinner"><circle cx="12" cy="12" r="9" opacity="0.25"/><path d="M12 3a9 9 0 019 9"/></svg>'
|
|
23
|
+
};
|
|
24
|
+
var DEFAULT_CLOSE_ICON = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg>';
|
|
25
|
+
var ASSERTIVE_TYPES = /* @__PURE__ */ new Set(["error", "warning"]);
|
|
26
|
+
var POSITIONS = [
|
|
27
|
+
"top-start",
|
|
28
|
+
"top-center",
|
|
29
|
+
"top-end",
|
|
30
|
+
"middle-start",
|
|
31
|
+
"middle-center",
|
|
32
|
+
"middle-end",
|
|
33
|
+
"bottom-start",
|
|
34
|
+
"bottom-center",
|
|
35
|
+
"bottom-end"
|
|
36
|
+
];
|
|
37
|
+
var DEFAULT_DURATIONS = {
|
|
38
|
+
success: 5e3,
|
|
39
|
+
error: 8e3,
|
|
40
|
+
warning: 6e3,
|
|
41
|
+
info: 4e3,
|
|
42
|
+
primary: 5e3,
|
|
43
|
+
secondary: 5e3,
|
|
44
|
+
loading: 0
|
|
45
|
+
};
|
|
46
|
+
var PRESETS = {
|
|
47
|
+
soft: {},
|
|
48
|
+
solid: { surface: "solid", elevation: "raised" },
|
|
49
|
+
minimal: { surface: "outline", elevation: "flat", radius: 10, accentEdge: 0 },
|
|
50
|
+
sharp: { radius: 4 },
|
|
51
|
+
material: { surface: "solid", elevation: "floating", radius: 12 }
|
|
52
|
+
};
|
|
53
|
+
var DENSITY = {
|
|
54
|
+
// padY, padX, font-size
|
|
55
|
+
compact: ["8px", "13px", "0.82rem"],
|
|
56
|
+
comfortable: ["12px", "16px", "0.875rem"],
|
|
57
|
+
spacious: ["16px", "20px", "0.94rem"]
|
|
58
|
+
};
|
|
59
|
+
var ELEVATION = {
|
|
60
|
+
flat: "0 1px 2px rgba(15,23,42,0.06)",
|
|
61
|
+
raised: "0 1px 2px rgba(15,23,42,0.05), 0 8px 20px -12px rgba(15,23,42,0.16)",
|
|
62
|
+
floating: "0 4px 10px -3px rgba(15,23,42,0.12), 0 20px 44px -14px rgba(15,23,42,0.34)"
|
|
63
|
+
};
|
|
64
|
+
function px(v) {
|
|
65
|
+
return typeof v === "number" ? `${v}px` : String(v);
|
|
66
|
+
}
|
|
67
|
+
function resolveTheme(theme) {
|
|
68
|
+
if (!theme) return {};
|
|
69
|
+
if (typeof theme === "string") return { ...PRESETS[theme] || {} };
|
|
70
|
+
const { preset, ...rest } = theme;
|
|
71
|
+
const base = preset ? PRESETS[preset] || {} : {};
|
|
72
|
+
return { ...base, ...rest };
|
|
73
|
+
}
|
|
74
|
+
function themeVars(t) {
|
|
75
|
+
const v = {};
|
|
76
|
+
if (t.width != null) v["--gat-width"] = px(t.width);
|
|
77
|
+
if (t.radius != null) v["--gat-radius"] = px(t.radius);
|
|
78
|
+
if (t.gap != null) v["--gat-gap"] = px(t.gap);
|
|
79
|
+
if (t.edge != null) v["--gat-edge"] = px(t.edge);
|
|
80
|
+
if (t.font) v["--gat-font"] = t.font;
|
|
81
|
+
if (t.density && DENSITY[t.density]) {
|
|
82
|
+
const [py, pxv, fs] = DENSITY[t.density];
|
|
83
|
+
v["--gat-pad-y"] = py;
|
|
84
|
+
v["--gat-pad-x"] = pxv;
|
|
85
|
+
v["--gat-font-size"] = fs;
|
|
86
|
+
}
|
|
87
|
+
if (t.elevation && ELEVATION[t.elevation]) v["--gat-shadow"] = ELEVATION[t.elevation];
|
|
88
|
+
if (t.accentEdge != null) v["--gat-accent-edge"] = px(t.accentEdge);
|
|
89
|
+
if (t.accent) v["--gat-primary"] = t.accent;
|
|
90
|
+
if (t.colors) {
|
|
91
|
+
for (const k of Object.keys(t.colors))
|
|
92
|
+
if (t.colors[k]) v[`--gat-${k}`] = t.colors[k];
|
|
93
|
+
}
|
|
94
|
+
if (t.text) v["--gat-text"] = t.text;
|
|
95
|
+
if (t.textSoft) v["--gat-text-soft"] = t.textSoft;
|
|
96
|
+
if (t.textMuted) v["--gat-text-muted"] = t.textMuted;
|
|
97
|
+
if (t.surfaceColor) {
|
|
98
|
+
v["--gat-surface"] = t.surfaceColor;
|
|
99
|
+
v["--gat-surface-solid"] = t.surfaceColor;
|
|
100
|
+
}
|
|
101
|
+
if (t.border) v["--gat-border"] = t.border;
|
|
102
|
+
if (t.shadow) v["--gat-shadow"] = t.shadow;
|
|
103
|
+
if (t.chip) v["--gat-chip"] = t.chip;
|
|
104
|
+
if (t.ease) v["--gat-ease"] = t.ease;
|
|
105
|
+
return v;
|
|
106
|
+
}
|
|
107
|
+
function verticalDir(position) {
|
|
108
|
+
return position.startsWith("bottom") ? -1 : 1;
|
|
109
|
+
}
|
|
110
|
+
function isRTL() {
|
|
111
|
+
if (!canUseDOM) return false;
|
|
112
|
+
const dir = document.documentElement.getAttribute("dir") || document.body && document.body.getAttribute("dir");
|
|
113
|
+
return dir === "rtl";
|
|
114
|
+
}
|
|
115
|
+
function offscreenTransform(position) {
|
|
116
|
+
const inFromLeft = "translateX(-115%)";
|
|
117
|
+
const inFromRight = "translateX(115%)";
|
|
118
|
+
const rtl = isRTL();
|
|
119
|
+
if (position.endsWith("start")) return rtl ? inFromRight : inFromLeft;
|
|
120
|
+
if (position.endsWith("end")) return rtl ? inFromLeft : inFromRight;
|
|
121
|
+
return verticalDir(position) === 1 ? "translateY(-140%)" : "translateY(140%)";
|
|
122
|
+
}
|
|
123
|
+
function swipeOpacity(dx) {
|
|
124
|
+
return Math.max(0.15, 1 - Math.abs(dx) / 220);
|
|
125
|
+
}
|
|
126
|
+
function normalizeId(idOrSelector) {
|
|
127
|
+
return idOrSelector.startsWith("#") ? idOrSelector.slice(1) : idOrSelector;
|
|
128
|
+
}
|
|
129
|
+
function now() {
|
|
130
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
131
|
+
}
|
|
132
|
+
function prefersReducedMotion() {
|
|
133
|
+
return canUseDOM && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
134
|
+
}
|
|
135
|
+
var toasterSeq = 0;
|
|
136
|
+
function makeToaster(config = {}) {
|
|
137
|
+
const seq = toasterSeq += 1;
|
|
138
|
+
const instanceClass = `ga-toaster-${seq}`;
|
|
139
|
+
const registry = /* @__PURE__ */ new Map();
|
|
140
|
+
const containers = /* @__PURE__ */ new Map();
|
|
141
|
+
let globalDefaults = { ...config.defaults || {} };
|
|
142
|
+
let logger = config.logger || null;
|
|
143
|
+
let liveRegions = null;
|
|
144
|
+
let escapeBound = false;
|
|
145
|
+
let visibilityBound = false;
|
|
146
|
+
let idCounter = 0;
|
|
147
|
+
let activeModalId = null;
|
|
148
|
+
let backdropEl = null;
|
|
149
|
+
const icons = { ...DEFAULT_ICONS };
|
|
150
|
+
let closeIcon = DEFAULT_CLOSE_ICON;
|
|
151
|
+
const durations = { ...DEFAULT_DURATIONS };
|
|
152
|
+
let maxVisible = DEFAULT_MAX_VISIBLE;
|
|
153
|
+
let peek = DEFAULT_PEEK;
|
|
154
|
+
let stackGap = DEFAULT_STACK_GAP;
|
|
155
|
+
let scaleStep = DEFAULT_SCALE_STEP;
|
|
156
|
+
let expandMode = "hover";
|
|
157
|
+
let newestOnTop = false;
|
|
158
|
+
let injectEnabled = config.injectStyles !== false;
|
|
159
|
+
const styleNonce = config.styleNonce;
|
|
160
|
+
const renderFn = config.render || null;
|
|
161
|
+
let themeTokens = {};
|
|
162
|
+
let surfaceMode;
|
|
163
|
+
let progressMode = "bar";
|
|
164
|
+
let themeStyleEl = null;
|
|
165
|
+
const mount = config.root || (canUseDOM ? document.body : null);
|
|
166
|
+
const isShadow = !!config.root && typeof config.root.host !== "undefined";
|
|
167
|
+
const styleTarget = isShadow ? config.root : canUseDOM ? document.head : null;
|
|
168
|
+
function applyConfigDurations(d) {
|
|
169
|
+
if (!d) return;
|
|
170
|
+
for (const k of Object.keys(d))
|
|
171
|
+
if (typeof d[k] === "number") durations[k] = d[k];
|
|
172
|
+
}
|
|
173
|
+
function applyConfigIcons(ic) {
|
|
174
|
+
if (!ic) return;
|
|
175
|
+
for (const k of Object.keys(ic)) {
|
|
176
|
+
if (k === "close") {
|
|
177
|
+
if (ic.close) closeIcon = ic.close;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
icons[k] = ic[k];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function applyConfigStack(s) {
|
|
184
|
+
if (!s) return;
|
|
185
|
+
if (typeof s.peek === "number") peek = s.peek;
|
|
186
|
+
if (typeof s.gap === "number") stackGap = s.gap;
|
|
187
|
+
if (typeof s.scaleStep === "number") scaleStep = s.scaleStep;
|
|
188
|
+
if (s.expand) expandMode = s.expand;
|
|
189
|
+
if (typeof s.newestOnTop === "boolean") newestOnTop = s.newestOnTop;
|
|
190
|
+
}
|
|
191
|
+
applyConfigDurations(config.durations);
|
|
192
|
+
applyConfigIcons(config.icons);
|
|
193
|
+
applyConfigStack(config.stack);
|
|
194
|
+
if (typeof config.maxVisible === "number")
|
|
195
|
+
maxVisible = Math.max(1, Math.floor(config.maxVisible) || 1);
|
|
196
|
+
function nextId() {
|
|
197
|
+
idCounter += 1;
|
|
198
|
+
const rand = Math.random().toString(36).slice(2, 8);
|
|
199
|
+
return `${PREFIX}-${idCounter}-${rand}`;
|
|
200
|
+
}
|
|
201
|
+
function log(event, payload) {
|
|
202
|
+
if (logger) {
|
|
203
|
+
try {
|
|
204
|
+
logger(event, payload);
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function injectStyles() {
|
|
210
|
+
if (!canUseDOM || !injectEnabled || !styleTarget) return;
|
|
211
|
+
const doc = document;
|
|
212
|
+
if (styleTarget.querySelector?.(`#${STYLE_ID}`)) return;
|
|
213
|
+
if (styleTarget === doc.head && doc.getElementById(STYLE_ID)) return;
|
|
214
|
+
const el = doc.createElement("style");
|
|
215
|
+
el.id = STYLE_ID;
|
|
216
|
+
if (styleNonce) el.setAttribute("nonce", styleNonce);
|
|
217
|
+
el.textContent = css;
|
|
218
|
+
styleTarget.appendChild(el);
|
|
219
|
+
}
|
|
220
|
+
function applyTheme() {
|
|
221
|
+
if (!canUseDOM || !styleTarget) return;
|
|
222
|
+
const t = themeTokens;
|
|
223
|
+
surfaceMode = t.surface;
|
|
224
|
+
progressMode = t.progress || "bar";
|
|
225
|
+
const sel = `.${instanceClass}.ga-toast-container`;
|
|
226
|
+
const light = themeVars(t);
|
|
227
|
+
const lightBody = Object.entries(light).map(([k, v]) => `${k}:${v}`).join(";");
|
|
228
|
+
const darkVars = t.dark ? themeVars(t.dark) : {};
|
|
229
|
+
const darkBody = Object.entries(darkVars).map(([k, v]) => `${k}:${v}`).join(";");
|
|
230
|
+
let cssText = "";
|
|
231
|
+
if (lightBody) cssText += `${sel}{${lightBody}}`;
|
|
232
|
+
if (darkBody)
|
|
233
|
+
cssText += `[data-ga-theme="dark"] ${sel},.ga-theme-dark ${sel}{${darkBody}}`;
|
|
234
|
+
if (!cssText) {
|
|
235
|
+
themeStyleEl?.remove();
|
|
236
|
+
themeStyleEl = null;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (!themeStyleEl) {
|
|
240
|
+
themeStyleEl = document.createElement("style");
|
|
241
|
+
themeStyleEl.id = `ga-toasts-theme-${seq}`;
|
|
242
|
+
if (styleNonce) themeStyleEl.setAttribute("nonce", styleNonce);
|
|
243
|
+
styleTarget.appendChild(themeStyleEl);
|
|
244
|
+
}
|
|
245
|
+
themeStyleEl.textContent = cssText;
|
|
246
|
+
}
|
|
247
|
+
function ensureLiveRegions() {
|
|
248
|
+
if (!canUseDOM || !mount) return;
|
|
249
|
+
if (liveRegions && liveRegions.polite.isConnected && liveRegions.assertive.isConnected)
|
|
250
|
+
return;
|
|
251
|
+
const make = (politeness) => {
|
|
252
|
+
const region = document.createElement("div");
|
|
253
|
+
region.className = "ga-toast-live-region";
|
|
254
|
+
region.setAttribute("aria-live", politeness);
|
|
255
|
+
region.setAttribute("aria-atomic", "true");
|
|
256
|
+
region.setAttribute("role", politeness === "assertive" ? "alert" : "status");
|
|
257
|
+
mount.appendChild(region);
|
|
258
|
+
return region;
|
|
259
|
+
};
|
|
260
|
+
liveRegions = { polite: make("polite"), assertive: make("assertive") };
|
|
261
|
+
}
|
|
262
|
+
function announce(text, assertive) {
|
|
263
|
+
if (!text) return;
|
|
264
|
+
ensureLiveRegions();
|
|
265
|
+
if (!liveRegions) return;
|
|
266
|
+
const region = assertive ? liveRegions.assertive : liveRegions.polite;
|
|
267
|
+
region.textContent = "";
|
|
268
|
+
window.setTimeout(() => {
|
|
269
|
+
region.textContent = text;
|
|
270
|
+
}, 50);
|
|
271
|
+
}
|
|
272
|
+
function getContainer(position) {
|
|
273
|
+
const existing = containers.get(position);
|
|
274
|
+
if (existing && existing.isConnected) return existing;
|
|
275
|
+
const container = document.createElement("div");
|
|
276
|
+
container.className = `ga-toast-container ga-toast-container-${position} ${instanceClass}`;
|
|
277
|
+
container.setAttribute("data-ga-position", position);
|
|
278
|
+
container.setAttribute("role", "region");
|
|
279
|
+
container.setAttribute("aria-label", "Notifications");
|
|
280
|
+
if (expandMode === "always") container.dataset.gaExpanded = "true";
|
|
281
|
+
if (expandMode === "hover") {
|
|
282
|
+
let collapseTimer = null;
|
|
283
|
+
const cancelCollapse = () => {
|
|
284
|
+
if (collapseTimer != null) {
|
|
285
|
+
clearTimeout(collapseTimer);
|
|
286
|
+
collapseTimer = null;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const expand = () => {
|
|
290
|
+
cancelCollapse();
|
|
291
|
+
setExpanded(container, true);
|
|
292
|
+
};
|
|
293
|
+
const collapse = () => {
|
|
294
|
+
cancelCollapse();
|
|
295
|
+
collapseTimer = setTimeout(() => {
|
|
296
|
+
collapseTimer = null;
|
|
297
|
+
setExpanded(container, false);
|
|
298
|
+
}, COLLAPSE_DELAY);
|
|
299
|
+
};
|
|
300
|
+
container.addEventListener("pointerenter", expand);
|
|
301
|
+
container.addEventListener("pointerleave", collapse);
|
|
302
|
+
container.addEventListener("focusin", expand);
|
|
303
|
+
container.addEventListener("focusout", (e) => {
|
|
304
|
+
if (!container.contains(e.relatedTarget)) collapse();
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
mount?.appendChild(container);
|
|
308
|
+
containers.set(position, container);
|
|
309
|
+
return container;
|
|
310
|
+
}
|
|
311
|
+
function setExpanded(container, expanded) {
|
|
312
|
+
if (expandMode !== "hover") return;
|
|
313
|
+
if (container.dataset.gaExpanded === "true" === expanded) return;
|
|
314
|
+
container.dataset.gaExpanded = expanded ? "true" : "false";
|
|
315
|
+
layout(container);
|
|
316
|
+
}
|
|
317
|
+
function instancesIn(container) {
|
|
318
|
+
return Array.from(container.children).map((child) => registry.get(child.id)).filter((inst) => !!inst);
|
|
319
|
+
}
|
|
320
|
+
function layout(container) {
|
|
321
|
+
const all = instancesIn(container);
|
|
322
|
+
const position = container.dataset.gaPosition || "top-end";
|
|
323
|
+
const dir = verticalDir(position);
|
|
324
|
+
const expanded = expandMode === "always" || expandMode === "hover" && container.dataset.gaExpanded === "true";
|
|
325
|
+
const reduce = prefersReducedMotion();
|
|
326
|
+
const front = newestOnTop ? all.slice() : all.slice().reverse();
|
|
327
|
+
container.style.setProperty("--ga-toasts-count", String(front.length));
|
|
328
|
+
let cumulative = 0;
|
|
329
|
+
front.forEach((inst, frontIndex) => {
|
|
330
|
+
if (inst.closing) return;
|
|
331
|
+
if (!inst.el.dataset.gaMounted) {
|
|
332
|
+
cumulative += inst.height + stackGap;
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
let translateY;
|
|
336
|
+
let scale;
|
|
337
|
+
let opacity;
|
|
338
|
+
const overflow = frontIndex >= maxVisible;
|
|
339
|
+
if (overflow) pauseTimer(inst, "overflow");
|
|
340
|
+
else resumeTimer(inst, "overflow");
|
|
341
|
+
if (expanded || reduce) {
|
|
342
|
+
translateY = dir * cumulative;
|
|
343
|
+
scale = 1;
|
|
344
|
+
opacity = 1;
|
|
345
|
+
} else {
|
|
346
|
+
translateY = dir * frontIndex * peek;
|
|
347
|
+
scale = Math.max(1 - frontIndex * scaleStep, 0.85);
|
|
348
|
+
opacity = overflow ? 0 : 1;
|
|
349
|
+
}
|
|
350
|
+
const swipe = inst.swipeX ? ` translateX(${inst.swipeX}px)` : "";
|
|
351
|
+
const ty = position.startsWith("middle") ? `calc(-50% + ${translateY}px)` : `${translateY}px`;
|
|
352
|
+
inst.el.style.transform = `translateY(${ty})${swipe} scale(${scale})`;
|
|
353
|
+
inst.el.style.opacity = inst.swipeX ? String(swipeOpacity(inst.swipeX)) : String(opacity);
|
|
354
|
+
inst.el.style.zIndex = String(1e3 + front.length - frontIndex);
|
|
355
|
+
inst.el.style.pointerEvents = opacity === 0 ? "none" : "auto";
|
|
356
|
+
inst.el.setAttribute("aria-hidden", opacity === 0 ? "true" : "false");
|
|
357
|
+
cumulative += inst.height + stackGap;
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
function measure(inst) {
|
|
361
|
+
const h = inst.el.offsetHeight;
|
|
362
|
+
if (h > 0) inst.height = h;
|
|
363
|
+
}
|
|
364
|
+
function resolveOptions(options) {
|
|
365
|
+
const merged = {
|
|
366
|
+
type: "info",
|
|
367
|
+
duration: 5e3,
|
|
368
|
+
closable: true,
|
|
369
|
+
position: "top-end",
|
|
370
|
+
animation: "slide",
|
|
371
|
+
swipeToClose: true,
|
|
372
|
+
closeOnEscape: true,
|
|
373
|
+
progress: true,
|
|
374
|
+
progressPosition: "bottom",
|
|
375
|
+
pauseOnHover: true,
|
|
376
|
+
pauseOnPageHidden: true,
|
|
377
|
+
autoIcon: true,
|
|
378
|
+
glassmorphism: true,
|
|
379
|
+
html: false,
|
|
380
|
+
...globalDefaults,
|
|
381
|
+
...options
|
|
382
|
+
};
|
|
383
|
+
merged.position = merged.position || "top-end";
|
|
384
|
+
if (!POSITIONS.includes(merged.position)) merged.position = "top-end";
|
|
385
|
+
return merged;
|
|
386
|
+
}
|
|
387
|
+
function iconFor(type) {
|
|
388
|
+
return icons[type] ?? icons.info ?? null;
|
|
389
|
+
}
|
|
390
|
+
function createCloseButton() {
|
|
391
|
+
const btn = document.createElement("button");
|
|
392
|
+
btn.type = "button";
|
|
393
|
+
btn.className = "ga-toast-close";
|
|
394
|
+
btn.setAttribute("aria-label", "Close notification");
|
|
395
|
+
btn.setAttribute("data-ga-close", "");
|
|
396
|
+
btn.innerHTML = closeIcon;
|
|
397
|
+
return btn;
|
|
398
|
+
}
|
|
399
|
+
function appendProgress(el, opts, type) {
|
|
400
|
+
if (progressMode === "ring" || !opts.progress || (opts.duration || 0) <= 0 || opts.progressPosition === "none")
|
|
401
|
+
return null;
|
|
402
|
+
const p = document.createElement("div");
|
|
403
|
+
p.className = `ga-toast-progress ga-toast-progress-${type}` + (opts.progressPosition === "top" ? " ga-toast-progress-top" : "");
|
|
404
|
+
el.appendChild(p);
|
|
405
|
+
return p;
|
|
406
|
+
}
|
|
407
|
+
function buildIcon(iconHtml, opts) {
|
|
408
|
+
const icon = document.createElement("div");
|
|
409
|
+
icon.className = "ga-toast-icon";
|
|
410
|
+
icon.innerHTML = iconHtml;
|
|
411
|
+
const wantRing = progressMode === "ring" && opts.progress !== false && (opts.duration || 0) > 0;
|
|
412
|
+
if (!wantRing) return { el: icon, ring: null };
|
|
413
|
+
icon.classList.add("ga-toast-icon-ring");
|
|
414
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
415
|
+
const svg = document.createElementNS(ns, "svg");
|
|
416
|
+
svg.setAttribute("class", "ga-toast-ring");
|
|
417
|
+
svg.setAttribute("viewBox", "0 0 36 36");
|
|
418
|
+
svg.setAttribute("aria-hidden", "true");
|
|
419
|
+
const track = document.createElementNS(ns, "circle");
|
|
420
|
+
track.setAttribute("class", "ga-toast-ring-track");
|
|
421
|
+
track.setAttribute("cx", "18");
|
|
422
|
+
track.setAttribute("cy", "18");
|
|
423
|
+
track.setAttribute("r", "16");
|
|
424
|
+
const bar = document.createElementNS(ns, "circle");
|
|
425
|
+
bar.setAttribute("class", "ga-toast-ring-bar");
|
|
426
|
+
bar.setAttribute("cx", "18");
|
|
427
|
+
bar.setAttribute("cy", "18");
|
|
428
|
+
bar.setAttribute("r", "16");
|
|
429
|
+
svg.appendChild(track);
|
|
430
|
+
svg.appendChild(bar);
|
|
431
|
+
icon.appendChild(svg);
|
|
432
|
+
return { el: icon, ring: bar };
|
|
433
|
+
}
|
|
434
|
+
function buildToastElement(opts, id) {
|
|
435
|
+
const type = opts.type || "info";
|
|
436
|
+
const el = document.createElement("div");
|
|
437
|
+
el.id = id;
|
|
438
|
+
const glass = surfaceMode === "glass" || surfaceMode === void 0 && opts.glassmorphism;
|
|
439
|
+
el.className = [
|
|
440
|
+
"ga-toast",
|
|
441
|
+
`ga-toast-${type}`,
|
|
442
|
+
opts.size ? `ga-toast-${opts.size}` : "",
|
|
443
|
+
opts.variant ? `ga-toast-${type}-${opts.variant}` : "",
|
|
444
|
+
opts.animation || "",
|
|
445
|
+
opts.compact ? "ga-toast-compact" : "",
|
|
446
|
+
glass ? "ga-toast-glass" : "",
|
|
447
|
+
surfaceMode === "outline" ? "ga-toast-outline" : "",
|
|
448
|
+
type === "loading" ? "ga-toast-loading" : "",
|
|
449
|
+
opts.className || ""
|
|
450
|
+
].filter(Boolean).join(" ");
|
|
451
|
+
const role = opts.role || (ASSERTIVE_TYPES.has(type) ? "alert" : "status");
|
|
452
|
+
el.setAttribute("role", role);
|
|
453
|
+
el.setAttribute("aria-live", "off");
|
|
454
|
+
el.setAttribute("data-ga-type", type);
|
|
455
|
+
if (role === "alertdialog" || role === "dialog") {
|
|
456
|
+
const label = [opts.title, opts.message].filter(Boolean).join(". ");
|
|
457
|
+
if (label) el.setAttribute("aria-label", label);
|
|
458
|
+
}
|
|
459
|
+
let customEl = null;
|
|
460
|
+
if (opts.content != null) {
|
|
461
|
+
customEl = typeof opts.content === "function" ? opts.content() : opts.content;
|
|
462
|
+
} else if (renderFn) {
|
|
463
|
+
const produced = renderFn(opts, { id, close: () => close(id) });
|
|
464
|
+
if (produced) customEl = produced;
|
|
465
|
+
}
|
|
466
|
+
if (customEl != null) {
|
|
467
|
+
el.classList.add("ga-toast-has-custom");
|
|
468
|
+
const wrap = document.createElement("div");
|
|
469
|
+
wrap.className = "ga-toast-custom";
|
|
470
|
+
if (typeof customEl === "string") wrap.innerHTML = customEl;
|
|
471
|
+
else wrap.appendChild(customEl);
|
|
472
|
+
el.appendChild(wrap);
|
|
473
|
+
if (opts.closable) el.appendChild(createCloseButton());
|
|
474
|
+
return { el, progressEl: appendProgress(el, opts, type), ring: null };
|
|
475
|
+
}
|
|
476
|
+
if (opts.avatar) {
|
|
477
|
+
const avatar = document.createElement("img");
|
|
478
|
+
avatar.className = "ga-toast-avatar";
|
|
479
|
+
avatar.src = opts.avatar;
|
|
480
|
+
avatar.alt = opts.avatarAlt || opts.title || "Notification";
|
|
481
|
+
el.appendChild(avatar);
|
|
482
|
+
}
|
|
483
|
+
let iconHtml = null;
|
|
484
|
+
if (opts.icon) iconHtml = String(opts.icon);
|
|
485
|
+
else if (opts.icon !== false && opts.autoIcon !== false && !opts.avatar)
|
|
486
|
+
iconHtml = iconFor(type);
|
|
487
|
+
let ring = null;
|
|
488
|
+
if (iconHtml) {
|
|
489
|
+
const built = buildIcon(iconHtml, opts);
|
|
490
|
+
ring = built.ring;
|
|
491
|
+
el.appendChild(built.el);
|
|
492
|
+
}
|
|
493
|
+
const content = document.createElement("div");
|
|
494
|
+
content.className = "ga-toast-content";
|
|
495
|
+
if (opts.title || opts.showStatus || opts.unread) {
|
|
496
|
+
const header = document.createElement("div");
|
|
497
|
+
header.className = "ga-toast-header";
|
|
498
|
+
if (opts.unread) {
|
|
499
|
+
const dot = document.createElement("span");
|
|
500
|
+
dot.className = "ga-toast-unread-dot";
|
|
501
|
+
header.appendChild(dot);
|
|
502
|
+
}
|
|
503
|
+
if (opts.title) {
|
|
504
|
+
const title = document.createElement("div");
|
|
505
|
+
title.className = "ga-toast-title" + (opts.truncateTitle ? " ga-toast-title-truncate" : "");
|
|
506
|
+
title.textContent = opts.title;
|
|
507
|
+
header.appendChild(title);
|
|
508
|
+
}
|
|
509
|
+
if (opts.showStatus) {
|
|
510
|
+
const status = document.createElement("span");
|
|
511
|
+
status.className = "ga-toast-status";
|
|
512
|
+
const label = String(opts.statusText || type);
|
|
513
|
+
status.textContent = label.charAt(0).toUpperCase() + label.slice(1);
|
|
514
|
+
header.appendChild(status);
|
|
515
|
+
}
|
|
516
|
+
content.appendChild(header);
|
|
517
|
+
}
|
|
518
|
+
if (opts.message || opts.meta) {
|
|
519
|
+
const body = document.createElement("div");
|
|
520
|
+
body.className = "ga-toast-body";
|
|
521
|
+
if (opts.meta) {
|
|
522
|
+
const meta = document.createElement("div");
|
|
523
|
+
meta.className = "ga-toast-meta";
|
|
524
|
+
meta.textContent = opts.meta;
|
|
525
|
+
body.appendChild(meta);
|
|
526
|
+
}
|
|
527
|
+
if (opts.message) {
|
|
528
|
+
const message = document.createElement("div");
|
|
529
|
+
message.className = "ga-toast-message";
|
|
530
|
+
if (opts.html) message.innerHTML = opts.message;
|
|
531
|
+
else message.textContent = opts.message;
|
|
532
|
+
body.appendChild(message);
|
|
533
|
+
}
|
|
534
|
+
content.appendChild(body);
|
|
535
|
+
}
|
|
536
|
+
if (opts.actions && opts.actions.length && !opts.compact) {
|
|
537
|
+
const actions = document.createElement("div");
|
|
538
|
+
actions.className = "ga-toast-actions";
|
|
539
|
+
for (const action of opts.actions) {
|
|
540
|
+
const btn = document.createElement("button");
|
|
541
|
+
btn.type = "button";
|
|
542
|
+
btn.className = [
|
|
543
|
+
"ga-toast-btn",
|
|
544
|
+
action.className || action.class || "ga-toast-btn-secondary"
|
|
545
|
+
].join(" ");
|
|
546
|
+
btn.textContent = action.text;
|
|
547
|
+
btn.setAttribute("data-ga-action", "");
|
|
548
|
+
actions.appendChild(btn);
|
|
549
|
+
}
|
|
550
|
+
content.appendChild(actions);
|
|
551
|
+
}
|
|
552
|
+
if (opts.steps && opts.steps > 1) {
|
|
553
|
+
const steps = document.createElement("div");
|
|
554
|
+
steps.className = "ga-toast-steps";
|
|
555
|
+
const active = Math.min(opts.steps, Math.max(1, opts.currentStep || 1));
|
|
556
|
+
for (let i = 1; i <= opts.steps; i += 1) {
|
|
557
|
+
const step = document.createElement("div");
|
|
558
|
+
step.className = "ga-toast-step" + (i <= active ? " ga-toast-step-active" : "");
|
|
559
|
+
steps.appendChild(step);
|
|
560
|
+
}
|
|
561
|
+
content.appendChild(steps);
|
|
562
|
+
}
|
|
563
|
+
el.appendChild(content);
|
|
564
|
+
if (opts.closable) el.appendChild(createCloseButton());
|
|
565
|
+
return { el, progressEl: appendProgress(el, opts, type), ring };
|
|
566
|
+
}
|
|
567
|
+
const RING_CIRC = 2 * Math.PI * 16;
|
|
568
|
+
function startTimer(inst) {
|
|
569
|
+
const { timer } = inst;
|
|
570
|
+
if (timer.duration <= 0 || timer.remaining <= 0) return;
|
|
571
|
+
if (timer.holds.size > 0) return;
|
|
572
|
+
timer.startedAt = now();
|
|
573
|
+
timer.handle = setTimeout(() => close(inst.id), timer.remaining);
|
|
574
|
+
animateProgress(inst, timer.remaining);
|
|
575
|
+
}
|
|
576
|
+
function pauseTimer(inst, reason) {
|
|
577
|
+
const { timer } = inst;
|
|
578
|
+
const wasHeld = timer.holds.size > 0;
|
|
579
|
+
timer.holds.add(reason);
|
|
580
|
+
if (wasHeld || timer.handle == null) return;
|
|
581
|
+
clearTimeout(timer.handle);
|
|
582
|
+
timer.handle = null;
|
|
583
|
+
const elapsed = now() - timer.startedAt;
|
|
584
|
+
timer.remaining = Math.max(0, timer.remaining - elapsed);
|
|
585
|
+
freezeProgress(inst);
|
|
586
|
+
}
|
|
587
|
+
function resumeTimer(inst, reason) {
|
|
588
|
+
const { timer } = inst;
|
|
589
|
+
if (!timer.holds.delete(reason)) return;
|
|
590
|
+
if (timer.holds.size > 0) return;
|
|
591
|
+
startTimer(inst);
|
|
592
|
+
}
|
|
593
|
+
function animateProgress(inst, ms) {
|
|
594
|
+
const fraction = inst.timer.duration > 0 ? ms / inst.timer.duration : 0;
|
|
595
|
+
if (inst.ring) {
|
|
596
|
+
const ring = inst.ring;
|
|
597
|
+
ring.style.transition = "none";
|
|
598
|
+
ring.style.strokeDasharray = String(RING_CIRC);
|
|
599
|
+
ring.style.strokeDashoffset = String(RING_CIRC * (1 - fraction));
|
|
600
|
+
void ring.getBoundingClientRect?.();
|
|
601
|
+
ring.style.transition = `stroke-dashoffset ${ms}ms linear`;
|
|
602
|
+
ring.style.strokeDashoffset = String(RING_CIRC);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const bar = inst.progressEl;
|
|
606
|
+
if (!bar) return;
|
|
607
|
+
bar.style.transition = "none";
|
|
608
|
+
bar.style.transform = `scaleX(${fraction})`;
|
|
609
|
+
void bar.offsetWidth;
|
|
610
|
+
bar.style.transition = `transform ${ms}ms linear`;
|
|
611
|
+
bar.style.transform = "scaleX(0)";
|
|
612
|
+
}
|
|
613
|
+
function freezeProgress(inst) {
|
|
614
|
+
const fraction = inst.timer.duration > 0 ? inst.timer.remaining / inst.timer.duration : 0;
|
|
615
|
+
if (inst.ring) {
|
|
616
|
+
inst.ring.style.transition = "none";
|
|
617
|
+
inst.ring.style.strokeDashoffset = String(RING_CIRC * (1 - fraction));
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const bar = inst.progressEl;
|
|
621
|
+
if (!bar) return;
|
|
622
|
+
bar.style.transition = "none";
|
|
623
|
+
bar.style.transform = `scaleX(${fraction})`;
|
|
624
|
+
}
|
|
625
|
+
function attachHandlers(inst, opts) {
|
|
626
|
+
const { el, controller } = inst;
|
|
627
|
+
const signal = controller.signal;
|
|
628
|
+
el.addEventListener(
|
|
629
|
+
"click",
|
|
630
|
+
(e) => {
|
|
631
|
+
const target = e.target;
|
|
632
|
+
if (target.closest("[data-ga-close]")) {
|
|
633
|
+
e.preventDefault();
|
|
634
|
+
close(inst.id);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const actionBtn = target.closest("[data-ga-action]");
|
|
638
|
+
if (actionBtn && opts.actions) {
|
|
639
|
+
const idx = Array.from(
|
|
640
|
+
actionBtn.parentElement?.children || []
|
|
641
|
+
).indexOf(actionBtn);
|
|
642
|
+
const action = opts.actions[idx];
|
|
643
|
+
if (action) {
|
|
644
|
+
const handler = action.onClick || action.click;
|
|
645
|
+
if (handler) handler(e, inst.handle);
|
|
646
|
+
if (action.closeOnClick !== false) close(inst.id);
|
|
647
|
+
}
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
if (opts.clickToClose && !target.closest(".ga-toast-actions")) {
|
|
651
|
+
close(inst.id);
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
{ signal }
|
|
655
|
+
);
|
|
656
|
+
if (opts.pauseOnHover) {
|
|
657
|
+
el.addEventListener("pointerenter", () => pauseTimer(inst, "hover"), { signal });
|
|
658
|
+
el.addEventListener("pointerleave", () => resumeTimer(inst, "hover"), { signal });
|
|
659
|
+
el.addEventListener("focusin", () => pauseTimer(inst, "focus"), { signal });
|
|
660
|
+
el.addEventListener("focusout", () => resumeTimer(inst, "focus"), { signal });
|
|
661
|
+
}
|
|
662
|
+
if (opts.swipeToClose) attachSwipe(inst);
|
|
663
|
+
if (opts.modal) {
|
|
664
|
+
el.addEventListener(
|
|
665
|
+
"keydown",
|
|
666
|
+
(e) => {
|
|
667
|
+
if (e.key !== "Tab") return;
|
|
668
|
+
const focusables = el.querySelectorAll(
|
|
669
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
670
|
+
);
|
|
671
|
+
if (!focusables.length) return;
|
|
672
|
+
const first = focusables[0];
|
|
673
|
+
const last = focusables[focusables.length - 1];
|
|
674
|
+
const active = document.activeElement;
|
|
675
|
+
if (e.shiftKey && active === first) {
|
|
676
|
+
e.preventDefault();
|
|
677
|
+
last.focus();
|
|
678
|
+
} else if (!e.shiftKey && active === last) {
|
|
679
|
+
e.preventDefault();
|
|
680
|
+
first.focus();
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
{ signal }
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function attachSwipe(inst) {
|
|
688
|
+
const { el, controller } = inst;
|
|
689
|
+
const signal = controller.signal;
|
|
690
|
+
const THRESHOLD = 70;
|
|
691
|
+
let dragging = false;
|
|
692
|
+
let swiping = false;
|
|
693
|
+
let startX = 0;
|
|
694
|
+
let startY = 0;
|
|
695
|
+
el.addEventListener(
|
|
696
|
+
"pointerdown",
|
|
697
|
+
(e) => {
|
|
698
|
+
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
699
|
+
if (e.target.closest("button, a, input, textarea, select"))
|
|
700
|
+
return;
|
|
701
|
+
dragging = true;
|
|
702
|
+
swiping = false;
|
|
703
|
+
startX = e.clientX;
|
|
704
|
+
startY = e.clientY;
|
|
705
|
+
pauseTimer(inst, "swipe");
|
|
706
|
+
try {
|
|
707
|
+
el.setPointerCapture(e.pointerId);
|
|
708
|
+
} catch {
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
{ signal }
|
|
712
|
+
);
|
|
713
|
+
el.addEventListener(
|
|
714
|
+
"pointermove",
|
|
715
|
+
(e) => {
|
|
716
|
+
if (!dragging) return;
|
|
717
|
+
const dx = e.clientX - startX;
|
|
718
|
+
const dy = e.clientY - startY;
|
|
719
|
+
if (Math.abs(dx) < 6 || Math.abs(dx) < Math.abs(dy)) return;
|
|
720
|
+
e.preventDefault();
|
|
721
|
+
if (!swiping) {
|
|
722
|
+
swiping = true;
|
|
723
|
+
el.classList.add("ga-toast-swiping");
|
|
724
|
+
const sel = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
|
|
725
|
+
sel?.removeAllRanges();
|
|
726
|
+
}
|
|
727
|
+
inst.swipeX = dx;
|
|
728
|
+
const container = el.parentElement;
|
|
729
|
+
if (container) layout(container);
|
|
730
|
+
},
|
|
731
|
+
{ signal }
|
|
732
|
+
);
|
|
733
|
+
const end = (e) => {
|
|
734
|
+
if (!dragging) return;
|
|
735
|
+
dragging = false;
|
|
736
|
+
swiping = false;
|
|
737
|
+
el.classList.remove("ga-toast-swiping");
|
|
738
|
+
const dx = e.clientX - startX;
|
|
739
|
+
if (Math.abs(dx) > THRESHOLD) {
|
|
740
|
+
const dir = dx > 0 ? 1 : -1;
|
|
741
|
+
inst.el.style.transition = "transform 0.2s ease, opacity 0.2s ease";
|
|
742
|
+
inst.el.style.transform = `translateX(${dir * 400}px)`;
|
|
743
|
+
inst.el.style.opacity = "0";
|
|
744
|
+
close(inst.id);
|
|
745
|
+
} else {
|
|
746
|
+
inst.swipeX = 0;
|
|
747
|
+
const container = el.parentElement;
|
|
748
|
+
if (container) layout(container);
|
|
749
|
+
resumeTimer(inst, "swipe");
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
el.addEventListener("pointerup", end, { signal });
|
|
753
|
+
el.addEventListener("pointercancel", end, { signal });
|
|
754
|
+
}
|
|
755
|
+
function bindEscape() {
|
|
756
|
+
if (escapeBound || !canUseDOM) return;
|
|
757
|
+
escapeBound = true;
|
|
758
|
+
document.addEventListener("keydown", (e) => {
|
|
759
|
+
if (e.key !== "Escape") return;
|
|
760
|
+
let newest = null;
|
|
761
|
+
for (const inst of registry.values()) {
|
|
762
|
+
if (inst.closing) continue;
|
|
763
|
+
if (inst.opts.closeOnEscape === false || !inst.opts.closable) continue;
|
|
764
|
+
newest = inst;
|
|
765
|
+
}
|
|
766
|
+
if (newest) close(newest.id);
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
function bindVisibility() {
|
|
770
|
+
if (visibilityBound || !canUseDOM || typeof document.addEventListener !== "function")
|
|
771
|
+
return;
|
|
772
|
+
visibilityBound = true;
|
|
773
|
+
document.addEventListener("visibilitychange", () => {
|
|
774
|
+
const hidden = document.hidden;
|
|
775
|
+
for (const inst of registry.values()) {
|
|
776
|
+
if (inst.closing || inst.opts.pauseOnPageHidden === false) continue;
|
|
777
|
+
if (hidden) pauseTimer(inst, "tab");
|
|
778
|
+
else resumeTimer(inst, "tab");
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
function showBackdrop() {
|
|
783
|
+
if (!canUseDOM || !mount) return;
|
|
784
|
+
if (!backdropEl) {
|
|
785
|
+
backdropEl = document.createElement("div");
|
|
786
|
+
backdropEl.className = "ga-toast-backdrop";
|
|
787
|
+
}
|
|
788
|
+
if (!backdropEl.isConnected) mount.appendChild(backdropEl);
|
|
789
|
+
const bd = backdropEl;
|
|
790
|
+
requestAnimationFrame(() => bd.classList.add("ga-toast-backdrop-show"));
|
|
791
|
+
}
|
|
792
|
+
function hideBackdrop() {
|
|
793
|
+
if (!backdropEl) return;
|
|
794
|
+
const bd = backdropEl;
|
|
795
|
+
bd.classList.remove("ga-toast-backdrop-show");
|
|
796
|
+
setTimeout(() => {
|
|
797
|
+
if (activeModalId == null && bd.parentNode) bd.remove();
|
|
798
|
+
}, 220);
|
|
799
|
+
}
|
|
800
|
+
function noopHandle(id) {
|
|
801
|
+
const handle = {
|
|
802
|
+
id,
|
|
803
|
+
el: canUseDOM ? document.createElement("div") : {},
|
|
804
|
+
update: () => handle,
|
|
805
|
+
close: () => {
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
return handle;
|
|
809
|
+
}
|
|
810
|
+
function show(options = {}) {
|
|
811
|
+
if (!canUseDOM) return noopHandle(options.id || nextId());
|
|
812
|
+
const opts = resolveOptions(options);
|
|
813
|
+
if (opts.id && registry.has(opts.id)) {
|
|
814
|
+
return update(opts.id, options) || noopHandle(opts.id);
|
|
815
|
+
}
|
|
816
|
+
if (opts.modal) {
|
|
817
|
+
if (activeModalId && registry.has(activeModalId)) {
|
|
818
|
+
return registry.get(activeModalId).handle;
|
|
819
|
+
}
|
|
820
|
+
opts.swipeToClose = false;
|
|
821
|
+
opts.closeOnEscape = false;
|
|
822
|
+
opts.moveFocus = true;
|
|
823
|
+
}
|
|
824
|
+
injectStyles();
|
|
825
|
+
bindEscape();
|
|
826
|
+
bindVisibility();
|
|
827
|
+
const id = opts.id || nextId();
|
|
828
|
+
const { el, progressEl, ring } = buildToastElement(opts, id);
|
|
829
|
+
const controller = new AbortController();
|
|
830
|
+
const timer = {
|
|
831
|
+
duration: opts.duration || 0,
|
|
832
|
+
remaining: opts.duration || 0,
|
|
833
|
+
startedAt: 0,
|
|
834
|
+
handle: null,
|
|
835
|
+
holds: /* @__PURE__ */ new Set()
|
|
836
|
+
};
|
|
837
|
+
const handle = {
|
|
838
|
+
id,
|
|
839
|
+
el,
|
|
840
|
+
update: (o) => update(id, o) ? handle : handle,
|
|
841
|
+
close: () => close(id)
|
|
842
|
+
};
|
|
843
|
+
const inst = {
|
|
844
|
+
id,
|
|
845
|
+
el,
|
|
846
|
+
handle,
|
|
847
|
+
opts,
|
|
848
|
+
controller,
|
|
849
|
+
progressEl,
|
|
850
|
+
ring,
|
|
851
|
+
timer,
|
|
852
|
+
height: 0,
|
|
853
|
+
closing: false,
|
|
854
|
+
swipeX: 0,
|
|
855
|
+
resizeObserver: null,
|
|
856
|
+
prevFocus: opts.moveFocus ? document.activeElement : null
|
|
857
|
+
};
|
|
858
|
+
registry.set(id, inst);
|
|
859
|
+
if (opts.modal) {
|
|
860
|
+
activeModalId = id;
|
|
861
|
+
el.setAttribute("aria-modal", "true");
|
|
862
|
+
showBackdrop();
|
|
863
|
+
}
|
|
864
|
+
const container = getContainer(opts.position);
|
|
865
|
+
el.style.transform = offscreenTransform(opts.position);
|
|
866
|
+
el.style.opacity = "0";
|
|
867
|
+
container.appendChild(el);
|
|
868
|
+
attachHandlers(inst, opts);
|
|
869
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
870
|
+
inst.resizeObserver = new ResizeObserver(() => {
|
|
871
|
+
measure(inst);
|
|
872
|
+
const parent = el.parentElement;
|
|
873
|
+
if (parent) layout(parent);
|
|
874
|
+
});
|
|
875
|
+
inst.resizeObserver.observe(el);
|
|
876
|
+
}
|
|
877
|
+
requestAnimationFrame(() => {
|
|
878
|
+
requestAnimationFrame(() => {
|
|
879
|
+
if (!registry.has(id)) return;
|
|
880
|
+
measure(inst);
|
|
881
|
+
el.dataset.gaMounted = "true";
|
|
882
|
+
el.style.opacity = "1";
|
|
883
|
+
layout(container);
|
|
884
|
+
startTimer(inst);
|
|
885
|
+
if (opts.moveFocus) {
|
|
886
|
+
const target = el.querySelector("[data-ga-action]") || el;
|
|
887
|
+
if (target === el) el.tabIndex = -1;
|
|
888
|
+
try {
|
|
889
|
+
target.focus({ preventScroll: true });
|
|
890
|
+
} catch {
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
});
|
|
895
|
+
if (!opts.modal && opts.role !== "alertdialog") {
|
|
896
|
+
announce(
|
|
897
|
+
[opts.title, opts.message].filter(Boolean).join(". "),
|
|
898
|
+
ASSERTIVE_TYPES.has(opts.type || "info")
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
if (opts.onShow) {
|
|
902
|
+
try {
|
|
903
|
+
opts.onShow(handle);
|
|
904
|
+
} catch (err) {
|
|
905
|
+
log("toast:onShow:error", err);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
log("toast:show", { id, type: opts.type });
|
|
909
|
+
return handle;
|
|
910
|
+
}
|
|
911
|
+
function close(target) {
|
|
912
|
+
if (!target) return;
|
|
913
|
+
const id = typeof target === "string" ? normalizeId(target) : target.id;
|
|
914
|
+
const inst = registry.get(id);
|
|
915
|
+
if (!inst || inst.closing) return;
|
|
916
|
+
inst.closing = true;
|
|
917
|
+
if (inst.timer.handle != null) {
|
|
918
|
+
clearTimeout(inst.timer.handle);
|
|
919
|
+
inst.timer.handle = null;
|
|
920
|
+
}
|
|
921
|
+
inst.controller.abort();
|
|
922
|
+
inst.resizeObserver?.disconnect();
|
|
923
|
+
const { el } = inst;
|
|
924
|
+
const container = el.parentElement;
|
|
925
|
+
if (!inst.swipeX) {
|
|
926
|
+
el.style.transition = "";
|
|
927
|
+
el.classList.add("ga-toast-hide");
|
|
928
|
+
el.style.transform = offscreenTransform(inst.opts.position);
|
|
929
|
+
el.style.opacity = "0";
|
|
930
|
+
}
|
|
931
|
+
let removed = false;
|
|
932
|
+
const finalize = () => {
|
|
933
|
+
if (removed) return;
|
|
934
|
+
removed = true;
|
|
935
|
+
el.removeEventListener("transitionend", onEnd);
|
|
936
|
+
registry.delete(id);
|
|
937
|
+
el.remove();
|
|
938
|
+
if (activeModalId === id) {
|
|
939
|
+
activeModalId = null;
|
|
940
|
+
hideBackdrop();
|
|
941
|
+
}
|
|
942
|
+
if (container) layout(container);
|
|
943
|
+
const prev = inst.prevFocus;
|
|
944
|
+
if (prev && typeof prev.focus === "function" && document.contains(prev)) {
|
|
945
|
+
try {
|
|
946
|
+
prev.focus({ preventScroll: true });
|
|
947
|
+
} catch {
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (inst.opts.onClose) {
|
|
951
|
+
try {
|
|
952
|
+
inst.opts.onClose(inst.handle);
|
|
953
|
+
} catch (err) {
|
|
954
|
+
log("toast:onClose:error", err);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
log("toast:close", { id });
|
|
958
|
+
};
|
|
959
|
+
const onEnd = (e) => {
|
|
960
|
+
if (e.target === el && (e.propertyName === "transform" || e.propertyName === "opacity"))
|
|
961
|
+
finalize();
|
|
962
|
+
};
|
|
963
|
+
el.addEventListener("transitionend", onEnd);
|
|
964
|
+
setTimeout(finalize, REMOVE_FALLBACK);
|
|
965
|
+
}
|
|
966
|
+
function update(target, options) {
|
|
967
|
+
const id = typeof target === "string" ? normalizeId(target) : target.id;
|
|
968
|
+
const inst = registry.get(id);
|
|
969
|
+
if (!inst) {
|
|
970
|
+
log("toast:update:not-found", id);
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
const opts = inst.opts;
|
|
974
|
+
if (options.title !== void 0) {
|
|
975
|
+
let title = inst.el.querySelector(".ga-toast-title");
|
|
976
|
+
if (!title && options.title) {
|
|
977
|
+
const content = inst.el.querySelector(".ga-toast-content");
|
|
978
|
+
if (content) {
|
|
979
|
+
let header = content.querySelector(".ga-toast-header");
|
|
980
|
+
if (!header) {
|
|
981
|
+
header = document.createElement("div");
|
|
982
|
+
header.className = "ga-toast-header";
|
|
983
|
+
content.insertBefore(header, content.firstChild);
|
|
984
|
+
}
|
|
985
|
+
title = document.createElement("div");
|
|
986
|
+
title.className = "ga-toast-title";
|
|
987
|
+
header.appendChild(title);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (title) title.textContent = options.title;
|
|
991
|
+
opts.title = options.title;
|
|
992
|
+
}
|
|
993
|
+
if (options.message !== void 0) {
|
|
994
|
+
const useHtml = options.html ?? opts.html;
|
|
995
|
+
let message = inst.el.querySelector(".ga-toast-message");
|
|
996
|
+
if (!message && options.message) {
|
|
997
|
+
let body = inst.el.querySelector(".ga-toast-body");
|
|
998
|
+
if (!body) {
|
|
999
|
+
body = document.createElement("div");
|
|
1000
|
+
body.className = "ga-toast-body";
|
|
1001
|
+
const content = inst.el.querySelector(".ga-toast-content");
|
|
1002
|
+
const anchor = content?.querySelector(".ga-toast-actions, .ga-toast-steps");
|
|
1003
|
+
if (anchor) content.insertBefore(body, anchor);
|
|
1004
|
+
else content?.appendChild(body);
|
|
1005
|
+
}
|
|
1006
|
+
message = document.createElement("div");
|
|
1007
|
+
message.className = "ga-toast-message";
|
|
1008
|
+
body.appendChild(message);
|
|
1009
|
+
}
|
|
1010
|
+
if (message) {
|
|
1011
|
+
if (useHtml) message.innerHTML = options.message;
|
|
1012
|
+
else message.textContent = options.message;
|
|
1013
|
+
}
|
|
1014
|
+
opts.message = options.message;
|
|
1015
|
+
}
|
|
1016
|
+
if (options.type && options.type !== opts.type) {
|
|
1017
|
+
const prev = opts.type;
|
|
1018
|
+
inst.el.classList.remove(`ga-toast-${prev}`, "ga-toast-loading");
|
|
1019
|
+
inst.el.classList.add(`ga-toast-${options.type}`);
|
|
1020
|
+
inst.el.setAttribute("data-ga-type", options.type);
|
|
1021
|
+
if (options.type === "loading") inst.el.classList.add("ga-toast-loading");
|
|
1022
|
+
if (inst.progressEl) {
|
|
1023
|
+
inst.progressEl.className = inst.progressEl.className.replace(
|
|
1024
|
+
/ga-toast-progress-\w+/,
|
|
1025
|
+
`ga-toast-progress-${options.type}`
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
const iconEl = inst.el.querySelector(".ga-toast-icon");
|
|
1029
|
+
if (iconEl && opts.autoIcon !== false && !options.icon) {
|
|
1030
|
+
const next = iconFor(options.type);
|
|
1031
|
+
if (next != null) iconEl.innerHTML = next;
|
|
1032
|
+
}
|
|
1033
|
+
opts.type = options.type;
|
|
1034
|
+
}
|
|
1035
|
+
if (options.icon !== void 0) {
|
|
1036
|
+
let iconEl = inst.el.querySelector(".ga-toast-icon");
|
|
1037
|
+
if (options.icon) {
|
|
1038
|
+
if (!iconEl) {
|
|
1039
|
+
iconEl = document.createElement("div");
|
|
1040
|
+
iconEl.className = "ga-toast-icon";
|
|
1041
|
+
const content = inst.el.querySelector(".ga-toast-content");
|
|
1042
|
+
inst.el.insertBefore(iconEl, content);
|
|
1043
|
+
}
|
|
1044
|
+
iconEl.innerHTML = String(options.icon);
|
|
1045
|
+
} else if (iconEl) {
|
|
1046
|
+
iconEl.remove();
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (options.closable !== void 0) {
|
|
1050
|
+
const existing = inst.el.querySelector(":scope > .ga-toast-close");
|
|
1051
|
+
if (options.closable && !existing) {
|
|
1052
|
+
inst.el.insertBefore(createCloseButton(), inst.progressEl || null);
|
|
1053
|
+
} else if (!options.closable && existing) {
|
|
1054
|
+
existing.remove();
|
|
1055
|
+
}
|
|
1056
|
+
opts.closable = options.closable;
|
|
1057
|
+
}
|
|
1058
|
+
if (options.duration !== void 0) {
|
|
1059
|
+
if (inst.timer.handle != null) clearTimeout(inst.timer.handle);
|
|
1060
|
+
inst.timer.duration = options.duration;
|
|
1061
|
+
inst.timer.remaining = options.duration;
|
|
1062
|
+
opts.duration = options.duration;
|
|
1063
|
+
if (options.duration > 0 && inst.el.dataset.gaMounted) startTimer(inst);
|
|
1064
|
+
}
|
|
1065
|
+
const parent = inst.el.parentElement;
|
|
1066
|
+
if (parent) layout(parent);
|
|
1067
|
+
log("toast:update", { id });
|
|
1068
|
+
return inst.handle;
|
|
1069
|
+
}
|
|
1070
|
+
function closeAll() {
|
|
1071
|
+
for (const id of Array.from(registry.keys())) close(id);
|
|
1072
|
+
}
|
|
1073
|
+
function clear(type) {
|
|
1074
|
+
if (!type) return closeAll();
|
|
1075
|
+
for (const inst of Array.from(registry.values()))
|
|
1076
|
+
if (inst.opts.type === type) close(inst.id);
|
|
1077
|
+
}
|
|
1078
|
+
function getCount(type) {
|
|
1079
|
+
if (!type) return registry.size;
|
|
1080
|
+
let n = 0;
|
|
1081
|
+
for (const inst of registry.values()) if (inst.opts.type === type) n += 1;
|
|
1082
|
+
return n;
|
|
1083
|
+
}
|
|
1084
|
+
function exists(id) {
|
|
1085
|
+
return registry.has(normalizeId(id));
|
|
1086
|
+
}
|
|
1087
|
+
function get(id) {
|
|
1088
|
+
return registry.get(normalizeId(id))?.el || null;
|
|
1089
|
+
}
|
|
1090
|
+
function typed(type) {
|
|
1091
|
+
return (message, options = {}) => show({ ...options, type, message, duration: options.duration ?? durations[type] });
|
|
1092
|
+
}
|
|
1093
|
+
const success = typed("success");
|
|
1094
|
+
const error = typed("error");
|
|
1095
|
+
const warning = typed("warning");
|
|
1096
|
+
const info = typed("info");
|
|
1097
|
+
function loading(message = "Loading\u2026", options = {}) {
|
|
1098
|
+
return show({
|
|
1099
|
+
closable: false,
|
|
1100
|
+
...options,
|
|
1101
|
+
type: "loading",
|
|
1102
|
+
message,
|
|
1103
|
+
duration: 0,
|
|
1104
|
+
progress: false
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
function confirm(message, options = {}) {
|
|
1108
|
+
const { confirmText, cancelText, onConfirm, onCancel, ...rest } = options;
|
|
1109
|
+
return show({
|
|
1110
|
+
type: "warning",
|
|
1111
|
+
duration: 0,
|
|
1112
|
+
closable: false,
|
|
1113
|
+
swipeToClose: false,
|
|
1114
|
+
role: "alertdialog",
|
|
1115
|
+
moveFocus: true,
|
|
1116
|
+
modal: true,
|
|
1117
|
+
position: "middle-center",
|
|
1118
|
+
...rest,
|
|
1119
|
+
message,
|
|
1120
|
+
actions: [
|
|
1121
|
+
{
|
|
1122
|
+
text: cancelText || "Cancel",
|
|
1123
|
+
className: "ga-toast-btn-secondary",
|
|
1124
|
+
onClick: () => onCancel?.()
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
text: confirmText || "Confirm",
|
|
1128
|
+
className: "ga-toast-btn-primary",
|
|
1129
|
+
onClick: () => onConfirm?.()
|
|
1130
|
+
}
|
|
1131
|
+
]
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
function promise(input, messages, options = {}) {
|
|
1135
|
+
const p = typeof input === "function" ? input() : input;
|
|
1136
|
+
const handle = loading(messages.loading, options);
|
|
1137
|
+
return p.then(
|
|
1138
|
+
(value) => {
|
|
1139
|
+
handle.update({
|
|
1140
|
+
type: "success",
|
|
1141
|
+
message: typeof messages.success === "function" ? messages.success(value) : messages.success,
|
|
1142
|
+
duration: options.duration ?? durations.success,
|
|
1143
|
+
closable: true
|
|
1144
|
+
});
|
|
1145
|
+
return value;
|
|
1146
|
+
},
|
|
1147
|
+
(err) => {
|
|
1148
|
+
handle.update({
|
|
1149
|
+
type: "error",
|
|
1150
|
+
message: typeof messages.error === "function" ? messages.error(err) : messages.error,
|
|
1151
|
+
duration: options.duration ?? durations.error,
|
|
1152
|
+
closable: true
|
|
1153
|
+
});
|
|
1154
|
+
throw err;
|
|
1155
|
+
}
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
function custom(content, options = {}) {
|
|
1159
|
+
return show({ ...options, content });
|
|
1160
|
+
}
|
|
1161
|
+
function setDefaults(defaults) {
|
|
1162
|
+
globalDefaults = { ...globalDefaults, ...defaults };
|
|
1163
|
+
}
|
|
1164
|
+
function setLogger(fn) {
|
|
1165
|
+
logger = typeof fn === "function" ? fn : null;
|
|
1166
|
+
}
|
|
1167
|
+
function setMaxVisible(count) {
|
|
1168
|
+
maxVisible = Math.max(1, Math.floor(count) || 1);
|
|
1169
|
+
containers.forEach((container) => layout(container));
|
|
1170
|
+
}
|
|
1171
|
+
function theme(tokens) {
|
|
1172
|
+
themeTokens = resolveTheme(tokens);
|
|
1173
|
+
applyTheme();
|
|
1174
|
+
containers.forEach((container) => layout(container));
|
|
1175
|
+
return api;
|
|
1176
|
+
}
|
|
1177
|
+
function configure(cfg) {
|
|
1178
|
+
if (cfg.defaults) setDefaults(cfg.defaults);
|
|
1179
|
+
if (cfg.logger !== void 0) logger = cfg.logger;
|
|
1180
|
+
applyConfigDurations(cfg.durations);
|
|
1181
|
+
applyConfigIcons(cfg.icons);
|
|
1182
|
+
applyConfigStack(cfg.stack);
|
|
1183
|
+
if (typeof cfg.maxVisible === "number")
|
|
1184
|
+
maxVisible = Math.max(1, Math.floor(cfg.maxVisible) || 1);
|
|
1185
|
+
if (cfg.injectStyles !== void 0) injectEnabled = cfg.injectStyles !== false;
|
|
1186
|
+
if (cfg.theme !== void 0) {
|
|
1187
|
+
themeTokens = resolveTheme(cfg.theme);
|
|
1188
|
+
applyTheme();
|
|
1189
|
+
}
|
|
1190
|
+
containers.forEach((container) => layout(container));
|
|
1191
|
+
return api;
|
|
1192
|
+
}
|
|
1193
|
+
const api = Object.assign(
|
|
1194
|
+
(message, options) => info(message, options),
|
|
1195
|
+
{
|
|
1196
|
+
show,
|
|
1197
|
+
success,
|
|
1198
|
+
error,
|
|
1199
|
+
warning,
|
|
1200
|
+
info,
|
|
1201
|
+
loading,
|
|
1202
|
+
confirm,
|
|
1203
|
+
promise,
|
|
1204
|
+
custom,
|
|
1205
|
+
close,
|
|
1206
|
+
closeAll,
|
|
1207
|
+
dismiss: close,
|
|
1208
|
+
dismissAll: closeAll,
|
|
1209
|
+
clear,
|
|
1210
|
+
update,
|
|
1211
|
+
get,
|
|
1212
|
+
exists,
|
|
1213
|
+
getCount,
|
|
1214
|
+
setDefaults,
|
|
1215
|
+
setMaxVisible,
|
|
1216
|
+
setLogger,
|
|
1217
|
+
configure,
|
|
1218
|
+
theme,
|
|
1219
|
+
injectStyles
|
|
1220
|
+
}
|
|
1221
|
+
);
|
|
1222
|
+
if (config.theme !== void 0) {
|
|
1223
|
+
themeTokens = resolveTheme(config.theme);
|
|
1224
|
+
applyTheme();
|
|
1225
|
+
}
|
|
1226
|
+
return api;
|
|
1227
|
+
}
|
|
1228
|
+
function createToaster(config = {}) {
|
|
1229
|
+
return makeToaster(config);
|
|
1230
|
+
}
|
|
1231
|
+
var toast = makeToaster();
|
|
1232
|
+
var GaToasts = toast;
|
|
1233
|
+
var src_default = toast;
|
|
1234
|
+
|
|
1235
|
+
export { GaToasts, createToaster, src_default as default, toast };
|