@deot/vc-components 1.0.50 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +108 -16
- package/dist/index.d.ts +80 -28
- package/dist/index.iife.js +4261 -38
- package/dist/index.js +107 -15
- package/dist/index.style.css +1 -1
- package/dist/index.umd.cjs +4261 -38
- package/package.json +2 -1
package/dist/index.iife.js
CHANGED
|
@@ -197,7 +197,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
197
197
|
return target;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
const getStyle$
|
|
200
|
+
const getStyle$2 = (el, name) => {
|
|
201
201
|
if (IS_SERVER$3 || !name) return "";
|
|
202
202
|
if (name === "float") {
|
|
203
203
|
name = "cssFloat";
|
|
@@ -213,8 +213,8 @@ var VcComponents = (function (exports, vue) {
|
|
|
213
213
|
const isScroller = (el, options) => {
|
|
214
214
|
if (IS_SERVER$3 || !el) return false;
|
|
215
215
|
const { className, direction } = options || {};
|
|
216
|
-
let overflow = getStyle$
|
|
217
|
-
overflow = overflow || getStyle$
|
|
216
|
+
let overflow = getStyle$2(el, `overflow-${direction ? "y" : "x"}`);
|
|
217
|
+
overflow = overflow || getStyle$2(el, "overflow");
|
|
218
218
|
return !!(overflow.match(/(scroll|auto)/) || className?.test(el.className));
|
|
219
219
|
};
|
|
220
220
|
|
|
@@ -7789,23 +7789,23 @@ var VcComponents = (function (exports, vue) {
|
|
|
7789
7789
|
...listeners
|
|
7790
7790
|
}), {
|
|
7791
7791
|
prepend: slots.prepend && (() => slots.prepend?.()),
|
|
7792
|
-
append:
|
|
7792
|
+
append: slots.append ? () => slots.append?.() : props.step ? () => {
|
|
7793
7793
|
return vue.createVNode("div", {
|
|
7794
7794
|
"class": "vc-input-number__icon"
|
|
7795
7795
|
}, [vue.createVNode("div", {
|
|
7796
7796
|
"class": "vc-input-number__up",
|
|
7797
|
-
"disabled": plusDisabled.value ? 'disabled' :
|
|
7797
|
+
"disabled": plusDisabled.value ? 'disabled' : void 0,
|
|
7798
7798
|
"onClick": e => handleStepper(e, 1)
|
|
7799
7799
|
}, [vue.createVNode(Icon, {
|
|
7800
7800
|
"type": "up"
|
|
7801
7801
|
}, null)]), vue.createVNode("div", {
|
|
7802
7802
|
"class": "vc-input-number__down",
|
|
7803
|
-
"disabled": minusDisabled.value ? 'disabled' :
|
|
7803
|
+
"disabled": minusDisabled.value ? 'disabled' : void 0,
|
|
7804
7804
|
"onClick": e => handleStepper(e, -1)
|
|
7805
7805
|
}, [vue.createVNode(Icon, {
|
|
7806
7806
|
"type": "down"
|
|
7807
7807
|
}, null)])]);
|
|
7808
|
-
} :
|
|
7808
|
+
} : void 0
|
|
7809
7809
|
});
|
|
7810
7810
|
};
|
|
7811
7811
|
}
|
|
@@ -17028,7 +17028,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
17028
17028
|
* @returns {boolean}
|
|
17029
17029
|
*/
|
|
17030
17030
|
|
|
17031
|
-
function isSafari$
|
|
17031
|
+
function isSafari$2() {
|
|
17032
17032
|
return !!(navigator.vendor && navigator.vendor.match(/apple/i));
|
|
17033
17033
|
}
|
|
17034
17034
|
|
|
@@ -17906,7 +17906,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
17906
17906
|
// that's because I want to show image before it's fully loaded,
|
|
17907
17907
|
// as browser can render parts of image while it is loading.
|
|
17908
17908
|
// We do not do this in Safari due to partial loading bug.
|
|
17909
|
-
if (supportsDecode && this.slide && (!this.slide.isActive || isSafari$
|
|
17909
|
+
if (supportsDecode && this.slide && (!this.slide.isActive || isSafari$2())) {
|
|
17910
17910
|
this.isDecoding = true; // purposefully using finally instead of then,
|
|
17911
17911
|
// as if srcset sizes changes dynamically - it may cause decode error
|
|
17912
17912
|
|
|
@@ -17937,7 +17937,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
17937
17937
|
return;
|
|
17938
17938
|
}
|
|
17939
17939
|
|
|
17940
|
-
if (this.isImageContent() && this.isDecoding && !isSafari$
|
|
17940
|
+
if (this.isImageContent() && this.isDecoding && !isSafari$2()) {
|
|
17941
17941
|
// add image to slide when it becomes active,
|
|
17942
17942
|
// even if it's not finished decoding
|
|
17943
17943
|
this.appendImage();
|
|
@@ -20657,27 +20657,109 @@ var VcComponents = (function (exports, vue) {
|
|
|
20657
20657
|
tag: {
|
|
20658
20658
|
type: String,
|
|
20659
20659
|
default: "div"
|
|
20660
|
+
},
|
|
20661
|
+
// useCORS
|
|
20662
|
+
crossOrigin: {
|
|
20663
|
+
type: String,
|
|
20664
|
+
// ''. 'anonymous', 'use-credentials'
|
|
20665
|
+
default: "anonymous",
|
|
20666
|
+
validator: (v) => /^(|anonymous|use-credentials)$/.test(v)
|
|
20667
|
+
},
|
|
20668
|
+
transformSource: Function,
|
|
20669
|
+
// 传递给snap-dom的配置项
|
|
20670
|
+
options: {
|
|
20671
|
+
type: Object,
|
|
20672
|
+
default: () => ({})
|
|
20660
20673
|
}
|
|
20661
20674
|
};
|
|
20662
20675
|
|
|
20663
20676
|
/** @jsxImportSource vue */
|
|
20664
20677
|
|
|
20665
|
-
const COMPONENT_NAME$Z = 'vc-
|
|
20666
|
-
const
|
|
20678
|
+
const COMPONENT_NAME$Z = 'vc-snapshot';
|
|
20679
|
+
const Snapshot = /* @__PURE__ */ vue.defineComponent({
|
|
20667
20680
|
name: COMPONENT_NAME$Z,
|
|
20668
20681
|
props: props$H,
|
|
20682
|
+
emits: ['ready'],
|
|
20669
20683
|
setup(props, {
|
|
20670
|
-
|
|
20684
|
+
emit,
|
|
20685
|
+
slots,
|
|
20686
|
+
expose
|
|
20671
20687
|
}) {
|
|
20688
|
+
const current = vue.ref();
|
|
20689
|
+
const instance = vue.ref();
|
|
20690
|
+
|
|
20691
|
+
// 网络的图片如果没有加上crossOrigin,且没有放在第一个就会出现问题(Safari)
|
|
20692
|
+
const refresh = async () => {
|
|
20693
|
+
if (!props.crossOrigin) return;
|
|
20694
|
+
const transformSource = props.transformSource || VcInstance.options.Snapshot?.transformSource || (v => v);
|
|
20695
|
+
return Promise.all(Array.from(current.value.querySelectorAll('img')).map(node => {
|
|
20696
|
+
return new Promise(resolve => {
|
|
20697
|
+
(async () => {
|
|
20698
|
+
let url;
|
|
20699
|
+
try {
|
|
20700
|
+
url = await transformSource(node.src);
|
|
20701
|
+
} catch (e) {
|
|
20702
|
+
console.error(e);
|
|
20703
|
+
}
|
|
20704
|
+
const image = new Image();
|
|
20705
|
+
image.crossOrigin = props.crossOrigin;
|
|
20706
|
+
image.src = `${url}?=${new Date().getTime()}`; // 强制不缓存
|
|
20707
|
+
image.onload = () => {
|
|
20708
|
+
node.src = image.src;
|
|
20709
|
+
resolve(1);
|
|
20710
|
+
};
|
|
20711
|
+
image.onerror = () => resolve(0);
|
|
20712
|
+
})();
|
|
20713
|
+
});
|
|
20714
|
+
}));
|
|
20715
|
+
};
|
|
20716
|
+
const toDataURL = async () => {
|
|
20717
|
+
await refresh();
|
|
20718
|
+
return instance.value.toRaw();
|
|
20719
|
+
};
|
|
20720
|
+
const download = async options => {
|
|
20721
|
+
await refresh();
|
|
20722
|
+
const _download = VcInstance.options.Snapshot?.download || (() => false);
|
|
20723
|
+
const allow = _download(options);
|
|
20724
|
+
if (allow && allow.then) {
|
|
20725
|
+
allow.catch(() => {
|
|
20726
|
+
instance.value.download(options);
|
|
20727
|
+
});
|
|
20728
|
+
return;
|
|
20729
|
+
}
|
|
20730
|
+
allow || instance.value.download(options);
|
|
20731
|
+
};
|
|
20732
|
+
expose({
|
|
20733
|
+
instance,
|
|
20734
|
+
refresh,
|
|
20735
|
+
toDataURL,
|
|
20736
|
+
download
|
|
20737
|
+
});
|
|
20738
|
+
vue.onMounted(async () => {
|
|
20739
|
+
try {
|
|
20740
|
+
let snapDOM = window.snapdom || (await Promise.resolve().then(() => snapdom$1));
|
|
20741
|
+
snapDOM = snapDOM.snapdom || snapDOM;
|
|
20742
|
+
instance.value = await snapDOM(current.value, props.options);
|
|
20743
|
+
emit('ready', {
|
|
20744
|
+
instance: instance.value,
|
|
20745
|
+
dependencies: {
|
|
20746
|
+
snapDOM
|
|
20747
|
+
}
|
|
20748
|
+
});
|
|
20749
|
+
} catch (e) {
|
|
20750
|
+
throw new VcError('snapshot', e);
|
|
20751
|
+
}
|
|
20752
|
+
});
|
|
20672
20753
|
return () => {
|
|
20673
20754
|
return vue.createVNode("div", {
|
|
20674
|
-
"
|
|
20755
|
+
"ref": current,
|
|
20756
|
+
"class": "vc-snapshot"
|
|
20675
20757
|
}, [slots?.default?.()]);
|
|
20676
20758
|
};
|
|
20677
20759
|
}
|
|
20678
20760
|
});
|
|
20679
20761
|
|
|
20680
|
-
const
|
|
20762
|
+
const MSnapshot = Snapshot;
|
|
20681
20763
|
|
|
20682
20764
|
const MIcon = Icon;
|
|
20683
20765
|
|
|
@@ -24350,6 +24432,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
24350
24432
|
checked,
|
|
24351
24433
|
classes,
|
|
24352
24434
|
computedLabel,
|
|
24435
|
+
isDisabled,
|
|
24353
24436
|
handleChange,
|
|
24354
24437
|
handleFocus,
|
|
24355
24438
|
handleBlur
|
|
@@ -24369,7 +24452,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
24369
24452
|
}, null)]), vue.createVNode("input", {
|
|
24370
24453
|
"checked": checked.value,
|
|
24371
24454
|
"name": radioName.value,
|
|
24372
|
-
"disabled":
|
|
24455
|
+
"disabled": isDisabled.value,
|
|
24373
24456
|
"type": "radio",
|
|
24374
24457
|
"onChange": handleChange,
|
|
24375
24458
|
"onFocus": handleFocus,
|
|
@@ -24384,7 +24467,11 @@ var VcComponents = (function (exports, vue) {
|
|
|
24384
24467
|
const COMPONENT_NAME$x = 'vc-radio-button';
|
|
24385
24468
|
const RadioButton = /* @__PURE__ */ vue.defineComponent({
|
|
24386
24469
|
name: COMPONENT_NAME$x,
|
|
24387
|
-
props:
|
|
24470
|
+
props: {
|
|
24471
|
+
...props$m,
|
|
24472
|
+
labelStyle: [String, Object],
|
|
24473
|
+
labelClass: [String, Object]
|
|
24474
|
+
},
|
|
24388
24475
|
emits: ['update:modelValue', 'change'],
|
|
24389
24476
|
setup(props, {
|
|
24390
24477
|
slots
|
|
@@ -24395,6 +24482,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
24395
24482
|
checked,
|
|
24396
24483
|
classes,
|
|
24397
24484
|
computedLabel,
|
|
24485
|
+
isDisabled,
|
|
24398
24486
|
handleChange,
|
|
24399
24487
|
handleFocus,
|
|
24400
24488
|
handleBlur
|
|
@@ -24406,12 +24494,15 @@ var VcComponents = (function (exports, vue) {
|
|
|
24406
24494
|
}, [vue.createVNode("input", {
|
|
24407
24495
|
"checked": checked.value,
|
|
24408
24496
|
"name": radioName.value,
|
|
24409
|
-
"disabled":
|
|
24497
|
+
"disabled": isDisabled.value,
|
|
24410
24498
|
"type": "radio",
|
|
24411
24499
|
"onChange": handleChange,
|
|
24412
24500
|
"onFocus": handleFocus,
|
|
24413
24501
|
"onBlur": handleBlur
|
|
24414
|
-
}, null),
|
|
24502
|
+
}, null), vue.createVNode("span", {
|
|
24503
|
+
"class": [props.labelClass, 'vc-radio-button__label'],
|
|
24504
|
+
"style": props.labelStyle
|
|
24505
|
+
}, [slots.default ? slots.default() : computedLabel.value || ''])]);
|
|
24415
24506
|
};
|
|
24416
24507
|
}
|
|
24417
24508
|
});
|
|
@@ -24525,6 +24616,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
24525
24616
|
checked,
|
|
24526
24617
|
classes,
|
|
24527
24618
|
computedLabel,
|
|
24619
|
+
isDisabled,
|
|
24528
24620
|
handleChange,
|
|
24529
24621
|
handleFocus,
|
|
24530
24622
|
handleBlur
|
|
@@ -24544,7 +24636,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
24544
24636
|
}, null)]), vue.createVNode("input", {
|
|
24545
24637
|
"checked": checked.value,
|
|
24546
24638
|
"name": radioName.value,
|
|
24547
|
-
"disabled":
|
|
24639
|
+
"disabled": isDisabled.value,
|
|
24548
24640
|
"type": "radio",
|
|
24549
24641
|
"onChange": handleChange,
|
|
24550
24642
|
"onFocus": handleFocus,
|
|
@@ -27189,7 +27281,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
27189
27281
|
let hiddenEl$1;
|
|
27190
27282
|
const getFitIndex = (options = {}) => {
|
|
27191
27283
|
const { el, line, value, suffix, indent = 0 } = options;
|
|
27192
|
-
let lineHeight = parseInt(getStyle$
|
|
27284
|
+
let lineHeight = parseInt(getStyle$2(el, "line-height"), 10);
|
|
27193
27285
|
if (!hiddenEl$1) {
|
|
27194
27286
|
hiddenEl$1 = document.createElement("div");
|
|
27195
27287
|
document.body.appendChild(hiddenEl$1);
|
|
@@ -27201,7 +27293,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
27201
27293
|
boxSizing,
|
|
27202
27294
|
sizingStyle
|
|
27203
27295
|
} = utils.getComputedStyle(el, SIZING_STYLE$1);
|
|
27204
|
-
const textIndent = `text-indent: ${parseInt(getStyle$
|
|
27296
|
+
const textIndent = `text-indent: ${parseInt(getStyle$2(el, "text-indent"), 10) + indent}px;`;
|
|
27205
27297
|
hiddenEl$1.setAttribute("style", `${sizingStyle};${textIndent};${HIDDEN_TEXT_STYLE}`);
|
|
27206
27298
|
let sideHeight = paddingSize || 0;
|
|
27207
27299
|
boxSizing === "border-box" && (sideHeight += borderSize);
|
|
@@ -56010,10 +56102,10 @@ var VcComponents = (function (exports, vue) {
|
|
|
56010
56102
|
return styleChanged;
|
|
56011
56103
|
}
|
|
56012
56104
|
function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) {
|
|
56013
|
-
var style = getStyle(el, scope.inHover);
|
|
56105
|
+
var style = getStyle$1(el, scope.inHover);
|
|
56014
56106
|
var prevStyle = forceSetAll
|
|
56015
56107
|
? null
|
|
56016
|
-
: (prevEl && getStyle(prevEl, scope.inHover) || {});
|
|
56108
|
+
: (prevEl && getStyle$1(prevEl, scope.inHover) || {});
|
|
56017
56109
|
if (style === prevStyle) {
|
|
56018
56110
|
return false;
|
|
56019
56111
|
}
|
|
@@ -56064,7 +56156,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
56064
56156
|
return styleChanged;
|
|
56065
56157
|
}
|
|
56066
56158
|
function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) {
|
|
56067
|
-
return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope);
|
|
56159
|
+
return bindCommonProps(ctx, getStyle$1(el, scope.inHover), prevEl && getStyle$1(prevEl, scope.inHover), forceSetAll, scope);
|
|
56068
56160
|
}
|
|
56069
56161
|
function setContextTransform(ctx, el) {
|
|
56070
56162
|
var m = el.transform;
|
|
@@ -56123,7 +56215,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
56123
56215
|
scope.batchFill = '';
|
|
56124
56216
|
scope.batchStroke = '';
|
|
56125
56217
|
}
|
|
56126
|
-
function getStyle(el, inHover) {
|
|
56218
|
+
function getStyle$1(el, inHover) {
|
|
56127
56219
|
return inHover ? (el.__hoverStyle || el.style) : el.style;
|
|
56128
56220
|
}
|
|
56129
56221
|
function brushSingle(ctx, el) {
|
|
@@ -56177,7 +56269,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
56177
56269
|
else if (!canBatchPath) {
|
|
56178
56270
|
flushPathDrawn(ctx, scope);
|
|
56179
56271
|
}
|
|
56180
|
-
var style = getStyle(el, scope.inHover);
|
|
56272
|
+
var style = getStyle$1(el, scope.inHover);
|
|
56181
56273
|
if (el instanceof Path) {
|
|
56182
56274
|
if (scope.lastDrawType !== DRAW_TYPE_PATH) {
|
|
56183
56275
|
forceSetStyle = true;
|
|
@@ -73564,7 +73656,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
73564
73656
|
if (!coordSys.axisPointerEnabled) {
|
|
73565
73657
|
return;
|
|
73566
73658
|
}
|
|
73567
|
-
var coordSysKey = makeKey(coordSys.model);
|
|
73659
|
+
var coordSysKey = makeKey$1(coordSys.model);
|
|
73568
73660
|
var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};
|
|
73569
73661
|
result.coordSysMap[coordSysKey] = coordSys;
|
|
73570
73662
|
// Set tooltip (like 'cross') is a convenient way to show axisPointer
|
|
@@ -73604,7 +73696,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
73604
73696
|
axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel;
|
|
73605
73697
|
var snap = axisPointerModel.get('snap');
|
|
73606
73698
|
var triggerEmphasis = axisPointerModel.get('triggerEmphasis');
|
|
73607
|
-
var axisKey = makeKey(axis.model);
|
|
73699
|
+
var axisKey = makeKey$1(axis.model);
|
|
73608
73700
|
var involveSeries = triggerTooltip || snap || axis.type === 'category';
|
|
73609
73701
|
// If result.axesInfo[key] exist, override it (tooltip has higher priority).
|
|
73610
73702
|
var axisInfo = result.axesInfo[axisKey] = {
|
|
@@ -73676,7 +73768,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
73676
73768
|
if (!coordSys || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) {
|
|
73677
73769
|
return;
|
|
73678
73770
|
}
|
|
73679
|
-
each$f(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {
|
|
73771
|
+
each$f(result.coordSysAxesInfo[makeKey$1(coordSys.model)], function (axisInfo) {
|
|
73680
73772
|
var axis = axisInfo.axis;
|
|
73681
73773
|
if (coordSys.getAxis(axis.dim) === axis) {
|
|
73682
73774
|
axisInfo.seriesModels.push(seriesModel);
|
|
@@ -73754,7 +73846,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
73754
73846
|
}
|
|
73755
73847
|
function getAxisInfo$1(axisModel) {
|
|
73756
73848
|
var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;
|
|
73757
|
-
return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];
|
|
73849
|
+
return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey$1(axisModel)];
|
|
73758
73850
|
}
|
|
73759
73851
|
function getAxisPointerModel(axisModel) {
|
|
73760
73852
|
var axisInfo = getAxisInfo$1(axisModel);
|
|
@@ -73767,7 +73859,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
73767
73859
|
* @param {module:echarts/model/Model} model
|
|
73768
73860
|
* @return {string} unique key
|
|
73769
73861
|
*/
|
|
73770
|
-
function makeKey(model) {
|
|
73862
|
+
function makeKey$1(model) {
|
|
73771
73863
|
return model.type + '||' + model.id;
|
|
73772
73864
|
}
|
|
73773
73865
|
|
|
@@ -96060,7 +96152,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
96060
96152
|
return;
|
|
96061
96153
|
}
|
|
96062
96154
|
var coordSysModel = axisInfo.coordSys.model;
|
|
96063
|
-
var coordSysKey = makeKey(coordSysModel);
|
|
96155
|
+
var coordSysKey = makeKey$1(coordSysModel);
|
|
96064
96156
|
var coordSysItem = dataByCoordSys.map[coordSysKey];
|
|
96065
96157
|
if (!coordSysItem) {
|
|
96066
96158
|
coordSysItem = dataByCoordSys.map[coordSysKey] = {
|
|
@@ -113289,7 +113381,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
113289
113381
|
* @returns {boolean}
|
|
113290
113382
|
*/
|
|
113291
113383
|
|
|
113292
|
-
function isSafari() {
|
|
113384
|
+
function isSafari$1() {
|
|
113293
113385
|
return !!(navigator.vendor && navigator.vendor.match(/apple/i));
|
|
113294
113386
|
}
|
|
113295
113387
|
|
|
@@ -118324,7 +118416,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
118324
118416
|
// that's because I want to show image before it's fully loaded,
|
|
118325
118417
|
// as browser can render parts of image while it is loading.
|
|
118326
118418
|
// We do not do this in Safari due to partial loading bug.
|
|
118327
|
-
if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {
|
|
118419
|
+
if (supportsDecode && this.slide && (!this.slide.isActive || isSafari$1())) {
|
|
118328
118420
|
this.isDecoding = true; // purposefully using finally instead of then,
|
|
118329
118421
|
// as if srcset sizes changes dynamically - it may cause decode error
|
|
118330
118422
|
|
|
@@ -118355,7 +118447,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
118355
118447
|
return;
|
|
118356
118448
|
}
|
|
118357
118449
|
|
|
118358
|
-
if (this.isImageContent() && this.isDecoding && !isSafari()) {
|
|
118450
|
+
if (this.isImageContent() && this.isDecoding && !isSafari$1()) {
|
|
118359
118451
|
// add image to slide when it becomes active,
|
|
118360
118452
|
// even if it's not finished decoding
|
|
118361
118453
|
this.appendImage();
|
|
@@ -133182,6 +133274,4137 @@ var VcComponents = (function (exports, vue) {
|
|
|
133182
133274
|
default: Quill
|
|
133183
133275
|
}, Symbol.toStringTag, { value: 'Module' }));
|
|
133184
133276
|
|
|
133277
|
+
/*
|
|
133278
|
+
* snapdom
|
|
133279
|
+
* v.1.9.14
|
|
133280
|
+
* Author Juan Martin Muda
|
|
133281
|
+
* License MIT
|
|
133282
|
+
**/
|
|
133283
|
+
|
|
133284
|
+
|
|
133285
|
+
// src/core/cache.js
|
|
133286
|
+
var cache = {
|
|
133287
|
+
image: /* @__PURE__ */ new Map(),
|
|
133288
|
+
background: /* @__PURE__ */ new Map(),
|
|
133289
|
+
resource: /* @__PURE__ */ new Map(),
|
|
133290
|
+
defaultStyle: /* @__PURE__ */ new Map(),
|
|
133291
|
+
baseStyle: /* @__PURE__ */ new Map(),
|
|
133292
|
+
computedStyle: /* @__PURE__ */ new WeakMap(),
|
|
133293
|
+
font: /* @__PURE__ */ new Set(),
|
|
133294
|
+
session: {
|
|
133295
|
+
styleMap: /* @__PURE__ */ new Map(),
|
|
133296
|
+
styleCache: /* @__PURE__ */ new WeakMap(),
|
|
133297
|
+
nodeMap: /* @__PURE__ */ new Map()
|
|
133298
|
+
}
|
|
133299
|
+
};
|
|
133300
|
+
function applyCachePolicy(policy = "soft") {
|
|
133301
|
+
switch (policy) {
|
|
133302
|
+
case "auto": {
|
|
133303
|
+
cache.session.styleMap = /* @__PURE__ */ new Map();
|
|
133304
|
+
cache.session.nodeMap = /* @__PURE__ */ new Map();
|
|
133305
|
+
return;
|
|
133306
|
+
}
|
|
133307
|
+
case "soft": {
|
|
133308
|
+
cache.session.styleMap = /* @__PURE__ */ new Map();
|
|
133309
|
+
cache.session.nodeMap = /* @__PURE__ */ new Map();
|
|
133310
|
+
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
133311
|
+
return;
|
|
133312
|
+
}
|
|
133313
|
+
case "full": {
|
|
133314
|
+
return;
|
|
133315
|
+
}
|
|
133316
|
+
case "disabled": {
|
|
133317
|
+
cache.session.styleMap = /* @__PURE__ */ new Map();
|
|
133318
|
+
cache.session.nodeMap = /* @__PURE__ */ new Map();
|
|
133319
|
+
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
133320
|
+
cache.computedStyle = /* @__PURE__ */ new WeakMap();
|
|
133321
|
+
cache.baseStyle = /* @__PURE__ */ new Map();
|
|
133322
|
+
cache.defaultStyle = /* @__PURE__ */ new Map();
|
|
133323
|
+
cache.image = /* @__PURE__ */ new Map();
|
|
133324
|
+
cache.background = /* @__PURE__ */ new Map();
|
|
133325
|
+
cache.resource = /* @__PURE__ */ new Map();
|
|
133326
|
+
cache.font = /* @__PURE__ */ new Set();
|
|
133327
|
+
return;
|
|
133328
|
+
}
|
|
133329
|
+
default: {
|
|
133330
|
+
cache.session.styleMap = /* @__PURE__ */ new Map();
|
|
133331
|
+
cache.session.nodeMap = /* @__PURE__ */ new Map();
|
|
133332
|
+
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
133333
|
+
return;
|
|
133334
|
+
}
|
|
133335
|
+
}
|
|
133336
|
+
}
|
|
133337
|
+
|
|
133338
|
+
// src/utils/helpers.js
|
|
133339
|
+
function extractURL(value) {
|
|
133340
|
+
const match = value.match(/url\((['"]?)(.*?)(\1)\)/);
|
|
133341
|
+
if (!match) return null;
|
|
133342
|
+
const url = match[2].trim();
|
|
133343
|
+
if (url.startsWith("#")) return null;
|
|
133344
|
+
return url;
|
|
133345
|
+
}
|
|
133346
|
+
function stripTranslate(transform) {
|
|
133347
|
+
if (!transform || transform === "none") return "";
|
|
133348
|
+
let cleaned = transform.replace(/translate[XY]?\([^)]*\)/g, "");
|
|
133349
|
+
cleaned = cleaned.replace(/matrix\(([^)]+)\)/g, (_, values) => {
|
|
133350
|
+
const parts = values.split(",").map((s) => s.trim());
|
|
133351
|
+
if (parts.length !== 6) return `matrix(${values})`;
|
|
133352
|
+
parts[4] = "0";
|
|
133353
|
+
parts[5] = "0";
|
|
133354
|
+
return `matrix(${parts.join(", ")})`;
|
|
133355
|
+
});
|
|
133356
|
+
cleaned = cleaned.replace(/matrix3d\(([^)]+)\)/g, (_, values) => {
|
|
133357
|
+
const parts = values.split(",").map((s) => s.trim());
|
|
133358
|
+
if (parts.length !== 16) return `matrix3d(${values})`;
|
|
133359
|
+
parts[12] = "0";
|
|
133360
|
+
parts[13] = "0";
|
|
133361
|
+
return `matrix3d(${parts.join(", ")})`;
|
|
133362
|
+
});
|
|
133363
|
+
return cleaned.trim().replace(/\s{2,}/g, " ");
|
|
133364
|
+
}
|
|
133365
|
+
function safeEncodeURI(uri) {
|
|
133366
|
+
if (/%[0-9A-Fa-f]{2}/.test(uri)) return uri;
|
|
133367
|
+
try {
|
|
133368
|
+
return encodeURI(uri);
|
|
133369
|
+
} catch {
|
|
133370
|
+
return uri;
|
|
133371
|
+
}
|
|
133372
|
+
}
|
|
133373
|
+
|
|
133374
|
+
// src/modules/snapFetch.js
|
|
133375
|
+
function createSnapLogger(prefix = "[snapDOM]", { ttlMs = 5 * 6e4, maxEntries = 12 } = {}) {
|
|
133376
|
+
const seen = /* @__PURE__ */ new Map();
|
|
133377
|
+
let emitted = 0;
|
|
133378
|
+
function log(level, key, msg) {
|
|
133379
|
+
if (emitted >= maxEntries) return;
|
|
133380
|
+
const now = Date.now();
|
|
133381
|
+
const until = seen.get(key) || 0;
|
|
133382
|
+
if (until > now) return;
|
|
133383
|
+
seen.set(key, now + ttlMs);
|
|
133384
|
+
emitted++;
|
|
133385
|
+
if (level === "warn" && console && console.warn) console.warn(`${prefix} ${msg}`);
|
|
133386
|
+
else if (console && console.error) console.error(`${prefix} ${msg}`);
|
|
133387
|
+
}
|
|
133388
|
+
return {
|
|
133389
|
+
warnOnce(key, msg) {
|
|
133390
|
+
log("warn", key, msg);
|
|
133391
|
+
},
|
|
133392
|
+
errorOnce(key, msg) {
|
|
133393
|
+
log("error", key, msg);
|
|
133394
|
+
},
|
|
133395
|
+
reset() {
|
|
133396
|
+
seen.clear();
|
|
133397
|
+
emitted = 0;
|
|
133398
|
+
}
|
|
133399
|
+
};
|
|
133400
|
+
}
|
|
133401
|
+
var snapLogger = createSnapLogger("[snapDOM]", { ttlMs: 3 * 6e4, maxEntries: 10 });
|
|
133402
|
+
var _inflight = /* @__PURE__ */ new Map();
|
|
133403
|
+
var _errorCache = /* @__PURE__ */ new Map();
|
|
133404
|
+
function isSpecialURL(url) {
|
|
133405
|
+
return /^data:|^blob:|^about:blank$/i.test(url);
|
|
133406
|
+
}
|
|
133407
|
+
function isAlreadyProxied(url, useProxy) {
|
|
133408
|
+
try {
|
|
133409
|
+
const baseHref = typeof location !== "undefined" && location.href ? location.href : "http://localhost/";
|
|
133410
|
+
const proxyBaseRaw = useProxy.includes("{url}") ? useProxy.split("{url}")[0] : useProxy;
|
|
133411
|
+
const proxyBase = new URL(proxyBaseRaw || ".", baseHref);
|
|
133412
|
+
const u = new URL(url, baseHref);
|
|
133413
|
+
if (u.origin === proxyBase.origin) return true;
|
|
133414
|
+
const sp = u.searchParams;
|
|
133415
|
+
if (sp && (sp.has("url") || sp.has("target"))) return true;
|
|
133416
|
+
} catch {
|
|
133417
|
+
}
|
|
133418
|
+
return false;
|
|
133419
|
+
}
|
|
133420
|
+
function shouldProxy(url, useProxy) {
|
|
133421
|
+
if (!useProxy) return false;
|
|
133422
|
+
if (isSpecialURL(url)) return false;
|
|
133423
|
+
if (isAlreadyProxied(url, useProxy)) return false;
|
|
133424
|
+
try {
|
|
133425
|
+
const base = typeof location !== "undefined" && location.href ? location.href : "http://localhost/";
|
|
133426
|
+
const u = new URL(url, base);
|
|
133427
|
+
return typeof location !== "undefined" ? u.origin !== location.origin : true;
|
|
133428
|
+
} catch {
|
|
133429
|
+
return !!useProxy;
|
|
133430
|
+
}
|
|
133431
|
+
}
|
|
133432
|
+
function applyProxy(url, useProxy) {
|
|
133433
|
+
if (!useProxy) return url;
|
|
133434
|
+
if (useProxy.includes("{url}")) {
|
|
133435
|
+
return useProxy.replace("{urlRaw}", safeEncodeURI(url)).replace("{url}", encodeURIComponent(url));
|
|
133436
|
+
}
|
|
133437
|
+
if (/[?&]url=?$/.test(useProxy)) {
|
|
133438
|
+
return `${useProxy}${encodeURIComponent(url)}`;
|
|
133439
|
+
}
|
|
133440
|
+
if (useProxy.endsWith("?")) {
|
|
133441
|
+
return `${useProxy}url=${encodeURIComponent(url)}`;
|
|
133442
|
+
}
|
|
133443
|
+
if (useProxy.endsWith("/")) {
|
|
133444
|
+
return `${useProxy}${safeEncodeURI(url)}`;
|
|
133445
|
+
}
|
|
133446
|
+
const sep = useProxy.includes("?") ? "&" : "?";
|
|
133447
|
+
return `${useProxy}${sep}url=${encodeURIComponent(url)}`;
|
|
133448
|
+
}
|
|
133449
|
+
function blobToDataURL(blob) {
|
|
133450
|
+
return new Promise((res, rej) => {
|
|
133451
|
+
const fr = new FileReader();
|
|
133452
|
+
fr.onload = () => res(String(fr.result || ""));
|
|
133453
|
+
fr.onerror = () => rej(new Error("read_failed"));
|
|
133454
|
+
fr.readAsDataURL(blob);
|
|
133455
|
+
});
|
|
133456
|
+
}
|
|
133457
|
+
function makeKey(url, o) {
|
|
133458
|
+
return [
|
|
133459
|
+
o.as || "blob",
|
|
133460
|
+
o.timeout ?? 3e3,
|
|
133461
|
+
o.useProxy || "",
|
|
133462
|
+
o.errorTTL ?? 8e3,
|
|
133463
|
+
url
|
|
133464
|
+
].join("|");
|
|
133465
|
+
}
|
|
133466
|
+
async function snapFetch(url, options = {}) {
|
|
133467
|
+
const as = options.as ?? "blob";
|
|
133468
|
+
const timeout = options.timeout ?? 3e3;
|
|
133469
|
+
const useProxy = options.useProxy || "";
|
|
133470
|
+
const errorTTL = options.errorTTL ?? 8e3;
|
|
133471
|
+
const headers = options.headers || {};
|
|
133472
|
+
const silent = !!options.silent;
|
|
133473
|
+
if (/^data:/i.test(url)) {
|
|
133474
|
+
try {
|
|
133475
|
+
if (as === "text") {
|
|
133476
|
+
return { ok: true, data: String(url), status: 200, url, fromCache: false };
|
|
133477
|
+
}
|
|
133478
|
+
if (as === "dataURL") {
|
|
133479
|
+
return {
|
|
133480
|
+
ok: true,
|
|
133481
|
+
data: String(url),
|
|
133482
|
+
status: 200,
|
|
133483
|
+
url,
|
|
133484
|
+
fromCache: false,
|
|
133485
|
+
mime: String(url).slice(5).split(";")[0] || ""
|
|
133486
|
+
};
|
|
133487
|
+
}
|
|
133488
|
+
const [, meta = "", data = ""] = String(url).match(/^data:([^,]*),(.*)$/) || [];
|
|
133489
|
+
const isBase64 = /;base64/i.test(meta);
|
|
133490
|
+
const bin = isBase64 ? atob(data) : decodeURIComponent(data);
|
|
133491
|
+
const bytes = new Uint8Array([...bin].map((c) => c.charCodeAt(0)));
|
|
133492
|
+
const b = new Blob([bytes], { type: (meta || "").split(";")[0] || "" });
|
|
133493
|
+
return { ok: true, data: b, status: 200, url, fromCache: false, mime: b.type || "" };
|
|
133494
|
+
} catch {
|
|
133495
|
+
return { ok: false, data: null, status: 0, url, fromCache: false, reason: "special_url_error" };
|
|
133496
|
+
}
|
|
133497
|
+
}
|
|
133498
|
+
if (/^blob:/i.test(url)) {
|
|
133499
|
+
try {
|
|
133500
|
+
const resp = await fetch(url);
|
|
133501
|
+
if (!resp.ok) {
|
|
133502
|
+
return { ok: false, data: null, status: resp.status, url, fromCache: false, reason: "http_error" };
|
|
133503
|
+
}
|
|
133504
|
+
const blob = await resp.blob();
|
|
133505
|
+
const mime = blob.type || resp.headers.get("content-type") || "";
|
|
133506
|
+
if (as === "dataURL") {
|
|
133507
|
+
const dataURL = await blobToDataURL(blob);
|
|
133508
|
+
return { ok: true, data: dataURL, status: resp.status, url, fromCache: false, mime };
|
|
133509
|
+
}
|
|
133510
|
+
if (as === "text") {
|
|
133511
|
+
const text = await blob.text();
|
|
133512
|
+
return { ok: true, data: text, status: resp.status, url, fromCache: false, mime };
|
|
133513
|
+
}
|
|
133514
|
+
return { ok: true, data: blob, status: resp.status, url, fromCache: false, mime };
|
|
133515
|
+
} catch {
|
|
133516
|
+
return { ok: false, data: null, status: 0, url, fromCache: false, reason: "network" };
|
|
133517
|
+
}
|
|
133518
|
+
}
|
|
133519
|
+
if (/^about:blank$/i.test(url)) {
|
|
133520
|
+
if (as === "dataURL") {
|
|
133521
|
+
return {
|
|
133522
|
+
ok: true,
|
|
133523
|
+
data: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==",
|
|
133524
|
+
status: 200,
|
|
133525
|
+
url,
|
|
133526
|
+
fromCache: false,
|
|
133527
|
+
mime: "image/png"
|
|
133528
|
+
};
|
|
133529
|
+
}
|
|
133530
|
+
return { ok: true, data: as === "text" ? "" : new Blob([]), status: 200, url, fromCache: false };
|
|
133531
|
+
}
|
|
133532
|
+
const key = makeKey(url, { as, timeout, useProxy, errorTTL });
|
|
133533
|
+
const e = _errorCache.get(key);
|
|
133534
|
+
if (e && e.until > Date.now()) {
|
|
133535
|
+
return { ...e.result, fromCache: true };
|
|
133536
|
+
} else if (e) {
|
|
133537
|
+
_errorCache.delete(key);
|
|
133538
|
+
}
|
|
133539
|
+
const inflight = _inflight.get(key);
|
|
133540
|
+
if (inflight) return inflight;
|
|
133541
|
+
const finalURL = shouldProxy(url, useProxy) ? applyProxy(url, useProxy) : url;
|
|
133542
|
+
let cred = options.credentials;
|
|
133543
|
+
if (!cred) {
|
|
133544
|
+
try {
|
|
133545
|
+
const base = typeof location !== "undefined" && location.href ? location.href : "http://localhost/";
|
|
133546
|
+
const u = new URL(url, base);
|
|
133547
|
+
const sameOrigin = typeof location !== "undefined" && u.origin === location.origin;
|
|
133548
|
+
cred = sameOrigin ? "include" : "omit";
|
|
133549
|
+
} catch {
|
|
133550
|
+
cred = "omit";
|
|
133551
|
+
}
|
|
133552
|
+
}
|
|
133553
|
+
const ctrl = new AbortController();
|
|
133554
|
+
const timer = setTimeout(() => ctrl.abort("timeout"), timeout);
|
|
133555
|
+
const p = (async () => {
|
|
133556
|
+
try {
|
|
133557
|
+
const resp = await fetch(finalURL, { signal: ctrl.signal, credentials: cred, headers });
|
|
133558
|
+
if (!resp.ok) {
|
|
133559
|
+
const result = { ok: false, data: null, status: resp.status, url: finalURL, fromCache: false, reason: "http_error" };
|
|
133560
|
+
if (errorTTL > 0) _errorCache.set(key, { until: Date.now() + errorTTL, result });
|
|
133561
|
+
if (!silent) {
|
|
133562
|
+
const short = `${resp.status} ${resp.statusText || ""}`.trim();
|
|
133563
|
+
snapLogger.warnOnce(
|
|
133564
|
+
`http:${resp.status}:${as}:${new URL(url, location?.href ?? "http://localhost/").origin}`,
|
|
133565
|
+
`HTTP error ${short} while fetching ${as} ${url}`
|
|
133566
|
+
);
|
|
133567
|
+
}
|
|
133568
|
+
options.onError && options.onError(result);
|
|
133569
|
+
return result;
|
|
133570
|
+
}
|
|
133571
|
+
if (as === "text") {
|
|
133572
|
+
const text = await resp.text();
|
|
133573
|
+
return { ok: true, data: text, status: resp.status, url: finalURL, fromCache: false };
|
|
133574
|
+
}
|
|
133575
|
+
const blob = await resp.blob();
|
|
133576
|
+
const mime = blob.type || resp.headers.get("content-type") || "";
|
|
133577
|
+
if (as === "dataURL") {
|
|
133578
|
+
const dataURL = await blobToDataURL(blob);
|
|
133579
|
+
return { ok: true, data: dataURL, status: resp.status, url: finalURL, fromCache: false, mime };
|
|
133580
|
+
}
|
|
133581
|
+
return { ok: true, data: blob, status: resp.status, url: finalURL, fromCache: false, mime };
|
|
133582
|
+
} catch (err) {
|
|
133583
|
+
const reason = err && typeof err === "object" && "name" in err && err.name === "AbortError" ? String(err.message || "").includes("timeout") ? "timeout" : "abort" : "network";
|
|
133584
|
+
const result = { ok: false, data: null, status: 0, url: finalURL, fromCache: false, reason };
|
|
133585
|
+
if (!/^blob:/i.test(url) && errorTTL > 0) {
|
|
133586
|
+
_errorCache.set(key, { until: Date.now() + errorTTL, result });
|
|
133587
|
+
}
|
|
133588
|
+
if (!silent) {
|
|
133589
|
+
const k = `${reason}:${as}:${new URL(url, location?.href ?? "http://localhost/").origin}`;
|
|
133590
|
+
const tips = reason === "timeout" ? `Timeout after ${timeout}ms. Consider increasing timeout or using a proxy for ${url}` : reason === "abort" ? `Request aborted while fetching ${as} ${url}` : `Network/CORS issue while fetching ${as} ${url}. A proxy may be required`;
|
|
133591
|
+
snapLogger.errorOnce(k, tips);
|
|
133592
|
+
}
|
|
133593
|
+
options.onError && options.onError(result);
|
|
133594
|
+
return result;
|
|
133595
|
+
} finally {
|
|
133596
|
+
clearTimeout(timer);
|
|
133597
|
+
_inflight.delete(key);
|
|
133598
|
+
}
|
|
133599
|
+
})();
|
|
133600
|
+
_inflight.set(key, p);
|
|
133601
|
+
return p;
|
|
133602
|
+
}
|
|
133603
|
+
|
|
133604
|
+
// src/utils/image.js
|
|
133605
|
+
function createBackground(baseCanvas, backgroundColor) {
|
|
133606
|
+
if (!backgroundColor || !baseCanvas.width || !baseCanvas.height) {
|
|
133607
|
+
return baseCanvas;
|
|
133608
|
+
}
|
|
133609
|
+
const temp = document.createElement("canvas");
|
|
133610
|
+
temp.width = baseCanvas.width;
|
|
133611
|
+
temp.height = baseCanvas.height;
|
|
133612
|
+
const ctx = temp.getContext("2d");
|
|
133613
|
+
ctx.fillStyle = backgroundColor;
|
|
133614
|
+
ctx.fillRect(0, 0, temp.width, temp.height);
|
|
133615
|
+
ctx.drawImage(baseCanvas, 0, 0);
|
|
133616
|
+
return temp;
|
|
133617
|
+
}
|
|
133618
|
+
async function inlineSingleBackgroundEntry(entry, options = {}) {
|
|
133619
|
+
const isGradient = /^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(entry);
|
|
133620
|
+
if (isGradient || entry.trim() === "none") {
|
|
133621
|
+
return entry;
|
|
133622
|
+
}
|
|
133623
|
+
const rawUrl = extractURL(entry);
|
|
133624
|
+
if (!rawUrl) {
|
|
133625
|
+
return entry;
|
|
133626
|
+
}
|
|
133627
|
+
const encodedUrl = safeEncodeURI(rawUrl);
|
|
133628
|
+
if (cache.background.has(encodedUrl)) {
|
|
133629
|
+
const dataUrl = cache.background.get(encodedUrl);
|
|
133630
|
+
return dataUrl ? `url("${dataUrl}")` : "none";
|
|
133631
|
+
}
|
|
133632
|
+
try {
|
|
133633
|
+
const dataUrl = await snapFetch(encodedUrl, { as: "dataURL", useProxy: options.useProxy });
|
|
133634
|
+
if (dataUrl.ok) {
|
|
133635
|
+
cache.background.set(encodedUrl, dataUrl.data);
|
|
133636
|
+
return `url("${dataUrl.data}")`;
|
|
133637
|
+
}
|
|
133638
|
+
cache.background.set(encodedUrl, null);
|
|
133639
|
+
return "none";
|
|
133640
|
+
} catch {
|
|
133641
|
+
cache.background.set(encodedUrl, null);
|
|
133642
|
+
return "none";
|
|
133643
|
+
}
|
|
133644
|
+
}
|
|
133645
|
+
|
|
133646
|
+
// src/utils/css.js
|
|
133647
|
+
var NO_CAPTURE_TAGS = /* @__PURE__ */ new Set([
|
|
133648
|
+
"meta",
|
|
133649
|
+
"script",
|
|
133650
|
+
"noscript",
|
|
133651
|
+
"title",
|
|
133652
|
+
"link",
|
|
133653
|
+
"template"
|
|
133654
|
+
]);
|
|
133655
|
+
var NO_DEFAULTS_TAGS = /* @__PURE__ */ new Set([
|
|
133656
|
+
// non-painting / head stuff
|
|
133657
|
+
"meta",
|
|
133658
|
+
"link",
|
|
133659
|
+
"style",
|
|
133660
|
+
"title",
|
|
133661
|
+
"noscript",
|
|
133662
|
+
"script",
|
|
133663
|
+
"template",
|
|
133664
|
+
// SVG whole namespace (safe for LeaderLine/presentation attrs)
|
|
133665
|
+
"g",
|
|
133666
|
+
"defs",
|
|
133667
|
+
"use",
|
|
133668
|
+
"marker",
|
|
133669
|
+
"mask",
|
|
133670
|
+
"clipPath",
|
|
133671
|
+
"pattern",
|
|
133672
|
+
"path",
|
|
133673
|
+
"polygon",
|
|
133674
|
+
"polyline",
|
|
133675
|
+
"line",
|
|
133676
|
+
"circle",
|
|
133677
|
+
"ellipse",
|
|
133678
|
+
"rect",
|
|
133679
|
+
"filter",
|
|
133680
|
+
"lineargradient",
|
|
133681
|
+
"radialgradient",
|
|
133682
|
+
"stop"
|
|
133683
|
+
]);
|
|
133684
|
+
var commonTags = [
|
|
133685
|
+
"div",
|
|
133686
|
+
"span",
|
|
133687
|
+
"p",
|
|
133688
|
+
"a",
|
|
133689
|
+
"img",
|
|
133690
|
+
"ul",
|
|
133691
|
+
"li",
|
|
133692
|
+
"button",
|
|
133693
|
+
"input",
|
|
133694
|
+
"select",
|
|
133695
|
+
"textarea",
|
|
133696
|
+
"label",
|
|
133697
|
+
"section",
|
|
133698
|
+
"article",
|
|
133699
|
+
"header",
|
|
133700
|
+
"footer",
|
|
133701
|
+
"nav",
|
|
133702
|
+
"main",
|
|
133703
|
+
"aside",
|
|
133704
|
+
"h1",
|
|
133705
|
+
"h2",
|
|
133706
|
+
"h3",
|
|
133707
|
+
"h4",
|
|
133708
|
+
"h5",
|
|
133709
|
+
"h6",
|
|
133710
|
+
"table",
|
|
133711
|
+
"thead",
|
|
133712
|
+
"tbody",
|
|
133713
|
+
"tr",
|
|
133714
|
+
"td",
|
|
133715
|
+
"th"
|
|
133716
|
+
];
|
|
133717
|
+
function precacheCommonTags() {
|
|
133718
|
+
for (let tag of commonTags) {
|
|
133719
|
+
const t = String(tag).toLowerCase();
|
|
133720
|
+
if (NO_CAPTURE_TAGS.has(t)) continue;
|
|
133721
|
+
if (NO_DEFAULTS_TAGS.has(t)) continue;
|
|
133722
|
+
getDefaultStyleForTag(t);
|
|
133723
|
+
}
|
|
133724
|
+
}
|
|
133725
|
+
function getDefaultStyleForTag(tagName) {
|
|
133726
|
+
tagName = String(tagName).toLowerCase();
|
|
133727
|
+
if (NO_DEFAULTS_TAGS.has(tagName)) {
|
|
133728
|
+
const empty = {};
|
|
133729
|
+
cache.defaultStyle.set(tagName, empty);
|
|
133730
|
+
return empty;
|
|
133731
|
+
}
|
|
133732
|
+
if (cache.defaultStyle.has(tagName)) {
|
|
133733
|
+
return cache.defaultStyle.get(tagName);
|
|
133734
|
+
}
|
|
133735
|
+
let sandbox = document.getElementById("snapdom-sandbox");
|
|
133736
|
+
if (!sandbox) {
|
|
133737
|
+
sandbox = document.createElement("div");
|
|
133738
|
+
sandbox.id = "snapdom-sandbox";
|
|
133739
|
+
sandbox.setAttribute("data-snapdom-sandbox", "true");
|
|
133740
|
+
sandbox.setAttribute("aria-hidden", "true");
|
|
133741
|
+
sandbox.style.position = "absolute";
|
|
133742
|
+
sandbox.style.left = "-9999px";
|
|
133743
|
+
sandbox.style.top = "-9999px";
|
|
133744
|
+
sandbox.style.width = "0px";
|
|
133745
|
+
sandbox.style.height = "0px";
|
|
133746
|
+
sandbox.style.overflow = "hidden";
|
|
133747
|
+
document.body.appendChild(sandbox);
|
|
133748
|
+
}
|
|
133749
|
+
const el = document.createElement(tagName);
|
|
133750
|
+
el.style.all = "initial";
|
|
133751
|
+
sandbox.appendChild(el);
|
|
133752
|
+
const styles = getComputedStyle(el);
|
|
133753
|
+
const defaults = {};
|
|
133754
|
+
for (let prop of styles) {
|
|
133755
|
+
if (shouldIgnoreProp(prop)) continue;
|
|
133756
|
+
const value = styles.getPropertyValue(prop);
|
|
133757
|
+
defaults[prop] = value;
|
|
133758
|
+
}
|
|
133759
|
+
sandbox.removeChild(el);
|
|
133760
|
+
cache.defaultStyle.set(tagName, defaults);
|
|
133761
|
+
return defaults;
|
|
133762
|
+
}
|
|
133763
|
+
var NO_PAINT_TOKEN = /(?:^|-)(animation|transition)(?:-|$)/i;
|
|
133764
|
+
var NO_PAINT_PREFIX = /^(--|view-timeline|scroll-timeline|animation-trigger|offset-|position-try|app-region|interactivity|overlay|view-transition|-webkit-locale|-webkit-user-(?:drag|modify)|-webkit-tap-highlight-color|-webkit-text-security)$/i;
|
|
133765
|
+
var NO_PAINT_EXACT = /* @__PURE__ */ new Set([
|
|
133766
|
+
// Interaction hints
|
|
133767
|
+
"cursor",
|
|
133768
|
+
"pointer-events",
|
|
133769
|
+
"touch-action",
|
|
133770
|
+
"user-select",
|
|
133771
|
+
// Printing/speech/reading-mode hints
|
|
133772
|
+
"print-color-adjust",
|
|
133773
|
+
"speak",
|
|
133774
|
+
"reading-flow",
|
|
133775
|
+
"reading-order",
|
|
133776
|
+
// Anchoring/container/timeline scopes (metadata for layout queries)
|
|
133777
|
+
"anchor-name",
|
|
133778
|
+
"anchor-scope",
|
|
133779
|
+
"container-name",
|
|
133780
|
+
"container-type",
|
|
133781
|
+
"timeline-scope"
|
|
133782
|
+
]);
|
|
133783
|
+
function shouldIgnoreProp(prop) {
|
|
133784
|
+
const p = String(prop).toLowerCase();
|
|
133785
|
+
if (NO_PAINT_EXACT.has(p)) return true;
|
|
133786
|
+
if (NO_PAINT_PREFIX.test(p)) return true;
|
|
133787
|
+
if (NO_PAINT_TOKEN.test(p)) return true;
|
|
133788
|
+
return false;
|
|
133789
|
+
}
|
|
133790
|
+
function getStyleKey(snapshot, tagName) {
|
|
133791
|
+
tagName = String(tagName || "").toLowerCase();
|
|
133792
|
+
if (NO_DEFAULTS_TAGS.has(tagName)) {
|
|
133793
|
+
return "";
|
|
133794
|
+
}
|
|
133795
|
+
const entries = [];
|
|
133796
|
+
const defaults = getDefaultStyleForTag(tagName);
|
|
133797
|
+
for (let [prop, value] of Object.entries(snapshot)) {
|
|
133798
|
+
if (shouldIgnoreProp(prop)) continue;
|
|
133799
|
+
const def = defaults[prop];
|
|
133800
|
+
if (value && value !== def) entries.push(`${prop}:${value}`);
|
|
133801
|
+
}
|
|
133802
|
+
entries.sort();
|
|
133803
|
+
return entries.join(";");
|
|
133804
|
+
}
|
|
133805
|
+
function collectUsedTagNames(root) {
|
|
133806
|
+
const tagSet = /* @__PURE__ */ new Set();
|
|
133807
|
+
if (root.nodeType !== Node.ELEMENT_NODE && root.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
|
|
133808
|
+
return [];
|
|
133809
|
+
}
|
|
133810
|
+
if (root.tagName) {
|
|
133811
|
+
tagSet.add(root.tagName.toLowerCase());
|
|
133812
|
+
}
|
|
133813
|
+
if (typeof root.querySelectorAll === "function") {
|
|
133814
|
+
root.querySelectorAll("*").forEach((el) => tagSet.add(el.tagName.toLowerCase()));
|
|
133815
|
+
}
|
|
133816
|
+
return Array.from(tagSet);
|
|
133817
|
+
}
|
|
133818
|
+
function generateDedupedBaseCSS(usedTagNames) {
|
|
133819
|
+
const groups = /* @__PURE__ */ new Map();
|
|
133820
|
+
for (let tagName of usedTagNames) {
|
|
133821
|
+
const styles = cache.defaultStyle.get(tagName);
|
|
133822
|
+
if (!styles) continue;
|
|
133823
|
+
const key = Object.entries(styles).map(([k, v]) => `${k}:${v};`).sort().join("");
|
|
133824
|
+
if (!key) continue;
|
|
133825
|
+
if (!groups.has(key)) {
|
|
133826
|
+
groups.set(key, []);
|
|
133827
|
+
}
|
|
133828
|
+
groups.get(key).push(tagName);
|
|
133829
|
+
}
|
|
133830
|
+
let css = "";
|
|
133831
|
+
for (let [styleBlock, tagList] of groups.entries()) {
|
|
133832
|
+
css += `${tagList.join(",")} { ${styleBlock} }
|
|
133833
|
+
`;
|
|
133834
|
+
}
|
|
133835
|
+
return css;
|
|
133836
|
+
}
|
|
133837
|
+
function generateCSSClasses(styleMap) {
|
|
133838
|
+
const keys = Array.from(new Set(styleMap.values())).filter(Boolean).sort();
|
|
133839
|
+
const classMap = /* @__PURE__ */ new Map();
|
|
133840
|
+
let i = 1;
|
|
133841
|
+
for (const k of keys) classMap.set(k, `c${i++}`);
|
|
133842
|
+
return classMap;
|
|
133843
|
+
}
|
|
133844
|
+
function getStyle(el, pseudo = null) {
|
|
133845
|
+
if (!(el instanceof Element)) {
|
|
133846
|
+
return window.getComputedStyle(el, pseudo);
|
|
133847
|
+
}
|
|
133848
|
+
let map = cache.computedStyle.get(el);
|
|
133849
|
+
if (!map) {
|
|
133850
|
+
map = /* @__PURE__ */ new Map();
|
|
133851
|
+
cache.computedStyle.set(el, map);
|
|
133852
|
+
}
|
|
133853
|
+
if (!map.has(pseudo)) {
|
|
133854
|
+
const st = window.getComputedStyle(el, pseudo);
|
|
133855
|
+
map.set(pseudo, st);
|
|
133856
|
+
}
|
|
133857
|
+
return map.get(pseudo);
|
|
133858
|
+
}
|
|
133859
|
+
function snapshotComputedStyle(style) {
|
|
133860
|
+
const snap = {};
|
|
133861
|
+
for (let prop of style) {
|
|
133862
|
+
snap[prop] = style.getPropertyValue(prop);
|
|
133863
|
+
}
|
|
133864
|
+
return snap;
|
|
133865
|
+
}
|
|
133866
|
+
function splitBackgroundImage(bg) {
|
|
133867
|
+
const parts = [];
|
|
133868
|
+
let depth = 0;
|
|
133869
|
+
let lastIndex = 0;
|
|
133870
|
+
for (let i = 0; i < bg.length; i++) {
|
|
133871
|
+
const char = bg[i];
|
|
133872
|
+
if (char === "(") depth++;
|
|
133873
|
+
if (char === ")") depth--;
|
|
133874
|
+
if (char === "," && depth === 0) {
|
|
133875
|
+
parts.push(bg.slice(lastIndex, i).trim());
|
|
133876
|
+
lastIndex = i + 1;
|
|
133877
|
+
}
|
|
133878
|
+
}
|
|
133879
|
+
parts.push(bg.slice(lastIndex).trim());
|
|
133880
|
+
return parts;
|
|
133881
|
+
}
|
|
133882
|
+
|
|
133883
|
+
// src/utils/browser.js
|
|
133884
|
+
function idle(fn, { fast = false } = {}) {
|
|
133885
|
+
if (fast) return fn();
|
|
133886
|
+
if ("requestIdleCallback" in window) {
|
|
133887
|
+
requestIdleCallback(fn, { timeout: 50 });
|
|
133888
|
+
} else {
|
|
133889
|
+
setTimeout(fn, 1);
|
|
133890
|
+
}
|
|
133891
|
+
}
|
|
133892
|
+
function isSafari() {
|
|
133893
|
+
const ua = typeof navigator !== "undefined" && navigator.userAgent ? navigator.userAgent : "";
|
|
133894
|
+
const isSafariUA = /^((?!chrome|android).)*safari/i.test(ua);
|
|
133895
|
+
const isUIWebView = /AppleWebKit/i.test(ua) && /Mobile/i.test(ua) && !/Safari/i.test(ua);
|
|
133896
|
+
const isWeChatUA = /(MicroMessenger|wxwork|WeCom|WindowsWechat|MacWechat)/i.test(ua);
|
|
133897
|
+
return isSafariUA || isUIWebView || isWeChatUA;
|
|
133898
|
+
}
|
|
133899
|
+
|
|
133900
|
+
// src/modules/styles.js
|
|
133901
|
+
var snapshotCache = /* @__PURE__ */ new WeakMap();
|
|
133902
|
+
var snapshotKeyCache = /* @__PURE__ */ new Map();
|
|
133903
|
+
var __epoch = 0;
|
|
133904
|
+
function bumpEpoch() {
|
|
133905
|
+
__epoch++;
|
|
133906
|
+
}
|
|
133907
|
+
var __wired = false;
|
|
133908
|
+
function setupInvalidationOnce(root = document.documentElement) {
|
|
133909
|
+
if (__wired) return;
|
|
133910
|
+
__wired = true;
|
|
133911
|
+
try {
|
|
133912
|
+
const domObs = new MutationObserver(() => bumpEpoch());
|
|
133913
|
+
domObs.observe(root, { subtree: true, childList: true, characterData: true, attributes: true });
|
|
133914
|
+
} catch {
|
|
133915
|
+
}
|
|
133916
|
+
try {
|
|
133917
|
+
const headObs = new MutationObserver(() => bumpEpoch());
|
|
133918
|
+
headObs.observe(document.head, { subtree: true, childList: true, characterData: true, attributes: true });
|
|
133919
|
+
} catch {
|
|
133920
|
+
}
|
|
133921
|
+
try {
|
|
133922
|
+
const f = document.fonts;
|
|
133923
|
+
if (f) {
|
|
133924
|
+
f.addEventListener?.("loadingdone", bumpEpoch);
|
|
133925
|
+
f.ready?.then(() => bumpEpoch()).catch(() => {
|
|
133926
|
+
});
|
|
133927
|
+
}
|
|
133928
|
+
} catch {
|
|
133929
|
+
}
|
|
133930
|
+
}
|
|
133931
|
+
function snapshotComputedStyleFull(style, options = {}) {
|
|
133932
|
+
const out = {};
|
|
133933
|
+
const vis = style.getPropertyValue("visibility");
|
|
133934
|
+
for (let i = 0; i < style.length; i++) {
|
|
133935
|
+
const prop = style[i];
|
|
133936
|
+
let val = style.getPropertyValue(prop);
|
|
133937
|
+
if ((prop === "background-image" || prop === "content") && val.includes("url(") && !val.includes("data:")) {
|
|
133938
|
+
val = "none";
|
|
133939
|
+
}
|
|
133940
|
+
out[prop] = val;
|
|
133941
|
+
}
|
|
133942
|
+
if (options.embedFonts) {
|
|
133943
|
+
const EXTRA_FONT_PROPS = [
|
|
133944
|
+
"font-feature-settings",
|
|
133945
|
+
"font-variation-settings",
|
|
133946
|
+
"font-kerning",
|
|
133947
|
+
"font-variant",
|
|
133948
|
+
"font-variant-ligatures",
|
|
133949
|
+
"font-optical-sizing"
|
|
133950
|
+
];
|
|
133951
|
+
for (const prop of EXTRA_FONT_PROPS) {
|
|
133952
|
+
if (out[prop]) continue;
|
|
133953
|
+
try {
|
|
133954
|
+
const v = style.getPropertyValue(prop);
|
|
133955
|
+
if (v) out[prop] = v;
|
|
133956
|
+
} catch {
|
|
133957
|
+
}
|
|
133958
|
+
}
|
|
133959
|
+
}
|
|
133960
|
+
if (vis === "hidden") out.opacity = "0";
|
|
133961
|
+
return out;
|
|
133962
|
+
}
|
|
133963
|
+
var __snapshotSig = /* @__PURE__ */ new WeakMap();
|
|
133964
|
+
function styleSignature(snap) {
|
|
133965
|
+
let sig = __snapshotSig.get(snap);
|
|
133966
|
+
if (sig) return sig;
|
|
133967
|
+
const entries = Object.entries(snap).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
133968
|
+
sig = entries.map(([k, v]) => `${k}:${v}`).join(";");
|
|
133969
|
+
__snapshotSig.set(snap, sig);
|
|
133970
|
+
return sig;
|
|
133971
|
+
}
|
|
133972
|
+
function getSnapshot(el, preStyle = null, options = {}) {
|
|
133973
|
+
const rec = snapshotCache.get(el);
|
|
133974
|
+
if (rec && rec.epoch === __epoch) return rec.snapshot;
|
|
133975
|
+
const style = preStyle || getComputedStyle(el);
|
|
133976
|
+
const snap = snapshotComputedStyleFull(style, options);
|
|
133977
|
+
stripHeightForWrappers(el, style, snap);
|
|
133978
|
+
snapshotCache.set(el, { epoch: __epoch, snapshot: snap });
|
|
133979
|
+
return snap;
|
|
133980
|
+
}
|
|
133981
|
+
function _resolveCtx(sessionOrCtx, opts) {
|
|
133982
|
+
if (sessionOrCtx && sessionOrCtx.session && sessionOrCtx.persist) return sessionOrCtx;
|
|
133983
|
+
if (sessionOrCtx && (sessionOrCtx.styleMap || sessionOrCtx.styleCache || sessionOrCtx.nodeMap)) {
|
|
133984
|
+
return {
|
|
133985
|
+
session: sessionOrCtx,
|
|
133986
|
+
persist: {
|
|
133987
|
+
snapshotKeyCache,
|
|
133988
|
+
defaultStyle: cache.defaultStyle,
|
|
133989
|
+
baseStyle: cache.baseStyle,
|
|
133990
|
+
image: cache.image,
|
|
133991
|
+
resource: cache.resource,
|
|
133992
|
+
background: cache.background,
|
|
133993
|
+
font: cache.font
|
|
133994
|
+
},
|
|
133995
|
+
options: opts || {}
|
|
133996
|
+
};
|
|
133997
|
+
}
|
|
133998
|
+
return {
|
|
133999
|
+
session: cache.session,
|
|
134000
|
+
persist: {
|
|
134001
|
+
snapshotKeyCache,
|
|
134002
|
+
defaultStyle: cache.defaultStyle,
|
|
134003
|
+
baseStyle: cache.baseStyle,
|
|
134004
|
+
image: cache.image,
|
|
134005
|
+
resource: cache.resource,
|
|
134006
|
+
background: cache.background,
|
|
134007
|
+
font: cache.font
|
|
134008
|
+
},
|
|
134009
|
+
options: sessionOrCtx || opts || {}
|
|
134010
|
+
};
|
|
134011
|
+
}
|
|
134012
|
+
async function inlineAllStyles(source, clone, sessionOrCtx, opts) {
|
|
134013
|
+
if (source.tagName === "STYLE") return;
|
|
134014
|
+
const ctx = _resolveCtx(sessionOrCtx, opts);
|
|
134015
|
+
const resetMode = ctx.options && ctx.options.cache || "auto";
|
|
134016
|
+
if (resetMode !== "disabled") setupInvalidationOnce(document.documentElement);
|
|
134017
|
+
if (resetMode === "disabled" && !ctx.session.__bumpedForDisabled) {
|
|
134018
|
+
bumpEpoch();
|
|
134019
|
+
snapshotKeyCache.clear();
|
|
134020
|
+
ctx.session.__bumpedForDisabled = true;
|
|
134021
|
+
}
|
|
134022
|
+
if (NO_DEFAULTS_TAGS.has(source.tagName?.toLowerCase())) {
|
|
134023
|
+
const author = source.getAttribute?.("style");
|
|
134024
|
+
if (author) clone.setAttribute("style", author);
|
|
134025
|
+
}
|
|
134026
|
+
const { session, persist } = ctx;
|
|
134027
|
+
if (!session.styleCache.has(source)) {
|
|
134028
|
+
session.styleCache.set(source, getComputedStyle(source));
|
|
134029
|
+
}
|
|
134030
|
+
const pre = session.styleCache.get(source);
|
|
134031
|
+
const snap = getSnapshot(source, pre, ctx.options);
|
|
134032
|
+
const sig = styleSignature(snap);
|
|
134033
|
+
let key = persist.snapshotKeyCache.get(sig);
|
|
134034
|
+
if (!key) {
|
|
134035
|
+
const tag = source.tagName?.toLowerCase() || "div";
|
|
134036
|
+
key = getStyleKey(snap, tag);
|
|
134037
|
+
persist.snapshotKeyCache.set(sig, key);
|
|
134038
|
+
}
|
|
134039
|
+
session.styleMap.set(clone, key);
|
|
134040
|
+
}
|
|
134041
|
+
function isReplaced(el) {
|
|
134042
|
+
return el instanceof HTMLImageElement || el instanceof HTMLCanvasElement || el instanceof HTMLVideoElement || el instanceof HTMLIFrameElement || el instanceof SVGElement || el instanceof HTMLObjectElement || el instanceof HTMLEmbedElement;
|
|
134043
|
+
}
|
|
134044
|
+
function hasBox(cs) {
|
|
134045
|
+
if (cs.backgroundImage && cs.backgroundImage !== "none") return true;
|
|
134046
|
+
if (cs.backgroundColor && cs.backgroundColor !== "rgba(0, 0, 0, 0)" && cs.backgroundColor !== "transparent") return true;
|
|
134047
|
+
if ((parseFloat(cs.borderTopWidth) || 0) > 0) return true;
|
|
134048
|
+
if ((parseFloat(cs.borderBottomWidth) || 0) > 0) return true;
|
|
134049
|
+
if ((parseFloat(cs.paddingTop) || 0) > 0) return true;
|
|
134050
|
+
if ((parseFloat(cs.paddingBottom) || 0) > 0) return true;
|
|
134051
|
+
const ob = cs.overflowBlock || cs.overflowY || "visible";
|
|
134052
|
+
return ob !== "visible";
|
|
134053
|
+
}
|
|
134054
|
+
function isFlexOrGridItem(el) {
|
|
134055
|
+
const p = el.parentElement;
|
|
134056
|
+
if (!p) return false;
|
|
134057
|
+
const pd = getComputedStyle(p).display || "";
|
|
134058
|
+
return pd.includes("flex") || pd.includes("grid");
|
|
134059
|
+
}
|
|
134060
|
+
function hasFlowFast(el, cs) {
|
|
134061
|
+
if (el.textContent && /\S/.test(el.textContent)) return true;
|
|
134062
|
+
const f = el.firstElementChild, l = el.lastElementChild;
|
|
134063
|
+
if (f && f.tagName === "BR" || l && l.tagName === "BR") return true;
|
|
134064
|
+
const sh = el.scrollHeight;
|
|
134065
|
+
if (sh === 0) return false;
|
|
134066
|
+
const pt = parseFloat(cs.paddingTop) || 0;
|
|
134067
|
+
const pb = parseFloat(cs.paddingBottom) || 0;
|
|
134068
|
+
return sh > pt + pb;
|
|
134069
|
+
}
|
|
134070
|
+
function stripHeightForWrappers(el, cs, snap) {
|
|
134071
|
+
if (el instanceof HTMLElement && el.style && el.style.height) return;
|
|
134072
|
+
const disp = cs.display || "";
|
|
134073
|
+
if (disp.includes("flex") || disp.includes("grid")) return;
|
|
134074
|
+
if (isReplaced(el)) return;
|
|
134075
|
+
const pos = cs.position;
|
|
134076
|
+
if (pos === "absolute" || pos === "fixed" || pos === "sticky") return;
|
|
134077
|
+
if (cs.transform !== "none") return;
|
|
134078
|
+
if (hasBox(cs)) return;
|
|
134079
|
+
if (isFlexOrGridItem(el)) return;
|
|
134080
|
+
if (!hasFlowFast(el, cs)) return;
|
|
134081
|
+
delete snap.height;
|
|
134082
|
+
delete snap["block-size"];
|
|
134083
|
+
}
|
|
134084
|
+
|
|
134085
|
+
// src/modules/CSSVar.js
|
|
134086
|
+
function resolveCSSVars(sourceEl, cloneEl) {
|
|
134087
|
+
if (!(sourceEl instanceof Element) || !(cloneEl instanceof Element)) return;
|
|
134088
|
+
const styleAttr = sourceEl.getAttribute?.("style");
|
|
134089
|
+
let hasVar = !!(styleAttr && styleAttr.includes("var("));
|
|
134090
|
+
if (!hasVar && sourceEl.attributes?.length) {
|
|
134091
|
+
const attrs = sourceEl.attributes;
|
|
134092
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
134093
|
+
const a = attrs[i];
|
|
134094
|
+
if (a && typeof a.value === "string" && a.value.includes("var(")) {
|
|
134095
|
+
hasVar = true;
|
|
134096
|
+
break;
|
|
134097
|
+
}
|
|
134098
|
+
}
|
|
134099
|
+
}
|
|
134100
|
+
if (!hasVar) return;
|
|
134101
|
+
let cs;
|
|
134102
|
+
try {
|
|
134103
|
+
cs = getComputedStyle(sourceEl);
|
|
134104
|
+
} catch {
|
|
134105
|
+
return;
|
|
134106
|
+
}
|
|
134107
|
+
const author = sourceEl.style;
|
|
134108
|
+
if (author && author.length) {
|
|
134109
|
+
for (let i = 0; i < author.length; i++) {
|
|
134110
|
+
const prop = author[i];
|
|
134111
|
+
const val = author.getPropertyValue(prop);
|
|
134112
|
+
if (!val || !val.includes("var(")) continue;
|
|
134113
|
+
const resolved = cs.getPropertyValue(prop);
|
|
134114
|
+
if (resolved) {
|
|
134115
|
+
try {
|
|
134116
|
+
cloneEl.style.setProperty(prop, resolved.trim(), author.getPropertyPriority(prop));
|
|
134117
|
+
} catch {
|
|
134118
|
+
}
|
|
134119
|
+
}
|
|
134120
|
+
}
|
|
134121
|
+
}
|
|
134122
|
+
if (sourceEl.attributes?.length) {
|
|
134123
|
+
const attrs = sourceEl.attributes;
|
|
134124
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
134125
|
+
const a = attrs[i];
|
|
134126
|
+
if (!a || typeof a.value !== "string" || !a.value.includes("var(")) continue;
|
|
134127
|
+
const propName = a.name;
|
|
134128
|
+
let resolved = "";
|
|
134129
|
+
try {
|
|
134130
|
+
resolved = cs.getPropertyValue(propName);
|
|
134131
|
+
} catch {
|
|
134132
|
+
}
|
|
134133
|
+
if (resolved) {
|
|
134134
|
+
try {
|
|
134135
|
+
cloneEl.style.setProperty(propName, resolved.trim());
|
|
134136
|
+
} catch {
|
|
134137
|
+
}
|
|
134138
|
+
}
|
|
134139
|
+
}
|
|
134140
|
+
}
|
|
134141
|
+
}
|
|
134142
|
+
|
|
134143
|
+
// src/core/clone.js
|
|
134144
|
+
function idleCallback(childList, callback, fast) {
|
|
134145
|
+
return Promise.all(childList.map((child) => {
|
|
134146
|
+
return new Promise((resolve) => {
|
|
134147
|
+
function deal() {
|
|
134148
|
+
idle((deadline) => {
|
|
134149
|
+
const hasIdleBudget = deadline && typeof deadline.timeRemaining === "function" ? deadline.timeRemaining() > 0 : true;
|
|
134150
|
+
if (hasIdleBudget) {
|
|
134151
|
+
callback(child, resolve);
|
|
134152
|
+
} else {
|
|
134153
|
+
deal();
|
|
134154
|
+
}
|
|
134155
|
+
}, { fast });
|
|
134156
|
+
}
|
|
134157
|
+
deal();
|
|
134158
|
+
});
|
|
134159
|
+
}));
|
|
134160
|
+
}
|
|
134161
|
+
function addNotSlottedRightmost(sel) {
|
|
134162
|
+
sel = sel.trim();
|
|
134163
|
+
if (!sel) return sel;
|
|
134164
|
+
if (/:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(sel)) return sel;
|
|
134165
|
+
return `${sel}:not([data-sd-slotted])`;
|
|
134166
|
+
}
|
|
134167
|
+
function wrapWithScope(selectorList, scopeSelector, excludeSlotted = true) {
|
|
134168
|
+
return selectorList.split(",").map((s) => s.trim()).filter(Boolean).map((s) => {
|
|
134169
|
+
if (s.startsWith(":where(")) return s;
|
|
134170
|
+
if (s.startsWith("@")) return s;
|
|
134171
|
+
const body = excludeSlotted ? addNotSlottedRightmost(s) : s;
|
|
134172
|
+
return `:where(${scopeSelector} ${body})`;
|
|
134173
|
+
}).join(", ");
|
|
134174
|
+
}
|
|
134175
|
+
function rewriteShadowCSS(cssText, scopeSelector) {
|
|
134176
|
+
if (!cssText) return "";
|
|
134177
|
+
cssText = cssText.replace(/:host\(([^)]+)\)/g, (_, sel) => {
|
|
134178
|
+
return `:where(${scopeSelector}:is(${sel.trim()}))`;
|
|
134179
|
+
});
|
|
134180
|
+
cssText = cssText.replace(/:host\b/g, `:where(${scopeSelector})`);
|
|
134181
|
+
cssText = cssText.replace(/:host-context\(([^)]+)\)/g, (_, sel) => {
|
|
134182
|
+
return `:where(:where(${sel.trim()}) ${scopeSelector})`;
|
|
134183
|
+
});
|
|
134184
|
+
cssText = cssText.replace(/::slotted\(([^)]+)\)/g, (_, sel) => {
|
|
134185
|
+
return `:where(${scopeSelector} ${sel.trim()})`;
|
|
134186
|
+
});
|
|
134187
|
+
cssText = cssText.replace(/(^|})(\s*)([^@}{]+){/g, (_, brace, ws, selectorList) => {
|
|
134188
|
+
const wrapped = wrapWithScope(
|
|
134189
|
+
selectorList,
|
|
134190
|
+
scopeSelector,
|
|
134191
|
+
/*excludeSlotted*/
|
|
134192
|
+
true
|
|
134193
|
+
);
|
|
134194
|
+
return `${brace}${ws}${wrapped}{`;
|
|
134195
|
+
});
|
|
134196
|
+
return cssText;
|
|
134197
|
+
}
|
|
134198
|
+
function nextShadowScopeId(sessionCache) {
|
|
134199
|
+
sessionCache.shadowScopeSeq = (sessionCache.shadowScopeSeq || 0) + 1;
|
|
134200
|
+
return `s${sessionCache.shadowScopeSeq}`;
|
|
134201
|
+
}
|
|
134202
|
+
function extractShadowCSS(sr) {
|
|
134203
|
+
let css = "";
|
|
134204
|
+
try {
|
|
134205
|
+
sr.querySelectorAll("style").forEach((s) => {
|
|
134206
|
+
css += (s.textContent || "") + "\n";
|
|
134207
|
+
});
|
|
134208
|
+
const sheets = sr.adoptedStyleSheets || [];
|
|
134209
|
+
for (const sh of sheets) {
|
|
134210
|
+
try {
|
|
134211
|
+
if (sh && sh.cssRules) {
|
|
134212
|
+
for (const rule of sh.cssRules) css += rule.cssText + "\n";
|
|
134213
|
+
}
|
|
134214
|
+
} catch {
|
|
134215
|
+
}
|
|
134216
|
+
}
|
|
134217
|
+
} catch {
|
|
134218
|
+
}
|
|
134219
|
+
return css;
|
|
134220
|
+
}
|
|
134221
|
+
function injectScopedStyle(hostClone, cssText, scopeId) {
|
|
134222
|
+
if (!cssText) return;
|
|
134223
|
+
const style = document.createElement("style");
|
|
134224
|
+
style.setAttribute("data-sd", scopeId);
|
|
134225
|
+
style.textContent = cssText;
|
|
134226
|
+
hostClone.insertBefore(style, hostClone.firstChild || null);
|
|
134227
|
+
}
|
|
134228
|
+
function freezeImgSrcset(original, cloned) {
|
|
134229
|
+
try {
|
|
134230
|
+
const chosen = original.currentSrc || original.src || "";
|
|
134231
|
+
if (!chosen) return;
|
|
134232
|
+
cloned.setAttribute("src", chosen);
|
|
134233
|
+
cloned.removeAttribute("srcset");
|
|
134234
|
+
cloned.removeAttribute("sizes");
|
|
134235
|
+
cloned.loading = "eager";
|
|
134236
|
+
cloned.decoding = "sync";
|
|
134237
|
+
} catch {
|
|
134238
|
+
}
|
|
134239
|
+
}
|
|
134240
|
+
function collectCustomPropsFromCSS(cssText) {
|
|
134241
|
+
const out = /* @__PURE__ */ new Set();
|
|
134242
|
+
if (!cssText) return out;
|
|
134243
|
+
const re = /var\(\s*(--[A-Za-z0-9_-]+)\b/g;
|
|
134244
|
+
let m;
|
|
134245
|
+
while (m = re.exec(cssText)) out.add(m[1]);
|
|
134246
|
+
return out;
|
|
134247
|
+
}
|
|
134248
|
+
function resolveCustomProp(el, name) {
|
|
134249
|
+
try {
|
|
134250
|
+
const cs = getComputedStyle(el);
|
|
134251
|
+
let v = cs.getPropertyValue(name).trim();
|
|
134252
|
+
if (v) return v;
|
|
134253
|
+
} catch {
|
|
134254
|
+
}
|
|
134255
|
+
try {
|
|
134256
|
+
const rootCS = getComputedStyle(document.documentElement);
|
|
134257
|
+
let v = rootCS.getPropertyValue(name).trim();
|
|
134258
|
+
if (v) return v;
|
|
134259
|
+
} catch {
|
|
134260
|
+
}
|
|
134261
|
+
return "";
|
|
134262
|
+
}
|
|
134263
|
+
function buildSeedCustomPropsRule(hostEl, names, scopeSelector) {
|
|
134264
|
+
const decls = [];
|
|
134265
|
+
for (const name of names) {
|
|
134266
|
+
const val = resolveCustomProp(hostEl, name);
|
|
134267
|
+
if (val) decls.push(`${name}: ${val};`);
|
|
134268
|
+
}
|
|
134269
|
+
if (!decls.length) return "";
|
|
134270
|
+
return `${scopeSelector}{${decls.join("")}}
|
|
134271
|
+
`;
|
|
134272
|
+
}
|
|
134273
|
+
function markSlottedSubtree(root) {
|
|
134274
|
+
if (!root) return;
|
|
134275
|
+
if (root.nodeType === Node.ELEMENT_NODE) {
|
|
134276
|
+
root.setAttribute("data-sd-slotted", "");
|
|
134277
|
+
}
|
|
134278
|
+
if (root.querySelectorAll) {
|
|
134279
|
+
root.querySelectorAll("*").forEach((el) => el.setAttribute("data-sd-slotted", ""));
|
|
134280
|
+
}
|
|
134281
|
+
}
|
|
134282
|
+
async function getAccessibleIframeDocument(iframe, attempts = 3) {
|
|
134283
|
+
const probe = () => {
|
|
134284
|
+
try {
|
|
134285
|
+
return iframe.contentDocument || iframe.contentWindow?.document || null;
|
|
134286
|
+
} catch {
|
|
134287
|
+
return null;
|
|
134288
|
+
}
|
|
134289
|
+
};
|
|
134290
|
+
let doc = probe();
|
|
134291
|
+
let i = 0;
|
|
134292
|
+
while (i < attempts && (!doc || !doc.body && !doc.documentElement)) {
|
|
134293
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
134294
|
+
doc = probe();
|
|
134295
|
+
i++;
|
|
134296
|
+
}
|
|
134297
|
+
return doc && (doc.body || doc.documentElement) ? doc : null;
|
|
134298
|
+
}
|
|
134299
|
+
function measureContentBox(el) {
|
|
134300
|
+
const rect = el.getBoundingClientRect();
|
|
134301
|
+
let bl = 0, br = 0, bt = 0, bb = 0;
|
|
134302
|
+
try {
|
|
134303
|
+
const cs = getComputedStyle(el);
|
|
134304
|
+
bl = parseFloat(cs.borderLeftWidth) || 0;
|
|
134305
|
+
br = parseFloat(cs.borderRightWidth) || 0;
|
|
134306
|
+
bt = parseFloat(cs.borderTopWidth) || 0;
|
|
134307
|
+
bb = parseFloat(cs.borderBottomWidth) || 0;
|
|
134308
|
+
} catch {
|
|
134309
|
+
}
|
|
134310
|
+
const contentWidth = Math.max(0, Math.round(rect.width - (bl + br)));
|
|
134311
|
+
const contentHeight = Math.max(0, Math.round(rect.height - (bt + bb)));
|
|
134312
|
+
return { contentWidth, contentHeight, rect };
|
|
134313
|
+
}
|
|
134314
|
+
function pinIframeViewport(doc, w, h) {
|
|
134315
|
+
const style = doc.createElement("style");
|
|
134316
|
+
style.setAttribute("data-sd-iframe-pin", "");
|
|
134317
|
+
style.textContent = `html, body {margin: 0 !important;padding: 0 !important;width: ${w}px !important;height: ${h}px !important;min-width: ${w}px !important;min-height: ${h}px !important;box-sizing: border-box !important;overflow: hidden !important;background-clip: border-box !important;}`;
|
|
134318
|
+
(doc.head || doc.documentElement).appendChild(style);
|
|
134319
|
+
return () => {
|
|
134320
|
+
try {
|
|
134321
|
+
style.remove();
|
|
134322
|
+
} catch {
|
|
134323
|
+
}
|
|
134324
|
+
};
|
|
134325
|
+
}
|
|
134326
|
+
async function rasterizeIframe(iframe, sessionCache, options) {
|
|
134327
|
+
const doc = await getAccessibleIframeDocument(iframe, 3);
|
|
134328
|
+
if (!doc) throw new Error("iframe document not accessible/ready");
|
|
134329
|
+
const { contentWidth, contentHeight, rect } = measureContentBox(iframe);
|
|
134330
|
+
const snap = options?.snap;
|
|
134331
|
+
if (!snap || typeof snap.toPng !== "function") {
|
|
134332
|
+
throw new Error("snapdom.toPng not available in iframe or window");
|
|
134333
|
+
}
|
|
134334
|
+
const nested = { ...options, scale: 1 };
|
|
134335
|
+
const unpin = pinIframeViewport(doc, contentWidth, contentHeight);
|
|
134336
|
+
let imgEl;
|
|
134337
|
+
try {
|
|
134338
|
+
imgEl = await snap.toPng(doc.documentElement, nested);
|
|
134339
|
+
} finally {
|
|
134340
|
+
unpin();
|
|
134341
|
+
}
|
|
134342
|
+
imgEl.style.display = "block";
|
|
134343
|
+
imgEl.style.width = `${contentWidth}px`;
|
|
134344
|
+
imgEl.style.height = `${contentHeight}px`;
|
|
134345
|
+
const wrapper = document.createElement("div");
|
|
134346
|
+
sessionCache.nodeMap.set(wrapper, iframe);
|
|
134347
|
+
inlineAllStyles(iframe, wrapper, sessionCache, options);
|
|
134348
|
+
wrapper.style.overflow = "hidden";
|
|
134349
|
+
wrapper.style.display = "block";
|
|
134350
|
+
if (!wrapper.style.width) wrapper.style.width = `${Math.round(rect.width)}px`;
|
|
134351
|
+
if (!wrapper.style.height) wrapper.style.height = `${Math.round(rect.height)}px`;
|
|
134352
|
+
wrapper.appendChild(imgEl);
|
|
134353
|
+
return wrapper;
|
|
134354
|
+
}
|
|
134355
|
+
async function deepClone(node, sessionCache, options) {
|
|
134356
|
+
if (!node) throw new Error("Invalid node");
|
|
134357
|
+
const clonedAssignedNodes = /* @__PURE__ */ new Set();
|
|
134358
|
+
let pendingSelectValue = null;
|
|
134359
|
+
let pendingTextAreaValue = null;
|
|
134360
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
134361
|
+
const tag = (node.localName || node.tagName || "").toLowerCase();
|
|
134362
|
+
if (node.id === "snapdom-sandbox" || node.hasAttribute("data-snapdom-sandbox")) {
|
|
134363
|
+
return null;
|
|
134364
|
+
}
|
|
134365
|
+
if (NO_CAPTURE_TAGS.has(tag)) {
|
|
134366
|
+
return null;
|
|
134367
|
+
}
|
|
134368
|
+
}
|
|
134369
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
134370
|
+
return node.cloneNode(true);
|
|
134371
|
+
}
|
|
134372
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
134373
|
+
return node.cloneNode(true);
|
|
134374
|
+
}
|
|
134375
|
+
if (node.getAttribute("data-capture") === "exclude") {
|
|
134376
|
+
if (options.excludeMode === "hide") {
|
|
134377
|
+
const spacer = document.createElement("div");
|
|
134378
|
+
const rect = node.getBoundingClientRect();
|
|
134379
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
134380
|
+
return spacer;
|
|
134381
|
+
} else if (options.excludeMode === "remove") {
|
|
134382
|
+
return null;
|
|
134383
|
+
}
|
|
134384
|
+
}
|
|
134385
|
+
if (options.exclude && Array.isArray(options.exclude)) {
|
|
134386
|
+
for (const selector of options.exclude) {
|
|
134387
|
+
try {
|
|
134388
|
+
if (node.matches?.(selector)) {
|
|
134389
|
+
if (options.excludeMode === "hide") {
|
|
134390
|
+
const spacer = document.createElement("div");
|
|
134391
|
+
const rect = node.getBoundingClientRect();
|
|
134392
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
134393
|
+
return spacer;
|
|
134394
|
+
} else if (options.excludeMode === "remove") {
|
|
134395
|
+
return null;
|
|
134396
|
+
}
|
|
134397
|
+
}
|
|
134398
|
+
} catch (err) {
|
|
134399
|
+
console.warn(`Invalid selector in exclude option: ${selector}`, err);
|
|
134400
|
+
}
|
|
134401
|
+
}
|
|
134402
|
+
}
|
|
134403
|
+
if (typeof options.filter === "function") {
|
|
134404
|
+
try {
|
|
134405
|
+
if (!options.filter(node)) {
|
|
134406
|
+
if (options.filterMode === "hide") {
|
|
134407
|
+
const spacer = document.createElement("div");
|
|
134408
|
+
const rect = node.getBoundingClientRect();
|
|
134409
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
134410
|
+
return spacer;
|
|
134411
|
+
} else if (options.filterMode === "remove") {
|
|
134412
|
+
return null;
|
|
134413
|
+
}
|
|
134414
|
+
}
|
|
134415
|
+
} catch (err) {
|
|
134416
|
+
console.warn("Error in filter function:", err);
|
|
134417
|
+
}
|
|
134418
|
+
}
|
|
134419
|
+
if (node.tagName === "IFRAME") {
|
|
134420
|
+
let sameOrigin = false;
|
|
134421
|
+
try {
|
|
134422
|
+
sameOrigin = !!(node.contentDocument || node.contentWindow?.document);
|
|
134423
|
+
} catch {
|
|
134424
|
+
sameOrigin = false;
|
|
134425
|
+
}
|
|
134426
|
+
if (sameOrigin) {
|
|
134427
|
+
try {
|
|
134428
|
+
const wrapper = await rasterizeIframe(node, sessionCache, options);
|
|
134429
|
+
return wrapper;
|
|
134430
|
+
} catch (err) {
|
|
134431
|
+
console.warn("[SnapDOM] iframe rasterization failed, fallback:", err);
|
|
134432
|
+
}
|
|
134433
|
+
}
|
|
134434
|
+
if (options.placeholders) {
|
|
134435
|
+
const fallback = document.createElement("div");
|
|
134436
|
+
fallback.style.cssText = `width:${node.offsetWidth}px;height:${node.offsetHeight}px;background-image:repeating-linear-gradient(45deg,#ddd,#ddd 5px,#f9f9f9 5px,#f9f9f9 10px);display:flex;align-items:center;justify-content:center;font-size:12px;color:#555;border:1px solid #aaa;`;
|
|
134437
|
+
inlineAllStyles(node, fallback, sessionCache, options);
|
|
134438
|
+
return fallback;
|
|
134439
|
+
} else {
|
|
134440
|
+
const rect = node.getBoundingClientRect();
|
|
134441
|
+
const spacer = document.createElement("div");
|
|
134442
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
134443
|
+
inlineAllStyles(node, spacer, sessionCache, options);
|
|
134444
|
+
return spacer;
|
|
134445
|
+
}
|
|
134446
|
+
}
|
|
134447
|
+
if (node.getAttribute("data-capture") === "placeholder") {
|
|
134448
|
+
const clone2 = node.cloneNode(false);
|
|
134449
|
+
sessionCache.nodeMap.set(clone2, node);
|
|
134450
|
+
inlineAllStyles(node, clone2, sessionCache, options);
|
|
134451
|
+
const placeholder = document.createElement("div");
|
|
134452
|
+
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
|
|
134453
|
+
placeholder.style.cssText = "color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;";
|
|
134454
|
+
clone2.appendChild(placeholder);
|
|
134455
|
+
return clone2;
|
|
134456
|
+
}
|
|
134457
|
+
if (node.tagName === "CANVAS") {
|
|
134458
|
+
const dataURL = node.toDataURL();
|
|
134459
|
+
const img = document.createElement("img");
|
|
134460
|
+
img.src = dataURL;
|
|
134461
|
+
img.width = node.width;
|
|
134462
|
+
img.height = node.height;
|
|
134463
|
+
sessionCache.nodeMap.set(img, node);
|
|
134464
|
+
inlineAllStyles(node, img, sessionCache, options);
|
|
134465
|
+
return img;
|
|
134466
|
+
}
|
|
134467
|
+
let clone;
|
|
134468
|
+
try {
|
|
134469
|
+
clone = node.cloneNode(false);
|
|
134470
|
+
resolveCSSVars(node, clone);
|
|
134471
|
+
sessionCache.nodeMap.set(clone, node);
|
|
134472
|
+
if (node.tagName === "IMG") {
|
|
134473
|
+
freezeImgSrcset(node, clone);
|
|
134474
|
+
try {
|
|
134475
|
+
const rect = node.getBoundingClientRect();
|
|
134476
|
+
let w = Math.round(rect.width || 0);
|
|
134477
|
+
let h = Math.round(rect.height || 0);
|
|
134478
|
+
if (!w || !h) {
|
|
134479
|
+
const computed = window.getComputedStyle(node);
|
|
134480
|
+
const cssW = parseFloat(computed.width) || 0;
|
|
134481
|
+
const cssH = parseFloat(computed.height) || 0;
|
|
134482
|
+
const attrW = parseInt(node.getAttribute("width") || "", 10) || 0;
|
|
134483
|
+
const attrH = parseInt(node.getAttribute("height") || "", 10) || 0;
|
|
134484
|
+
const propW = node.width || node.naturalWidth || 0;
|
|
134485
|
+
const propH = node.height || node.naturalHeight || 0;
|
|
134486
|
+
w = Math.round(w || cssW || attrW || propW || 0);
|
|
134487
|
+
h = Math.round(h || cssH || attrH || propH || 0);
|
|
134488
|
+
}
|
|
134489
|
+
if (w) clone.dataset.snapdomWidth = String(w);
|
|
134490
|
+
if (h) clone.dataset.snapdomHeight = String(h);
|
|
134491
|
+
} catch {
|
|
134492
|
+
}
|
|
134493
|
+
}
|
|
134494
|
+
} catch (err) {
|
|
134495
|
+
console.error("[Snapdom] Failed to clone node:", node, err);
|
|
134496
|
+
throw err;
|
|
134497
|
+
}
|
|
134498
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
134499
|
+
const rect = node.getBoundingClientRect();
|
|
134500
|
+
clone.style.width = `${rect.width}px`;
|
|
134501
|
+
clone.style.height = `${rect.height}px`;
|
|
134502
|
+
}
|
|
134503
|
+
if (node instanceof HTMLInputElement) {
|
|
134504
|
+
clone.value = node.value;
|
|
134505
|
+
clone.setAttribute("value", node.value);
|
|
134506
|
+
if (node.checked !== void 0) {
|
|
134507
|
+
clone.checked = node.checked;
|
|
134508
|
+
if (node.checked) clone.setAttribute("checked", "");
|
|
134509
|
+
if (node.indeterminate) clone.indeterminate = node.indeterminate;
|
|
134510
|
+
}
|
|
134511
|
+
}
|
|
134512
|
+
if (node instanceof HTMLSelectElement) {
|
|
134513
|
+
pendingSelectValue = node.value;
|
|
134514
|
+
}
|
|
134515
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
134516
|
+
pendingTextAreaValue = node.value;
|
|
134517
|
+
}
|
|
134518
|
+
inlineAllStyles(node, clone, sessionCache, options);
|
|
134519
|
+
if (node.shadowRoot) {
|
|
134520
|
+
let callback2 = function(child, resolve) {
|
|
134521
|
+
if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "STYLE") {
|
|
134522
|
+
return resolve(null);
|
|
134523
|
+
} else {
|
|
134524
|
+
deepClone(child, sessionCache, options).then((clonedChild) => {
|
|
134525
|
+
resolve(clonedChild || null);
|
|
134526
|
+
}).catch(() => {
|
|
134527
|
+
resolve(null);
|
|
134528
|
+
});
|
|
134529
|
+
}
|
|
134530
|
+
};
|
|
134531
|
+
try {
|
|
134532
|
+
const slots = node.shadowRoot.querySelectorAll("slot");
|
|
134533
|
+
for (const s of slots) {
|
|
134534
|
+
let assigned = [];
|
|
134535
|
+
try {
|
|
134536
|
+
assigned = s.assignedNodes?.({ flatten: true }) || s.assignedNodes?.() || [];
|
|
134537
|
+
} catch {
|
|
134538
|
+
assigned = s.assignedNodes?.() || [];
|
|
134539
|
+
}
|
|
134540
|
+
for (const an of assigned) clonedAssignedNodes.add(an);
|
|
134541
|
+
}
|
|
134542
|
+
} catch {
|
|
134543
|
+
}
|
|
134544
|
+
const scopeId = nextShadowScopeId(sessionCache);
|
|
134545
|
+
const scopeSelector = `[data-sd="${scopeId}"]`;
|
|
134546
|
+
try {
|
|
134547
|
+
clone.setAttribute("data-sd", scopeId);
|
|
134548
|
+
} catch {
|
|
134549
|
+
}
|
|
134550
|
+
const rawCSS = extractShadowCSS(node.shadowRoot);
|
|
134551
|
+
const rewritten = rewriteShadowCSS(rawCSS, scopeSelector);
|
|
134552
|
+
const neededVars = collectCustomPropsFromCSS(rawCSS);
|
|
134553
|
+
const seed = buildSeedCustomPropsRule(node, neededVars, scopeSelector);
|
|
134554
|
+
injectScopedStyle(clone, seed + rewritten, scopeId);
|
|
134555
|
+
const shadowFrag = document.createDocumentFragment();
|
|
134556
|
+
const cloneList2 = await idleCallback(Array.from(node.shadowRoot.childNodes), callback2, options.fast);
|
|
134557
|
+
shadowFrag.append(...cloneList2.filter((clonedChild) => !!clonedChild));
|
|
134558
|
+
clone.appendChild(shadowFrag);
|
|
134559
|
+
}
|
|
134560
|
+
if (node.tagName === "SLOT") {
|
|
134561
|
+
let callback2 = function(child, resolve) {
|
|
134562
|
+
deepClone(child, sessionCache, options).then((clonedChild) => {
|
|
134563
|
+
if (clonedChild) {
|
|
134564
|
+
markSlottedSubtree(clonedChild);
|
|
134565
|
+
}
|
|
134566
|
+
resolve(clonedChild || null);
|
|
134567
|
+
}).catch(() => {
|
|
134568
|
+
resolve(null);
|
|
134569
|
+
});
|
|
134570
|
+
};
|
|
134571
|
+
const assigned = node.assignedNodes?.({ flatten: true }) || [];
|
|
134572
|
+
const nodesToClone = assigned.length > 0 ? assigned : Array.from(node.childNodes);
|
|
134573
|
+
const fragment = document.createDocumentFragment();
|
|
134574
|
+
const cloneList2 = await idleCallback(Array.from(nodesToClone), callback2, options.fast);
|
|
134575
|
+
fragment.append(...cloneList2.filter((clonedChild) => !!clonedChild));
|
|
134576
|
+
return fragment;
|
|
134577
|
+
}
|
|
134578
|
+
function callback(child, resolve) {
|
|
134579
|
+
if (clonedAssignedNodes.has(child)) return resolve(null);
|
|
134580
|
+
deepClone(child, sessionCache, options).then((clonedChild) => {
|
|
134581
|
+
resolve(clonedChild || null);
|
|
134582
|
+
}).catch(() => {
|
|
134583
|
+
resolve(null);
|
|
134584
|
+
});
|
|
134585
|
+
}
|
|
134586
|
+
const cloneList = await idleCallback(Array.from(node.childNodes), callback, options.fast);
|
|
134587
|
+
clone.append(...cloneList.filter((clonedChild) => !!clonedChild));
|
|
134588
|
+
if (pendingSelectValue !== null && clone instanceof HTMLSelectElement) {
|
|
134589
|
+
clone.value = pendingSelectValue;
|
|
134590
|
+
for (const opt of clone.options) {
|
|
134591
|
+
if (opt.value === pendingSelectValue) {
|
|
134592
|
+
opt.setAttribute("selected", "");
|
|
134593
|
+
} else {
|
|
134594
|
+
opt.removeAttribute("selected");
|
|
134595
|
+
}
|
|
134596
|
+
}
|
|
134597
|
+
}
|
|
134598
|
+
if (pendingTextAreaValue !== null && clone instanceof HTMLTextAreaElement) {
|
|
134599
|
+
clone.textContent = pendingTextAreaValue;
|
|
134600
|
+
}
|
|
134601
|
+
return clone;
|
|
134602
|
+
}
|
|
134603
|
+
|
|
134604
|
+
// src/modules/iconFonts.js
|
|
134605
|
+
var defaultIconFonts = [
|
|
134606
|
+
// /uicons/i,
|
|
134607
|
+
/font\s*awesome/i,
|
|
134608
|
+
/material\s*icons/i,
|
|
134609
|
+
/ionicons/i,
|
|
134610
|
+
/glyphicons/i,
|
|
134611
|
+
/feather/i,
|
|
134612
|
+
/bootstrap\s*icons/i,
|
|
134613
|
+
/remix\s*icons/i,
|
|
134614
|
+
/heroicons/i,
|
|
134615
|
+
/layui/i,
|
|
134616
|
+
/lucide/i
|
|
134617
|
+
];
|
|
134618
|
+
var userIconFonts = [];
|
|
134619
|
+
function extendIconFonts(fonts) {
|
|
134620
|
+
const list = Array.isArray(fonts) ? fonts : [fonts];
|
|
134621
|
+
for (const f of list) {
|
|
134622
|
+
if (f instanceof RegExp) {
|
|
134623
|
+
userIconFonts.push(f);
|
|
134624
|
+
} else if (typeof f === "string") {
|
|
134625
|
+
userIconFonts.push(new RegExp(f, "i"));
|
|
134626
|
+
} else {
|
|
134627
|
+
console.warn("[snapdom] Ignored invalid iconFont value:", f);
|
|
134628
|
+
}
|
|
134629
|
+
}
|
|
134630
|
+
}
|
|
134631
|
+
function isIconFont2(input) {
|
|
134632
|
+
const text = typeof input === "string" ? input : "";
|
|
134633
|
+
const candidates = [...defaultIconFonts, ...userIconFonts];
|
|
134634
|
+
for (const rx of candidates) {
|
|
134635
|
+
if (rx instanceof RegExp && rx.test(text)) return true;
|
|
134636
|
+
}
|
|
134637
|
+
if (/icon/i.test(text) || /glyph/i.test(text) || /symbols/i.test(text) || /feather/i.test(text) || /fontawesome/i.test(text)) return true;
|
|
134638
|
+
return false;
|
|
134639
|
+
}
|
|
134640
|
+
|
|
134641
|
+
// src/modules/fonts.js
|
|
134642
|
+
async function iconToImage(unicodeChar, fontFamily, fontWeight, fontSize = 32, color = "#000") {
|
|
134643
|
+
fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, "");
|
|
134644
|
+
const dpr = window.devicePixelRatio || 1;
|
|
134645
|
+
try {
|
|
134646
|
+
await document.fonts.ready;
|
|
134647
|
+
} catch {
|
|
134648
|
+
}
|
|
134649
|
+
const span = document.createElement("span");
|
|
134650
|
+
span.textContent = unicodeChar;
|
|
134651
|
+
span.style.position = "absolute";
|
|
134652
|
+
span.style.visibility = "hidden";
|
|
134653
|
+
span.style.fontFamily = `"${fontFamily}"`;
|
|
134654
|
+
span.style.fontWeight = fontWeight || "normal";
|
|
134655
|
+
span.style.fontSize = `${fontSize}px`;
|
|
134656
|
+
span.style.lineHeight = "1";
|
|
134657
|
+
span.style.whiteSpace = "nowrap";
|
|
134658
|
+
span.style.padding = "0";
|
|
134659
|
+
span.style.margin = "0";
|
|
134660
|
+
document.body.appendChild(span);
|
|
134661
|
+
const rect = span.getBoundingClientRect();
|
|
134662
|
+
const width = Math.ceil(rect.width);
|
|
134663
|
+
const height = Math.ceil(rect.height);
|
|
134664
|
+
document.body.removeChild(span);
|
|
134665
|
+
const canvas = document.createElement("canvas");
|
|
134666
|
+
canvas.width = Math.max(1, width * dpr);
|
|
134667
|
+
canvas.height = Math.max(1, height * dpr);
|
|
134668
|
+
const ctx = canvas.getContext("2d");
|
|
134669
|
+
ctx.scale(dpr, dpr);
|
|
134670
|
+
ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`;
|
|
134671
|
+
ctx.textAlign = "left";
|
|
134672
|
+
ctx.textBaseline = "top";
|
|
134673
|
+
ctx.fillStyle = color;
|
|
134674
|
+
ctx.fillText(unicodeChar, 0, 0);
|
|
134675
|
+
return {
|
|
134676
|
+
dataUrl: canvas.toDataURL(),
|
|
134677
|
+
width,
|
|
134678
|
+
height
|
|
134679
|
+
};
|
|
134680
|
+
}
|
|
134681
|
+
var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
|
|
134682
|
+
"serif",
|
|
134683
|
+
"sans-serif",
|
|
134684
|
+
"monospace",
|
|
134685
|
+
"cursive",
|
|
134686
|
+
"fantasy",
|
|
134687
|
+
"system-ui",
|
|
134688
|
+
"emoji",
|
|
134689
|
+
"math",
|
|
134690
|
+
"fangsong",
|
|
134691
|
+
"ui-serif",
|
|
134692
|
+
"ui-sans-serif",
|
|
134693
|
+
"ui-monospace",
|
|
134694
|
+
"ui-rounded"
|
|
134695
|
+
]);
|
|
134696
|
+
function pickPrimaryFamily(familyList) {
|
|
134697
|
+
if (!familyList) return "";
|
|
134698
|
+
for (let raw of familyList.split(",")) {
|
|
134699
|
+
let f = raw.trim().replace(/^['"]+|['"]+$/g, "");
|
|
134700
|
+
if (!f) continue;
|
|
134701
|
+
if (!GENERIC_FAMILIES.has(f.toLowerCase())) return f;
|
|
134702
|
+
}
|
|
134703
|
+
return "";
|
|
134704
|
+
}
|
|
134705
|
+
function normWeight(w) {
|
|
134706
|
+
const t = String(w ?? "400").trim().toLowerCase();
|
|
134707
|
+
if (t === "normal") return 400;
|
|
134708
|
+
if (t === "bold") return 700;
|
|
134709
|
+
const n = parseInt(t, 10);
|
|
134710
|
+
return Number.isFinite(n) ? Math.min(900, Math.max(100, n)) : 400;
|
|
134711
|
+
}
|
|
134712
|
+
function normStyle(s) {
|
|
134713
|
+
const t = String(s ?? "normal").trim().toLowerCase();
|
|
134714
|
+
if (t.startsWith("italic")) return "italic";
|
|
134715
|
+
if (t.startsWith("oblique")) return "oblique";
|
|
134716
|
+
return "normal";
|
|
134717
|
+
}
|
|
134718
|
+
function normStretchPct(st) {
|
|
134719
|
+
const m = String(st ?? "100%").match(/(\d+(?:\.\d+)?)\s*%/);
|
|
134720
|
+
return m ? Math.max(50, Math.min(200, parseFloat(m[1]))) : 100;
|
|
134721
|
+
}
|
|
134722
|
+
function parseWeightSpec(spec) {
|
|
134723
|
+
const s = String(spec || "400").trim();
|
|
134724
|
+
const m = s.match(/^(\d{2,3})\s+(\d{2,3})$/);
|
|
134725
|
+
if (m) {
|
|
134726
|
+
const a = normWeight(m[1]), b = normWeight(m[2]);
|
|
134727
|
+
return { min: Math.min(a, b), max: Math.max(a, b) };
|
|
134728
|
+
}
|
|
134729
|
+
const v = normWeight(s);
|
|
134730
|
+
return { min: v, max: v };
|
|
134731
|
+
}
|
|
134732
|
+
function parseStyleSpec(spec) {
|
|
134733
|
+
const t = String(spec || "normal").trim().toLowerCase();
|
|
134734
|
+
if (t === "italic") return { kind: "italic" };
|
|
134735
|
+
if (t.startsWith("oblique")) return { kind: "oblique" };
|
|
134736
|
+
return { kind: "normal" };
|
|
134737
|
+
}
|
|
134738
|
+
function parseStretchSpec(spec) {
|
|
134739
|
+
const s = String(spec || "100%").trim();
|
|
134740
|
+
const mm = s.match(/(\d+(?:\.\d+)?)\s*%\s+(\d+(?:\.\d+)?)\s*%/);
|
|
134741
|
+
if (mm) {
|
|
134742
|
+
const a = parseFloat(mm[1]), b = parseFloat(mm[2]);
|
|
134743
|
+
return { min: Math.min(a, b), max: Math.max(a, b) };
|
|
134744
|
+
}
|
|
134745
|
+
const m = s.match(/(\d+(?:\.\d+)?)\s*%/);
|
|
134746
|
+
const v = m ? parseFloat(m[1]) : 100;
|
|
134747
|
+
return { min: v, max: v };
|
|
134748
|
+
}
|
|
134749
|
+
function isLikelyFontStylesheet(href, requiredFamilies) {
|
|
134750
|
+
if (!href) return false;
|
|
134751
|
+
try {
|
|
134752
|
+
const u = new URL(href, location.href);
|
|
134753
|
+
const sameOrigin = u.origin === location.origin;
|
|
134754
|
+
if (sameOrigin) return true;
|
|
134755
|
+
const host = u.host.toLowerCase();
|
|
134756
|
+
const FONT_HOSTS = [
|
|
134757
|
+
"fonts.googleapis.com",
|
|
134758
|
+
"fonts.gstatic.com",
|
|
134759
|
+
"use.typekit.net",
|
|
134760
|
+
"p.typekit.net",
|
|
134761
|
+
"kit.fontawesome.com",
|
|
134762
|
+
"use.fontawesome.com"
|
|
134763
|
+
];
|
|
134764
|
+
if (FONT_HOSTS.some((h) => host.endsWith(h))) return true;
|
|
134765
|
+
const path = (u.pathname + u.search).toLowerCase();
|
|
134766
|
+
if (/\bfont(s)?\b/.test(path) || /\.woff2?(\b|$)/.test(path)) return true;
|
|
134767
|
+
for (const fam of requiredFamilies) {
|
|
134768
|
+
const tokenA = fam.toLowerCase().replace(/\s+/g, "+");
|
|
134769
|
+
const tokenB = fam.toLowerCase().replace(/\s+/g, "-");
|
|
134770
|
+
if (path.includes(tokenA) || path.includes(tokenB)) return true;
|
|
134771
|
+
}
|
|
134772
|
+
return false;
|
|
134773
|
+
} catch {
|
|
134774
|
+
return false;
|
|
134775
|
+
}
|
|
134776
|
+
}
|
|
134777
|
+
function familiesFromRequired(required) {
|
|
134778
|
+
const out = /* @__PURE__ */ new Set();
|
|
134779
|
+
for (const k of required || []) {
|
|
134780
|
+
const fam = String(k).split("__")[0]?.trim();
|
|
134781
|
+
if (fam) out.add(fam);
|
|
134782
|
+
}
|
|
134783
|
+
return out;
|
|
134784
|
+
}
|
|
134785
|
+
function rewriteRelativeUrls(cssText, baseHref) {
|
|
134786
|
+
if (!cssText) return cssText;
|
|
134787
|
+
return cssText.replace(
|
|
134788
|
+
/url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,
|
|
134789
|
+
(m, q, u) => {
|
|
134790
|
+
const src = (u || "").trim();
|
|
134791
|
+
if (!src || /^data:|^blob:|^https?:|^file:|^about:/i.test(src)) return m;
|
|
134792
|
+
let abs = src;
|
|
134793
|
+
try {
|
|
134794
|
+
abs = new URL(src, baseHref || location.href).href;
|
|
134795
|
+
} catch {
|
|
134796
|
+
}
|
|
134797
|
+
return `url("${abs}")`;
|
|
134798
|
+
}
|
|
134799
|
+
);
|
|
134800
|
+
}
|
|
134801
|
+
var IMPORT_ANY_RE = /@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g;
|
|
134802
|
+
var MAX_IMPORT_DEPTH = 4;
|
|
134803
|
+
async function inlineImportsAndRewrite(cssText, ownerHref, useProxy) {
|
|
134804
|
+
if (!cssText) return cssText;
|
|
134805
|
+
const visited = /* @__PURE__ */ new Set();
|
|
134806
|
+
function normalizeUrl(u, base) {
|
|
134807
|
+
try {
|
|
134808
|
+
return new URL(u, base || location.href).href;
|
|
134809
|
+
} catch {
|
|
134810
|
+
return u;
|
|
134811
|
+
}
|
|
134812
|
+
}
|
|
134813
|
+
async function resolveOnce(text, baseHref, depth = 0) {
|
|
134814
|
+
if (depth > MAX_IMPORT_DEPTH) {
|
|
134815
|
+
console.warn(`[snapDOM] @import depth exceeded (${MAX_IMPORT_DEPTH}) at ${baseHref}`);
|
|
134816
|
+
return text;
|
|
134817
|
+
}
|
|
134818
|
+
let out = "";
|
|
134819
|
+
let last = 0;
|
|
134820
|
+
let m;
|
|
134821
|
+
while (m = IMPORT_ANY_RE.exec(text)) {
|
|
134822
|
+
out += text.slice(last, m.index);
|
|
134823
|
+
last = IMPORT_ANY_RE.lastIndex;
|
|
134824
|
+
const rawUrl = (m[2] || m[4] || "").trim();
|
|
134825
|
+
const absUrl = normalizeUrl(rawUrl, baseHref);
|
|
134826
|
+
if (visited.has(absUrl)) {
|
|
134827
|
+
console.warn(`[snapDOM] Skipping circular @import: ${absUrl}`);
|
|
134828
|
+
continue;
|
|
134829
|
+
}
|
|
134830
|
+
visited.add(absUrl);
|
|
134831
|
+
let imported = "";
|
|
134832
|
+
try {
|
|
134833
|
+
const r = await snapFetch(absUrl, { as: "text", useProxy, silent: true });
|
|
134834
|
+
if (r.ok && typeof r.data === "string") imported = r.data;
|
|
134835
|
+
} catch {
|
|
134836
|
+
}
|
|
134837
|
+
if (imported) {
|
|
134838
|
+
imported = rewriteRelativeUrls(imported, absUrl);
|
|
134839
|
+
imported = await resolveOnce(imported, absUrl, depth + 1);
|
|
134840
|
+
out += `
|
|
134841
|
+
/* inlined: ${absUrl} */
|
|
134842
|
+
${imported}
|
|
134843
|
+
`;
|
|
134844
|
+
} else {
|
|
134845
|
+
out += m[0];
|
|
134846
|
+
}
|
|
134847
|
+
}
|
|
134848
|
+
out += text.slice(last);
|
|
134849
|
+
return out;
|
|
134850
|
+
}
|
|
134851
|
+
let rewritten = rewriteRelativeUrls(cssText, ownerHref || location.href);
|
|
134852
|
+
rewritten = await resolveOnce(rewritten, ownerHref || location.href, 0);
|
|
134853
|
+
return rewritten;
|
|
134854
|
+
}
|
|
134855
|
+
var URL_RE = /url\((["']?)([^"')]+)\1\)/g;
|
|
134856
|
+
var FACE_RE = /@font-face[^{}]*\{[^}]*\}/g;
|
|
134857
|
+
function parseUnicodeRange(ur) {
|
|
134858
|
+
if (!ur) return [];
|
|
134859
|
+
const ranges = [];
|
|
134860
|
+
const parts = ur.split(",").map((s) => s.trim()).filter(Boolean);
|
|
134861
|
+
for (const p of parts) {
|
|
134862
|
+
const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);
|
|
134863
|
+
if (!m) continue;
|
|
134864
|
+
const a = m[1], b = m[2];
|
|
134865
|
+
const expand = (hex) => {
|
|
134866
|
+
if (!hex.includes("?")) return parseInt(hex, 16);
|
|
134867
|
+
const min = parseInt(hex.replace(/\?/g, "0"), 16);
|
|
134868
|
+
const max = parseInt(hex.replace(/\?/g, "F"), 16);
|
|
134869
|
+
return [min, max];
|
|
134870
|
+
};
|
|
134871
|
+
if (b) {
|
|
134872
|
+
const A = expand(a), B = expand(b);
|
|
134873
|
+
const min = Array.isArray(A) ? A[0] : A;
|
|
134874
|
+
const max = Array.isArray(B) ? B[1] : B;
|
|
134875
|
+
ranges.push([Math.min(min, max), Math.max(min, max)]);
|
|
134876
|
+
} else {
|
|
134877
|
+
const X = expand(a);
|
|
134878
|
+
if (Array.isArray(X)) ranges.push([X[0], X[1]]);
|
|
134879
|
+
else ranges.push([X, X]);
|
|
134880
|
+
}
|
|
134881
|
+
}
|
|
134882
|
+
return ranges;
|
|
134883
|
+
}
|
|
134884
|
+
function unicodeIntersects(used, ranges) {
|
|
134885
|
+
if (!ranges.length) return true;
|
|
134886
|
+
if (!used || used.size === 0) return true;
|
|
134887
|
+
for (const cp of used) {
|
|
134888
|
+
for (const [a, b] of ranges) if (cp >= a && cp <= b) return true;
|
|
134889
|
+
}
|
|
134890
|
+
return false;
|
|
134891
|
+
}
|
|
134892
|
+
function extractSrcUrls(srcValue, baseHref) {
|
|
134893
|
+
const urls = [];
|
|
134894
|
+
if (!srcValue) return urls;
|
|
134895
|
+
for (const m of srcValue.matchAll(URL_RE)) {
|
|
134896
|
+
let u = (m[2] || "").trim();
|
|
134897
|
+
if (!u || u.startsWith("data:")) continue;
|
|
134898
|
+
if (!/^https?:/i.test(u)) {
|
|
134899
|
+
try {
|
|
134900
|
+
u = new URL(u, baseHref || location.href).href;
|
|
134901
|
+
} catch {
|
|
134902
|
+
}
|
|
134903
|
+
}
|
|
134904
|
+
urls.push(u);
|
|
134905
|
+
}
|
|
134906
|
+
return urls;
|
|
134907
|
+
}
|
|
134908
|
+
async function inlineUrlsInCssBlock(cssBlock, baseHref, useProxy = "") {
|
|
134909
|
+
let out = cssBlock;
|
|
134910
|
+
for (const m of cssBlock.matchAll(URL_RE)) {
|
|
134911
|
+
const raw = extractURL(m[0]);
|
|
134912
|
+
if (!raw) continue;
|
|
134913
|
+
let abs = raw;
|
|
134914
|
+
if (!abs.startsWith("http") && !abs.startsWith("data:")) {
|
|
134915
|
+
try {
|
|
134916
|
+
abs = new URL(abs, baseHref || location.href).href;
|
|
134917
|
+
} catch {
|
|
134918
|
+
}
|
|
134919
|
+
}
|
|
134920
|
+
if (isIconFont2(abs)) continue;
|
|
134921
|
+
if (cache.resource?.has(abs)) {
|
|
134922
|
+
cache.font?.add(abs);
|
|
134923
|
+
out = out.replace(m[0], `url(${cache.resource.get(abs)})`);
|
|
134924
|
+
continue;
|
|
134925
|
+
}
|
|
134926
|
+
if (cache.font?.has(abs)) continue;
|
|
134927
|
+
try {
|
|
134928
|
+
const r = await snapFetch(abs, { as: "dataURL", useProxy, silent: true });
|
|
134929
|
+
if (r.ok && typeof r.data === "string") {
|
|
134930
|
+
const b64 = r.data;
|
|
134931
|
+
cache.resource?.set(abs, b64);
|
|
134932
|
+
cache.font?.add(abs);
|
|
134933
|
+
out = out.replace(m[0], `url(${b64})`);
|
|
134934
|
+
}
|
|
134935
|
+
} catch {
|
|
134936
|
+
console.warn("[snapDOM] Failed to fetch font resource:", abs);
|
|
134937
|
+
}
|
|
134938
|
+
}
|
|
134939
|
+
return out;
|
|
134940
|
+
}
|
|
134941
|
+
function subsetFromRanges(ranges) {
|
|
134942
|
+
if (!ranges.length) return null;
|
|
134943
|
+
const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b));
|
|
134944
|
+
const latin = hit(0, 255) || hit(305, 305);
|
|
134945
|
+
const latinExt = hit(256, 591) || hit(7680, 7935);
|
|
134946
|
+
const greek = hit(880, 1023);
|
|
134947
|
+
const cyr = hit(1024, 1279);
|
|
134948
|
+
const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432);
|
|
134949
|
+
if (viet) return "vietnamese";
|
|
134950
|
+
if (cyr) return "cyrillic";
|
|
134951
|
+
if (greek) return "greek";
|
|
134952
|
+
if (latinExt) return "latin-ext";
|
|
134953
|
+
if (latin) return "latin";
|
|
134954
|
+
return null;
|
|
134955
|
+
}
|
|
134956
|
+
function buildSimpleExcluder(ex = {}) {
|
|
134957
|
+
const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase()));
|
|
134958
|
+
const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase()));
|
|
134959
|
+
const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase()));
|
|
134960
|
+
return (meta, parsedRanges) => {
|
|
134961
|
+
if (famSet.size && famSet.has(meta.family.toLowerCase())) return true;
|
|
134962
|
+
if (domSet.size) {
|
|
134963
|
+
for (const u of meta.srcUrls) {
|
|
134964
|
+
try {
|
|
134965
|
+
if (domSet.has(new URL(u).host.toLowerCase())) return true;
|
|
134966
|
+
} catch {
|
|
134967
|
+
}
|
|
134968
|
+
}
|
|
134969
|
+
}
|
|
134970
|
+
if (subSet.size) {
|
|
134971
|
+
const label = subsetFromRanges(parsedRanges);
|
|
134972
|
+
if (label && subSet.has(label)) return true;
|
|
134973
|
+
}
|
|
134974
|
+
return false;
|
|
134975
|
+
};
|
|
134976
|
+
}
|
|
134977
|
+
function dedupeFontFaces(cssText) {
|
|
134978
|
+
if (!cssText) return cssText;
|
|
134979
|
+
const FACE_RE_G = /@font-face[^{}]*\{[^}]*\}/gi;
|
|
134980
|
+
const seen = /* @__PURE__ */ new Set();
|
|
134981
|
+
const out = [];
|
|
134982
|
+
for (const block of cssText.match(FACE_RE_G) || []) {
|
|
134983
|
+
const familyRaw = block.match(/font-family:\s*([^;]+);/i)?.[1] || "";
|
|
134984
|
+
const family = pickPrimaryFamily(familyRaw);
|
|
134985
|
+
const weightSpec = (block.match(/font-weight:\s*([^;]+);/i)?.[1] || "400").trim();
|
|
134986
|
+
const styleSpec = (block.match(/font-style:\s*([^;]+);/i)?.[1] || "normal").trim();
|
|
134987
|
+
const stretchSpec = (block.match(/font-stretch:\s*([^;]+);/i)?.[1] || "100%").trim();
|
|
134988
|
+
const urange = (block.match(/unicode-range:\s*([^;]+);/i)?.[1] || "").trim();
|
|
134989
|
+
const srcRaw = (block.match(/src\s*:\s*([^;]+);/i)?.[1] || "").trim();
|
|
134990
|
+
const urls = extractSrcUrls(srcRaw, location.href);
|
|
134991
|
+
const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
|
|
134992
|
+
const key = [
|
|
134993
|
+
String(family || "").toLowerCase(),
|
|
134994
|
+
weightSpec,
|
|
134995
|
+
styleSpec,
|
|
134996
|
+
stretchSpec,
|
|
134997
|
+
urange.toLowerCase(),
|
|
134998
|
+
srcPart
|
|
134999
|
+
].join("|");
|
|
135000
|
+
if (!seen.has(key)) {
|
|
135001
|
+
seen.add(key);
|
|
135002
|
+
out.push(block);
|
|
135003
|
+
}
|
|
135004
|
+
}
|
|
135005
|
+
if (out.length === 0) return cssText;
|
|
135006
|
+
let i = 0;
|
|
135007
|
+
return cssText.replace(FACE_RE_G, () => out[i++] || "");
|
|
135008
|
+
}
|
|
135009
|
+
function buildFontsCacheKey(required, exclude, localFonts, useProxy) {
|
|
135010
|
+
const req = Array.from(required || []).sort().join("|");
|
|
135011
|
+
const ex = exclude ? JSON.stringify({
|
|
135012
|
+
families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(),
|
|
135013
|
+
domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(),
|
|
135014
|
+
subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort()
|
|
135015
|
+
}) : "";
|
|
135016
|
+
const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|");
|
|
135017
|
+
const px = useProxy || "";
|
|
135018
|
+
return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`;
|
|
135019
|
+
}
|
|
135020
|
+
async function collectFacesFromSheet(sheet, baseHref, emitFace, ctx) {
|
|
135021
|
+
let rules;
|
|
135022
|
+
try {
|
|
135023
|
+
rules = sheet.cssRules || [];
|
|
135024
|
+
} catch {
|
|
135025
|
+
return;
|
|
135026
|
+
}
|
|
135027
|
+
const normalizeUrl = (u, base) => {
|
|
135028
|
+
try {
|
|
135029
|
+
return new URL(u, base || location.href).href;
|
|
135030
|
+
} catch {
|
|
135031
|
+
return u;
|
|
135032
|
+
}
|
|
135033
|
+
};
|
|
135034
|
+
for (const rule of rules) {
|
|
135035
|
+
if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet) {
|
|
135036
|
+
const childHref = rule.href ? normalizeUrl(rule.href, baseHref) : baseHref;
|
|
135037
|
+
if (ctx.depth >= MAX_IMPORT_DEPTH) {
|
|
135038
|
+
console.warn(`[snapDOM] CSSOM import depth exceeded (${MAX_IMPORT_DEPTH}) at ${childHref}`);
|
|
135039
|
+
continue;
|
|
135040
|
+
}
|
|
135041
|
+
if (childHref && ctx.visitedSheets.has(childHref)) {
|
|
135042
|
+
console.warn(`[snapDOM] Skipping circular CSSOM import: ${childHref}`);
|
|
135043
|
+
continue;
|
|
135044
|
+
}
|
|
135045
|
+
if (childHref) ctx.visitedSheets.add(childHref);
|
|
135046
|
+
const nextCtx = { ...ctx, depth: (ctx.depth || 0) + 1 };
|
|
135047
|
+
await collectFacesFromSheet(rule.styleSheet, childHref, emitFace, nextCtx);
|
|
135048
|
+
continue;
|
|
135049
|
+
}
|
|
135050
|
+
if (rule.type === CSSRule.FONT_FACE_RULE) {
|
|
135051
|
+
const famRaw = (rule.style.getPropertyValue("font-family") || "").trim();
|
|
135052
|
+
const family = pickPrimaryFamily(famRaw);
|
|
135053
|
+
if (!family || isIconFont2(family)) continue;
|
|
135054
|
+
const weightSpec = (rule.style.getPropertyValue("font-weight") || "400").trim();
|
|
135055
|
+
const styleSpec = (rule.style.getPropertyValue("font-style") || "normal").trim();
|
|
135056
|
+
const stretchSpec = (rule.style.getPropertyValue("font-stretch") || "100%").trim();
|
|
135057
|
+
const srcRaw = (rule.style.getPropertyValue("src") || "").trim();
|
|
135058
|
+
const urange = (rule.style.getPropertyValue("unicode-range") || "").trim();
|
|
135059
|
+
if (!ctx.faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
135060
|
+
const ranges = parseUnicodeRange(urange);
|
|
135061
|
+
if (!unicodeIntersects(ctx.usedCodepoints, ranges)) continue;
|
|
135062
|
+
const meta = {
|
|
135063
|
+
family,
|
|
135064
|
+
weightSpec,
|
|
135065
|
+
styleSpec,
|
|
135066
|
+
stretchSpec,
|
|
135067
|
+
unicodeRange: urange,
|
|
135068
|
+
srcRaw,
|
|
135069
|
+
srcUrls: extractSrcUrls(srcRaw, baseHref || location.href),
|
|
135070
|
+
href: baseHref || location.href
|
|
135071
|
+
};
|
|
135072
|
+
if (ctx.simpleExcluder && ctx.simpleExcluder(meta, ranges)) continue;
|
|
135073
|
+
if (/url\(/i.test(srcRaw)) {
|
|
135074
|
+
const inlinedSrc = await inlineUrlsInCssBlock(srcRaw, baseHref || location.href, ctx.useProxy);
|
|
135075
|
+
await emitFace(`@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
|
|
135076
|
+
} else {
|
|
135077
|
+
await emitFace(`@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
|
|
135078
|
+
}
|
|
135079
|
+
}
|
|
135080
|
+
}
|
|
135081
|
+
}
|
|
135082
|
+
async function embedCustomFonts({
|
|
135083
|
+
required,
|
|
135084
|
+
usedCodepoints,
|
|
135085
|
+
exclude = void 0,
|
|
135086
|
+
localFonts = [],
|
|
135087
|
+
useProxy = ""
|
|
135088
|
+
} = {}) {
|
|
135089
|
+
if (!(required instanceof Set)) required = /* @__PURE__ */ new Set();
|
|
135090
|
+
if (!(usedCodepoints instanceof Set)) usedCodepoints = /* @__PURE__ */ new Set();
|
|
135091
|
+
const requiredIndex = /* @__PURE__ */ new Map();
|
|
135092
|
+
for (const key of required) {
|
|
135093
|
+
const [fam, w, s, st] = String(key).split("__");
|
|
135094
|
+
if (!fam) continue;
|
|
135095
|
+
const arr = requiredIndex.get(fam) || [];
|
|
135096
|
+
arr.push({ w: parseInt(w, 10), s, st: parseInt(st, 10) });
|
|
135097
|
+
requiredIndex.set(fam, arr);
|
|
135098
|
+
}
|
|
135099
|
+
function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
|
|
135100
|
+
if (!requiredIndex.has(fam)) return false;
|
|
135101
|
+
const need = requiredIndex.get(fam);
|
|
135102
|
+
const ws = parseWeightSpec(weightSpec);
|
|
135103
|
+
const ss = parseStyleSpec(styleSpec);
|
|
135104
|
+
const ts = parseStretchSpec(stretchSpec);
|
|
135105
|
+
const faceIsRange = ws.min !== ws.max;
|
|
135106
|
+
const faceSingleW = ws.min;
|
|
135107
|
+
const styleOK = (reqKind) => ss.kind === "normal" && reqKind === "normal" || ss.kind !== "normal" && (reqKind === "italic" || reqKind === "oblique");
|
|
135108
|
+
let exactMatched = false;
|
|
135109
|
+
for (const r of need) {
|
|
135110
|
+
const wOk = faceIsRange ? r.w >= ws.min && r.w <= ws.max : r.w === faceSingleW;
|
|
135111
|
+
const sOk = styleOK(normStyle(r.s));
|
|
135112
|
+
const tOk = r.st >= ts.min && r.st <= ts.max;
|
|
135113
|
+
if (wOk && sOk && tOk) {
|
|
135114
|
+
exactMatched = true;
|
|
135115
|
+
break;
|
|
135116
|
+
}
|
|
135117
|
+
}
|
|
135118
|
+
if (exactMatched) return true;
|
|
135119
|
+
if (!faceIsRange) {
|
|
135120
|
+
for (const r of need) {
|
|
135121
|
+
const sOk = styleOK(normStyle(r.s));
|
|
135122
|
+
const tOk = r.st >= ts.min && r.st <= ts.max;
|
|
135123
|
+
const nearWeight = Math.abs(faceSingleW - r.w) <= 300;
|
|
135124
|
+
if (nearWeight && sOk && tOk) return true;
|
|
135125
|
+
}
|
|
135126
|
+
}
|
|
135127
|
+
return false;
|
|
135128
|
+
}
|
|
135129
|
+
const simpleExcluder = buildSimpleExcluder(exclude);
|
|
135130
|
+
const cacheKey = buildFontsCacheKey(required, exclude, localFonts, useProxy);
|
|
135131
|
+
if (cache.resource?.has(cacheKey)) {
|
|
135132
|
+
return cache.resource.get(cacheKey);
|
|
135133
|
+
}
|
|
135134
|
+
const requiredFamilies = familiesFromRequired(required);
|
|
135135
|
+
const importUrls = [];
|
|
135136
|
+
const IMPORT_ANY_RE_LOCAL = IMPORT_ANY_RE;
|
|
135137
|
+
for (const styleTag of document.querySelectorAll("style")) {
|
|
135138
|
+
const cssText = styleTag.textContent || "";
|
|
135139
|
+
for (const m of cssText.matchAll(IMPORT_ANY_RE_LOCAL)) {
|
|
135140
|
+
const u = (m[2] || m[4] || "").trim();
|
|
135141
|
+
if (!u || isIconFont2(u)) continue;
|
|
135142
|
+
const hasLink = !!document.querySelector(`link[rel="stylesheet"][href="${u}"]`);
|
|
135143
|
+
if (!hasLink) importUrls.push(u);
|
|
135144
|
+
}
|
|
135145
|
+
}
|
|
135146
|
+
if (importUrls.length) {
|
|
135147
|
+
await Promise.all(importUrls.map((u) => new Promise((resolve) => {
|
|
135148
|
+
if (document.querySelector(`link[rel="stylesheet"][href="${u}"]`)) return resolve(null);
|
|
135149
|
+
const link = document.createElement("link");
|
|
135150
|
+
link.rel = "stylesheet";
|
|
135151
|
+
link.href = u;
|
|
135152
|
+
link.setAttribute("data-snapdom", "injected-import");
|
|
135153
|
+
link.onload = () => resolve(link);
|
|
135154
|
+
link.onerror = () => resolve(null);
|
|
135155
|
+
document.head.appendChild(link);
|
|
135156
|
+
})));
|
|
135157
|
+
}
|
|
135158
|
+
let finalCSS = "";
|
|
135159
|
+
const linkNodes = Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter((l) => !!l.href);
|
|
135160
|
+
for (const link of linkNodes) {
|
|
135161
|
+
try {
|
|
135162
|
+
if (isIconFont2(link.href)) continue;
|
|
135163
|
+
let cssText = "";
|
|
135164
|
+
let sameOrigin = false;
|
|
135165
|
+
try {
|
|
135166
|
+
sameOrigin = new URL(link.href, location.href).origin === location.origin;
|
|
135167
|
+
} catch {
|
|
135168
|
+
}
|
|
135169
|
+
if (!sameOrigin) {
|
|
135170
|
+
if (!isLikelyFontStylesheet(link.href, requiredFamilies)) continue;
|
|
135171
|
+
}
|
|
135172
|
+
if (sameOrigin) {
|
|
135173
|
+
const sheet = Array.from(document.styleSheets).find((s) => s.href === link.href);
|
|
135174
|
+
if (sheet) {
|
|
135175
|
+
try {
|
|
135176
|
+
const rules = sheet.cssRules || [];
|
|
135177
|
+
cssText = Array.from(rules).map((r) => r.cssText).join("");
|
|
135178
|
+
} catch {
|
|
135179
|
+
}
|
|
135180
|
+
}
|
|
135181
|
+
}
|
|
135182
|
+
if (!cssText) {
|
|
135183
|
+
const res = await snapFetch(link.href, { as: "text", useProxy });
|
|
135184
|
+
cssText = res.data;
|
|
135185
|
+
if (isIconFont2(link.href)) continue;
|
|
135186
|
+
}
|
|
135187
|
+
cssText = await inlineImportsAndRewrite(cssText, link.href, useProxy);
|
|
135188
|
+
let facesOut = "";
|
|
135189
|
+
for (const face of cssText.match(FACE_RE) || []) {
|
|
135190
|
+
const famRaw = (face.match(/font-family:\s*([^;]+);/i)?.[1] || "").trim();
|
|
135191
|
+
const family = pickPrimaryFamily(famRaw);
|
|
135192
|
+
if (!family || isIconFont2(family)) continue;
|
|
135193
|
+
const weightSpec = (face.match(/font-weight:\s*([^;]+);/i)?.[1] || "400").trim();
|
|
135194
|
+
const styleSpec = (face.match(/font-style:\s*([^;]+);/i)?.[1] || "normal").trim();
|
|
135195
|
+
const stretchSpec = (face.match(/font-stretch:\s*([^;]+);/i)?.[1] || "100%").trim();
|
|
135196
|
+
const urange = (face.match(/unicode-range:\s*([^;]+);/i)?.[1] || "").trim();
|
|
135197
|
+
const srcRaw = (face.match(/src\s*:\s*([^;]+);/i)?.[1] || "").trim();
|
|
135198
|
+
const srcUrls = extractSrcUrls(srcRaw, link.href);
|
|
135199
|
+
if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
135200
|
+
const ranges = parseUnicodeRange(urange);
|
|
135201
|
+
if (!unicodeIntersects(usedCodepoints, ranges)) continue;
|
|
135202
|
+
const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: link.href };
|
|
135203
|
+
if (exclude && simpleExcluder(meta, ranges)) continue;
|
|
135204
|
+
const newFace = /url\(/i.test(srcRaw) ? await inlineUrlsInCssBlock(face, link.href, useProxy) : face;
|
|
135205
|
+
facesOut += newFace;
|
|
135206
|
+
}
|
|
135207
|
+
if (facesOut.trim()) finalCSS += facesOut;
|
|
135208
|
+
} catch {
|
|
135209
|
+
console.warn("[snapDOM] Failed to process stylesheet:", link.href);
|
|
135210
|
+
}
|
|
135211
|
+
}
|
|
135212
|
+
const ctx = {
|
|
135213
|
+
requiredIndex,
|
|
135214
|
+
usedCodepoints,
|
|
135215
|
+
faceMatchesRequired,
|
|
135216
|
+
simpleExcluder: exclude ? buildSimpleExcluder(exclude) : null,
|
|
135217
|
+
useProxy,
|
|
135218
|
+
visitedSheets: /* @__PURE__ */ new Set(),
|
|
135219
|
+
depth: 0
|
|
135220
|
+
};
|
|
135221
|
+
for (const sheet of document.styleSheets) {
|
|
135222
|
+
if (sheet.href && linkNodes.some((l) => l.href === sheet.href)) continue;
|
|
135223
|
+
try {
|
|
135224
|
+
const rootHref = sheet.href || location.href;
|
|
135225
|
+
if (rootHref) ctx.visitedSheets.add(rootHref);
|
|
135226
|
+
await collectFacesFromSheet(
|
|
135227
|
+
sheet,
|
|
135228
|
+
rootHref,
|
|
135229
|
+
async (faceCss) => {
|
|
135230
|
+
finalCSS += faceCss;
|
|
135231
|
+
},
|
|
135232
|
+
ctx
|
|
135233
|
+
);
|
|
135234
|
+
} catch {
|
|
135235
|
+
}
|
|
135236
|
+
}
|
|
135237
|
+
try {
|
|
135238
|
+
for (const f of document.fonts || []) {
|
|
135239
|
+
if (!f || !f.family || f.status !== "loaded" || !f._snapdomSrc) continue;
|
|
135240
|
+
const fam = String(f.family).replace(/^['"]+|['"]+$/g, "");
|
|
135241
|
+
if (isIconFont2(fam)) continue;
|
|
135242
|
+
if (!requiredIndex.has(fam)) continue;
|
|
135243
|
+
if (exclude?.families && exclude.families.some((n) => String(n).toLowerCase() === fam.toLowerCase())) {
|
|
135244
|
+
continue;
|
|
135245
|
+
}
|
|
135246
|
+
let b64 = f._snapdomSrc;
|
|
135247
|
+
if (!String(b64).startsWith("data:")) {
|
|
135248
|
+
if (cache.resource?.has(f._snapdomSrc)) {
|
|
135249
|
+
b64 = cache.resource.get(f._snapdomSrc);
|
|
135250
|
+
cache.font?.add(f._snapdomSrc);
|
|
135251
|
+
} else if (!cache.font?.has(f._snapdomSrc)) {
|
|
135252
|
+
try {
|
|
135253
|
+
const r = await snapFetch(f._snapdomSrc, { as: "dataURL", useProxy, silent: true });
|
|
135254
|
+
if (r.ok && typeof r.data === "string") {
|
|
135255
|
+
b64 = r.data;
|
|
135256
|
+
cache.resource?.set(f._snapdomSrc, b64);
|
|
135257
|
+
cache.font?.add(f._snapdomSrc);
|
|
135258
|
+
} else {
|
|
135259
|
+
continue;
|
|
135260
|
+
}
|
|
135261
|
+
} catch {
|
|
135262
|
+
console.warn("[snapDOM] Failed to fetch dynamic font src:", f._snapdomSrc);
|
|
135263
|
+
continue;
|
|
135264
|
+
}
|
|
135265
|
+
}
|
|
135266
|
+
}
|
|
135267
|
+
finalCSS += `@font-face{font-family:'${fam}';src:url(${b64});font-style:${f.style || "normal"};font-weight:${f.weight || "normal"};}`;
|
|
135268
|
+
}
|
|
135269
|
+
} catch {
|
|
135270
|
+
}
|
|
135271
|
+
for (const font of localFonts) {
|
|
135272
|
+
if (!font || typeof font !== "object") continue;
|
|
135273
|
+
const family = String(font.family || "").replace(/^['"]+|['"]+$/g, "");
|
|
135274
|
+
if (!family || isIconFont2(family)) continue;
|
|
135275
|
+
if (!requiredIndex.has(family)) continue;
|
|
135276
|
+
if (exclude?.families && exclude.families.some((n) => String(n).toLowerCase() === family.toLowerCase())) continue;
|
|
135277
|
+
const weight = font.weight != null ? String(font.weight) : "normal";
|
|
135278
|
+
const style = font.style != null ? String(font.style) : "normal";
|
|
135279
|
+
const stretch = font.stretchPct != null ? `${font.stretchPct}%` : "100%";
|
|
135280
|
+
const src = String(font.src || "");
|
|
135281
|
+
let b64 = src;
|
|
135282
|
+
if (!b64.startsWith("data:")) {
|
|
135283
|
+
if (cache.resource?.has(src)) {
|
|
135284
|
+
b64 = cache.resource.get(src);
|
|
135285
|
+
cache.font?.add(src);
|
|
135286
|
+
} else if (!cache.font?.has(src)) {
|
|
135287
|
+
try {
|
|
135288
|
+
const r = await snapFetch(src, { as: "dataURL", useProxy, silent: true });
|
|
135289
|
+
if (r.ok && typeof r.data === "string") {
|
|
135290
|
+
b64 = r.data;
|
|
135291
|
+
cache.resource?.set(src, b64);
|
|
135292
|
+
cache.font?.add(src);
|
|
135293
|
+
} else {
|
|
135294
|
+
continue;
|
|
135295
|
+
}
|
|
135296
|
+
} catch {
|
|
135297
|
+
console.warn("[snapDOM] Failed to fetch localFonts src:", src);
|
|
135298
|
+
continue;
|
|
135299
|
+
}
|
|
135300
|
+
}
|
|
135301
|
+
}
|
|
135302
|
+
finalCSS += `@font-face{font-family:'${family}';src:url(${b64});font-style:${style};font-weight:${weight};font-stretch:${stretch};}`;
|
|
135303
|
+
}
|
|
135304
|
+
if (finalCSS) {
|
|
135305
|
+
finalCSS = dedupeFontFaces(finalCSS);
|
|
135306
|
+
cache.resource?.set(cacheKey, finalCSS);
|
|
135307
|
+
}
|
|
135308
|
+
return finalCSS;
|
|
135309
|
+
}
|
|
135310
|
+
function collectUsedFontVariants(root) {
|
|
135311
|
+
const req = /* @__PURE__ */ new Set();
|
|
135312
|
+
if (!root) return req;
|
|
135313
|
+
const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
|
|
135314
|
+
const addFromStyle = (cs) => {
|
|
135315
|
+
const family = pickPrimaryFamily(cs.fontFamily);
|
|
135316
|
+
if (!family) return;
|
|
135317
|
+
const key = (w, s, st) => `${family}__${normWeight(w)}__${normStyle(s)}__${normStretchPct(st)}`;
|
|
135318
|
+
req.add(key(cs.fontWeight, cs.fontStyle, cs.fontStretch));
|
|
135319
|
+
};
|
|
135320
|
+
addFromStyle(getComputedStyle(root));
|
|
135321
|
+
const csBeforeRoot = getComputedStyle(root, "::before");
|
|
135322
|
+
if (csBeforeRoot && csBeforeRoot.content && csBeforeRoot.content !== "none") addFromStyle(csBeforeRoot);
|
|
135323
|
+
const csAfterRoot = getComputedStyle(root, "::after");
|
|
135324
|
+
if (csAfterRoot && csAfterRoot.content && csAfterRoot.content !== "none") addFromStyle(csAfterRoot);
|
|
135325
|
+
while (tw.nextNode()) {
|
|
135326
|
+
const el = (
|
|
135327
|
+
/** @type {Element} */
|
|
135328
|
+
tw.currentNode
|
|
135329
|
+
);
|
|
135330
|
+
const cs = getComputedStyle(el);
|
|
135331
|
+
addFromStyle(cs);
|
|
135332
|
+
const b = getComputedStyle(el, "::before");
|
|
135333
|
+
if (b && b.content && b.content !== "none") addFromStyle(b);
|
|
135334
|
+
const a = getComputedStyle(el, "::after");
|
|
135335
|
+
if (a && a.content && a.content !== "none") addFromStyle(a);
|
|
135336
|
+
}
|
|
135337
|
+
return req;
|
|
135338
|
+
}
|
|
135339
|
+
function collectUsedCodepoints(root) {
|
|
135340
|
+
const used = /* @__PURE__ */ new Set();
|
|
135341
|
+
const pushText = (txt) => {
|
|
135342
|
+
if (!txt) return;
|
|
135343
|
+
for (const ch of txt) used.add(ch.codePointAt(0));
|
|
135344
|
+
};
|
|
135345
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null);
|
|
135346
|
+
while (walker.nextNode()) {
|
|
135347
|
+
const n = walker.currentNode;
|
|
135348
|
+
if (n.nodeType === Node.TEXT_NODE) {
|
|
135349
|
+
pushText(n.nodeValue || "");
|
|
135350
|
+
} else if (n.nodeType === Node.ELEMENT_NODE) {
|
|
135351
|
+
const el = (
|
|
135352
|
+
/** @type {Element} */
|
|
135353
|
+
n
|
|
135354
|
+
);
|
|
135355
|
+
for (const pseudo of ["::before", "::after"]) {
|
|
135356
|
+
const cs = getComputedStyle(el, pseudo);
|
|
135357
|
+
const c = cs?.getPropertyValue("content");
|
|
135358
|
+
if (!c || c === "none") continue;
|
|
135359
|
+
if (/^"/.test(c) || /^'/.test(c)) {
|
|
135360
|
+
pushText(c.slice(1, -1));
|
|
135361
|
+
} else {
|
|
135362
|
+
const matches = c.match(/\\[0-9A-Fa-f]{1,6}/g);
|
|
135363
|
+
if (matches) {
|
|
135364
|
+
for (const m of matches) {
|
|
135365
|
+
try {
|
|
135366
|
+
used.add(parseInt(m.slice(1), 16));
|
|
135367
|
+
} catch {
|
|
135368
|
+
}
|
|
135369
|
+
}
|
|
135370
|
+
}
|
|
135371
|
+
}
|
|
135372
|
+
}
|
|
135373
|
+
}
|
|
135374
|
+
}
|
|
135375
|
+
return used;
|
|
135376
|
+
}
|
|
135377
|
+
async function ensureFontsReady(families, warmupRepetitions = 2) {
|
|
135378
|
+
try {
|
|
135379
|
+
await document.fonts.ready;
|
|
135380
|
+
} catch {
|
|
135381
|
+
}
|
|
135382
|
+
const fams = Array.from(families || []).filter(Boolean);
|
|
135383
|
+
if (fams.length === 0) return;
|
|
135384
|
+
const warmupOnce = () => {
|
|
135385
|
+
const container = document.createElement("div");
|
|
135386
|
+
container.style.cssText = "position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;";
|
|
135387
|
+
for (const fam of fams) {
|
|
135388
|
+
const span = document.createElement("span");
|
|
135389
|
+
span.textContent = "AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E";
|
|
135390
|
+
span.style.fontFamily = `"${fam}"`;
|
|
135391
|
+
span.style.fontWeight = "700";
|
|
135392
|
+
span.style.fontStyle = "italic";
|
|
135393
|
+
span.style.fontSize = "32px";
|
|
135394
|
+
span.style.lineHeight = "1";
|
|
135395
|
+
span.style.whiteSpace = "nowrap";
|
|
135396
|
+
span.style.margin = "0";
|
|
135397
|
+
span.style.padding = "0";
|
|
135398
|
+
container.appendChild(span);
|
|
135399
|
+
}
|
|
135400
|
+
document.body.appendChild(container);
|
|
135401
|
+
container.offsetWidth;
|
|
135402
|
+
document.body.removeChild(container);
|
|
135403
|
+
};
|
|
135404
|
+
for (let i = 0; i < Math.max(1, warmupRepetitions); i++) {
|
|
135405
|
+
warmupOnce();
|
|
135406
|
+
await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
|
|
135407
|
+
}
|
|
135408
|
+
}
|
|
135409
|
+
|
|
135410
|
+
// src/modules/counter.js
|
|
135411
|
+
function hasCounters(input) {
|
|
135412
|
+
return /\bcounter\s*\(|\bcounters\s*\(/.test(input || "");
|
|
135413
|
+
}
|
|
135414
|
+
function unquoteDoubleStrings(s) {
|
|
135415
|
+
return (s || "").replace(/"([^"]*)"/g, "$1");
|
|
135416
|
+
}
|
|
135417
|
+
function alpha(n, upper = false) {
|
|
135418
|
+
let s = "", x = Math.max(1, n);
|
|
135419
|
+
while (x > 0) {
|
|
135420
|
+
x--;
|
|
135421
|
+
s = String.fromCharCode(97 + x % 26) + s;
|
|
135422
|
+
x = Math.floor(x / 26);
|
|
135423
|
+
}
|
|
135424
|
+
return upper ? s.toUpperCase() : s;
|
|
135425
|
+
}
|
|
135426
|
+
function roman(n, upper = true) {
|
|
135427
|
+
const map = [[1e3, "M"], [900, "CM"], [500, "D"], [400, "CD"], [100, "C"], [90, "XC"], [50, "L"], [40, "XL"], [10, "X"], [9, "IX"], [5, "V"], [4, "IV"], [1, "I"]];
|
|
135428
|
+
let num = Math.max(1, Math.min(3999, n)), out = "";
|
|
135429
|
+
for (const [v, sym] of map) while (num >= v) {
|
|
135430
|
+
out += sym;
|
|
135431
|
+
num -= v;
|
|
135432
|
+
}
|
|
135433
|
+
return upper ? out : out.toLowerCase();
|
|
135434
|
+
}
|
|
135435
|
+
function formatCounter(value, style) {
|
|
135436
|
+
switch ((style || "decimal").toLowerCase()) {
|
|
135437
|
+
case "decimal":
|
|
135438
|
+
return String(Math.max(0, value));
|
|
135439
|
+
case "decimal-leading-zero":
|
|
135440
|
+
return (value < 10 ? "0" : "") + String(Math.max(0, value));
|
|
135441
|
+
case "lower-alpha":
|
|
135442
|
+
return alpha(value, false);
|
|
135443
|
+
case "upper-alpha":
|
|
135444
|
+
return alpha(value, true);
|
|
135445
|
+
case "lower-roman":
|
|
135446
|
+
return roman(value, false);
|
|
135447
|
+
case "upper-roman":
|
|
135448
|
+
return roman(value, true);
|
|
135449
|
+
default:
|
|
135450
|
+
return String(Math.max(0, value));
|
|
135451
|
+
}
|
|
135452
|
+
}
|
|
135453
|
+
function buildCounterContext(root) {
|
|
135454
|
+
const nodeCounters = /* @__PURE__ */ new WeakMap();
|
|
135455
|
+
const rootEl = root instanceof Document ? root.documentElement : root;
|
|
135456
|
+
const isLi = (el) => el && el.tagName === "LI";
|
|
135457
|
+
const countPrevLi = (li) => {
|
|
135458
|
+
let c = 0, p = li?.parentElement;
|
|
135459
|
+
if (!p) return 0;
|
|
135460
|
+
for (const sib of p.children) {
|
|
135461
|
+
if (sib === li) break;
|
|
135462
|
+
if (sib.tagName === "LI") c++;
|
|
135463
|
+
}
|
|
135464
|
+
return c;
|
|
135465
|
+
};
|
|
135466
|
+
const cloneMap = (m) => {
|
|
135467
|
+
const out = /* @__PURE__ */ new Map();
|
|
135468
|
+
for (const [k, arr] of m) out.set(k, arr.slice());
|
|
135469
|
+
return out;
|
|
135470
|
+
};
|
|
135471
|
+
const applyTo = (baseMap, parentMap, el) => {
|
|
135472
|
+
const map = cloneMap(baseMap);
|
|
135473
|
+
let reset;
|
|
135474
|
+
try {
|
|
135475
|
+
reset = el.style?.counterReset || getComputedStyle(el).counterReset;
|
|
135476
|
+
} catch {
|
|
135477
|
+
}
|
|
135478
|
+
if (reset && reset !== "none") {
|
|
135479
|
+
for (const part of reset.split(",")) {
|
|
135480
|
+
const toks = part.trim().split(/\s+/);
|
|
135481
|
+
const name = toks[0];
|
|
135482
|
+
const val = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 0;
|
|
135483
|
+
if (!name) continue;
|
|
135484
|
+
const parentStack = parentMap.get(name);
|
|
135485
|
+
if (parentStack && parentStack.length) {
|
|
135486
|
+
const s = parentStack.slice();
|
|
135487
|
+
s.push(val);
|
|
135488
|
+
map.set(name, s);
|
|
135489
|
+
} else {
|
|
135490
|
+
map.set(name, [val]);
|
|
135491
|
+
}
|
|
135492
|
+
}
|
|
135493
|
+
}
|
|
135494
|
+
let inc;
|
|
135495
|
+
try {
|
|
135496
|
+
inc = el.style?.counterIncrement || getComputedStyle(el).counterIncrement;
|
|
135497
|
+
} catch {
|
|
135498
|
+
}
|
|
135499
|
+
if (inc && inc !== "none") {
|
|
135500
|
+
for (const part of inc.split(",")) {
|
|
135501
|
+
const toks = part.trim().split(/\s+/);
|
|
135502
|
+
const name = toks[0];
|
|
135503
|
+
const by = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 1;
|
|
135504
|
+
if (!name) continue;
|
|
135505
|
+
const stack = map.get(name) || [];
|
|
135506
|
+
if (stack.length === 0) stack.push(0);
|
|
135507
|
+
stack[stack.length - 1] += by;
|
|
135508
|
+
map.set(name, stack);
|
|
135509
|
+
}
|
|
135510
|
+
}
|
|
135511
|
+
try {
|
|
135512
|
+
const cs = getComputedStyle(el);
|
|
135513
|
+
if (cs.display === "list-item" && isLi(el)) {
|
|
135514
|
+
const p = el.parentElement;
|
|
135515
|
+
let idx = 1;
|
|
135516
|
+
if (p && p.tagName === "OL") {
|
|
135517
|
+
const startAttr = p.getAttribute("start");
|
|
135518
|
+
const start = Number.isFinite(Number(startAttr)) ? Number(startAttr) : 1;
|
|
135519
|
+
const prev = countPrevLi(el);
|
|
135520
|
+
const ownAttr = el.getAttribute("value");
|
|
135521
|
+
idx = Number.isFinite(Number(ownAttr)) ? Number(ownAttr) : start + prev;
|
|
135522
|
+
} else {
|
|
135523
|
+
idx = 1 + countPrevLi(el);
|
|
135524
|
+
}
|
|
135525
|
+
const s = map.get("list-item") || [];
|
|
135526
|
+
if (s.length === 0) s.push(0);
|
|
135527
|
+
s[s.length - 1] = idx;
|
|
135528
|
+
map.set("list-item", s);
|
|
135529
|
+
}
|
|
135530
|
+
} catch {
|
|
135531
|
+
}
|
|
135532
|
+
return map;
|
|
135533
|
+
};
|
|
135534
|
+
const build = (el, parentMap, carryMap) => {
|
|
135535
|
+
const curr = applyTo(carryMap, parentMap, el);
|
|
135536
|
+
nodeCounters.set(el, curr);
|
|
135537
|
+
let nextCarry = curr;
|
|
135538
|
+
for (const child of el.children) {
|
|
135539
|
+
const childCarry = build(child, curr, nextCarry);
|
|
135540
|
+
nextCarry = childCarry;
|
|
135541
|
+
}
|
|
135542
|
+
return curr;
|
|
135543
|
+
};
|
|
135544
|
+
const empty = /* @__PURE__ */ new Map();
|
|
135545
|
+
build(rootEl, empty, empty);
|
|
135546
|
+
return {
|
|
135547
|
+
/**
|
|
135548
|
+
* Get top value for counter name at given node.
|
|
135549
|
+
* @param {Element} node
|
|
135550
|
+
* @param {string} name
|
|
135551
|
+
*/
|
|
135552
|
+
get(node, name) {
|
|
135553
|
+
const s = nodeCounters.get(node)?.get(name);
|
|
135554
|
+
return s && s.length ? s[s.length - 1] : 0;
|
|
135555
|
+
},
|
|
135556
|
+
/**
|
|
135557
|
+
* Get full stack for counter name at given node.
|
|
135558
|
+
* @param {Element} node
|
|
135559
|
+
* @param {string} name
|
|
135560
|
+
*/
|
|
135561
|
+
getStack(node, name) {
|
|
135562
|
+
const s = nodeCounters.get(node)?.get(name);
|
|
135563
|
+
return s ? s.slice() : [];
|
|
135564
|
+
}
|
|
135565
|
+
};
|
|
135566
|
+
}
|
|
135567
|
+
function resolveCountersInContent(raw, node, ctx) {
|
|
135568
|
+
if (!raw || raw === "none") return raw;
|
|
135569
|
+
try {
|
|
135570
|
+
const RX = /\b(counter|counters)\s*\(([^)]+)\)/g;
|
|
135571
|
+
let out = raw.replace(RX, (_, fn, args) => {
|
|
135572
|
+
const parts = String(args).split(",").map((s) => s.trim());
|
|
135573
|
+
if (fn === "counter") {
|
|
135574
|
+
const name = parts[0]?.replace(/^["']|["']$/g, "");
|
|
135575
|
+
const style = (parts[1] || "decimal").toLowerCase();
|
|
135576
|
+
const v = ctx.get(node, name);
|
|
135577
|
+
return formatCounter(v, style);
|
|
135578
|
+
} else {
|
|
135579
|
+
const name = parts[0]?.replace(/^["']|["']$/g, "");
|
|
135580
|
+
const sep = parts[1]?.replace(/^["']|["']$/g, "") ?? "";
|
|
135581
|
+
const style = (parts[2] || "decimal").toLowerCase();
|
|
135582
|
+
const stack = ctx.getStack(node, name);
|
|
135583
|
+
if (!stack.length) return "";
|
|
135584
|
+
const pieces = stack.map((v) => formatCounter(v, style));
|
|
135585
|
+
return pieces.join(sep);
|
|
135586
|
+
}
|
|
135587
|
+
});
|
|
135588
|
+
return unquoteDoubleStrings(out);
|
|
135589
|
+
} catch {
|
|
135590
|
+
return "- ";
|
|
135591
|
+
}
|
|
135592
|
+
}
|
|
135593
|
+
|
|
135594
|
+
// src/modules/pseudo.js
|
|
135595
|
+
var counterCtx = null;
|
|
135596
|
+
var __siblingCounters = /* @__PURE__ */ new WeakMap();
|
|
135597
|
+
function unquoteDoubleStrings2(s) {
|
|
135598
|
+
return (s || "").replace(/"([^"]*)"/g, "$1");
|
|
135599
|
+
}
|
|
135600
|
+
function collapseCssContent(raw) {
|
|
135601
|
+
if (!raw) return "";
|
|
135602
|
+
const tokens = [];
|
|
135603
|
+
const rx = /"([^"]*)"/g;
|
|
135604
|
+
let m;
|
|
135605
|
+
while (m = rx.exec(raw)) tokens.push(m[1]);
|
|
135606
|
+
if (tokens.length) return tokens.join("");
|
|
135607
|
+
return unquoteDoubleStrings2(raw);
|
|
135608
|
+
}
|
|
135609
|
+
function withSiblingOverrides(node, base) {
|
|
135610
|
+
const parent = node.parentElement;
|
|
135611
|
+
const map = parent ? __siblingCounters.get(parent) : null;
|
|
135612
|
+
if (!map) return base;
|
|
135613
|
+
return {
|
|
135614
|
+
get(n, name) {
|
|
135615
|
+
const v = base.get(n, name);
|
|
135616
|
+
const ov = map.get(name);
|
|
135617
|
+
return typeof ov === "number" ? Math.max(v, ov) : v;
|
|
135618
|
+
},
|
|
135619
|
+
getStack(n, name) {
|
|
135620
|
+
const s = base.getStack(n, name);
|
|
135621
|
+
if (!s.length) return s;
|
|
135622
|
+
const ov = map.get(name);
|
|
135623
|
+
if (typeof ov === "number") {
|
|
135624
|
+
const out = s.slice();
|
|
135625
|
+
out[out.length - 1] = Math.max(out[out.length - 1], ov);
|
|
135626
|
+
return out;
|
|
135627
|
+
}
|
|
135628
|
+
return s;
|
|
135629
|
+
}
|
|
135630
|
+
};
|
|
135631
|
+
}
|
|
135632
|
+
function deriveCounterCtxForPseudo(node, pseudoStyle, baseCtx) {
|
|
135633
|
+
const modStacks = /* @__PURE__ */ new Map();
|
|
135634
|
+
function parseListDecl(value) {
|
|
135635
|
+
const out = [];
|
|
135636
|
+
if (!value || value === "none") return out;
|
|
135637
|
+
for (const part of String(value).split(",")) {
|
|
135638
|
+
const toks = part.trim().split(/\s+/);
|
|
135639
|
+
const name = toks[0];
|
|
135640
|
+
const num = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : void 0;
|
|
135641
|
+
if (name) out.push({ name, num });
|
|
135642
|
+
}
|
|
135643
|
+
return out;
|
|
135644
|
+
}
|
|
135645
|
+
const resets = parseListDecl(pseudoStyle?.counterReset);
|
|
135646
|
+
const incs = parseListDecl(pseudoStyle?.counterIncrement);
|
|
135647
|
+
function getStackDerived(name) {
|
|
135648
|
+
if (modStacks.has(name)) return modStacks.get(name).slice();
|
|
135649
|
+
let stack = baseCtx.getStack(node, name);
|
|
135650
|
+
stack = stack.length ? stack.slice() : [];
|
|
135651
|
+
const r = resets.find((x) => x.name === name);
|
|
135652
|
+
if (r) {
|
|
135653
|
+
const val = Number.isFinite(r.num) ? r.num : 0;
|
|
135654
|
+
stack = stack.length ? [...stack, val] : [val];
|
|
135655
|
+
}
|
|
135656
|
+
const inc = incs.find((x) => x.name === name);
|
|
135657
|
+
if (inc) {
|
|
135658
|
+
const by = Number.isFinite(inc.num) ? inc.num : 1;
|
|
135659
|
+
if (stack.length === 0) stack = [0];
|
|
135660
|
+
stack[stack.length - 1] += by;
|
|
135661
|
+
}
|
|
135662
|
+
modStacks.set(name, stack.slice());
|
|
135663
|
+
return stack;
|
|
135664
|
+
}
|
|
135665
|
+
return {
|
|
135666
|
+
get(_node, name) {
|
|
135667
|
+
const s = getStackDerived(name);
|
|
135668
|
+
return s.length ? s[s.length - 1] : 0;
|
|
135669
|
+
},
|
|
135670
|
+
getStack(_node, name) {
|
|
135671
|
+
return getStackDerived(name);
|
|
135672
|
+
},
|
|
135673
|
+
/** expone increments del pseudo para que el caller pueda propagar a hermanos */
|
|
135674
|
+
__incs: incs
|
|
135675
|
+
};
|
|
135676
|
+
}
|
|
135677
|
+
function resolvePseudoContentAndIncs(node, pseudo, baseCtx) {
|
|
135678
|
+
let ps;
|
|
135679
|
+
try {
|
|
135680
|
+
ps = getComputedStyle(node, pseudo);
|
|
135681
|
+
} catch {
|
|
135682
|
+
}
|
|
135683
|
+
const raw = ps?.content;
|
|
135684
|
+
if (!raw || raw === "none" || raw === "normal") return { text: "", incs: [] };
|
|
135685
|
+
const baseWithSiblings = withSiblingOverrides(node, baseCtx);
|
|
135686
|
+
const derived = deriveCounterCtxForPseudo(node, ps, baseWithSiblings);
|
|
135687
|
+
let resolved = hasCounters(raw) ? resolveCountersInContent(raw, node, derived) : raw;
|
|
135688
|
+
const text = collapseCssContent(resolved);
|
|
135689
|
+
return { text, incs: derived.__incs || [] };
|
|
135690
|
+
}
|
|
135691
|
+
async function inlinePseudoElements(source, clone, sessionCache, options) {
|
|
135692
|
+
if (!(source instanceof Element) || !(clone instanceof Element)) return;
|
|
135693
|
+
if (!counterCtx) {
|
|
135694
|
+
try {
|
|
135695
|
+
counterCtx = buildCounterContext(source.ownerDocument || document);
|
|
135696
|
+
} catch {
|
|
135697
|
+
}
|
|
135698
|
+
}
|
|
135699
|
+
for (const pseudo of ["::before", "::after", "::first-letter"]) {
|
|
135700
|
+
try {
|
|
135701
|
+
const style = getStyle(source, pseudo);
|
|
135702
|
+
if (!style || typeof style[Symbol.iterator] !== "function") continue;
|
|
135703
|
+
const isEmptyPseudo = style.content === "none" && style.backgroundImage === "none" && style.backgroundColor === "transparent" && (style.borderStyle === "none" || parseFloat(style.borderWidth) === 0) && (!style.transform || style.transform === "none") && style.display === "inline";
|
|
135704
|
+
if (isEmptyPseudo) continue;
|
|
135705
|
+
if (pseudo === "::first-letter") {
|
|
135706
|
+
const normal = getComputedStyle(source);
|
|
135707
|
+
const isMeaningful = style.color !== normal.color || style.fontSize !== normal.fontSize || style.fontWeight !== normal.fontWeight;
|
|
135708
|
+
if (!isMeaningful) continue;
|
|
135709
|
+
const textNode = Array.from(clone.childNodes).find(
|
|
135710
|
+
(n) => n.nodeType === Node.TEXT_NODE && n.textContent?.trim().length > 0
|
|
135711
|
+
);
|
|
135712
|
+
if (!textNode) continue;
|
|
135713
|
+
const text = textNode.textContent;
|
|
135714
|
+
const match = text.match(/^([^\p{L}\p{N}\s]*[\p{L}\p{N}](?:['’])?)/u);
|
|
135715
|
+
const first = match?.[0];
|
|
135716
|
+
const rest = text.slice(first?.length || 0);
|
|
135717
|
+
if (!first || /[\uD800-\uDFFF]/.test(first)) continue;
|
|
135718
|
+
const span = document.createElement("span");
|
|
135719
|
+
span.textContent = first;
|
|
135720
|
+
span.dataset.snapdomPseudo = "::first-letter";
|
|
135721
|
+
const snapshot2 = snapshotComputedStyle(style);
|
|
135722
|
+
const key2 = getStyleKey(snapshot2, "span");
|
|
135723
|
+
sessionCache.styleMap.set(span, key2);
|
|
135724
|
+
const restNode = document.createTextNode(rest);
|
|
135725
|
+
clone.replaceChild(restNode, textNode);
|
|
135726
|
+
clone.insertBefore(span, restNode);
|
|
135727
|
+
continue;
|
|
135728
|
+
}
|
|
135729
|
+
const rawContent = style.content;
|
|
135730
|
+
const { text: cleanContent, incs } = resolvePseudoContentAndIncs(source, pseudo, counterCtx);
|
|
135731
|
+
const bg = style.backgroundImage;
|
|
135732
|
+
const bgColor = style.backgroundColor;
|
|
135733
|
+
const fontFamily = style.fontFamily;
|
|
135734
|
+
const fontSize = parseInt(style.fontSize) || 32;
|
|
135735
|
+
const fontWeight = parseInt(style.fontWeight) || false;
|
|
135736
|
+
const color = style.color || "#000";
|
|
135737
|
+
const borderStyle = style.borderStyle;
|
|
135738
|
+
const borderWidth = parseFloat(style.borderWidth);
|
|
135739
|
+
const transform = style.transform;
|
|
135740
|
+
const isIconFont22 = isIconFont2(fontFamily);
|
|
135741
|
+
const hasExplicitContent = rawContent !== "none" && cleanContent !== "";
|
|
135742
|
+
const hasBg = bg && bg !== "none";
|
|
135743
|
+
const hasBgColor = bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)";
|
|
135744
|
+
const hasBorder = borderStyle && borderStyle !== "none" && borderWidth > 0;
|
|
135745
|
+
const hasTransform = transform && transform !== "none";
|
|
135746
|
+
const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBorder || hasTransform;
|
|
135747
|
+
if (!shouldRender) {
|
|
135748
|
+
if (incs && incs.length && source.parentElement) {
|
|
135749
|
+
const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map();
|
|
135750
|
+
for (const { name } of incs) {
|
|
135751
|
+
if (!name) continue;
|
|
135752
|
+
const baseWithSibs = withSiblingOverrides(source, counterCtx);
|
|
135753
|
+
const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs);
|
|
135754
|
+
const finalVal = derived.get(source, name);
|
|
135755
|
+
map.set(name, finalVal);
|
|
135756
|
+
}
|
|
135757
|
+
__siblingCounters.set(source.parentElement, map);
|
|
135758
|
+
}
|
|
135759
|
+
continue;
|
|
135760
|
+
}
|
|
135761
|
+
const pseudoEl = document.createElement("span");
|
|
135762
|
+
pseudoEl.dataset.snapdomPseudo = pseudo;
|
|
135763
|
+
pseudoEl.style.verticalAlign = "middle";
|
|
135764
|
+
pseudoEl.style.pointerEvents = "none";
|
|
135765
|
+
const snapshot = snapshotComputedStyle(style);
|
|
135766
|
+
const key = getStyleKey(snapshot, "span");
|
|
135767
|
+
sessionCache.styleMap.set(pseudoEl, key);
|
|
135768
|
+
if (isIconFont22 && cleanContent && cleanContent.length === 1) {
|
|
135769
|
+
const { dataUrl, width: w, height: h } = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color);
|
|
135770
|
+
const imgEl = document.createElement("img");
|
|
135771
|
+
imgEl.src = dataUrl;
|
|
135772
|
+
imgEl.style = `height:${fontSize}px;width:${w / h * fontSize}px;object-fit:contain;`;
|
|
135773
|
+
pseudoEl.appendChild(imgEl);
|
|
135774
|
+
clone.dataset.snapdomHasIcon = "true";
|
|
135775
|
+
} else if (cleanContent && cleanContent.startsWith("url(")) {
|
|
135776
|
+
const rawUrl = extractURL(cleanContent);
|
|
135777
|
+
if (rawUrl?.trim()) {
|
|
135778
|
+
try {
|
|
135779
|
+
const imgEl = document.createElement("img");
|
|
135780
|
+
const dataUrl = await snapFetch(safeEncodeURI(rawUrl), { as: "dataURL", useProxy: options.useProxy });
|
|
135781
|
+
imgEl.src = dataUrl.data;
|
|
135782
|
+
imgEl.style = `width:${fontSize}px;height:auto;object-fit:contain;`;
|
|
135783
|
+
pseudoEl.appendChild(imgEl);
|
|
135784
|
+
} catch (e) {
|
|
135785
|
+
console.error(`[snapdom] Error in pseudo ${pseudo} for`, source, e);
|
|
135786
|
+
}
|
|
135787
|
+
}
|
|
135788
|
+
} else if (!isIconFont22 && hasExplicitContent) {
|
|
135789
|
+
pseudoEl.textContent = cleanContent;
|
|
135790
|
+
}
|
|
135791
|
+
pseudoEl.style.background = "none";
|
|
135792
|
+
if ("mask" in pseudoEl.style) {
|
|
135793
|
+
pseudoEl.style.mask = "none";
|
|
135794
|
+
}
|
|
135795
|
+
if (hasBg) {
|
|
135796
|
+
try {
|
|
135797
|
+
const bgSplits = splitBackgroundImage(bg);
|
|
135798
|
+
const newBgParts = await Promise.all(bgSplits.map(inlineSingleBackgroundEntry));
|
|
135799
|
+
pseudoEl.style.backgroundImage = newBgParts.join(", ");
|
|
135800
|
+
} catch (e) {
|
|
135801
|
+
console.warn(`[snapdom] Failed to inline background-image for ${pseudo}`, e);
|
|
135802
|
+
}
|
|
135803
|
+
}
|
|
135804
|
+
if (hasBgColor) pseudoEl.style.backgroundColor = bgColor;
|
|
135805
|
+
const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent?.trim() !== "";
|
|
135806
|
+
const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBorder || hasTransform;
|
|
135807
|
+
if (incs && incs.length && source.parentElement) {
|
|
135808
|
+
const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map();
|
|
135809
|
+
const baseWithSibs = withSiblingOverrides(source, counterCtx);
|
|
135810
|
+
const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs);
|
|
135811
|
+
for (const { name } of incs) {
|
|
135812
|
+
if (!name) continue;
|
|
135813
|
+
const finalVal = derived.get(source, name);
|
|
135814
|
+
map.set(name, finalVal);
|
|
135815
|
+
}
|
|
135816
|
+
__siblingCounters.set(source.parentElement, map);
|
|
135817
|
+
}
|
|
135818
|
+
if (!hasVisibleBox) continue;
|
|
135819
|
+
if (pseudo === "::before") {
|
|
135820
|
+
clone.insertBefore(pseudoEl, clone.firstChild);
|
|
135821
|
+
} else {
|
|
135822
|
+
clone.appendChild(pseudoEl);
|
|
135823
|
+
}
|
|
135824
|
+
} catch (e) {
|
|
135825
|
+
console.warn(`[snapdom] Failed to capture ${pseudo} for`, source, e);
|
|
135826
|
+
}
|
|
135827
|
+
}
|
|
135828
|
+
const sChildren = Array.from(source.children);
|
|
135829
|
+
const cChildren = Array.from(clone.children).filter((child) => !child.dataset.snapdomPseudo);
|
|
135830
|
+
for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
|
|
135831
|
+
await inlinePseudoElements(sChildren[i], cChildren[i], sessionCache, options);
|
|
135832
|
+
}
|
|
135833
|
+
}
|
|
135834
|
+
|
|
135835
|
+
// src/modules/svgDefs.js
|
|
135836
|
+
function inlineExternalDefsAndSymbols(rootElement) {
|
|
135837
|
+
if (!rootElement) return;
|
|
135838
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
135839
|
+
rootElement.querySelectorAll("use").forEach((use) => {
|
|
135840
|
+
const href = use.getAttribute("xlink:href") || use.getAttribute("href");
|
|
135841
|
+
if (href && href.startsWith("#")) {
|
|
135842
|
+
usedIds.add(href.slice(1));
|
|
135843
|
+
}
|
|
135844
|
+
});
|
|
135845
|
+
if (!usedIds.size) return;
|
|
135846
|
+
const allGlobal = Array.from(document.querySelectorAll("svg > symbol, svg > defs"));
|
|
135847
|
+
const globalSymbols = allGlobal.filter((el) => el.tagName.toLowerCase() === "symbol");
|
|
135848
|
+
const globalDefs = allGlobal.filter((el) => el.tagName.toLowerCase() === "defs");
|
|
135849
|
+
let container = rootElement.querySelector("svg.inline-defs-container");
|
|
135850
|
+
if (!container) {
|
|
135851
|
+
container = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
135852
|
+
container.setAttribute("aria-hidden", "true");
|
|
135853
|
+
container.setAttribute("style", "position: absolute; width: 0; height: 0; overflow: hidden;");
|
|
135854
|
+
container.classList.add("inline-defs-container");
|
|
135855
|
+
rootElement.insertBefore(container, rootElement.firstChild);
|
|
135856
|
+
}
|
|
135857
|
+
const existingIds = /* @__PURE__ */ new Set();
|
|
135858
|
+
rootElement.querySelectorAll("symbol[id], defs > *[id]").forEach((el) => {
|
|
135859
|
+
existingIds.add(el.id);
|
|
135860
|
+
});
|
|
135861
|
+
usedIds.forEach((id) => {
|
|
135862
|
+
if (existingIds.has(id)) return;
|
|
135863
|
+
const symbol = globalSymbols.find((sym) => sym.id === id);
|
|
135864
|
+
if (symbol) {
|
|
135865
|
+
container.appendChild(symbol.cloneNode(true));
|
|
135866
|
+
existingIds.add(id);
|
|
135867
|
+
return;
|
|
135868
|
+
}
|
|
135869
|
+
for (const defs of globalDefs) {
|
|
135870
|
+
const defEl = defs.querySelector(`#${CSS.escape(id)}`);
|
|
135871
|
+
if (defEl) {
|
|
135872
|
+
let defsContainer = container.querySelector("defs");
|
|
135873
|
+
if (!defsContainer) {
|
|
135874
|
+
defsContainer = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
135875
|
+
container.appendChild(defsContainer);
|
|
135876
|
+
}
|
|
135877
|
+
defsContainer.appendChild(defEl.cloneNode(true));
|
|
135878
|
+
existingIds.add(id);
|
|
135879
|
+
break;
|
|
135880
|
+
}
|
|
135881
|
+
}
|
|
135882
|
+
});
|
|
135883
|
+
}
|
|
135884
|
+
|
|
135885
|
+
// src/modules/changeCSS.js
|
|
135886
|
+
function freezeSticky(originalRoot, cloneRoot) {
|
|
135887
|
+
if (!originalRoot || !cloneRoot) return;
|
|
135888
|
+
const scrollTop = originalRoot.scrollTop || 0;
|
|
135889
|
+
if (!scrollTop) return;
|
|
135890
|
+
if (getComputedStyle(cloneRoot).position === "static") {
|
|
135891
|
+
cloneRoot.style.position = "relative";
|
|
135892
|
+
}
|
|
135893
|
+
const rootRect = originalRoot.getBoundingClientRect();
|
|
135894
|
+
const viewportH = originalRoot.clientHeight;
|
|
135895
|
+
const PH_ATTR = "data-snap-ph";
|
|
135896
|
+
const walker = document.createTreeWalker(originalRoot, NodeFilter.SHOW_ELEMENT);
|
|
135897
|
+
while (walker.nextNode()) {
|
|
135898
|
+
const el = (
|
|
135899
|
+
/** @type {HTMLElement} */
|
|
135900
|
+
walker.currentNode
|
|
135901
|
+
);
|
|
135902
|
+
const cs = getComputedStyle(el);
|
|
135903
|
+
const pos = cs.position;
|
|
135904
|
+
if (pos !== "sticky" && pos !== "-webkit-sticky") continue;
|
|
135905
|
+
const topInit = _toPx(cs.top);
|
|
135906
|
+
const bottomInit = _toPx(cs.bottom);
|
|
135907
|
+
if (topInit == null && bottomInit == null) continue;
|
|
135908
|
+
const path = _pathOf(el, originalRoot);
|
|
135909
|
+
const cloneEl = _findByPathIgnoringPlaceholders(cloneRoot, path, PH_ATTR);
|
|
135910
|
+
if (!cloneEl) continue;
|
|
135911
|
+
const elRect = el.getBoundingClientRect();
|
|
135912
|
+
const widthPx = elRect.width;
|
|
135913
|
+
const heightPx = elRect.height;
|
|
135914
|
+
const leftPx = elRect.left - rootRect.left;
|
|
135915
|
+
if (!(widthPx > 0 && heightPx > 0)) continue;
|
|
135916
|
+
if (!Number.isFinite(leftPx)) continue;
|
|
135917
|
+
const topAbsPx = topInit != null ? topInit + scrollTop : scrollTop + (viewportH - heightPx - /** bottomInit non-null */
|
|
135918
|
+
bottomInit);
|
|
135919
|
+
if (!Number.isFinite(topAbsPx)) continue;
|
|
135920
|
+
const zParsed = Number.parseInt(cs.zIndex, 10);
|
|
135921
|
+
const hasZ = Number.isFinite(zParsed);
|
|
135922
|
+
const overlayZ = hasZ ? Math.max(zParsed, 1) + 1 : 2;
|
|
135923
|
+
const placeholderZ = hasZ ? zParsed - 1 : 0;
|
|
135924
|
+
const ph = cloneEl.cloneNode(false);
|
|
135925
|
+
ph.setAttribute(PH_ATTR, "1");
|
|
135926
|
+
ph.style.position = "sticky";
|
|
135927
|
+
ph.style.left = `${leftPx}px`;
|
|
135928
|
+
ph.style.top = `${topAbsPx}px`;
|
|
135929
|
+
ph.style.width = `${widthPx}px`;
|
|
135930
|
+
ph.style.height = `${heightPx}px`;
|
|
135931
|
+
ph.style.visibility = "hidden";
|
|
135932
|
+
ph.style.zIndex = String(placeholderZ);
|
|
135933
|
+
ph.style.overflow = "hidden";
|
|
135934
|
+
ph.style.background = "transparent";
|
|
135935
|
+
ph.style.boxShadow = "none";
|
|
135936
|
+
ph.style.filter = "none";
|
|
135937
|
+
cloneEl.parentElement?.insertBefore(ph, cloneEl);
|
|
135938
|
+
cloneEl.style.position = "absolute";
|
|
135939
|
+
cloneEl.style.left = `${leftPx}px`;
|
|
135940
|
+
cloneEl.style.top = `${topAbsPx}px`;
|
|
135941
|
+
cloneEl.style.bottom = "auto";
|
|
135942
|
+
cloneEl.style.zIndex = String(overlayZ);
|
|
135943
|
+
cloneEl.style.pointerEvents = "none";
|
|
135944
|
+
}
|
|
135945
|
+
}
|
|
135946
|
+
function _toPx(v) {
|
|
135947
|
+
if (!v || v === "auto") return null;
|
|
135948
|
+
const n = Number.parseFloat(v);
|
|
135949
|
+
return Number.isFinite(n) ? n : null;
|
|
135950
|
+
}
|
|
135951
|
+
function _pathOf(el, root) {
|
|
135952
|
+
const path = [];
|
|
135953
|
+
for (let cur = el; cur && cur !== root; ) {
|
|
135954
|
+
const p = cur.parentElement;
|
|
135955
|
+
if (!p) break;
|
|
135956
|
+
path.push(Array.prototype.indexOf.call(p.children, cur));
|
|
135957
|
+
cur = p;
|
|
135958
|
+
}
|
|
135959
|
+
return path.reverse();
|
|
135960
|
+
}
|
|
135961
|
+
function _findByPathIgnoringPlaceholders(root, path, phAttr) {
|
|
135962
|
+
let cur = root;
|
|
135963
|
+
for (let i = 0; i < path.length; i++) {
|
|
135964
|
+
const kids = _childrenWithoutPlaceholders(cur, phAttr);
|
|
135965
|
+
cur = /** @type {HTMLElement|undefined} */
|
|
135966
|
+
kids[path[i]];
|
|
135967
|
+
if (!cur) return null;
|
|
135968
|
+
}
|
|
135969
|
+
return cur instanceof HTMLElement ? cur : null;
|
|
135970
|
+
}
|
|
135971
|
+
function _childrenWithoutPlaceholders(el, phAttr) {
|
|
135972
|
+
const out = [];
|
|
135973
|
+
const ch = el.children;
|
|
135974
|
+
for (let i = 0; i < ch.length; i++) {
|
|
135975
|
+
const c = ch[i];
|
|
135976
|
+
if (!c.hasAttribute(phAttr)) out.push(c);
|
|
135977
|
+
}
|
|
135978
|
+
return out;
|
|
135979
|
+
}
|
|
135980
|
+
|
|
135981
|
+
// src/core/prepare.js
|
|
135982
|
+
async function prepareClone(element, options = {}) {
|
|
135983
|
+
const sessionCache = {
|
|
135984
|
+
styleMap: cache.session.styleMap,
|
|
135985
|
+
styleCache: cache.session.styleCache,
|
|
135986
|
+
nodeMap: cache.session.nodeMap
|
|
135987
|
+
};
|
|
135988
|
+
let clone;
|
|
135989
|
+
let classCSS = "";
|
|
135990
|
+
let shadowScopedCSS = "";
|
|
135991
|
+
stabilizeLayout(element);
|
|
135992
|
+
try {
|
|
135993
|
+
inlineExternalDefsAndSymbols(element);
|
|
135994
|
+
} catch (e) {
|
|
135995
|
+
console.warn("inlineExternal defs or symbol failed:", e);
|
|
135996
|
+
}
|
|
135997
|
+
try {
|
|
135998
|
+
clone = await deepClone(element, sessionCache, options, element);
|
|
135999
|
+
} catch (e) {
|
|
136000
|
+
console.warn("deepClone failed:", e);
|
|
136001
|
+
throw e;
|
|
136002
|
+
}
|
|
136003
|
+
try {
|
|
136004
|
+
await inlinePseudoElements(element, clone, sessionCache, options);
|
|
136005
|
+
} catch (e) {
|
|
136006
|
+
console.warn("inlinePseudoElements failed:", e);
|
|
136007
|
+
}
|
|
136008
|
+
await resolveBlobUrlsInTree(clone);
|
|
136009
|
+
try {
|
|
136010
|
+
const styleNodes = clone.querySelectorAll("style[data-sd]");
|
|
136011
|
+
for (const s of styleNodes) {
|
|
136012
|
+
shadowScopedCSS += s.textContent || "";
|
|
136013
|
+
s.remove();
|
|
136014
|
+
}
|
|
136015
|
+
} catch {
|
|
136016
|
+
}
|
|
136017
|
+
const keyToClass = generateCSSClasses(sessionCache.styleMap);
|
|
136018
|
+
classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
|
|
136019
|
+
classCSS = shadowScopedCSS + classCSS;
|
|
136020
|
+
for (const [node, key] of sessionCache.styleMap.entries()) {
|
|
136021
|
+
if (node.tagName === "STYLE") continue;
|
|
136022
|
+
if (node.getRootNode && node.getRootNode() instanceof ShadowRoot) {
|
|
136023
|
+
node.setAttribute("style", key.replace(/;/g, "; "));
|
|
136024
|
+
continue;
|
|
136025
|
+
}
|
|
136026
|
+
const className = keyToClass.get(key);
|
|
136027
|
+
if (className) node.classList.add(className);
|
|
136028
|
+
const bgImage = node.style?.backgroundImage;
|
|
136029
|
+
const hasIcon = node.dataset?.snapdomHasIcon;
|
|
136030
|
+
if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
|
|
136031
|
+
if (hasIcon) {
|
|
136032
|
+
node.style.verticalAlign = "middle";
|
|
136033
|
+
node.style.display = "inline";
|
|
136034
|
+
}
|
|
136035
|
+
}
|
|
136036
|
+
for (const [cloneNode, originalNode] of sessionCache.nodeMap.entries()) {
|
|
136037
|
+
const scrollX = originalNode.scrollLeft;
|
|
136038
|
+
const scrollY = originalNode.scrollTop;
|
|
136039
|
+
const hasScroll = scrollX || scrollY;
|
|
136040
|
+
if (hasScroll && cloneNode instanceof HTMLElement) {
|
|
136041
|
+
cloneNode.style.overflow = "hidden";
|
|
136042
|
+
cloneNode.style.scrollbarWidth = "none";
|
|
136043
|
+
cloneNode.style.msOverflowStyle = "none";
|
|
136044
|
+
const inner = document.createElement("div");
|
|
136045
|
+
inner.style.transform = `translate(${-scrollX}px, ${-scrollY}px)`;
|
|
136046
|
+
inner.style.willChange = "transform";
|
|
136047
|
+
inner.style.display = "inline-block";
|
|
136048
|
+
inner.style.width = "100%";
|
|
136049
|
+
while (cloneNode.firstChild) {
|
|
136050
|
+
inner.appendChild(cloneNode.firstChild);
|
|
136051
|
+
}
|
|
136052
|
+
cloneNode.appendChild(inner);
|
|
136053
|
+
}
|
|
136054
|
+
}
|
|
136055
|
+
const contentRoot = clone instanceof HTMLElement && clone.firstElementChild instanceof HTMLElement ? clone.firstElementChild : clone;
|
|
136056
|
+
freezeSticky(element, contentRoot);
|
|
136057
|
+
if (element === sessionCache.nodeMap.get(clone)) {
|
|
136058
|
+
const computed = sessionCache.styleCache.get(element) || window.getComputedStyle(element);
|
|
136059
|
+
sessionCache.styleCache.set(element, computed);
|
|
136060
|
+
const transform = stripTranslate(computed.transform);
|
|
136061
|
+
clone.style.margin = "0";
|
|
136062
|
+
clone.style.top = "auto";
|
|
136063
|
+
clone.style.left = "auto";
|
|
136064
|
+
clone.style.right = "auto";
|
|
136065
|
+
clone.style.bottom = "auto";
|
|
136066
|
+
clone.style.animation = "none";
|
|
136067
|
+
clone.style.transition = "none";
|
|
136068
|
+
clone.style.willChange = "auto";
|
|
136069
|
+
clone.style.float = "none";
|
|
136070
|
+
clone.style.clear = "none";
|
|
136071
|
+
clone.style.transform = transform || "";
|
|
136072
|
+
}
|
|
136073
|
+
for (const [cloneNode, originalNode] of sessionCache.nodeMap.entries()) {
|
|
136074
|
+
if (originalNode.tagName === "PRE") {
|
|
136075
|
+
cloneNode.style.marginTop = "0";
|
|
136076
|
+
cloneNode.style.marginBlockStart = "0";
|
|
136077
|
+
}
|
|
136078
|
+
}
|
|
136079
|
+
return { clone, classCSS, styleCache: sessionCache.styleCache };
|
|
136080
|
+
}
|
|
136081
|
+
function stabilizeLayout(element) {
|
|
136082
|
+
const style = getComputedStyle(element);
|
|
136083
|
+
const outlineStyle = style.outlineStyle;
|
|
136084
|
+
const outlineWidth = style.outlineWidth;
|
|
136085
|
+
const borderStyle = style.borderStyle;
|
|
136086
|
+
const borderWidth = style.borderWidth;
|
|
136087
|
+
const outlineVisible = outlineStyle !== "none" && parseFloat(outlineWidth) > 0;
|
|
136088
|
+
const borderAbsent = borderStyle === "none" || parseFloat(borderWidth) === 0;
|
|
136089
|
+
if (outlineVisible && borderAbsent) {
|
|
136090
|
+
element.style.border = `${outlineWidth} solid transparent`;
|
|
136091
|
+
}
|
|
136092
|
+
}
|
|
136093
|
+
var _blobToDataUrlCache = /* @__PURE__ */ new Map();
|
|
136094
|
+
async function blobUrlToDataUrl(blobUrl) {
|
|
136095
|
+
if (cache.resource?.has(blobUrl)) return cache.resource.get(blobUrl);
|
|
136096
|
+
if (_blobToDataUrlCache.has(blobUrl)) return _blobToDataUrlCache.get(blobUrl);
|
|
136097
|
+
const p = (async () => {
|
|
136098
|
+
const r = await snapFetch(blobUrl, { as: "dataURL", silent: true });
|
|
136099
|
+
if (!r.ok || typeof r.data !== "string") {
|
|
136100
|
+
throw new Error(`[snapDOM] Failed to read blob URL: ${blobUrl}`);
|
|
136101
|
+
}
|
|
136102
|
+
cache.resource?.set(blobUrl, r.data);
|
|
136103
|
+
return r.data;
|
|
136104
|
+
})();
|
|
136105
|
+
_blobToDataUrlCache.set(blobUrl, p);
|
|
136106
|
+
try {
|
|
136107
|
+
const data = await p;
|
|
136108
|
+
_blobToDataUrlCache.set(blobUrl, data);
|
|
136109
|
+
return data;
|
|
136110
|
+
} catch (e) {
|
|
136111
|
+
_blobToDataUrlCache.delete(blobUrl);
|
|
136112
|
+
throw e;
|
|
136113
|
+
}
|
|
136114
|
+
}
|
|
136115
|
+
var BLOB_URL_RE = /\bblob:[^)"'\s]+/g;
|
|
136116
|
+
async function replaceBlobUrlsInCssText(cssText) {
|
|
136117
|
+
if (!cssText || cssText.indexOf("blob:") === -1) return cssText;
|
|
136118
|
+
const uniques = Array.from(new Set(cssText.match(BLOB_URL_RE) || []));
|
|
136119
|
+
if (uniques.length === 0) return cssText;
|
|
136120
|
+
let out = cssText;
|
|
136121
|
+
for (const u of uniques) {
|
|
136122
|
+
try {
|
|
136123
|
+
const d = await blobUrlToDataUrl(u);
|
|
136124
|
+
out = out.split(u).join(d);
|
|
136125
|
+
} catch {
|
|
136126
|
+
}
|
|
136127
|
+
}
|
|
136128
|
+
return out;
|
|
136129
|
+
}
|
|
136130
|
+
function isBlobUrl(u) {
|
|
136131
|
+
return typeof u === "string" && u.startsWith("blob:");
|
|
136132
|
+
}
|
|
136133
|
+
function parseSrcset(srcset) {
|
|
136134
|
+
return (srcset || "").split(",").map((s) => s.trim()).filter(Boolean).map((item) => {
|
|
136135
|
+
const m = item.match(/^(\S+)(\s+.+)?$/);
|
|
136136
|
+
return m ? { url: m[1], desc: m[2] || "" } : null;
|
|
136137
|
+
}).filter(Boolean);
|
|
136138
|
+
}
|
|
136139
|
+
function stringifySrcset(parts) {
|
|
136140
|
+
return parts.map((p) => p.desc ? `${p.url} ${p.desc.trim()}` : p.url).join(", ");
|
|
136141
|
+
}
|
|
136142
|
+
async function resolveBlobUrlsInTree(root) {
|
|
136143
|
+
if (!root) return;
|
|
136144
|
+
const imgs = root.querySelectorAll ? root.querySelectorAll("img") : [];
|
|
136145
|
+
for (const img of imgs) {
|
|
136146
|
+
try {
|
|
136147
|
+
const srcAttr = img.getAttribute("src");
|
|
136148
|
+
const effective = srcAttr || img.currentSrc || "";
|
|
136149
|
+
if (isBlobUrl(effective)) {
|
|
136150
|
+
const data = await blobUrlToDataUrl(effective);
|
|
136151
|
+
img.setAttribute("src", data);
|
|
136152
|
+
}
|
|
136153
|
+
const srcset = img.getAttribute("srcset");
|
|
136154
|
+
if (srcset && srcset.includes("blob:")) {
|
|
136155
|
+
const parts = parseSrcset(srcset);
|
|
136156
|
+
let changed = false;
|
|
136157
|
+
for (const p of parts) {
|
|
136158
|
+
if (isBlobUrl(p.url)) {
|
|
136159
|
+
try {
|
|
136160
|
+
p.url = await blobUrlToDataUrl(p.url);
|
|
136161
|
+
changed = true;
|
|
136162
|
+
} catch {
|
|
136163
|
+
}
|
|
136164
|
+
}
|
|
136165
|
+
}
|
|
136166
|
+
if (changed) img.setAttribute("srcset", stringifySrcset(parts));
|
|
136167
|
+
}
|
|
136168
|
+
} catch {
|
|
136169
|
+
}
|
|
136170
|
+
}
|
|
136171
|
+
const svgImages = root.querySelectorAll ? root.querySelectorAll("image") : [];
|
|
136172
|
+
for (const node of svgImages) {
|
|
136173
|
+
try {
|
|
136174
|
+
const XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
136175
|
+
const href = node.getAttribute("href") || node.getAttributeNS?.(XLINK_NS, "href");
|
|
136176
|
+
if (isBlobUrl(href)) {
|
|
136177
|
+
const d = await blobUrlToDataUrl(href);
|
|
136178
|
+
node.setAttribute("href", d);
|
|
136179
|
+
node.removeAttributeNS?.(XLINK_NS, "href");
|
|
136180
|
+
}
|
|
136181
|
+
} catch {
|
|
136182
|
+
}
|
|
136183
|
+
}
|
|
136184
|
+
const styled = root.querySelectorAll ? root.querySelectorAll("[style*='blob:']") : [];
|
|
136185
|
+
for (const el of styled) {
|
|
136186
|
+
try {
|
|
136187
|
+
const styleText = el.getAttribute("style");
|
|
136188
|
+
if (styleText && styleText.includes("blob:")) {
|
|
136189
|
+
const replaced = await replaceBlobUrlsInCssText(styleText);
|
|
136190
|
+
el.setAttribute("style", replaced);
|
|
136191
|
+
}
|
|
136192
|
+
} catch {
|
|
136193
|
+
}
|
|
136194
|
+
}
|
|
136195
|
+
const styleTags = root.querySelectorAll ? root.querySelectorAll("style") : [];
|
|
136196
|
+
for (const s of styleTags) {
|
|
136197
|
+
try {
|
|
136198
|
+
const css = s.textContent || "";
|
|
136199
|
+
if (css.includes("blob:")) {
|
|
136200
|
+
s.textContent = await replaceBlobUrlsInCssText(css);
|
|
136201
|
+
}
|
|
136202
|
+
} catch {
|
|
136203
|
+
}
|
|
136204
|
+
}
|
|
136205
|
+
const urlAttrs = ["poster"];
|
|
136206
|
+
for (const attr of urlAttrs) {
|
|
136207
|
+
const nodes = root.querySelectorAll ? root.querySelectorAll(`[${attr}^='blob:']`) : [];
|
|
136208
|
+
for (const n of nodes) {
|
|
136209
|
+
try {
|
|
136210
|
+
const u = n.getAttribute(attr);
|
|
136211
|
+
if (isBlobUrl(u)) {
|
|
136212
|
+
n.setAttribute(attr, await blobUrlToDataUrl(u));
|
|
136213
|
+
}
|
|
136214
|
+
} catch {
|
|
136215
|
+
}
|
|
136216
|
+
}
|
|
136217
|
+
}
|
|
136218
|
+
}
|
|
136219
|
+
|
|
136220
|
+
// src/modules/images.js
|
|
136221
|
+
async function inlineImages(clone, options = {}) {
|
|
136222
|
+
const imgs = Array.from(clone.querySelectorAll("img"));
|
|
136223
|
+
const processImg = async (img) => {
|
|
136224
|
+
if (!img.getAttribute("src")) {
|
|
136225
|
+
const eff = img.currentSrc || img.src || "";
|
|
136226
|
+
if (eff) img.setAttribute("src", eff);
|
|
136227
|
+
}
|
|
136228
|
+
img.removeAttribute("srcset");
|
|
136229
|
+
img.removeAttribute("sizes");
|
|
136230
|
+
const src = img.src || "";
|
|
136231
|
+
if (!src) return;
|
|
136232
|
+
const r = await snapFetch(src, { as: "dataURL", useProxy: options.useProxy });
|
|
136233
|
+
if (r.ok && typeof r.data === "string" && r.data.startsWith("data:")) {
|
|
136234
|
+
img.src = r.data;
|
|
136235
|
+
if (!img.width) img.width = img.naturalWidth || 100;
|
|
136236
|
+
if (!img.height) img.height = img.naturalHeight || 100;
|
|
136237
|
+
return;
|
|
136238
|
+
}
|
|
136239
|
+
const { fallbackURL } = options || {};
|
|
136240
|
+
if (fallbackURL) {
|
|
136241
|
+
try {
|
|
136242
|
+
const dsW = parseInt(img.dataset?.snapdomWidth || "", 10) || 0;
|
|
136243
|
+
const dsH = parseInt(img.dataset?.snapdomHeight || "", 10) || 0;
|
|
136244
|
+
const attrW = parseInt(img.getAttribute("width") || "", 10) || 0;
|
|
136245
|
+
const attrH = parseInt(img.getAttribute("height") || "", 10) || 0;
|
|
136246
|
+
const styleW = parseFloat(img.style?.width || "") || 0;
|
|
136247
|
+
const styleH = parseFloat(img.style?.height || "") || 0;
|
|
136248
|
+
const fbW = dsW || styleW || attrW || img.width || void 0;
|
|
136249
|
+
const fbH = dsH || styleH || attrH || img.height || void 0;
|
|
136250
|
+
const fallbackUrl = typeof fallbackURL === "function" ? await fallbackURL({ width: fbW, height: fbH, src, element: img }) : fallbackURL;
|
|
136251
|
+
if (fallbackUrl) {
|
|
136252
|
+
const fallbackData = await snapFetch(fallbackUrl, { as: "dataURL", useProxy: options.useProxy });
|
|
136253
|
+
img.src = fallbackData.data;
|
|
136254
|
+
if (!img.width && fbW) img.width = fbW;
|
|
136255
|
+
if (!img.height && fbH) img.height = fbH;
|
|
136256
|
+
if (!img.width) img.width = img.naturalWidth || 100;
|
|
136257
|
+
if (!img.height) img.height = img.naturalHeight || 100;
|
|
136258
|
+
return;
|
|
136259
|
+
}
|
|
136260
|
+
} catch {
|
|
136261
|
+
}
|
|
136262
|
+
}
|
|
136263
|
+
const w = img.width || img.naturalWidth || 100;
|
|
136264
|
+
const h = img.height || img.naturalHeight || 100;
|
|
136265
|
+
if (options.placeholders !== false) {
|
|
136266
|
+
const fallback = document.createElement("div");
|
|
136267
|
+
fallback.style.cssText = [
|
|
136268
|
+
`width:${w}px`,
|
|
136269
|
+
`height:${h}px`,
|
|
136270
|
+
"background:#ccc",
|
|
136271
|
+
"display:inline-block",
|
|
136272
|
+
"text-align:center",
|
|
136273
|
+
`line-height:${h}px`,
|
|
136274
|
+
"color:#666",
|
|
136275
|
+
"font-size:12px",
|
|
136276
|
+
"overflow:hidden"
|
|
136277
|
+
].join(";");
|
|
136278
|
+
fallback.textContent = "img";
|
|
136279
|
+
img.replaceWith(fallback);
|
|
136280
|
+
} else {
|
|
136281
|
+
const spacer = document.createElement("div");
|
|
136282
|
+
spacer.style.cssText = `display:inline-block;width:${w}px;height:${h}px;visibility:hidden;`;
|
|
136283
|
+
img.replaceWith(spacer);
|
|
136284
|
+
}
|
|
136285
|
+
};
|
|
136286
|
+
for (let i = 0; i < imgs.length; i += 4) {
|
|
136287
|
+
const group = imgs.slice(i, i + 4).map(processImg);
|
|
136288
|
+
await Promise.allSettled(group);
|
|
136289
|
+
}
|
|
136290
|
+
}
|
|
136291
|
+
|
|
136292
|
+
// src/modules/background.js
|
|
136293
|
+
async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
|
|
136294
|
+
const queue = [[source, clone]];
|
|
136295
|
+
const URL_PROPS = [
|
|
136296
|
+
"background-image",
|
|
136297
|
+
// Mask shorthands & images (both standard and WebKit)
|
|
136298
|
+
"mask",
|
|
136299
|
+
"mask-image",
|
|
136300
|
+
"-webkit-mask",
|
|
136301
|
+
"-webkit-mask-image",
|
|
136302
|
+
// Mask sources (rare, but keep)
|
|
136303
|
+
"mask-source",
|
|
136304
|
+
"mask-box-image-source",
|
|
136305
|
+
"mask-border-source",
|
|
136306
|
+
"-webkit-mask-box-image-source",
|
|
136307
|
+
// Border image
|
|
136308
|
+
"border-image",
|
|
136309
|
+
"border-image-source"
|
|
136310
|
+
];
|
|
136311
|
+
const MASK_LAYOUT_PROPS = [
|
|
136312
|
+
"mask-position",
|
|
136313
|
+
"mask-size",
|
|
136314
|
+
"mask-repeat",
|
|
136315
|
+
// WebKit variants
|
|
136316
|
+
"-webkit-mask-position",
|
|
136317
|
+
"-webkit-mask-size",
|
|
136318
|
+
"-webkit-mask-repeat",
|
|
136319
|
+
// Extra (optional but helpful across engines)
|
|
136320
|
+
"mask-origin",
|
|
136321
|
+
"mask-clip",
|
|
136322
|
+
"-webkit-mask-origin",
|
|
136323
|
+
"-webkit-mask-clip",
|
|
136324
|
+
// Some engines expose X/Y position separately:
|
|
136325
|
+
"-webkit-mask-position-x",
|
|
136326
|
+
"-webkit-mask-position-y"
|
|
136327
|
+
];
|
|
136328
|
+
const BORDER_AUX_PROPS = [
|
|
136329
|
+
"border-image-slice",
|
|
136330
|
+
"border-image-width",
|
|
136331
|
+
"border-image-outset",
|
|
136332
|
+
"border-image-repeat"
|
|
136333
|
+
];
|
|
136334
|
+
while (queue.length) {
|
|
136335
|
+
const [srcNode, cloneNode] = queue.shift();
|
|
136336
|
+
const style = styleCache.get(srcNode) || getStyle(srcNode);
|
|
136337
|
+
if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
|
|
136338
|
+
const hasBorderImage = (() => {
|
|
136339
|
+
const bi = style.getPropertyValue("border-image");
|
|
136340
|
+
const bis = style.getPropertyValue("border-image-source");
|
|
136341
|
+
return bi && bi !== "none" || bis && bis !== "none";
|
|
136342
|
+
})();
|
|
136343
|
+
for (const prop of URL_PROPS) {
|
|
136344
|
+
const val = style.getPropertyValue(prop);
|
|
136345
|
+
if (!val || val === "none") continue;
|
|
136346
|
+
const splits = splitBackgroundImage(val);
|
|
136347
|
+
const inlined = await Promise.all(
|
|
136348
|
+
splits.map((entry) => inlineSingleBackgroundEntry(entry, options))
|
|
136349
|
+
);
|
|
136350
|
+
if (inlined.some((p) => p && p !== "none" && !/^url\(undefined/.test(p))) {
|
|
136351
|
+
cloneNode.style.setProperty(prop, inlined.join(", "));
|
|
136352
|
+
}
|
|
136353
|
+
}
|
|
136354
|
+
for (const prop of MASK_LAYOUT_PROPS) {
|
|
136355
|
+
const val = style.getPropertyValue(prop);
|
|
136356
|
+
if (!val || val === "initial") continue;
|
|
136357
|
+
cloneNode.style.setProperty(prop, val);
|
|
136358
|
+
}
|
|
136359
|
+
if (hasBorderImage) {
|
|
136360
|
+
for (const prop of BORDER_AUX_PROPS) {
|
|
136361
|
+
const val = style.getPropertyValue(prop);
|
|
136362
|
+
if (!val || val === "initial") continue;
|
|
136363
|
+
cloneNode.style.setProperty(prop, val);
|
|
136364
|
+
}
|
|
136365
|
+
}
|
|
136366
|
+
const sChildren = Array.from(srcNode.children);
|
|
136367
|
+
const cChildren = Array.from(cloneNode.children);
|
|
136368
|
+
for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
|
|
136369
|
+
queue.push([sChildren[i], cChildren[i]]);
|
|
136370
|
+
}
|
|
136371
|
+
}
|
|
136372
|
+
}
|
|
136373
|
+
|
|
136374
|
+
// src/modules/lineClamp.js
|
|
136375
|
+
function lineClamp(el) {
|
|
136376
|
+
if (!el) return () => {
|
|
136377
|
+
};
|
|
136378
|
+
const lines = getClamp(el);
|
|
136379
|
+
if (lines <= 0) return () => {
|
|
136380
|
+
};
|
|
136381
|
+
if (!isPlainTextContainer(el)) return () => {
|
|
136382
|
+
};
|
|
136383
|
+
const cs = getComputedStyle(el);
|
|
136384
|
+
const targetH = Math.round(usedLineHeightPx(cs) * lines + vpad(cs));
|
|
136385
|
+
const original = el.textContent ?? "";
|
|
136386
|
+
const prevText = original;
|
|
136387
|
+
if (el.scrollHeight <= targetH + 0.5) {
|
|
136388
|
+
return () => {
|
|
136389
|
+
};
|
|
136390
|
+
}
|
|
136391
|
+
let lo = 0, hi = original.length, best = -1;
|
|
136392
|
+
while (lo <= hi) {
|
|
136393
|
+
const mid = lo + hi >> 1;
|
|
136394
|
+
el.textContent = original.slice(0, mid) + "\u2026";
|
|
136395
|
+
if (el.scrollHeight <= targetH + 0.5) {
|
|
136396
|
+
best = mid;
|
|
136397
|
+
lo = mid + 1;
|
|
136398
|
+
} else {
|
|
136399
|
+
hi = mid - 1;
|
|
136400
|
+
}
|
|
136401
|
+
}
|
|
136402
|
+
el.textContent = (best >= 0 ? original.slice(0, best) : "") + "\u2026";
|
|
136403
|
+
return () => {
|
|
136404
|
+
el.textContent = prevText;
|
|
136405
|
+
};
|
|
136406
|
+
}
|
|
136407
|
+
function getClamp(el) {
|
|
136408
|
+
const cs = getComputedStyle(el);
|
|
136409
|
+
let v = cs.getPropertyValue("-webkit-line-clamp") || cs.getPropertyValue("line-clamp");
|
|
136410
|
+
v = (v || "").trim();
|
|
136411
|
+
const n = parseInt(v, 10);
|
|
136412
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
136413
|
+
}
|
|
136414
|
+
function usedLineHeightPx(cs) {
|
|
136415
|
+
const lh = (cs.lineHeight || "").trim();
|
|
136416
|
+
const fs = parseFloat(cs.fontSize) || 16;
|
|
136417
|
+
if (!lh || lh === "normal") return Math.round(fs * 1.2);
|
|
136418
|
+
if (lh.endsWith("px")) return parseFloat(lh);
|
|
136419
|
+
if (/^\d+(\.\d+)?$/.test(lh)) return Math.round(parseFloat(lh) * fs);
|
|
136420
|
+
if (lh.endsWith("%")) return Math.round(parseFloat(lh) / 100 * fs);
|
|
136421
|
+
return Math.round(fs * 1.2);
|
|
136422
|
+
}
|
|
136423
|
+
function vpad(cs) {
|
|
136424
|
+
return (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);
|
|
136425
|
+
}
|
|
136426
|
+
function isPlainTextContainer(el) {
|
|
136427
|
+
if (el.childElementCount > 0) return false;
|
|
136428
|
+
return Array.from(el.childNodes).some((n) => n.nodeType === Node.TEXT_NODE);
|
|
136429
|
+
}
|
|
136430
|
+
|
|
136431
|
+
// src/core/capture.js
|
|
136432
|
+
function stripRootShadows(originalEl, cloneRoot) {
|
|
136433
|
+
if (!originalEl || !cloneRoot || !cloneRoot.style) return;
|
|
136434
|
+
const cs = getComputedStyle(originalEl);
|
|
136435
|
+
try {
|
|
136436
|
+
cloneRoot.style.boxShadow = "none";
|
|
136437
|
+
} catch {
|
|
136438
|
+
}
|
|
136439
|
+
try {
|
|
136440
|
+
cloneRoot.style.textShadow = "none";
|
|
136441
|
+
} catch {
|
|
136442
|
+
}
|
|
136443
|
+
try {
|
|
136444
|
+
cloneRoot.style.outline = "none";
|
|
136445
|
+
} catch {
|
|
136446
|
+
}
|
|
136447
|
+
const f = cs.filter || "";
|
|
136448
|
+
const cleaned = f.replace(/\bblur\([^()]*\)\s*/gi, "").replace(/\bdrop-shadow\([^()]*\)\s*/gi, "").trim().replace(/\s+/g, " ");
|
|
136449
|
+
try {
|
|
136450
|
+
cloneRoot.style.filter = cleaned.length ? cleaned : "none";
|
|
136451
|
+
} catch {
|
|
136452
|
+
}
|
|
136453
|
+
}
|
|
136454
|
+
async function captureDOM(element, options) {
|
|
136455
|
+
if (!element) throw new Error("Element cannot be null or undefined");
|
|
136456
|
+
applyCachePolicy(options.cache);
|
|
136457
|
+
const fast = options.fast;
|
|
136458
|
+
const straighten = !!options.straighten;
|
|
136459
|
+
const noShadows = !!options.noShadows;
|
|
136460
|
+
let clone, classCSS, styleCache;
|
|
136461
|
+
let fontsCSS = "";
|
|
136462
|
+
let baseCSS = "";
|
|
136463
|
+
let dataURL;
|
|
136464
|
+
let svgString;
|
|
136465
|
+
let rootTransform2D = null;
|
|
136466
|
+
const undoClamp = lineClamp(element);
|
|
136467
|
+
try {
|
|
136468
|
+
({ clone, classCSS, styleCache } = await prepareClone(element, options));
|
|
136469
|
+
if (straighten && clone) {
|
|
136470
|
+
rootTransform2D = normalizeRootTransforms(element, clone);
|
|
136471
|
+
}
|
|
136472
|
+
if (noShadows && clone) {
|
|
136473
|
+
stripRootShadows(element, clone);
|
|
136474
|
+
}
|
|
136475
|
+
} finally {
|
|
136476
|
+
undoClamp();
|
|
136477
|
+
}
|
|
136478
|
+
await new Promise((resolve) => {
|
|
136479
|
+
idle(async () => {
|
|
136480
|
+
await inlineImages(clone, options);
|
|
136481
|
+
resolve();
|
|
136482
|
+
}, { fast });
|
|
136483
|
+
});
|
|
136484
|
+
await new Promise((resolve) => {
|
|
136485
|
+
idle(async () => {
|
|
136486
|
+
await inlineBackgroundImages(element, clone, styleCache, options);
|
|
136487
|
+
resolve();
|
|
136488
|
+
}, { fast });
|
|
136489
|
+
});
|
|
136490
|
+
if (options.embedFonts) {
|
|
136491
|
+
await new Promise((resolve) => {
|
|
136492
|
+
idle(async () => {
|
|
136493
|
+
const required = collectUsedFontVariants(element);
|
|
136494
|
+
const usedCodepoints = collectUsedCodepoints(element);
|
|
136495
|
+
if (isSafari()) {
|
|
136496
|
+
const families = new Set(
|
|
136497
|
+
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
136498
|
+
);
|
|
136499
|
+
await ensureFontsReady(families, 1);
|
|
136500
|
+
}
|
|
136501
|
+
fontsCSS = await embedCustomFonts({
|
|
136502
|
+
required,
|
|
136503
|
+
usedCodepoints,
|
|
136504
|
+
exclude: options.excludeFonts,
|
|
136505
|
+
useProxy: options.useProxy
|
|
136506
|
+
});
|
|
136507
|
+
resolve();
|
|
136508
|
+
}, { fast });
|
|
136509
|
+
});
|
|
136510
|
+
}
|
|
136511
|
+
const usedTags = collectUsedTagNames(clone).sort();
|
|
136512
|
+
const tagKey = usedTags.join(",");
|
|
136513
|
+
if (cache.baseStyle.has(tagKey)) {
|
|
136514
|
+
baseCSS = cache.baseStyle.get(tagKey);
|
|
136515
|
+
} else {
|
|
136516
|
+
await new Promise((resolve) => {
|
|
136517
|
+
idle(() => {
|
|
136518
|
+
baseCSS = generateDedupedBaseCSS(usedTags);
|
|
136519
|
+
cache.baseStyle.set(tagKey, baseCSS);
|
|
136520
|
+
resolve();
|
|
136521
|
+
}, { fast });
|
|
136522
|
+
});
|
|
136523
|
+
}
|
|
136524
|
+
await new Promise((resolve) => {
|
|
136525
|
+
idle(() => {
|
|
136526
|
+
const csEl = getComputedStyle(element);
|
|
136527
|
+
function parseFilterDropShadows(cs) {
|
|
136528
|
+
const raw = `${cs.filter || ""} ${cs.webkitFilter || ""}`.trim();
|
|
136529
|
+
if (!raw || raw === "none") {
|
|
136530
|
+
return { bleed: { top: 0, right: 0, bottom: 0, left: 0 }, has: false };
|
|
136531
|
+
}
|
|
136532
|
+
const tokens = raw.match(/drop-shadow\((?:[^()]|\([^()]*\))*\)/gi) || [];
|
|
136533
|
+
let t = 0, r = 0, b = 0, l = 0;
|
|
136534
|
+
let found = false;
|
|
136535
|
+
for (const tok of tokens) {
|
|
136536
|
+
found = true;
|
|
136537
|
+
const nums = tok.match(/-?\d+(?:\.\d+)?px/gi)?.map((v) => parseFloat(v)) || [];
|
|
136538
|
+
const [ox = 0, oy = 0, blur = 0] = nums;
|
|
136539
|
+
const extX = Math.abs(ox) + blur;
|
|
136540
|
+
const extY = Math.abs(oy) + blur;
|
|
136541
|
+
r = Math.max(r, extX + Math.max(ox, 0));
|
|
136542
|
+
l = Math.max(l, extX + Math.max(-ox, 0));
|
|
136543
|
+
b = Math.max(b, extY + Math.max(oy, 0));
|
|
136544
|
+
t = Math.max(t, extY + Math.max(-oy, 0));
|
|
136545
|
+
}
|
|
136546
|
+
return { bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) }, has: found };
|
|
136547
|
+
}
|
|
136548
|
+
const rect = element.getBoundingClientRect();
|
|
136549
|
+
const w0 = Math.max(1, Math.ceil(element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
|
|
136550
|
+
const h0 = Math.max(1, Math.ceil(element.offsetHeight || parseFloat(csEl.height) || rect.height || 1));
|
|
136551
|
+
const coerceNum = (v, def = NaN) => {
|
|
136552
|
+
const n = typeof v === "string" ? parseFloat(v) : v;
|
|
136553
|
+
return Number.isFinite(n) ? n : def;
|
|
136554
|
+
};
|
|
136555
|
+
const optW = coerceNum(options.width);
|
|
136556
|
+
const optH = coerceNum(options.height);
|
|
136557
|
+
let w = w0, h = h0;
|
|
136558
|
+
const hasW = Number.isFinite(optW);
|
|
136559
|
+
const hasH = Number.isFinite(optH);
|
|
136560
|
+
const aspect0 = h0 > 0 ? w0 / h0 : 1;
|
|
136561
|
+
if (hasW && hasH) {
|
|
136562
|
+
w = Math.max(1, Math.ceil(optW));
|
|
136563
|
+
h = Math.max(1, Math.ceil(optH));
|
|
136564
|
+
} else if (hasW) {
|
|
136565
|
+
w = Math.max(1, Math.ceil(optW));
|
|
136566
|
+
h = Math.max(1, Math.ceil(w / (aspect0 || 1)));
|
|
136567
|
+
} else if (hasH) {
|
|
136568
|
+
h = Math.max(1, Math.ceil(optH));
|
|
136569
|
+
w = Math.max(1, Math.ceil(h * (aspect0 || 1)));
|
|
136570
|
+
} else {
|
|
136571
|
+
w = w0;
|
|
136572
|
+
h = h0;
|
|
136573
|
+
}
|
|
136574
|
+
let minX = 0, minY = 0, maxX = w0, maxY = h0;
|
|
136575
|
+
if (straighten && rootTransform2D && Number.isFinite(rootTransform2D.a)) {
|
|
136576
|
+
const M2 = { a: rootTransform2D.a, b: rootTransform2D.b || 0, c: rootTransform2D.c || 0, d: rootTransform2D.d || 1, e: 0, f: 0 };
|
|
136577
|
+
const bb2 = bboxWithOriginFull(w0, h0, M2, 0, 0);
|
|
136578
|
+
minX = bb2.minX;
|
|
136579
|
+
minY = bb2.minY;
|
|
136580
|
+
maxX = bb2.maxX;
|
|
136581
|
+
maxY = bb2.maxY;
|
|
136582
|
+
} else {
|
|
136583
|
+
const useTFBBox = !straighten && hasTFBBox(element);
|
|
136584
|
+
if (useTFBBox) {
|
|
136585
|
+
const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
|
|
136586
|
+
const ind2 = readIndividualTransforms(element);
|
|
136587
|
+
const TOTAL = readTotalTransformMatrix({
|
|
136588
|
+
baseTransform: baseTransform2,
|
|
136589
|
+
rotate: ind2.rotate || "0deg",
|
|
136590
|
+
scale: ind2.scale,
|
|
136591
|
+
translate: ind2.translate
|
|
136592
|
+
});
|
|
136593
|
+
const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0);
|
|
136594
|
+
const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString());
|
|
136595
|
+
const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2);
|
|
136596
|
+
minX = bb.minX;
|
|
136597
|
+
minY = bb.minY;
|
|
136598
|
+
maxX = bb.maxX;
|
|
136599
|
+
maxY = bb.maxY;
|
|
136600
|
+
}
|
|
136601
|
+
}
|
|
136602
|
+
const bleedShadow = parseBoxShadow(csEl);
|
|
136603
|
+
const bleedBlur = parseFilterBlur(csEl);
|
|
136604
|
+
const bleedOutline = parseOutline(csEl);
|
|
136605
|
+
const drop = parseFilterDropShadows(csEl);
|
|
136606
|
+
const bleed = noShadows ? { top: 0, right: 0, bottom: 0, left: 0 } : {
|
|
136607
|
+
top: bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top,
|
|
136608
|
+
right: bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right,
|
|
136609
|
+
bottom: bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom,
|
|
136610
|
+
left: bleedShadow.left + bleedBlur.left + bleedOutline.left + drop.bleed.left
|
|
136611
|
+
};
|
|
136612
|
+
minX -= bleed.left;
|
|
136613
|
+
minY -= bleed.top;
|
|
136614
|
+
maxX += bleed.right;
|
|
136615
|
+
maxY += bleed.bottom;
|
|
136616
|
+
const vbW0 = Math.max(1, Math.ceil(maxX - minX));
|
|
136617
|
+
const vbH0 = Math.max(1, Math.ceil(maxY - minY));
|
|
136618
|
+
const outW = Math.max(1, Math.round(vbW0 * (hasW || hasH ? w / w0 : 1)));
|
|
136619
|
+
const outH = Math.max(1, Math.round(vbH0 * (hasH || hasW ? h / h0 : 1)));
|
|
136620
|
+
const svgNS = "http://www.w3.org/2000/svg";
|
|
136621
|
+
const basePad = isSafari() ? 1 : 0;
|
|
136622
|
+
const extraPad = straighten ? 1 : 0;
|
|
136623
|
+
const pad = basePad + extraPad;
|
|
136624
|
+
const fo = document.createElementNS(svgNS, "foreignObject");
|
|
136625
|
+
const vbMinX = Math.floor(minX);
|
|
136626
|
+
const vbMinY = Math.floor(minY);
|
|
136627
|
+
fo.setAttribute("x", String(-(vbMinX - pad)));
|
|
136628
|
+
fo.setAttribute("y", String(-(vbMinY - pad)));
|
|
136629
|
+
fo.setAttribute("width", String(Math.ceil(w0 + pad * 2)));
|
|
136630
|
+
fo.setAttribute("height", String(Math.ceil(h0 + pad * 2)));
|
|
136631
|
+
fo.style.overflow = "visible";
|
|
136632
|
+
const styleTag = document.createElement("style");
|
|
136633
|
+
styleTag.textContent = baseCSS + fontsCSS + "svg{overflow:visible;} foreignObject{overflow:visible;}" + classCSS;
|
|
136634
|
+
fo.appendChild(styleTag);
|
|
136635
|
+
const container = document.createElement("div");
|
|
136636
|
+
container.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
136637
|
+
container.style.width = `${w0}px`;
|
|
136638
|
+
container.style.height = `${h0}px`;
|
|
136639
|
+
container.style.overflow = "visible";
|
|
136640
|
+
clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
136641
|
+
container.appendChild(clone);
|
|
136642
|
+
fo.appendChild(container);
|
|
136643
|
+
const serializer = new XMLSerializer();
|
|
136644
|
+
const foString = serializer.serializeToString(fo);
|
|
136645
|
+
const vbW = vbW0 + pad * 2;
|
|
136646
|
+
const vbH = vbH0 + pad * 2;
|
|
136647
|
+
const wantsSize = hasW || hasH;
|
|
136648
|
+
options.meta = { w0, h0, vbW, vbH, targetW: w, targetH: h };
|
|
136649
|
+
const svgOutW = isSafari() && wantsSize ? vbW : outW + pad * 2;
|
|
136650
|
+
const svgOutH = isSafari() && wantsSize ? vbH : outH + pad * 2;
|
|
136651
|
+
const svgHeader = `<svg xmlns="${svgNS}" width="${svgOutW}" height="${svgOutH}" viewBox="0 0 ${vbW} ${vbH}">`;
|
|
136652
|
+
const svgFooter = "</svg>";
|
|
136653
|
+
svgString = svgHeader + foString + svgFooter;
|
|
136654
|
+
dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
|
|
136655
|
+
resolve();
|
|
136656
|
+
}, { fast });
|
|
136657
|
+
});
|
|
136658
|
+
const sandbox = document.getElementById("snapdom-sandbox");
|
|
136659
|
+
if (sandbox && sandbox.style.position === "absolute") sandbox.remove();
|
|
136660
|
+
return dataURL;
|
|
136661
|
+
}
|
|
136662
|
+
function normalizeRootTransforms(originalEl, cloneRoot) {
|
|
136663
|
+
if (!originalEl || !cloneRoot || !cloneRoot.style) return null;
|
|
136664
|
+
const cs = getComputedStyle(originalEl);
|
|
136665
|
+
try {
|
|
136666
|
+
cloneRoot.style.transformOrigin = "0 0";
|
|
136667
|
+
} catch {
|
|
136668
|
+
}
|
|
136669
|
+
try {
|
|
136670
|
+
if ("translate" in cloneRoot.style) cloneRoot.style.translate = "none";
|
|
136671
|
+
if ("rotate" in cloneRoot.style) cloneRoot.style.rotate = "none";
|
|
136672
|
+
} catch {
|
|
136673
|
+
}
|
|
136674
|
+
const tr = cs.transform || "none";
|
|
136675
|
+
if (tr === "none") {
|
|
136676
|
+
try {
|
|
136677
|
+
const M = matrixFromComputed(originalEl);
|
|
136678
|
+
if (M.a === 1 && M.b === 0 && M.c === 0 && M.d === 1) {
|
|
136679
|
+
cloneRoot.style.transform = "none";
|
|
136680
|
+
return { a: 1, b: 0, c: 0, d: 1 };
|
|
136681
|
+
}
|
|
136682
|
+
} catch {
|
|
136683
|
+
}
|
|
136684
|
+
}
|
|
136685
|
+
const m2d = tr.match(/^matrix\(\s*([^)]+)\)$/i);
|
|
136686
|
+
if (m2d) {
|
|
136687
|
+
const nums = m2d[1].split(",").map((v) => parseFloat(v.trim()));
|
|
136688
|
+
if (nums.length === 6 && nums.every(Number.isFinite)) {
|
|
136689
|
+
const [a, b, c, d] = nums;
|
|
136690
|
+
const scaleX = Math.sqrt(a * a + b * b) || 0;
|
|
136691
|
+
let a1 = 0, b1 = 0, shear = 0, c2 = 0, d2 = 0, scaleY = 0;
|
|
136692
|
+
if (scaleX > 0) {
|
|
136693
|
+
a1 = a / scaleX;
|
|
136694
|
+
b1 = b / scaleX;
|
|
136695
|
+
shear = a1 * c + b1 * d;
|
|
136696
|
+
c2 = c - a1 * shear;
|
|
136697
|
+
d2 = d - b1 * shear;
|
|
136698
|
+
scaleY = Math.sqrt(c2 * c2 + d2 * d2) || 0;
|
|
136699
|
+
if (scaleY > 0) shear = shear / scaleY;
|
|
136700
|
+
else shear = 0;
|
|
136701
|
+
}
|
|
136702
|
+
const aP = scaleX;
|
|
136703
|
+
const bP = 0;
|
|
136704
|
+
const cP = shear * scaleY;
|
|
136705
|
+
const dP = scaleY;
|
|
136706
|
+
try {
|
|
136707
|
+
cloneRoot.style.transform = `matrix(${aP}, ${bP}, ${cP}, ${dP}, 0, 0)`;
|
|
136708
|
+
} catch {
|
|
136709
|
+
}
|
|
136710
|
+
return { a: aP, b: bP, c: cP, d: dP };
|
|
136711
|
+
}
|
|
136712
|
+
}
|
|
136713
|
+
try {
|
|
136714
|
+
const legacy = String(tr).trim();
|
|
136715
|
+
cloneRoot.style.transform = legacy + " translate(0px, 0px) rotate(0deg)";
|
|
136716
|
+
return null;
|
|
136717
|
+
} catch {
|
|
136718
|
+
return null;
|
|
136719
|
+
}
|
|
136720
|
+
}
|
|
136721
|
+
function parseBoxShadow(cs) {
|
|
136722
|
+
const v = cs.boxShadow || "";
|
|
136723
|
+
if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
136724
|
+
const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim());
|
|
136725
|
+
let t = 0, r = 0, b2 = 0, l = 0;
|
|
136726
|
+
for (const part of parts) {
|
|
136727
|
+
const nums = part.match(/-?\d+(\.\d+)?px/g)?.map((n) => parseFloat(n)) || [];
|
|
136728
|
+
if (nums.length < 2) continue;
|
|
136729
|
+
const [ox2, oy2, blur = 0, spread = 0] = nums;
|
|
136730
|
+
const extX = Math.abs(ox2) + blur + spread;
|
|
136731
|
+
const extY = Math.abs(oy2) + blur + spread;
|
|
136732
|
+
r = Math.max(r, extX + Math.max(ox2, 0));
|
|
136733
|
+
l = Math.max(l, extX + Math.max(-ox2, 0));
|
|
136734
|
+
b2 = Math.max(b2, extY + Math.max(oy2, 0));
|
|
136735
|
+
t = Math.max(t, extY + Math.max(-oy2, 0));
|
|
136736
|
+
}
|
|
136737
|
+
return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) };
|
|
136738
|
+
}
|
|
136739
|
+
function parseFilterBlur(cs) {
|
|
136740
|
+
const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/);
|
|
136741
|
+
const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0;
|
|
136742
|
+
return { top: b2, right: b2, bottom: b2, left: b2 };
|
|
136743
|
+
}
|
|
136744
|
+
function parseOutline(cs) {
|
|
136745
|
+
if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
136746
|
+
const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0);
|
|
136747
|
+
return { top: w2, right: w2, bottom: w2, left: w2 };
|
|
136748
|
+
}
|
|
136749
|
+
function bboxWithOriginFull(w2, h2, M, ox2, oy2) {
|
|
136750
|
+
const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0;
|
|
136751
|
+
function pt(x, y) {
|
|
136752
|
+
let X = x - ox2, Y = y - oy2;
|
|
136753
|
+
let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y;
|
|
136754
|
+
X2 += ox2 + e2;
|
|
136755
|
+
Y2 += oy2 + f2;
|
|
136756
|
+
return [X2, Y2];
|
|
136757
|
+
}
|
|
136758
|
+
const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)];
|
|
136759
|
+
let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity;
|
|
136760
|
+
for (const [X, Y] of P) {
|
|
136761
|
+
if (X < minX2) minX2 = X;
|
|
136762
|
+
if (Y < minY2) minY2 = Y;
|
|
136763
|
+
if (X > maxX2) maxX2 = X;
|
|
136764
|
+
if (Y > maxY2) maxY2 = Y;
|
|
136765
|
+
}
|
|
136766
|
+
return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 };
|
|
136767
|
+
}
|
|
136768
|
+
function hasTFBBox(el) {
|
|
136769
|
+
return hasBBoxAffectingTransform(el);
|
|
136770
|
+
}
|
|
136771
|
+
function matrixFromComputed(el) {
|
|
136772
|
+
const tr = getComputedStyle(el).transform;
|
|
136773
|
+
if (!tr || tr === "none") return new DOMMatrix();
|
|
136774
|
+
try {
|
|
136775
|
+
return new DOMMatrix(tr);
|
|
136776
|
+
} catch {
|
|
136777
|
+
return new WebKitCSSMatrix(tr);
|
|
136778
|
+
}
|
|
136779
|
+
}
|
|
136780
|
+
function readIndividualTransforms(el) {
|
|
136781
|
+
const out = { rotate: "0deg", scale: null, translate: null };
|
|
136782
|
+
const map = typeof el.computedStyleMap === "function" ? el.computedStyleMap() : null;
|
|
136783
|
+
if (map) {
|
|
136784
|
+
const safeGet = (prop) => {
|
|
136785
|
+
try {
|
|
136786
|
+
if (typeof map.has === "function" && !map.has(prop)) return null;
|
|
136787
|
+
if (typeof map.get !== "function") return null;
|
|
136788
|
+
return map.get(prop);
|
|
136789
|
+
} catch {
|
|
136790
|
+
return null;
|
|
136791
|
+
}
|
|
136792
|
+
};
|
|
136793
|
+
const rot = safeGet("rotate");
|
|
136794
|
+
if (rot) {
|
|
136795
|
+
if (rot.angle) {
|
|
136796
|
+
const ang = rot.angle;
|
|
136797
|
+
out.rotate = ang.unit === "rad" ? ang.value * 180 / Math.PI + "deg" : ang.value + ang.unit;
|
|
136798
|
+
} else if (rot.unit) {
|
|
136799
|
+
out.rotate = rot.unit === "rad" ? rot.value * 180 / Math.PI + "deg" : rot.value + rot.unit;
|
|
136800
|
+
} else {
|
|
136801
|
+
out.rotate = String(rot);
|
|
136802
|
+
}
|
|
136803
|
+
} else {
|
|
136804
|
+
const cs2 = getComputedStyle(el);
|
|
136805
|
+
out.rotate = cs2.rotate && cs2.rotate !== "none" ? cs2.rotate : "0deg";
|
|
136806
|
+
}
|
|
136807
|
+
const sc = safeGet("scale");
|
|
136808
|
+
if (sc) {
|
|
136809
|
+
const sx = "x" in sc && sc.x?.value != null ? sc.x.value : Array.isArray(sc) ? sc[0]?.value : Number(sc) || 1;
|
|
136810
|
+
const sy = "y" in sc && sc.y?.value != null ? sc.y.value : Array.isArray(sc) ? sc[1]?.value : sx;
|
|
136811
|
+
out.scale = `${sx} ${sy}`;
|
|
136812
|
+
} else {
|
|
136813
|
+
const cs2 = getComputedStyle(el);
|
|
136814
|
+
out.scale = cs2.scale && cs2.scale !== "none" ? cs2.scale : null;
|
|
136815
|
+
}
|
|
136816
|
+
const tr = safeGet("translate");
|
|
136817
|
+
if (tr) {
|
|
136818
|
+
const tx = "x" in tr && "value" in tr.x ? tr.x.value : Array.isArray(tr) ? tr[0]?.value : 0;
|
|
136819
|
+
const ty = "y" in tr && "value" in tr.y ? tr.y.value : Array.isArray(tr) ? tr[1]?.value : 0;
|
|
136820
|
+
const ux = "x" in tr && tr.x?.unit ? tr.x.unit : "px";
|
|
136821
|
+
const uy = "y" in tr && tr.y?.unit ? tr.y.unit : "px";
|
|
136822
|
+
out.translate = `${tx}${ux} ${ty}${uy}`;
|
|
136823
|
+
} else {
|
|
136824
|
+
const cs2 = getComputedStyle(el);
|
|
136825
|
+
out.translate = cs2.translate && cs2.translate !== "none" ? cs2.translate : null;
|
|
136826
|
+
}
|
|
136827
|
+
return out;
|
|
136828
|
+
}
|
|
136829
|
+
const cs = getComputedStyle(el);
|
|
136830
|
+
out.rotate = cs.rotate && cs.rotate !== "none" ? cs.rotate : "0deg";
|
|
136831
|
+
out.scale = cs.scale && cs.scale !== "none" ? cs.scale : null;
|
|
136832
|
+
out.translate = cs.translate && cs.translate !== "none" ? cs.translate : null;
|
|
136833
|
+
return out;
|
|
136834
|
+
}
|
|
136835
|
+
function hasBBoxAffectingTransform(el) {
|
|
136836
|
+
const cs = getComputedStyle(el);
|
|
136837
|
+
const t = cs.transform || "none";
|
|
136838
|
+
const hasMatrix = t !== "none" && !/^matrix\(\s*1\s*,\s*0\s*,\s*0\s*,\s*1\s*,\s*0\s*,\s*0\s*\)$/i.test(t);
|
|
136839
|
+
if (hasMatrix) return true;
|
|
136840
|
+
const r = cs.rotate && cs.rotate !== "none" && cs.rotate !== "0deg";
|
|
136841
|
+
const s = cs.scale && cs.scale !== "none" && cs.scale !== "1";
|
|
136842
|
+
const tr = cs.translate && cs.translate !== "none" && cs.translate !== "0px 0px";
|
|
136843
|
+
return Boolean(r || s || tr);
|
|
136844
|
+
}
|
|
136845
|
+
function parseTransformOriginPx(cs, w, h) {
|
|
136846
|
+
const raw = (cs.transformOrigin || "0 0").trim().split(/\s+/);
|
|
136847
|
+
const [oxRaw, oyRaw] = [raw[0] || "0", raw[1] || "0"];
|
|
136848
|
+
const toPx = (token, size) => {
|
|
136849
|
+
const t = token.toLowerCase();
|
|
136850
|
+
if (t === "left" || t === "top") return 0;
|
|
136851
|
+
if (t === "center") return size / 2;
|
|
136852
|
+
if (t === "right") return size;
|
|
136853
|
+
if (t === "bottom") return size;
|
|
136854
|
+
if (t.endsWith("px")) return parseFloat(t) || 0;
|
|
136855
|
+
if (t.endsWith("%")) return (parseFloat(t) || 0) * size / 100;
|
|
136856
|
+
if (/^-?\d+(\.\d+)?$/.test(t)) return parseFloat(t) || 0;
|
|
136857
|
+
return 0;
|
|
136858
|
+
};
|
|
136859
|
+
return {
|
|
136860
|
+
ox: toPx(oxRaw, w),
|
|
136861
|
+
oy: toPx(oyRaw, h)
|
|
136862
|
+
};
|
|
136863
|
+
}
|
|
136864
|
+
var __measureHost = null;
|
|
136865
|
+
function getMeasureHost() {
|
|
136866
|
+
if (__measureHost) return __measureHost;
|
|
136867
|
+
const n = document.createElement("div");
|
|
136868
|
+
n.id = "snapdom-measure-slot";
|
|
136869
|
+
n.setAttribute("aria-hidden", "true");
|
|
136870
|
+
Object.assign(n.style, {
|
|
136871
|
+
position: "absolute",
|
|
136872
|
+
left: "-99999px",
|
|
136873
|
+
top: "0px",
|
|
136874
|
+
width: "0px",
|
|
136875
|
+
height: "0px",
|
|
136876
|
+
overflow: "hidden",
|
|
136877
|
+
opacity: "0",
|
|
136878
|
+
pointerEvents: "none",
|
|
136879
|
+
contain: "size layout style"
|
|
136880
|
+
});
|
|
136881
|
+
document.documentElement.appendChild(n);
|
|
136882
|
+
__measureHost = n;
|
|
136883
|
+
return n;
|
|
136884
|
+
}
|
|
136885
|
+
function readTotalTransformMatrix(t) {
|
|
136886
|
+
const host = getMeasureHost();
|
|
136887
|
+
const tmp = document.createElement("div");
|
|
136888
|
+
tmp.style.transformOrigin = "0 0";
|
|
136889
|
+
if (t.baseTransform) tmp.style.transform = t.baseTransform;
|
|
136890
|
+
if (t.rotate) tmp.style.rotate = t.rotate;
|
|
136891
|
+
if (t.scale) tmp.style.scale = t.scale;
|
|
136892
|
+
if (t.translate) tmp.style.translate = t.translate;
|
|
136893
|
+
host.appendChild(tmp);
|
|
136894
|
+
const M = matrixFromComputed(tmp);
|
|
136895
|
+
host.removeChild(tmp);
|
|
136896
|
+
return M;
|
|
136897
|
+
}
|
|
136898
|
+
|
|
136899
|
+
// src/core/context.js
|
|
136900
|
+
function normalizeCachePolicy(v) {
|
|
136901
|
+
if (typeof v === "string") {
|
|
136902
|
+
const s = v.toLowerCase().trim();
|
|
136903
|
+
if (s === "disabled" || s === "full" || s === "auto" || s === "soft") return (
|
|
136904
|
+
/** @type {CachePolicy} */
|
|
136905
|
+
s
|
|
136906
|
+
);
|
|
136907
|
+
}
|
|
136908
|
+
return "soft";
|
|
136909
|
+
}
|
|
136910
|
+
function createContext(options = {}) {
|
|
136911
|
+
const resolvedFormat = options.format ?? "png";
|
|
136912
|
+
const cachePolicy = normalizeCachePolicy(options.cache);
|
|
136913
|
+
return {
|
|
136914
|
+
// Debug & perf
|
|
136915
|
+
debug: options.debug ?? false,
|
|
136916
|
+
fast: options.fast ?? true,
|
|
136917
|
+
scale: options.scale ?? 1,
|
|
136918
|
+
// DOM filters
|
|
136919
|
+
exclude: options.exclude ?? [],
|
|
136920
|
+
excludeMode: options.excludeMode ?? "hide",
|
|
136921
|
+
filter: options.filter ?? null,
|
|
136922
|
+
filterMode: options.filterMode ?? "hide",
|
|
136923
|
+
// Placeholders
|
|
136924
|
+
placeholders: options.placeholders !== false,
|
|
136925
|
+
// default true
|
|
136926
|
+
// Fonts
|
|
136927
|
+
embedFonts: options.embedFonts ?? false,
|
|
136928
|
+
iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
|
|
136929
|
+
localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
|
|
136930
|
+
excludeFonts: options.excludeFonts ?? void 0,
|
|
136931
|
+
fallbackURL: options.fallbackURL ?? void 0,
|
|
136932
|
+
/** @type {CachePolicy} */
|
|
136933
|
+
cache: cachePolicy,
|
|
136934
|
+
// Network
|
|
136935
|
+
useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
|
|
136936
|
+
// Output
|
|
136937
|
+
width: options.width ?? null,
|
|
136938
|
+
height: options.height ?? null,
|
|
136939
|
+
format: resolvedFormat,
|
|
136940
|
+
type: options.type ?? "svg",
|
|
136941
|
+
quality: options.quality ?? 0.92,
|
|
136942
|
+
dpr: options.dpr ?? (window.devicePixelRatio || 1),
|
|
136943
|
+
backgroundColor: options.backgroundColor ?? (["jpg", "jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null),
|
|
136944
|
+
filename: options.filename ?? "snapDOM",
|
|
136945
|
+
// NEW flags (user-friendly)
|
|
136946
|
+
straighten: options.straighten ?? false,
|
|
136947
|
+
noShadows: options.noShadows ?? false
|
|
136948
|
+
// Plugins (reservado)
|
|
136949
|
+
// plugins: normalizePlugins(...),
|
|
136950
|
+
};
|
|
136951
|
+
}
|
|
136952
|
+
|
|
136953
|
+
// src/exporters/toCanvas.js
|
|
136954
|
+
function isSvgDataURL(u) {
|
|
136955
|
+
return typeof u === "string" && /^data:image\/svg\+xml/i.test(u);
|
|
136956
|
+
}
|
|
136957
|
+
function decodeSvgFromDataURL(u) {
|
|
136958
|
+
const i = u.indexOf(",");
|
|
136959
|
+
return i >= 0 ? decodeURIComponent(u.slice(i + 1)) : "";
|
|
136960
|
+
}
|
|
136961
|
+
function encodeSvgToDataURL(svgText) {
|
|
136962
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgText)}`;
|
|
136963
|
+
}
|
|
136964
|
+
function splitDecls(s) {
|
|
136965
|
+
let parts = [], buf = "", depth = 0;
|
|
136966
|
+
for (let i = 0; i < s.length; i++) {
|
|
136967
|
+
const ch = s[i];
|
|
136968
|
+
if (ch === "(") depth++;
|
|
136969
|
+
if (ch === ")") depth = Math.max(0, depth - 1);
|
|
136970
|
+
if (ch === ";" && depth === 0) {
|
|
136971
|
+
parts.push(buf);
|
|
136972
|
+
buf = "";
|
|
136973
|
+
} else buf += ch;
|
|
136974
|
+
}
|
|
136975
|
+
if (buf.trim()) parts.push(buf);
|
|
136976
|
+
return parts.map((x) => x.trim()).filter(Boolean);
|
|
136977
|
+
}
|
|
136978
|
+
function boxShadowToDropShadow(value) {
|
|
136979
|
+
const layers = [];
|
|
136980
|
+
let buf = "", depth = 0;
|
|
136981
|
+
for (let i = 0; i < value.length; i++) {
|
|
136982
|
+
const ch = value[i];
|
|
136983
|
+
if (ch === "(") depth++;
|
|
136984
|
+
if (ch === ")") depth = Math.max(0, depth - 1);
|
|
136985
|
+
if (ch === "," && depth === 0) {
|
|
136986
|
+
layers.push(buf.trim());
|
|
136987
|
+
buf = "";
|
|
136988
|
+
} else buf += ch;
|
|
136989
|
+
}
|
|
136990
|
+
if (buf.trim()) layers.push(buf.trim());
|
|
136991
|
+
const fns = [];
|
|
136992
|
+
for (const layer of layers) {
|
|
136993
|
+
if (/\binset\b/i.test(layer)) continue;
|
|
136994
|
+
const nums = layer.match(/-?\d+(?:\.\d+)?px/gi) || [];
|
|
136995
|
+
const [ox = "0px", oy = "0px", blur = "0px"] = nums;
|
|
136996
|
+
let color = layer.replace(/-?\d+(?:\.\d+)?px/gi, "").replace(/\binset\b/ig, "").trim().replace(/\s{2,}/g, " ");
|
|
136997
|
+
const hasColor = !!color && color !== ",";
|
|
136998
|
+
fns.push(`drop-shadow(${ox} ${oy} ${blur}${hasColor ? ` ${color}` : ""})`);
|
|
136999
|
+
}
|
|
137000
|
+
return fns.join(" ");
|
|
137001
|
+
}
|
|
137002
|
+
function rewriteDeclList(list) {
|
|
137003
|
+
const decls = splitDecls(list);
|
|
137004
|
+
let filter = null, wfilter = null, box = null;
|
|
137005
|
+
const rest = [];
|
|
137006
|
+
for (const d of decls) {
|
|
137007
|
+
const idx = d.indexOf(":");
|
|
137008
|
+
if (idx < 0) continue;
|
|
137009
|
+
const prop = d.slice(0, idx).trim().toLowerCase();
|
|
137010
|
+
const val = d.slice(idx + 1).trim();
|
|
137011
|
+
if (prop === "box-shadow") box = val;
|
|
137012
|
+
else if (prop === "filter") filter = val;
|
|
137013
|
+
else if (prop === "-webkit-filter") wfilter = val;
|
|
137014
|
+
else rest.push([prop, val]);
|
|
137015
|
+
}
|
|
137016
|
+
if (box) {
|
|
137017
|
+
const ds = boxShadowToDropShadow(box);
|
|
137018
|
+
if (ds) {
|
|
137019
|
+
filter = filter ? `${filter} ${ds}` : ds;
|
|
137020
|
+
wfilter = wfilter ? `${wfilter} ${ds}` : ds;
|
|
137021
|
+
}
|
|
137022
|
+
}
|
|
137023
|
+
const out = [...rest];
|
|
137024
|
+
if (filter) out.push(["filter", filter]);
|
|
137025
|
+
if (wfilter) out.push(["-webkit-filter", wfilter]);
|
|
137026
|
+
return out.map(([k, v]) => `${k}:${v}`).join(";");
|
|
137027
|
+
}
|
|
137028
|
+
function rewriteCssBlock(css) {
|
|
137029
|
+
return css.replace(/([^{}]+)\{([^}]*)\}/g, (_m, sel, body) => `${sel}{${rewriteDeclList(body)}}`);
|
|
137030
|
+
}
|
|
137031
|
+
function rewriteSvgBoxShadowToDropShadow(svgText) {
|
|
137032
|
+
svgText = svgText.replace(
|
|
137033
|
+
/<style[^>]*>([\s\S]*?)<\/style>/gi,
|
|
137034
|
+
(m, css) => m.replace(css, rewriteCssBlock(css))
|
|
137035
|
+
);
|
|
137036
|
+
svgText = svgText.replace(
|
|
137037
|
+
/style=(['"])([\s\S]*?)\1/gi,
|
|
137038
|
+
(m, q, body) => `style=${q}${rewriteDeclList(body)}${q}`
|
|
137039
|
+
);
|
|
137040
|
+
return svgText;
|
|
137041
|
+
}
|
|
137042
|
+
function maybeConvertBoxShadowForSafari(url) {
|
|
137043
|
+
if (!isSafari() || !isSvgDataURL(url)) return url;
|
|
137044
|
+
try {
|
|
137045
|
+
const svg = decodeSvgFromDataURL(url);
|
|
137046
|
+
const fixed = rewriteSvgBoxShadowToDropShadow(svg);
|
|
137047
|
+
return encodeSvgToDataURL(fixed);
|
|
137048
|
+
} catch {
|
|
137049
|
+
return url;
|
|
137050
|
+
}
|
|
137051
|
+
}
|
|
137052
|
+
async function toCanvas(url, options) {
|
|
137053
|
+
let { width: optW, height: optH, scale = 1, dpr = 1, meta = {} } = options;
|
|
137054
|
+
url = maybeConvertBoxShadowForSafari(url);
|
|
137055
|
+
const img = new Image();
|
|
137056
|
+
img.loading = "eager";
|
|
137057
|
+
img.decoding = "sync";
|
|
137058
|
+
img.crossOrigin = "anonymous";
|
|
137059
|
+
img.src = url;
|
|
137060
|
+
await img.decode();
|
|
137061
|
+
const natW = img.naturalWidth;
|
|
137062
|
+
const natH = img.naturalHeight;
|
|
137063
|
+
const refW = Number.isFinite(meta.w0) ? meta.w0 : natW;
|
|
137064
|
+
const refH = Number.isFinite(meta.h0) ? meta.h0 : natH;
|
|
137065
|
+
let outW, outH;
|
|
137066
|
+
const hasW = Number.isFinite(optW);
|
|
137067
|
+
const hasH = Number.isFinite(optH);
|
|
137068
|
+
if (hasW && hasH) {
|
|
137069
|
+
outW = Math.max(1, optW);
|
|
137070
|
+
outH = Math.max(1, optH);
|
|
137071
|
+
} else if (hasW) {
|
|
137072
|
+
const k = optW / Math.max(1, refW);
|
|
137073
|
+
outW = optW;
|
|
137074
|
+
outH = Math.round(refH * k);
|
|
137075
|
+
} else if (hasH) {
|
|
137076
|
+
const k = optH / Math.max(1, refH);
|
|
137077
|
+
outH = optH;
|
|
137078
|
+
outW = Math.round(refW * k);
|
|
137079
|
+
} else {
|
|
137080
|
+
outW = natW;
|
|
137081
|
+
outH = natH;
|
|
137082
|
+
}
|
|
137083
|
+
outW = Math.round(outW * scale);
|
|
137084
|
+
outH = Math.round(outH * scale);
|
|
137085
|
+
const canvas = document.createElement("canvas");
|
|
137086
|
+
canvas.width = Math.ceil(outW * dpr);
|
|
137087
|
+
canvas.height = Math.ceil(outH * dpr);
|
|
137088
|
+
canvas.style.width = `${outW}px`;
|
|
137089
|
+
canvas.style.height = `${outH}px`;
|
|
137090
|
+
const ctx = canvas.getContext("2d");
|
|
137091
|
+
if (dpr !== 1) ctx.scale(dpr, dpr);
|
|
137092
|
+
ctx.drawImage(img, 0, 0, outW, outH);
|
|
137093
|
+
return canvas;
|
|
137094
|
+
}
|
|
137095
|
+
|
|
137096
|
+
// src/modules/rasterize.js
|
|
137097
|
+
async function rasterize(url, options) {
|
|
137098
|
+
const canvas = await toCanvas(url, options);
|
|
137099
|
+
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
137100
|
+
const img = new Image();
|
|
137101
|
+
img.src = finalCanvas.toDataURL(`image/${options.format}`, options.quality);
|
|
137102
|
+
await img.decode();
|
|
137103
|
+
img.style.width = `${finalCanvas.width / options.dpr}px`;
|
|
137104
|
+
img.style.height = `${finalCanvas.height / options.dpr}px`;
|
|
137105
|
+
return img;
|
|
137106
|
+
}
|
|
137107
|
+
|
|
137108
|
+
// src/exporters/toImg.js
|
|
137109
|
+
async function toImg(url, options) {
|
|
137110
|
+
const { scale = 1, width, height, meta = {} } = options;
|
|
137111
|
+
const hasW = Number.isFinite(width);
|
|
137112
|
+
const hasH = Number.isFinite(height);
|
|
137113
|
+
const wantsScale = Number.isFinite(scale) && scale !== 1 || hasW || hasH;
|
|
137114
|
+
if (isSafari() && wantsScale) {
|
|
137115
|
+
const pngUrl = await rasterize(url, { ...options, format: "png", quality: 1, meta });
|
|
137116
|
+
return pngUrl;
|
|
137117
|
+
}
|
|
137118
|
+
const img = new Image();
|
|
137119
|
+
img.decoding = "sync";
|
|
137120
|
+
img.loading = "eager";
|
|
137121
|
+
img.src = url;
|
|
137122
|
+
await img.decode();
|
|
137123
|
+
if (hasW && hasH) {
|
|
137124
|
+
img.style.width = `${width}px`;
|
|
137125
|
+
img.style.height = `${height}px`;
|
|
137126
|
+
} else if (hasW) {
|
|
137127
|
+
const refW = Number.isFinite(meta.w0) ? meta.w0 : img.naturalWidth;
|
|
137128
|
+
const refH = Number.isFinite(meta.h0) ? meta.h0 : img.naturalHeight;
|
|
137129
|
+
const k = width / Math.max(1, refW);
|
|
137130
|
+
img.style.width = `${width}px`;
|
|
137131
|
+
img.style.height = `${Math.round(refH * k)}px`;
|
|
137132
|
+
} else if (hasH) {
|
|
137133
|
+
const refW = Number.isFinite(meta.w0) ? meta.w0 : img.naturalWidth;
|
|
137134
|
+
const refH = Number.isFinite(meta.h0) ? meta.h0 : img.naturalHeight;
|
|
137135
|
+
const k = height / Math.max(1, refH);
|
|
137136
|
+
img.style.height = `${height}px`;
|
|
137137
|
+
img.style.width = `${Math.round(refW * k)}px`;
|
|
137138
|
+
} else {
|
|
137139
|
+
const cssW = Math.round(img.naturalWidth * scale);
|
|
137140
|
+
const cssH = Math.round(img.naturalHeight * scale);
|
|
137141
|
+
img.style.width = `${cssW}px`;
|
|
137142
|
+
img.style.height = `${cssH}px`;
|
|
137143
|
+
if (typeof url === "string" && url.startsWith("data:image/svg+xml")) {
|
|
137144
|
+
try {
|
|
137145
|
+
const decoded = decodeURIComponent(url.split(",")[1]);
|
|
137146
|
+
const patched = decoded.replace(/width="[^"]*"/, `width="${cssW}"`).replace(/height="[^"]*"/, `height="${cssH}"`);
|
|
137147
|
+
url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(patched)}`;
|
|
137148
|
+
img.src = url;
|
|
137149
|
+
} catch {
|
|
137150
|
+
}
|
|
137151
|
+
}
|
|
137152
|
+
}
|
|
137153
|
+
return img;
|
|
137154
|
+
}
|
|
137155
|
+
|
|
137156
|
+
// src/exporters/toBlob.js
|
|
137157
|
+
async function toBlob(url, options) {
|
|
137158
|
+
const type = options.type;
|
|
137159
|
+
if (type === "svg") {
|
|
137160
|
+
const svgText = decodeURIComponent(url.split(",")[1]);
|
|
137161
|
+
return new Blob([svgText], { type: "image/svg+xml" });
|
|
137162
|
+
}
|
|
137163
|
+
const canvas = await toCanvas(url, options);
|
|
137164
|
+
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
137165
|
+
return new Promise(
|
|
137166
|
+
(resolve) => finalCanvas.toBlob(
|
|
137167
|
+
(blob) => resolve(blob),
|
|
137168
|
+
`image/${type}`,
|
|
137169
|
+
options.quality
|
|
137170
|
+
)
|
|
137171
|
+
);
|
|
137172
|
+
}
|
|
137173
|
+
|
|
137174
|
+
// src/exporters/download.js
|
|
137175
|
+
async function download(url, options) {
|
|
137176
|
+
options.dpr = 1;
|
|
137177
|
+
if (options.format === "svg") {
|
|
137178
|
+
const blob = await toBlob(url, { ...options, type: "svg" });
|
|
137179
|
+
const objectURL = URL.createObjectURL(blob);
|
|
137180
|
+
const a2 = document.createElement("a");
|
|
137181
|
+
a2.href = objectURL;
|
|
137182
|
+
a2.download = options.filename;
|
|
137183
|
+
a2.click();
|
|
137184
|
+
URL.revokeObjectURL(objectURL);
|
|
137185
|
+
return;
|
|
137186
|
+
}
|
|
137187
|
+
const canvas = await toCanvas(url, options);
|
|
137188
|
+
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
137189
|
+
const a = document.createElement("a");
|
|
137190
|
+
a.href = finalCanvas.toDataURL(`image/${options.format}`, options.quality);
|
|
137191
|
+
a.download = options.filename;
|
|
137192
|
+
a.click();
|
|
137193
|
+
}
|
|
137194
|
+
|
|
137195
|
+
// src/api/snapdom.js
|
|
137196
|
+
var INTERNAL_TOKEN = Symbol("snapdom.internal");
|
|
137197
|
+
var _safariWarmup = false;
|
|
137198
|
+
async function snapdom(element, userOptions) {
|
|
137199
|
+
if (!element) throw new Error("Element cannot be null or undefined");
|
|
137200
|
+
const context = createContext(userOptions);
|
|
137201
|
+
if (isSafari() && (context.embedFonts === true || hasBackgroundOrMask(element))) {
|
|
137202
|
+
for (let i = 0; i < 3; i++) {
|
|
137203
|
+
try {
|
|
137204
|
+
await safariWarmup(element, userOptions);
|
|
137205
|
+
console.log("Iteraci\xF3n n\xFAmero:", i);
|
|
137206
|
+
_safariWarmup = false;
|
|
137207
|
+
} catch {
|
|
137208
|
+
}
|
|
137209
|
+
}
|
|
137210
|
+
}
|
|
137211
|
+
if (context.iconFonts && context.iconFonts.length > 0) extendIconFonts(context.iconFonts);
|
|
137212
|
+
if (!context.snap) {
|
|
137213
|
+
context.snap = {
|
|
137214
|
+
toPng: (el, opts) => snapdom.toPng(el, opts),
|
|
137215
|
+
toSvg: (el, opts) => snapdom.toSvg(el, opts)
|
|
137216
|
+
};
|
|
137217
|
+
}
|
|
137218
|
+
return snapdom.capture(element, context, INTERNAL_TOKEN);
|
|
137219
|
+
}
|
|
137220
|
+
snapdom.capture = async (el, context, _token) => {
|
|
137221
|
+
if (_token !== INTERNAL_TOKEN) throw new Error("[snapdom.capture] is internal. Use snapdom(...) instead.");
|
|
137222
|
+
const url = await captureDOM(el, context);
|
|
137223
|
+
const ensureContext = (opts) => ({ ...context, ...opts || {} });
|
|
137224
|
+
const withFormat = (format) => (opts) => {
|
|
137225
|
+
const next = ensureContext({ ...opts || {}, format });
|
|
137226
|
+
const wantsJpeg = format === "jpeg" || format === "jpg";
|
|
137227
|
+
const noBg = next.backgroundColor == null || next.backgroundColor === "transparent";
|
|
137228
|
+
if (wantsJpeg && noBg) {
|
|
137229
|
+
next.backgroundColor = "#ffffff";
|
|
137230
|
+
}
|
|
137231
|
+
return rasterize(url, next);
|
|
137232
|
+
};
|
|
137233
|
+
return {
|
|
137234
|
+
url,
|
|
137235
|
+
toRaw: () => url,
|
|
137236
|
+
toImg: (opts) => toImg(url, ensureContext(opts)),
|
|
137237
|
+
toSvg: (opts) => toImg(url, ensureContext(opts)),
|
|
137238
|
+
toCanvas: (opts) => toCanvas(url, ensureContext(opts)),
|
|
137239
|
+
toBlob: (opts) => toBlob(url, ensureContext(opts)),
|
|
137240
|
+
toPng: withFormat("png"),
|
|
137241
|
+
toJpg: withFormat("jpeg"),
|
|
137242
|
+
toWebp: withFormat("webp"),
|
|
137243
|
+
download: (opts) => download(url, ensureContext(opts))
|
|
137244
|
+
};
|
|
137245
|
+
};
|
|
137246
|
+
snapdom.toRaw = (el, options) => snapdom(el, options).then((result) => result.toRaw());
|
|
137247
|
+
snapdom.toImg = (el, options) => snapdom(el, options).then((result) => result.toImg());
|
|
137248
|
+
snapdom.toSvg = (el, options) => snapdom(el, options).then((result) => result.toSvg());
|
|
137249
|
+
snapdom.toCanvas = (el, options) => snapdom(el, options).then((result) => result.toCanvas());
|
|
137250
|
+
snapdom.toBlob = (el, options) => snapdom(el, options).then((result) => result.toBlob());
|
|
137251
|
+
snapdom.toPng = (el, options) => snapdom(el, { ...options, format: "png" }).then((result) => result.toPng());
|
|
137252
|
+
snapdom.toJpg = (el, options) => snapdom(el, { ...options, format: "jpeg" }).then((result) => result.toJpg());
|
|
137253
|
+
snapdom.toWebp = (el, options) => snapdom(el, { ...options, format: "webp" }).then((result) => result.toWebp());
|
|
137254
|
+
snapdom.download = (el, options) => snapdom(el, options).then((result) => result.download());
|
|
137255
|
+
async function safariWarmup(element, baseOptions) {
|
|
137256
|
+
if (_safariWarmup) return;
|
|
137257
|
+
const preflight = {
|
|
137258
|
+
...baseOptions,
|
|
137259
|
+
fast: true,
|
|
137260
|
+
embedFonts: true,
|
|
137261
|
+
scale: 0.2
|
|
137262
|
+
};
|
|
137263
|
+
let url;
|
|
137264
|
+
try {
|
|
137265
|
+
url = await captureDOM(element, preflight);
|
|
137266
|
+
} catch {
|
|
137267
|
+
return;
|
|
137268
|
+
}
|
|
137269
|
+
await new Promise((resolve) => {
|
|
137270
|
+
const img = new Image();
|
|
137271
|
+
img.decoding = "sync";
|
|
137272
|
+
img.loading = "eager";
|
|
137273
|
+
img.style.position = "fixed";
|
|
137274
|
+
img.style.left = 0;
|
|
137275
|
+
img.style.top = 0;
|
|
137276
|
+
img.style.width = "10px";
|
|
137277
|
+
img.style.height = "10px";
|
|
137278
|
+
img.style.opacity = "0.01";
|
|
137279
|
+
img.style.transform = "translateZ(10px)";
|
|
137280
|
+
img.style.willChange = "transform,opacity;";
|
|
137281
|
+
img.src = url;
|
|
137282
|
+
const cleanup = async () => {
|
|
137283
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
137284
|
+
if (img && img.parentNode) img.parentNode.removeChild(img);
|
|
137285
|
+
_safariWarmup = true;
|
|
137286
|
+
resolve();
|
|
137287
|
+
};
|
|
137288
|
+
document.body.appendChild(img);
|
|
137289
|
+
cleanup();
|
|
137290
|
+
});
|
|
137291
|
+
}
|
|
137292
|
+
function hasBackgroundOrMask(el) {
|
|
137293
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_ELEMENT);
|
|
137294
|
+
while (walker.nextNode()) {
|
|
137295
|
+
const node = (
|
|
137296
|
+
/** @type {Element} */
|
|
137297
|
+
walker.currentNode
|
|
137298
|
+
);
|
|
137299
|
+
const cs = getComputedStyle(node);
|
|
137300
|
+
const bg = cs.backgroundImage && cs.backgroundImage !== "none";
|
|
137301
|
+
const mask = cs.maskImage && cs.maskImage !== "none" || cs.webkitMaskImage && cs.webkitMaskImage !== "none";
|
|
137302
|
+
if (bg || mask) return true;
|
|
137303
|
+
}
|
|
137304
|
+
return false;
|
|
137305
|
+
}
|
|
137306
|
+
|
|
137307
|
+
// src/api/preCache.js
|
|
137308
|
+
async function preCache(root = document, options = {}) {
|
|
137309
|
+
const {
|
|
137310
|
+
embedFonts = true,
|
|
137311
|
+
useProxy = ""
|
|
137312
|
+
} = options;
|
|
137313
|
+
const cacheMode = options.cache ?? options.cacheOpt ?? "full";
|
|
137314
|
+
applyCachePolicy(cacheMode);
|
|
137315
|
+
try {
|
|
137316
|
+
await document.fonts?.ready;
|
|
137317
|
+
} catch {
|
|
137318
|
+
}
|
|
137319
|
+
try {
|
|
137320
|
+
precacheCommonTags();
|
|
137321
|
+
} catch {
|
|
137322
|
+
}
|
|
137323
|
+
cache.session = cache.session || {};
|
|
137324
|
+
if (!cache.session.styleCache) {
|
|
137325
|
+
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
137326
|
+
}
|
|
137327
|
+
cache.image = cache.image || /* @__PURE__ */ new Map();
|
|
137328
|
+
try {
|
|
137329
|
+
await inlineBackgroundImages(
|
|
137330
|
+
root,
|
|
137331
|
+
/* mirror */
|
|
137332
|
+
void 0,
|
|
137333
|
+
cache.session.styleCache,
|
|
137334
|
+
{ useProxy }
|
|
137335
|
+
);
|
|
137336
|
+
} catch {
|
|
137337
|
+
}
|
|
137338
|
+
let imgEls = [], allEls = [];
|
|
137339
|
+
try {
|
|
137340
|
+
if (root?.querySelectorAll) {
|
|
137341
|
+
imgEls = Array.from(root.querySelectorAll("img[src]"));
|
|
137342
|
+
allEls = Array.from(root.querySelectorAll("*"));
|
|
137343
|
+
}
|
|
137344
|
+
} catch {
|
|
137345
|
+
}
|
|
137346
|
+
const promises = [];
|
|
137347
|
+
for (const img of imgEls) {
|
|
137348
|
+
const src = img?.currentSrc || img?.src;
|
|
137349
|
+
if (!src) continue;
|
|
137350
|
+
if (!cache.image.has(src)) {
|
|
137351
|
+
const p = Promise.resolve().then(async () => {
|
|
137352
|
+
const res = await snapFetch(src, { as: "dataURL", useProxy });
|
|
137353
|
+
if (res?.ok && typeof res.data === "string") {
|
|
137354
|
+
cache.image.set(src, res.data);
|
|
137355
|
+
}
|
|
137356
|
+
}).catch(() => {
|
|
137357
|
+
});
|
|
137358
|
+
promises.push(p);
|
|
137359
|
+
}
|
|
137360
|
+
}
|
|
137361
|
+
for (const el of allEls) {
|
|
137362
|
+
let bg = "";
|
|
137363
|
+
try {
|
|
137364
|
+
bg = getStyle(el).backgroundImage;
|
|
137365
|
+
} catch {
|
|
137366
|
+
}
|
|
137367
|
+
if (bg && bg !== "none") {
|
|
137368
|
+
const parts = splitBackgroundImage(bg);
|
|
137369
|
+
for (const entry of parts) {
|
|
137370
|
+
if (entry.startsWith("url(")) {
|
|
137371
|
+
const p = Promise.resolve().then(() => inlineSingleBackgroundEntry(entry, { ...options, useProxy })).catch(() => {
|
|
137372
|
+
});
|
|
137373
|
+
promises.push(p);
|
|
137374
|
+
}
|
|
137375
|
+
}
|
|
137376
|
+
}
|
|
137377
|
+
}
|
|
137378
|
+
if (embedFonts) {
|
|
137379
|
+
try {
|
|
137380
|
+
const required = collectUsedFontVariants(root);
|
|
137381
|
+
const usedCodepoints = collectUsedCodepoints(root);
|
|
137382
|
+
const safari = typeof isSafari === "function" ? isSafari() : !!isSafari;
|
|
137383
|
+
if (safari) {
|
|
137384
|
+
const families = new Set(
|
|
137385
|
+
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
137386
|
+
);
|
|
137387
|
+
await ensureFontsReady(families, 3);
|
|
137388
|
+
}
|
|
137389
|
+
await embedCustomFonts({
|
|
137390
|
+
required,
|
|
137391
|
+
usedCodepoints,
|
|
137392
|
+
exclude: options.excludeFonts,
|
|
137393
|
+
localFonts: options.localFonts,
|
|
137394
|
+
useProxy: options.useProxy ?? useProxy
|
|
137395
|
+
});
|
|
137396
|
+
} catch {
|
|
137397
|
+
}
|
|
137398
|
+
}
|
|
137399
|
+
await Promise.allSettled(promises);
|
|
137400
|
+
}
|
|
137401
|
+
|
|
137402
|
+
const snapdom$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
137403
|
+
__proto__: null,
|
|
137404
|
+
preCache,
|
|
137405
|
+
snapdom
|
|
137406
|
+
}, Symbol.toStringTag, { value: 'Module' }));
|
|
137407
|
+
|
|
133185
137408
|
exports.ActionSheet = ActionSheet;
|
|
133186
137409
|
exports.Affix = Affix;
|
|
133187
137410
|
exports.Alert = Alert;
|
|
@@ -133215,7 +137438,6 @@ var VcComponents = (function (exports, vue) {
|
|
|
133215
137438
|
exports.Form = Form;
|
|
133216
137439
|
exports.FormItem = FormItem;
|
|
133217
137440
|
exports.Fragment = Fragment;
|
|
133218
|
-
exports.HTMLToImage = HTMLToImage;
|
|
133219
137441
|
exports.Icon = Icon;
|
|
133220
137442
|
exports.IconManager = IconManager;
|
|
133221
137443
|
exports.Image = Image$2;
|
|
@@ -133260,7 +137482,6 @@ var VcComponents = (function (exports, vue) {
|
|
|
133260
137482
|
exports.MForm = MForm;
|
|
133261
137483
|
exports.MFormItem = MFormItem;
|
|
133262
137484
|
exports.MFragment = MFragment;
|
|
133263
|
-
exports.MHTMLToImage = MHTMLToImage;
|
|
133264
137485
|
exports.MIcon = MIcon;
|
|
133265
137486
|
exports.MImage = MImage;
|
|
133266
137487
|
exports.MImageCrop = MImageCrop;
|
|
@@ -133294,6 +137515,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
133294
137515
|
exports.MScroller = MScroller;
|
|
133295
137516
|
exports.MSelect = MSelect;
|
|
133296
137517
|
exports.MSlider = MSlider;
|
|
137518
|
+
exports.MSnapshot = MSnapshot;
|
|
133297
137519
|
exports.MSortList = MSortList;
|
|
133298
137520
|
exports.MSpin = MSpin;
|
|
133299
137521
|
exports.MSteps = MSteps;
|
|
@@ -133347,6 +137569,7 @@ var VcComponents = (function (exports, vue) {
|
|
|
133347
137569
|
exports.ScrollerWheel = ScrollerWheel;
|
|
133348
137570
|
exports.Select = Select;
|
|
133349
137571
|
exports.Slider = Slider;
|
|
137572
|
+
exports.Snapshot = Snapshot;
|
|
133350
137573
|
exports.SortList = SortList;
|
|
133351
137574
|
exports.Spin = Spin;
|
|
133352
137575
|
exports.Steps = Steps;
|