|
@@ -38,9 +38,16 @@
|
|
|
const PREFIX = 'layer-';
|
|
const PREFIX = 'layer-';
|
|
|
const RING_TYPES = new Set(['success', 'error', 'warning', 'info', 'question']);
|
|
const RING_TYPES = new Set(['success', 'error', 'warning', 'info', 'question']);
|
|
|
const RING_BG_PARTS_SELECTOR = `.${PREFIX}success-circular-line-left, .${PREFIX}success-circular-line-right, .${PREFIX}success-fix`;
|
|
const RING_BG_PARTS_SELECTOR = `.${PREFIX}success-circular-line-left, .${PREFIX}success-circular-line-right, .${PREFIX}success-fix`;
|
|
|
- const LOTTIE_PREFIX = 'svg:';
|
|
|
|
|
|
|
+ const SVGANI_PREFIX = 'svg:';
|
|
|
const BG_SVG_PREFIX = 'svg(';
|
|
const BG_SVG_PREFIX = 'svg(';
|
|
|
const BG_CSS_PREFIX = 'css(';
|
|
const BG_CSS_PREFIX = 'css(';
|
|
|
|
|
+ const THEME_VALUES = new Set(['auto', 'dark', 'light']);
|
|
|
|
|
+
|
|
|
|
|
+ const normalizeTheme = (value) => {
|
|
|
|
|
+ if (typeof value !== 'string') return 'auto';
|
|
|
|
|
+ const v = value.trim().toLowerCase();
|
|
|
|
|
+ return THEME_VALUES.has(v) ? v : 'auto';
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
const normalizeOptions = (options, text, icon) => {
|
|
const normalizeOptions = (options, text, icon) => {
|
|
|
if (typeof options !== 'string') return options || {};
|
|
if (typeof options !== 'string') return options || {};
|
|
@@ -116,24 +123,24 @@
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // Lottie (svg.js) lazy loader for "svg:*" icon type
|
|
|
|
|
- let _lottieReady = null;
|
|
|
|
|
- let _lottiePrefetchScheduled = false;
|
|
|
|
|
- const isLottieIcon = (icon) => {
|
|
|
|
|
|
|
+ // SvgAni (svg.js) lazy loader for "svg:*" icon type
|
|
|
|
|
+ let _svgAniReady = null;
|
|
|
|
|
+ let _svgAniPrefetchScheduled = false;
|
|
|
|
|
+ const isSvgAniIcon = (icon) => {
|
|
|
if (typeof icon !== 'string') return false;
|
|
if (typeof icon !== 'string') return false;
|
|
|
const s = icon.trim();
|
|
const s = icon.trim();
|
|
|
- return s.startsWith(LOTTIE_PREFIX);
|
|
|
|
|
|
|
+ return s.startsWith(SVGANI_PREFIX);
|
|
|
};
|
|
};
|
|
|
- const getLottieIconName = (icon) => {
|
|
|
|
|
- if (!isLottieIcon(icon)) return '';
|
|
|
|
|
- let name = String(icon || '').trim().slice(LOTTIE_PREFIX.length).trim();
|
|
|
|
|
|
|
+ const getSvgAniIconName = (icon) => {
|
|
|
|
|
+ if (!isSvgAniIcon(icon)) return '';
|
|
|
|
|
+ let name = String(icon || '').trim().slice(SVGANI_PREFIX.length).trim();
|
|
|
if (name === 'loadding') name = 'loading';
|
|
if (name === 'loadding') name = 'loading';
|
|
|
return name;
|
|
return name;
|
|
|
};
|
|
};
|
|
|
- const normalizeLottieName = (raw) => {
|
|
|
|
|
|
|
+ const normalizeSvgAniName = (raw) => {
|
|
|
let name = String(raw || '').trim();
|
|
let name = String(raw || '').trim();
|
|
|
if (!name) return '';
|
|
if (!name) return '';
|
|
|
- if (name.startsWith(LOTTIE_PREFIX)) name = getLottieIconName(name);
|
|
|
|
|
|
|
+ if (name.startsWith(SVGANI_PREFIX)) name = getSvgAniIconName(name);
|
|
|
if (name === 'loadding') name = 'loading';
|
|
if (name === 'loadding') name = 'loading';
|
|
|
return name;
|
|
return name;
|
|
|
};
|
|
};
|
|
@@ -152,11 +159,11 @@
|
|
|
return '';
|
|
return '';
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
- const resolveLottieScriptUrl = () => {
|
|
|
|
|
|
|
+ const resolveSvgAniScriptUrl = () => {
|
|
|
const base = getLayerScriptBase();
|
|
const base = getLayerScriptBase();
|
|
|
return base ? (base + 'svg/svg.js') : 'svg/svg.js';
|
|
return base ? (base + 'svg/svg.js') : 'svg/svg.js';
|
|
|
};
|
|
};
|
|
|
- const resolveLottieJsonUrl = (name) => {
|
|
|
|
|
|
|
+ const resolveSvgAniJsonUrl = (name) => {
|
|
|
const raw = String(name || '').trim();
|
|
const raw = String(name || '').trim();
|
|
|
if (!raw) return '';
|
|
if (!raw) return '';
|
|
|
if (/^(https?:)?\/\//.test(raw)) return raw;
|
|
if (/^(https?:)?\/\//.test(raw)) return raw;
|
|
@@ -165,15 +172,15 @@
|
|
|
const file = raw.endsWith('.json') ? raw : (raw + '.json');
|
|
const file = raw.endsWith('.json') ? raw : (raw + '.json');
|
|
|
return (base ? base : '') + 'svg/' + file;
|
|
return (base ? base : '') + 'svg/' + file;
|
|
|
};
|
|
};
|
|
|
- const ensureLottieLib = () => {
|
|
|
|
|
|
|
+ const ensureSvgAniLib = () => {
|
|
|
try {
|
|
try {
|
|
|
if (typeof window === 'undefined') return Promise.resolve(null);
|
|
if (typeof window === 'undefined') return Promise.resolve(null);
|
|
|
if (window.lottie) return Promise.resolve(window.lottie);
|
|
if (window.lottie) return Promise.resolve(window.lottie);
|
|
|
if (typeof document === 'undefined' || !document.head) return Promise.resolve(null);
|
|
if (typeof document === 'undefined' || !document.head) return Promise.resolve(null);
|
|
|
- if (_lottieReady) return _lottieReady;
|
|
|
|
|
|
|
+ if (_svgAniReady) return _svgAniReady;
|
|
|
|
|
|
|
|
- const existing = document.getElementById('layer-lottie-lib');
|
|
|
|
|
- _lottieReady = new Promise((resolve) => {
|
|
|
|
|
|
|
+ const existing = document.getElementById('layer-svgani-lib');
|
|
|
|
|
+ _svgAniReady = new Promise((resolve) => {
|
|
|
const finish = () => resolve(window.lottie || null);
|
|
const finish = () => resolve(window.lottie || null);
|
|
|
if (existing) {
|
|
if (existing) {
|
|
|
try { existing.addEventListener('load', finish, { once: true }); } catch {}
|
|
try { existing.addEventListener('load', finish, { once: true }); } catch {}
|
|
@@ -182,33 +189,50 @@
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
const script = document.createElement('script');
|
|
const script = document.createElement('script');
|
|
|
- script.id = 'layer-lottie-lib';
|
|
|
|
|
|
|
+ script.id = 'layer-svgani-lib';
|
|
|
script.async = true;
|
|
script.async = true;
|
|
|
- script.src = resolveLottieScriptUrl();
|
|
|
|
|
|
|
+ script.src = resolveSvgAniScriptUrl();
|
|
|
try { script.addEventListener('load', finish, { once: true }); } catch {}
|
|
try { script.addEventListener('load', finish, { once: true }); } catch {}
|
|
|
try { script.addEventListener('error', finish, { once: true }); } catch {}
|
|
try { script.addEventListener('error', finish, { once: true }); } catch {}
|
|
|
setTimeout(finish, 1800);
|
|
setTimeout(finish, 1800);
|
|
|
document.head.appendChild(script);
|
|
document.head.appendChild(script);
|
|
|
});
|
|
});
|
|
|
- return _lottieReady;
|
|
|
|
|
|
|
+ return _svgAniReady;
|
|
|
} catch {
|
|
} catch {
|
|
|
return Promise.resolve(null);
|
|
return Promise.resolve(null);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
- const scheduleLottiePrefetch = () => {
|
|
|
|
|
- if (_lottiePrefetchScheduled) return;
|
|
|
|
|
- _lottiePrefetchScheduled = true;
|
|
|
|
|
|
|
+ const scheduleSvgAniPrefetch = () => {
|
|
|
|
|
+ if (_svgAniPrefetchScheduled) return;
|
|
|
|
|
+ _svgAniPrefetchScheduled = true;
|
|
|
try {
|
|
try {
|
|
|
if (typeof window === 'undefined') return;
|
|
if (typeof window === 'undefined') return;
|
|
|
const start = () => {
|
|
const start = () => {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- try { ensureLottieLib(); } catch {}
|
|
|
|
|
|
|
+ try { ensureSvgAniLib(); } catch {}
|
|
|
}, 0);
|
|
}, 0);
|
|
|
};
|
|
};
|
|
|
if (document.readyState === 'complete') start();
|
|
if (document.readyState === 'complete') start();
|
|
|
else window.addEventListener('load', start, { once: true });
|
|
else window.addEventListener('load', start, { once: true });
|
|
|
} catch {}
|
|
} catch {}
|
|
|
};
|
|
};
|
|
|
|
|
+ const waitForConnected = (el) => new Promise((resolve) => {
|
|
|
|
|
+ if (!el) return resolve(false);
|
|
|
|
|
+ if (el.isConnected) return resolve(true);
|
|
|
|
|
+ let done = false;
|
|
|
|
|
+ const finish = () => {
|
|
|
|
|
+ if (done) return;
|
|
|
|
|
+ done = true;
|
|
|
|
|
+ resolve(!!el.isConnected);
|
|
|
|
|
+ };
|
|
|
|
|
+ try {
|
|
|
|
|
+ requestAnimationFrame(() => requestAnimationFrame(finish));
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ setTimeout(finish, 0);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setTimeout(finish, 120);
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
class Layer {
|
|
class Layer {
|
|
|
constructor() {
|
|
constructor() {
|
|
@@ -321,7 +345,7 @@
|
|
|
text: '',
|
|
text: '',
|
|
|
icon: null,
|
|
icon: null,
|
|
|
iconSize: null, // e.g. '6em' / '72px'
|
|
iconSize: null, // e.g. '6em' / '72px'
|
|
|
- iconLoop: null, // lottie only: true/false/null (auto)
|
|
|
|
|
|
|
+ iconLoop: null, // svgAni only: true/false/null (auto)
|
|
|
confirmButtonText: 'OK',
|
|
confirmButtonText: 'OK',
|
|
|
cancelButtonText: 'Cancel',
|
|
cancelButtonText: 'Cancel',
|
|
|
showCancelButton: false,
|
|
showCancelButton: false,
|
|
@@ -329,9 +353,12 @@
|
|
|
closeOnEsc: true,
|
|
closeOnEsc: true,
|
|
|
iconAnimation: true,
|
|
iconAnimation: true,
|
|
|
popupAnimation: true,
|
|
popupAnimation: true,
|
|
|
|
|
+ theme: 'auto',
|
|
|
background: null,
|
|
background: null,
|
|
|
width: null,
|
|
width: null,
|
|
|
height: null,
|
|
height: null,
|
|
|
|
|
+ iwidth: null,
|
|
|
|
|
+ iheight: null,
|
|
|
nextIcon: null, // flow-only: icon for Next button
|
|
nextIcon: null, // flow-only: icon for Next button
|
|
|
prevIcon: null, // flow-only: icon for Back button
|
|
prevIcon: null, // flow-only: icon for Back button
|
|
|
// Content:
|
|
// Content:
|
|
@@ -434,7 +461,7 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
_render(meta = null) {
|
|
_render(meta = null) {
|
|
|
- this._destroyLottieIcon();
|
|
|
|
|
|
|
+ this._destroySvgAniIcon();
|
|
|
// Remove existing if any (but first, try to restore any mounted DOM from the previous instance)
|
|
// Remove existing if any (but first, try to restore any mounted DOM from the previous instance)
|
|
|
const existing = document.querySelector(`.${PREFIX}overlay`);
|
|
const existing = document.querySelector(`.${PREFIX}overlay`);
|
|
|
const wantReplace = !!(this.params && this.params.replace);
|
|
const wantReplace = !!(this.params && this.params.replace);
|
|
@@ -489,6 +516,7 @@
|
|
|
this.dom.popup = el('div', `${PREFIX}popup`);
|
|
this.dom.popup = el('div', `${PREFIX}popup`);
|
|
|
this.dom.overlay.appendChild(this.dom.popup);
|
|
this.dom.overlay.appendChild(this.dom.popup);
|
|
|
this._applyPopupSize(this.params);
|
|
this._applyPopupSize(this.params);
|
|
|
|
|
+ this._applyPopupTheme(this.params);
|
|
|
|
|
|
|
|
// Background (full popup)
|
|
// Background (full popup)
|
|
|
this._applyBackgroundForOptions(this.params, { force: true });
|
|
this._applyBackgroundForOptions(this.params, { force: true });
|
|
@@ -589,7 +617,7 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
_renderFlowUI() {
|
|
_renderFlowUI() {
|
|
|
- this._destroyLottieIcon();
|
|
|
|
|
|
|
+ this._destroySvgAniIcon();
|
|
|
// Icon/title/content/actions are stable; steps are pre-mounted and toggled.
|
|
// Icon/title/content/actions are stable; steps are pre-mounted and toggled.
|
|
|
const popup = this.dom.popup;
|
|
const popup = this.dom.popup;
|
|
|
if (!popup) return;
|
|
if (!popup) return;
|
|
@@ -598,6 +626,7 @@
|
|
|
while (popup.firstChild) popup.removeChild(popup.firstChild);
|
|
while (popup.firstChild) popup.removeChild(popup.firstChild);
|
|
|
|
|
|
|
|
this._applyPopupSize(this.params);
|
|
this._applyPopupSize(this.params);
|
|
|
|
|
+ this._applyPopupTheme(this.params);
|
|
|
|
|
|
|
|
// Background (full popup)
|
|
// Background (full popup)
|
|
|
this._applyBackgroundForOptions(this.params, { force: true });
|
|
this._applyBackgroundForOptions(this.params, { force: true });
|
|
@@ -718,6 +747,13 @@
|
|
|
_createIcon(type) {
|
|
_createIcon(type) {
|
|
|
const rawType = String(type || '').trim();
|
|
const rawType = String(type || '').trim();
|
|
|
const icon = el('div', `${PREFIX}icon ${rawType}`);
|
|
const icon = el('div', `${PREFIX}icon ${rawType}`);
|
|
|
|
|
+ const applyIconBoxSize = () => {
|
|
|
|
|
+ if (!this.params) return;
|
|
|
|
|
+ const w = this._normalizeSizeValue(this.params.iwidth);
|
|
|
|
|
+ const h = this._normalizeSizeValue(this.params.iheight);
|
|
|
|
|
+ if (w) icon.style.width = w;
|
|
|
|
|
+ if (h) icon.style.height = h;
|
|
|
|
|
+ };
|
|
|
const applyIconSize = (mode) => {
|
|
const applyIconSize = (mode) => {
|
|
|
if (!(this.params && this.params.iconSize)) return;
|
|
if (!(this.params && this.params.iconSize)) return;
|
|
|
try {
|
|
try {
|
|
@@ -793,16 +829,17 @@
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- if (isLottieIcon(rawType)) {
|
|
|
|
|
- // Lottie animation icon: svg:<name>
|
|
|
|
|
- const name = getLottieIconName(rawType);
|
|
|
|
|
- icon.className = `${PREFIX}icon ${PREFIX}icon-lottie`;
|
|
|
|
|
- icon.dataset.lottie = name;
|
|
|
|
|
- const container = el('div', `${PREFIX}lottie`);
|
|
|
|
|
|
|
+ if (isSvgAniIcon(rawType)) {
|
|
|
|
|
+ // SvgAni animation icon: svg:<name>
|
|
|
|
|
+ const name = getSvgAniIconName(rawType);
|
|
|
|
|
+ icon.className = `${PREFIX}icon ${PREFIX}icon-svgAni`;
|
|
|
|
|
+ icon.dataset.svgani = name;
|
|
|
|
|
+ const container = el('div', `${PREFIX}svgAni`);
|
|
|
icon.appendChild(container);
|
|
icon.appendChild(container);
|
|
|
applyIconSize('box');
|
|
applyIconSize('box');
|
|
|
- scheduleLottiePrefetch();
|
|
|
|
|
- this._initLottieIcon(icon, name);
|
|
|
|
|
|
|
+ applyIconBoxSize();
|
|
|
|
|
+ scheduleSvgAniPrefetch();
|
|
|
|
|
+ this._initSvgAniIcon(icon, name);
|
|
|
return icon;
|
|
return icon;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -831,6 +868,7 @@
|
|
|
appendRingParts();
|
|
appendRingParts();
|
|
|
|
|
|
|
|
applyIconSize('font');
|
|
applyIconSize('font');
|
|
|
|
|
+ applyIconBoxSize();
|
|
|
|
|
|
|
|
// SVG only draws the inner symbol (no SVG ring)
|
|
// SVG only draws the inner symbol (no SVG ring)
|
|
|
const svg = createInnerMarkSvg();
|
|
const svg = createInnerMarkSvg();
|
|
@@ -841,6 +879,7 @@
|
|
|
|
|
|
|
|
// Default to SVG icons for other/custom types
|
|
// Default to SVG icons for other/custom types
|
|
|
applyIconSize('box');
|
|
applyIconSize('box');
|
|
|
|
|
+ applyIconBoxSize();
|
|
|
|
|
|
|
|
const svg = createInnerMarkSvg();
|
|
const svg = createInnerMarkSvg();
|
|
|
|
|
|
|
@@ -887,17 +926,29 @@
|
|
|
popup.style.overflow = 'auto';
|
|
popup.style.overflow = 'auto';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ _applyPopupTheme(options) {
|
|
|
|
|
+ const popup = this.dom && this.dom.popup;
|
|
|
|
|
+ if (!popup) return;
|
|
|
|
|
+ const theme = normalizeTheme(options && options.theme);
|
|
|
|
|
+ try {
|
|
|
|
|
+ popup.classList.remove(`${PREFIX}theme-auto`, `${PREFIX}theme-light`, `${PREFIX}theme-dark`);
|
|
|
|
|
+ } catch {}
|
|
|
|
|
+ try {
|
|
|
|
|
+ popup.classList.add(`${PREFIX}theme-${theme}`);
|
|
|
|
|
+ } catch {}
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
_normalizeBackgroundSpec(raw) {
|
|
_normalizeBackgroundSpec(raw) {
|
|
|
if (!raw || typeof raw !== 'string') return null;
|
|
if (!raw || typeof raw !== 'string') return null;
|
|
|
const s = raw.trim();
|
|
const s = raw.trim();
|
|
|
if (!s) return null;
|
|
if (!s) return null;
|
|
|
if (s.startsWith(BG_SVG_PREFIX) && s.endsWith(')')) {
|
|
if (s.startsWith(BG_SVG_PREFIX) && s.endsWith(')')) {
|
|
|
- const name = normalizeLottieName(s.slice(BG_SVG_PREFIX.length, -1));
|
|
|
|
|
|
|
+ const name = normalizeSvgAniName(s.slice(BG_SVG_PREFIX.length, -1));
|
|
|
if (!name) return null;
|
|
if (!name) return null;
|
|
|
return { type: 'svg', name, key: `svg:${name}` };
|
|
return { type: 'svg', name, key: `svg:${name}` };
|
|
|
}
|
|
}
|
|
|
- if (s.startsWith(LOTTIE_PREFIX)) {
|
|
|
|
|
- const name = normalizeLottieName(s);
|
|
|
|
|
|
|
+ if (s.startsWith(SVGANI_PREFIX)) {
|
|
|
|
|
+ const name = normalizeSvgAniName(s);
|
|
|
if (!name) return null;
|
|
if (!name) return null;
|
|
|
return { type: 'svg', name, key: `svg:${name}` };
|
|
return { type: 'svg', name, key: `svg:${name}` };
|
|
|
}
|
|
}
|
|
@@ -934,9 +985,9 @@
|
|
|
} else if (spec.type === 'css') {
|
|
} else if (spec.type === 'css') {
|
|
|
try { bg.style.cssText += ';' + spec.css; } catch {}
|
|
try { bg.style.cssText += ';' + spec.css; } catch {}
|
|
|
} else if (spec.type === 'svg') {
|
|
} else if (spec.type === 'svg') {
|
|
|
- const container = el('div', `${PREFIX}lottie`);
|
|
|
|
|
|
|
+ const container = el('div', `${PREFIX}svgAni`);
|
|
|
bg.appendChild(container);
|
|
bg.appendChild(container);
|
|
|
- this._initLottieBackground(bg, spec.name);
|
|
|
|
|
|
|
+ this._initSvgAniBackground(bg, spec.name);
|
|
|
}
|
|
}
|
|
|
return bg;
|
|
return bg;
|
|
|
}
|
|
}
|
|
@@ -947,7 +998,7 @@
|
|
|
const spec = this._normalizeBackgroundSpec(options && options.background);
|
|
const spec = this._normalizeBackgroundSpec(options && options.background);
|
|
|
if (!spec) {
|
|
if (!spec) {
|
|
|
if (this.dom.background) {
|
|
if (this.dom.background) {
|
|
|
- this._destroyLottieBackground(this.dom.background);
|
|
|
|
|
|
|
+ this._destroySvgAniBackground(this.dom.background);
|
|
|
try { this.dom.background.remove(); } catch {}
|
|
try { this.dom.background.remove(); } catch {}
|
|
|
}
|
|
}
|
|
|
this.dom.background = null;
|
|
this.dom.background = null;
|
|
@@ -957,7 +1008,7 @@
|
|
|
}
|
|
}
|
|
|
if (!force && this._isSameBackgroundSpec(this._backgroundSpec, spec)) return;
|
|
if (!force && this._isSameBackgroundSpec(this._backgroundSpec, spec)) return;
|
|
|
if (this.dom.background) {
|
|
if (this.dom.background) {
|
|
|
- this._destroyLottieBackground(this.dom.background);
|
|
|
|
|
|
|
+ this._destroySvgAniBackground(this.dom.background);
|
|
|
try { this.dom.background.remove(); } catch {}
|
|
try { this.dom.background.remove(); } catch {}
|
|
|
}
|
|
}
|
|
|
const bgEl = this._createBackgroundEl(spec);
|
|
const bgEl = this._createBackgroundEl(spec);
|
|
@@ -1029,7 +1080,7 @@
|
|
|
} catch {}
|
|
} catch {}
|
|
|
|
|
|
|
|
if (fromEl) {
|
|
if (fromEl) {
|
|
|
- this._destroyLottieBackground(fromEl);
|
|
|
|
|
|
|
+ this._destroySvgAniBackground(fromEl);
|
|
|
try { fromEl.remove(); } catch {}
|
|
try { fromEl.remove(); } catch {}
|
|
|
}
|
|
}
|
|
|
if (toEl) {
|
|
if (toEl) {
|
|
@@ -1040,29 +1091,29 @@
|
|
|
this._backgroundSpec = nextSpec || null;
|
|
this._backgroundSpec = nextSpec || null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _destroyLottieBackground(bgEl) {
|
|
|
|
|
|
|
+ _destroySvgAniBackground(bgEl) {
|
|
|
if (!bgEl) return;
|
|
if (!bgEl) return;
|
|
|
- const inst = bgEl._lottieInstance;
|
|
|
|
|
|
|
+ const inst = bgEl._svgAniInstance;
|
|
|
if (inst && typeof inst.destroy === 'function') {
|
|
if (inst && typeof inst.destroy === 'function') {
|
|
|
try { inst.destroy(); } catch {}
|
|
try { inst.destroy(); } catch {}
|
|
|
}
|
|
}
|
|
|
- try { bgEl._lottieInstance = null; } catch {}
|
|
|
|
|
|
|
+ try { bgEl._svgAniInstance = null; } catch {}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _initLottieBackground(bgEl, name) {
|
|
|
|
|
|
|
+ _initSvgAniBackground(bgEl, name) {
|
|
|
if (!bgEl) return;
|
|
if (!bgEl) return;
|
|
|
- const container = bgEl.querySelector(`.${PREFIX}lottie`);
|
|
|
|
|
|
|
+ const container = bgEl.querySelector(`.${PREFIX}svgAni`);
|
|
|
if (!container) return;
|
|
if (!container) return;
|
|
|
- const cleanName = normalizeLottieName(name);
|
|
|
|
|
|
|
+ const cleanName = normalizeSvgAniName(name);
|
|
|
if (!cleanName) return;
|
|
if (!cleanName) return;
|
|
|
|
|
|
|
|
- const url = resolveLottieJsonUrl(cleanName);
|
|
|
|
|
|
|
+ const url = resolveSvgAniJsonUrl(cleanName);
|
|
|
if (!url) return;
|
|
if (!url) return;
|
|
|
|
|
|
|
|
const showError = (msg) => {
|
|
const showError = (msg) => {
|
|
|
try {
|
|
try {
|
|
|
container.textContent = String(msg || '');
|
|
container.textContent = String(msg || '');
|
|
|
- container.classList.add(`${PREFIX}lottie-error`);
|
|
|
|
|
|
|
+ container.classList.add(`${PREFIX}svgAni-error`);
|
|
|
} catch {}
|
|
} catch {}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -1094,25 +1145,25 @@
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const boot = async () => {
|
|
const boot = async () => {
|
|
|
- const lottie = await ensureLottieLib();
|
|
|
|
|
- if (!lottie) {
|
|
|
|
|
- showError('Lottie lib not available');
|
|
|
|
|
|
|
+ const svgAniLib = await ensureSvgAniLib();
|
|
|
|
|
+ if (!svgAniLib) {
|
|
|
|
|
+ showError('SvgAni lib not available');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
const data = await loadData();
|
|
const data = await loadData();
|
|
|
if (!data) throw new Error('empty json');
|
|
if (!data) throw new Error('empty json');
|
|
|
try { container.textContent = ''; } catch {}
|
|
try { container.textContent = ''; } catch {}
|
|
|
- const anim = lottie.loadAnimation({
|
|
|
|
|
|
|
+ const anim = svgAniLib.loadAnimation({
|
|
|
container,
|
|
container,
|
|
|
renderer: 'svg',
|
|
renderer: 'svg',
|
|
|
loop: true,
|
|
loop: true,
|
|
|
autoplay: true,
|
|
autoplay: true,
|
|
|
animationData: data
|
|
animationData: data
|
|
|
});
|
|
});
|
|
|
- bgEl._lottieInstance = anim;
|
|
|
|
|
|
|
+ bgEl._svgAniInstance = anim;
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
- showError('Lottie load failed');
|
|
|
|
|
|
|
+ showError('SvgAni load failed');
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -1239,7 +1290,7 @@
|
|
|
const icon = this.dom.icon;
|
|
const icon = this.dom.icon;
|
|
|
if (!icon) return;
|
|
if (!icon) return;
|
|
|
const type = (this.params && this.params.icon) || '';
|
|
const type = (this.params && this.params.icon) || '';
|
|
|
- if (isLottieIcon(type)) return;
|
|
|
|
|
|
|
+ if (isSvgAniIcon(type)) return;
|
|
|
|
|
|
|
|
// Ring animation (same as success) for all built-in icons
|
|
// Ring animation (same as success) for all built-in icons
|
|
|
if (RING_TYPES.has(type)) this._adjustRingBackgroundColor();
|
|
if (RING_TYPES.has(type)) this._adjustRingBackgroundColor();
|
|
@@ -1295,8 +1346,8 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
_forceDestroy(reason = 'replace') {
|
|
_forceDestroy(reason = 'replace') {
|
|
|
- try { this._destroyLottieIcon(); } catch {}
|
|
|
|
|
- try { this._destroyLottieBackground(this.dom && this.dom.background); } catch {}
|
|
|
|
|
|
|
+ try { this._destroySvgAniIcon(); } catch {}
|
|
|
|
|
+ try { this._destroySvgAniBackground(this.dom && this.dom.background); } catch {}
|
|
|
// Restore mounted DOM (if any) and cleanup listeners; also resolve the promise so it doesn't hang.
|
|
// Restore mounted DOM (if any) and cleanup listeners; also resolve the promise so it doesn't hang.
|
|
|
try {
|
|
try {
|
|
|
if (this._flowSteps && this._flowSteps.length) this._unmountFlowMounted();
|
|
if (this._flowSteps && this._flowSteps.length) this._unmountFlowMounted();
|
|
@@ -1316,8 +1367,8 @@
|
|
|
_close(isConfirmed, reason) {
|
|
_close(isConfirmed, reason) {
|
|
|
if (this._isClosing) return;
|
|
if (this._isClosing) return;
|
|
|
this._isClosing = true;
|
|
this._isClosing = true;
|
|
|
- try { this._destroyLottieIcon(); } catch {}
|
|
|
|
|
- try { this._destroyLottieBackground(this.dom && this.dom.background); } catch {}
|
|
|
|
|
|
|
+ try { this._destroySvgAniIcon(); } catch {}
|
|
|
|
|
+ try { this._destroySvgAniBackground(this.dom && this.dom.background); } catch {}
|
|
|
|
|
|
|
|
const shouldDelayUnmount = !!(
|
|
const shouldDelayUnmount = !!(
|
|
|
(this._mounted && this._mounted.kind === 'move') ||
|
|
(this._mounted && this._mounted.kind === 'move') ||
|
|
@@ -1857,6 +1908,7 @@
|
|
|
// Apply new options (title/buttons/icon policy) before showing the pane
|
|
// Apply new options (title/buttons/icon policy) before showing the pane
|
|
|
this._flowIndex = nextIndex;
|
|
this._flowIndex = nextIndex;
|
|
|
this.params = nextOptions;
|
|
this.params = nextOptions;
|
|
|
|
|
+ this._applyPopupTheme(this.params);
|
|
|
|
|
|
|
|
// Update icon/title/buttons without recreating DOM
|
|
// Update icon/title/buttons without recreating DOM
|
|
|
try {
|
|
try {
|
|
@@ -1871,14 +1923,14 @@
|
|
|
try {
|
|
try {
|
|
|
const wantsIcon = !!this.params.icon;
|
|
const wantsIcon = !!this.params.icon;
|
|
|
if (!wantsIcon && this.dom.icon) {
|
|
if (!wantsIcon && this.dom.icon) {
|
|
|
- this._destroyLottieIcon();
|
|
|
|
|
|
|
+ this._destroySvgAniIcon();
|
|
|
this.dom.icon.remove();
|
|
this.dom.icon.remove();
|
|
|
this.dom.icon = null;
|
|
this.dom.icon = null;
|
|
|
} else if (wantsIcon) {
|
|
} else if (wantsIcon) {
|
|
|
const same = this._isSameIconType(this.dom.icon, this.params.icon);
|
|
const same = this._isSameIconType(this.dom.icon, this.params.icon);
|
|
|
if (!this.dom.icon || !same) {
|
|
if (!this.dom.icon || !same) {
|
|
|
if (this.dom.icon) {
|
|
if (this.dom.icon) {
|
|
|
- this._destroyLottieIcon();
|
|
|
|
|
|
|
+ this._destroySvgAniIcon();
|
|
|
this.dom.icon.remove();
|
|
this.dom.icon.remove();
|
|
|
}
|
|
}
|
|
|
this.dom.icon = this._createIcon(this.params.icon);
|
|
this.dom.icon = this._createIcon(this.params.icon);
|
|
@@ -1983,9 +2035,9 @@
|
|
|
_isSameIconType(iconEl, type) {
|
|
_isSameIconType(iconEl, type) {
|
|
|
if (!iconEl) return false;
|
|
if (!iconEl) return false;
|
|
|
const raw = String(type || '').trim();
|
|
const raw = String(type || '').trim();
|
|
|
- if (isLottieIcon(raw)) {
|
|
|
|
|
- const name = getLottieIconName(raw);
|
|
|
|
|
- return iconEl.dataset && iconEl.dataset.lottie === name;
|
|
|
|
|
|
|
+ if (isSvgAniIcon(raw)) {
|
|
|
|
|
+ const name = getSvgAniIconName(raw);
|
|
|
|
|
+ return iconEl.dataset && iconEl.dataset.svgani === name;
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
return iconEl.classList && iconEl.classList.contains(raw);
|
|
return iconEl.classList && iconEl.classList.contains(raw);
|
|
@@ -1994,24 +2046,24 @@
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _destroyLottieIcon() {
|
|
|
|
|
|
|
+ _destroySvgAniIcon() {
|
|
|
const icon = this.dom && this.dom.icon;
|
|
const icon = this.dom && this.dom.icon;
|
|
|
if (!icon) return;
|
|
if (!icon) return;
|
|
|
- const inst = icon._lottieInstance;
|
|
|
|
|
|
|
+ const inst = icon._svgAniInstance;
|
|
|
if (inst && typeof inst.destroy === 'function') {
|
|
if (inst && typeof inst.destroy === 'function') {
|
|
|
try { inst.destroy(); } catch {}
|
|
try { inst.destroy(); } catch {}
|
|
|
}
|
|
}
|
|
|
- try { icon._lottieInstance = null; } catch {}
|
|
|
|
|
|
|
+ try { icon._svgAniInstance = null; } catch {}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _initLottieIcon(iconEl, name) {
|
|
|
|
|
|
|
+ _initSvgAniIcon(iconEl, name) {
|
|
|
if (!iconEl) return;
|
|
if (!iconEl) return;
|
|
|
- const container = iconEl.querySelector(`.${PREFIX}lottie`);
|
|
|
|
|
|
|
+ const container = iconEl.querySelector(`.${PREFIX}svgAni`);
|
|
|
if (!container) return;
|
|
if (!container) return;
|
|
|
const cleanName = String(name || '').trim();
|
|
const cleanName = String(name || '').trim();
|
|
|
if (!cleanName) return;
|
|
if (!cleanName) return;
|
|
|
|
|
|
|
|
- const url = resolveLottieJsonUrl(cleanName);
|
|
|
|
|
|
|
+ const url = resolveSvgAniJsonUrl(cleanName);
|
|
|
if (!url) return;
|
|
if (!url) return;
|
|
|
|
|
|
|
|
const wantsLoop = (this.params && typeof this.params.iconLoop === 'boolean')
|
|
const wantsLoop = (this.params && typeof this.params.iconLoop === 'boolean')
|
|
@@ -2022,7 +2074,7 @@
|
|
|
const showError = (msg) => {
|
|
const showError = (msg) => {
|
|
|
try {
|
|
try {
|
|
|
container.textContent = String(msg || '');
|
|
container.textContent = String(msg || '');
|
|
|
- container.classList.add(`${PREFIX}lottie-error`);
|
|
|
|
|
|
|
+ container.classList.add(`${PREFIX}svgAni-error`);
|
|
|
} catch {}
|
|
} catch {}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -2054,12 +2106,13 @@
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
(async () => {
|
|
(async () => {
|
|
|
- const lottie = await ensureLottieLib();
|
|
|
|
|
- if (!lottie) {
|
|
|
|
|
- showError('Lottie lib not loaded.');
|
|
|
|
|
|
|
+ const svgAniLib = await ensureSvgAniLib();
|
|
|
|
|
+ if (!svgAniLib) {
|
|
|
|
|
+ showError('SvgAni lib not loaded.');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- if (!iconEl.isConnected) return;
|
|
|
|
|
|
|
+ const connected = await waitForConnected(iconEl);
|
|
|
|
|
+ if (!connected) return;
|
|
|
let data = null;
|
|
let data = null;
|
|
|
try { data = await loadData(); } catch {}
|
|
try { data = await loadData(); } catch {}
|
|
|
if (!data) {
|
|
if (!data) {
|
|
@@ -2068,14 +2121,14 @@
|
|
|
}
|
|
}
|
|
|
if (!iconEl.isConnected) return;
|
|
if (!iconEl.isConnected) return;
|
|
|
try {
|
|
try {
|
|
|
- const anim = lottie.loadAnimation({
|
|
|
|
|
|
|
+ const anim = svgAniLib.loadAnimation({
|
|
|
container,
|
|
container,
|
|
|
renderer: 'svg',
|
|
renderer: 'svg',
|
|
|
loop: wantsLoop,
|
|
loop: wantsLoop,
|
|
|
autoplay: wantsAutoplay,
|
|
autoplay: wantsAutoplay,
|
|
|
animationData: data
|
|
animationData: data
|
|
|
});
|
|
});
|
|
|
- iconEl._lottieInstance = anim;
|
|
|
|
|
|
|
+ iconEl._svgAniInstance = anim;
|
|
|
if (!wantsAutoplay && anim && typeof anim.goToAndStop === 'function') {
|
|
if (!wantsAutoplay && anim && typeof anim.goToAndStop === 'function') {
|
|
|
anim.goToAndStop(0, true);
|
|
anim.goToAndStop(0, true);
|
|
|
}
|
|
}
|
|
@@ -2086,13 +2139,14 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
_rerenderInside() {
|
|
_rerenderInside() {
|
|
|
- this._destroyLottieIcon();
|
|
|
|
|
|
|
+ this._destroySvgAniIcon();
|
|
|
// Update popup content without recreating overlay (used in flow transitions)
|
|
// Update popup content without recreating overlay (used in flow transitions)
|
|
|
const popup = this.dom && this.dom.popup;
|
|
const popup = this.dom && this.dom.popup;
|
|
|
if (!popup) return;
|
|
if (!popup) return;
|
|
|
|
|
|
|
|
// Clear popup (but keep reference)
|
|
// Clear popup (but keep reference)
|
|
|
while (popup.firstChild) popup.removeChild(popup.firstChild);
|
|
while (popup.firstChild) popup.removeChild(popup.firstChild);
|
|
|
|
|
+ this._applyPopupTheme(this.params);
|
|
|
|
|
|
|
|
// Icon
|
|
// Icon
|
|
|
this.dom.icon = null;
|
|
this.dom.icon = null;
|