@amplifyup/sdk 0.1.17 → 0.1.19
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/AmplifyRenderer.d.mts +1 -1
- package/dist/AmplifyRenderer.d.ts +1 -1
- package/dist/AmplifyRenderer.js +278 -18
- package/dist/AmplifyRenderer.js.map +1 -1
- package/dist/AmplifyRenderer.mjs +278 -18
- package/dist/AmplifyRenderer.mjs.map +1 -1
- package/dist/index.d.mts +25 -4
- package/dist/index.d.ts +25 -4
- package/dist/index.js +228 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +228 -19
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +278 -18
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +278 -18
- package/dist/react.mjs.map +1 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/{types-B2Swk8BW.d.mts → types-Cy5aWQ5c.d.mts} +4 -0
- package/dist/{types-B2Swk8BW.d.ts → types-Cy5aWQ5c.d.ts} +4 -0
- package/package.json +1 -1
package/dist/AmplifyRenderer.js
CHANGED
|
@@ -368,6 +368,9 @@ var AmplifyUpSDK = class {
|
|
|
368
368
|
this.attachedEventListeners = [];
|
|
369
369
|
this.trackingIntervals = [];
|
|
370
370
|
this.trackingCleanup = null;
|
|
371
|
+
this.componentViewObservers = [];
|
|
372
|
+
this.componentViewSeen = /* @__PURE__ */ new Set();
|
|
373
|
+
this.pageEngagementActive = false;
|
|
371
374
|
this.adapter = adapter || new AWSAdapter();
|
|
372
375
|
if (typeof window !== "undefined") {
|
|
373
376
|
this.isVisualEditorMode = this.detectVisualEditorMode();
|
|
@@ -540,6 +543,7 @@ var AmplifyUpSDK = class {
|
|
|
540
543
|
this.initialPageSent = true;
|
|
541
544
|
const url = window.location.pathname;
|
|
542
545
|
this.page(url);
|
|
546
|
+
this.setupPageEngagement();
|
|
543
547
|
}
|
|
544
548
|
}
|
|
545
549
|
if (this.config?.debug && this.initialized) {
|
|
@@ -572,6 +576,168 @@ var AmplifyUpSDK = class {
|
|
|
572
576
|
}
|
|
573
577
|
this.trackingIntervals.forEach((id) => clearInterval(id));
|
|
574
578
|
this.trackingIntervals = [];
|
|
579
|
+
this.cleanupComponentViewTracking();
|
|
580
|
+
this.pageEngagementActive = false;
|
|
581
|
+
}
|
|
582
|
+
/** Current page path for engagement attribution. */
|
|
583
|
+
currentPath() {
|
|
584
|
+
if (typeof window === "undefined") return "/";
|
|
585
|
+
return window.location.pathname || "/";
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Automatic page-level Scroll Depth + Time on Page (dwell heartbeat).
|
|
589
|
+
*/
|
|
590
|
+
setupPageEngagement() {
|
|
591
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
592
|
+
if (this.isPreviewMode() || this.pageEngagementActive) return;
|
|
593
|
+
this.pageEngagementActive = true;
|
|
594
|
+
const milestones = [25, 50, 75, 100];
|
|
595
|
+
const reached = /* @__PURE__ */ new Set();
|
|
596
|
+
let visibleMs = 0;
|
|
597
|
+
let visibleSince = document.visibilityState === "visible" ? Date.now() : null;
|
|
598
|
+
let lastDwellSecondsSent = 0;
|
|
599
|
+
let scrollRaf = null;
|
|
600
|
+
const path = () => this.currentPath();
|
|
601
|
+
const measureScrollPercent = () => {
|
|
602
|
+
const doc = document.documentElement;
|
|
603
|
+
const body = document.body;
|
|
604
|
+
const scrollTop = window.scrollY || doc.scrollTop || body?.scrollTop || 0;
|
|
605
|
+
const scrollHeight = Math.max(
|
|
606
|
+
doc.scrollHeight,
|
|
607
|
+
body?.scrollHeight || 0,
|
|
608
|
+
doc.offsetHeight,
|
|
609
|
+
body?.offsetHeight || 0
|
|
610
|
+
);
|
|
611
|
+
const clientHeight = window.innerHeight || doc.clientHeight || 0;
|
|
612
|
+
const traversable = Math.max(scrollHeight - clientHeight, 0);
|
|
613
|
+
if (traversable <= 0) return 100;
|
|
614
|
+
return Math.min(100, Math.round(scrollTop / traversable * 100));
|
|
615
|
+
};
|
|
616
|
+
const checkScroll = () => {
|
|
617
|
+
if (this.isPreviewMode()) return;
|
|
618
|
+
const pct = measureScrollPercent();
|
|
619
|
+
for (const milestone of milestones) {
|
|
620
|
+
if (pct >= milestone && !reached.has(milestone)) {
|
|
621
|
+
reached.add(milestone);
|
|
622
|
+
this.track("Scroll Depth", {
|
|
623
|
+
percentage: milestone,
|
|
624
|
+
path: path()
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
const onScroll = () => {
|
|
630
|
+
if (scrollRaf != null) return;
|
|
631
|
+
scrollRaf = window.requestAnimationFrame(() => {
|
|
632
|
+
scrollRaf = null;
|
|
633
|
+
checkScroll();
|
|
634
|
+
});
|
|
635
|
+
};
|
|
636
|
+
const accumulateVisible = () => {
|
|
637
|
+
if (visibleSince == null) return;
|
|
638
|
+
visibleMs += Date.now() - visibleSince;
|
|
639
|
+
visibleSince = Date.now();
|
|
640
|
+
};
|
|
641
|
+
const emitDwell = (force = false) => {
|
|
642
|
+
if (this.isPreviewMode()) return;
|
|
643
|
+
accumulateVisible();
|
|
644
|
+
const seconds = Math.floor(visibleMs / 1e3);
|
|
645
|
+
if (seconds <= 0) return;
|
|
646
|
+
if (!force && seconds <= lastDwellSecondsSent) return;
|
|
647
|
+
lastDwellSecondsSent = seconds;
|
|
648
|
+
this.track("Time on Page", {
|
|
649
|
+
seconds,
|
|
650
|
+
path: path()
|
|
651
|
+
});
|
|
652
|
+
};
|
|
653
|
+
const onVisibility = () => {
|
|
654
|
+
if (document.visibilityState === "visible") {
|
|
655
|
+
visibleSince = Date.now();
|
|
656
|
+
} else {
|
|
657
|
+
emitDwell(true);
|
|
658
|
+
visibleSince = null;
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
const onPageHide = () => {
|
|
662
|
+
emitDwell(true);
|
|
663
|
+
};
|
|
664
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
665
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
666
|
+
window.addEventListener("pagehide", onPageHide);
|
|
667
|
+
checkScroll();
|
|
668
|
+
const heartbeat = setInterval(() => {
|
|
669
|
+
if (document.visibilityState === "visible") {
|
|
670
|
+
emitDwell(false);
|
|
671
|
+
}
|
|
672
|
+
}, 15e3);
|
|
673
|
+
this.trackingIntervals.push(heartbeat);
|
|
674
|
+
const previousCleanup = this.trackingCleanup;
|
|
675
|
+
this.trackingCleanup = () => {
|
|
676
|
+
window.removeEventListener("scroll", onScroll);
|
|
677
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
678
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
679
|
+
if (scrollRaf != null) {
|
|
680
|
+
window.cancelAnimationFrame(scrollRaf);
|
|
681
|
+
scrollRaf = null;
|
|
682
|
+
}
|
|
683
|
+
previousCleanup?.();
|
|
684
|
+
this.pageEngagementActive = false;
|
|
685
|
+
};
|
|
686
|
+
if (this.config?.debug) {
|
|
687
|
+
console.log("[AmplifyUp SDK] Page engagement tracking enabled");
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Automatic Component View when component hosts enter the viewport.
|
|
692
|
+
*/
|
|
693
|
+
setupComponentViewTracking() {
|
|
694
|
+
if (typeof document === "undefined" || typeof IntersectionObserver === "undefined") {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
if (this.isPreviewMode()) return;
|
|
698
|
+
this.cleanupComponentViewTracking();
|
|
699
|
+
const hosts = document.querySelectorAll("[data-amplifyup-component]");
|
|
700
|
+
if (hosts.length === 0) {
|
|
701
|
+
if (this.config?.debug) {
|
|
702
|
+
console.log("[AmplifyUp SDK] No component hosts found for Component View");
|
|
703
|
+
}
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const observer = new IntersectionObserver(
|
|
707
|
+
(entries) => {
|
|
708
|
+
entries.forEach((entry) => {
|
|
709
|
+
if (!entry.isIntersecting) return;
|
|
710
|
+
const el = entry.target;
|
|
711
|
+
const componentId = el.getAttribute("data-amplifyup-component") || el.getAttribute("data-component-id");
|
|
712
|
+
if (!componentId || this.componentViewSeen.has(componentId)) {
|
|
713
|
+
observer.unobserve(el);
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
this.componentViewSeen.add(componentId);
|
|
717
|
+
const componentName = el.getAttribute("data-component-name") || void 0;
|
|
718
|
+
this.track("Component View", {
|
|
719
|
+
componentId,
|
|
720
|
+
componentName,
|
|
721
|
+
path: this.currentPath()
|
|
722
|
+
});
|
|
723
|
+
observer.unobserve(el);
|
|
724
|
+
});
|
|
725
|
+
},
|
|
726
|
+
{ threshold: 0.5 }
|
|
727
|
+
);
|
|
728
|
+
hosts.forEach((host) => observer.observe(host));
|
|
729
|
+
this.componentViewObservers.push(observer);
|
|
730
|
+
if (this.config?.debug) {
|
|
731
|
+
console.log(
|
|
732
|
+
"[AmplifyUp SDK] Component View tracking enabled for",
|
|
733
|
+
hosts.length,
|
|
734
|
+
"hosts"
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
cleanupComponentViewTracking() {
|
|
739
|
+
this.componentViewObservers.forEach((obs) => obs.disconnect());
|
|
740
|
+
this.componentViewObservers = [];
|
|
575
741
|
}
|
|
576
742
|
/**
|
|
577
743
|
* Track a page view
|
|
@@ -611,9 +777,13 @@ var AmplifyUpSDK = class {
|
|
|
611
777
|
instanceId,
|
|
612
778
|
trackingId: this.config?.trackingId,
|
|
613
779
|
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
780
|
+
path: properties?.path || (typeof window !== "undefined" ? window.location.pathname : void 0),
|
|
614
781
|
// Timestamp is included in event payload
|
|
615
782
|
...properties
|
|
616
783
|
};
|
|
784
|
+
if (!trackProperties.path && typeof window !== "undefined") {
|
|
785
|
+
trackProperties.path = window.location.pathname;
|
|
786
|
+
}
|
|
617
787
|
this.adapter.track(eventName, trackProperties);
|
|
618
788
|
}
|
|
619
789
|
/**
|
|
@@ -902,6 +1072,13 @@ Available Console Commands:
|
|
|
902
1072
|
if (pageConfig?.eventTracking) {
|
|
903
1073
|
this.setupEventTracking(pageConfig.eventTracking);
|
|
904
1074
|
}
|
|
1075
|
+
if (typeof window !== "undefined") {
|
|
1076
|
+
window.setTimeout(() => this.setupComponentViewTracking(), 150);
|
|
1077
|
+
window.setTimeout(() => {
|
|
1078
|
+
this.setupComponentViewTracking();
|
|
1079
|
+
this.refreshEventTracking();
|
|
1080
|
+
}, 800);
|
|
1081
|
+
}
|
|
905
1082
|
return pageConfig;
|
|
906
1083
|
}
|
|
907
1084
|
/**
|
|
@@ -909,10 +1086,10 @@ Available Console Commands:
|
|
|
909
1086
|
*/
|
|
910
1087
|
setupEventTracking(eventConfig) {
|
|
911
1088
|
if (typeof document === "undefined") return;
|
|
912
|
-
this.
|
|
913
|
-
this.eventTrackingConfig = eventConfig;
|
|
1089
|
+
this.detachEventListeners();
|
|
1090
|
+
this.eventTrackingConfig = Array.isArray(eventConfig) ? [...eventConfig] : [];
|
|
914
1091
|
if (this.config?.debug) {
|
|
915
|
-
console.log("[AmplifyUp SDK] Setting up event tracking:",
|
|
1092
|
+
console.log("[AmplifyUp SDK] Setting up event tracking:", this.eventTrackingConfig.length, "events");
|
|
916
1093
|
}
|
|
917
1094
|
if (document.readyState === "loading") {
|
|
918
1095
|
document.addEventListener("DOMContentLoaded", () => this.attachEventListeners());
|
|
@@ -927,19 +1104,35 @@ Available Console Commands:
|
|
|
927
1104
|
if (typeof document === "undefined") return;
|
|
928
1105
|
this.eventTrackingConfig.forEach((eventConfig) => {
|
|
929
1106
|
if (eventConfig.enabled === false) return;
|
|
1107
|
+
if (!eventConfig.selector) {
|
|
1108
|
+
if (this.config?.debug) {
|
|
1109
|
+
console.warn(`[AmplifyUp SDK] Event ${eventConfig.eventName} has no selector, skipping`);
|
|
1110
|
+
}
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
930
1113
|
let targetElements = [];
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1114
|
+
try {
|
|
1115
|
+
const escapeAttr = (value) => typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(value) : value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
1116
|
+
const scopeRoot = eventConfig.componentId ? document.querySelector(
|
|
1117
|
+
`[data-amplifyup-component="${escapeAttr(eventConfig.componentId)}"], [data-component-id="${escapeAttr(eventConfig.componentId)}"]`
|
|
1118
|
+
) : document;
|
|
1119
|
+
if (!scopeRoot) {
|
|
935
1120
|
if (this.config?.debug) {
|
|
936
|
-
console.
|
|
1121
|
+
console.log(
|
|
1122
|
+
`[AmplifyUp SDK] Component host not found for ${eventConfig.componentId}`
|
|
1123
|
+
);
|
|
937
1124
|
}
|
|
938
1125
|
return;
|
|
939
1126
|
}
|
|
940
|
-
|
|
1127
|
+
targetElements = Array.from(
|
|
1128
|
+
scopeRoot.querySelectorAll(eventConfig.selector)
|
|
1129
|
+
);
|
|
1130
|
+
if (scopeRoot instanceof Element && scopeRoot !== document.documentElement && scopeRoot.matches?.(eventConfig.selector)) {
|
|
1131
|
+
targetElements.unshift(scopeRoot);
|
|
1132
|
+
}
|
|
1133
|
+
} catch (e) {
|
|
941
1134
|
if (this.config?.debug) {
|
|
942
|
-
console.warn(`[AmplifyUp SDK]
|
|
1135
|
+
console.warn(`[AmplifyUp SDK] Invalid selector: ${eventConfig.selector}`, e);
|
|
943
1136
|
}
|
|
944
1137
|
return;
|
|
945
1138
|
}
|
|
@@ -995,8 +1188,15 @@ Available Console Commands:
|
|
|
995
1188
|
handleTrackedEvent(event, config, element) {
|
|
996
1189
|
const properties = {
|
|
997
1190
|
eventType: config.eventType,
|
|
998
|
-
selector: config.selector
|
|
1191
|
+
selector: config.selector,
|
|
1192
|
+
path: this.currentPath()
|
|
999
1193
|
};
|
|
1194
|
+
if (config.componentId) {
|
|
1195
|
+
properties.componentId = config.componentId;
|
|
1196
|
+
}
|
|
1197
|
+
if (config.componentName) {
|
|
1198
|
+
properties.componentName = config.componentName;
|
|
1199
|
+
}
|
|
1000
1200
|
if (config.properties && config.properties.length > 0) {
|
|
1001
1201
|
config.properties.forEach((prop) => {
|
|
1002
1202
|
const dataAttrValue = element.getAttribute(`data-${prop}`);
|
|
@@ -1067,9 +1267,9 @@ Available Console Commands:
|
|
|
1067
1267
|
element._amplifyupViewObserver = observer;
|
|
1068
1268
|
}
|
|
1069
1269
|
/**
|
|
1070
|
-
*
|
|
1270
|
+
* Detach listeners/observers without clearing the saved event config.
|
|
1071
1271
|
*/
|
|
1072
|
-
|
|
1272
|
+
detachEventListeners() {
|
|
1073
1273
|
this.attachedEventListeners.forEach(({ element, eventType, handler }) => {
|
|
1074
1274
|
element.removeEventListener(eventType, handler);
|
|
1075
1275
|
});
|
|
@@ -1083,6 +1283,12 @@ Available Console Commands:
|
|
|
1083
1283
|
}
|
|
1084
1284
|
});
|
|
1085
1285
|
}
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Clean up all attached event listeners and clear config
|
|
1289
|
+
*/
|
|
1290
|
+
cleanupEventTracking() {
|
|
1291
|
+
this.detachEventListeners();
|
|
1086
1292
|
this.eventTrackingConfig = [];
|
|
1087
1293
|
if (this.config?.debug) {
|
|
1088
1294
|
console.log("[AmplifyUp SDK] Cleaned up event tracking");
|
|
@@ -1092,11 +1298,13 @@ Available Console Commands:
|
|
|
1092
1298
|
* Manually trigger event tracking setup (useful after dynamic content loads)
|
|
1093
1299
|
*/
|
|
1094
1300
|
refreshEventTracking() {
|
|
1095
|
-
if (this.eventTrackingConfig.length
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1301
|
+
if (this.eventTrackingConfig.length === 0) return;
|
|
1302
|
+
const config = [...this.eventTrackingConfig];
|
|
1303
|
+
this.detachEventListeners();
|
|
1304
|
+
this.eventTrackingConfig = config;
|
|
1305
|
+
this.attachEventListeners();
|
|
1306
|
+
if (this.config?.debug) {
|
|
1307
|
+
console.log("[AmplifyUp SDK] Refreshed event tracking:", config.length, "events");
|
|
1100
1308
|
}
|
|
1101
1309
|
}
|
|
1102
1310
|
/** Origins allowed to send Composer postMessage commands to the SDK. */
|
|
@@ -2089,6 +2297,7 @@ function getSDK(adapter) {
|
|
|
2089
2297
|
return sdkInstance;
|
|
2090
2298
|
}
|
|
2091
2299
|
var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
|
|
2300
|
+
var refreshEventTracking = () => getSDK().refreshEventTracking();
|
|
2092
2301
|
getSDK();
|
|
2093
2302
|
react.createContext(null);
|
|
2094
2303
|
var usePathname = null;
|
|
@@ -2148,6 +2357,32 @@ function AmplifyRenderer({
|
|
|
2148
2357
|
});
|
|
2149
2358
|
}
|
|
2150
2359
|
}, [pageConfig]);
|
|
2360
|
+
react.useEffect(() => {
|
|
2361
|
+
if (!pageConfig?.eventTracking?.length) return;
|
|
2362
|
+
const sdk = getSDK();
|
|
2363
|
+
if (!sdk.isInitialized()) return;
|
|
2364
|
+
sdk.setupEventTracking(pageConfig.eventTracking);
|
|
2365
|
+
const t1 = window.setTimeout(() => {
|
|
2366
|
+
sdk.setupComponentViewTracking();
|
|
2367
|
+
refreshEventTracking();
|
|
2368
|
+
}, 200);
|
|
2369
|
+
const t2 = window.setTimeout(() => {
|
|
2370
|
+
sdk.setupComponentViewTracking();
|
|
2371
|
+
refreshEventTracking();
|
|
2372
|
+
}, 1e3);
|
|
2373
|
+
return () => {
|
|
2374
|
+
window.clearTimeout(t1);
|
|
2375
|
+
window.clearTimeout(t2);
|
|
2376
|
+
};
|
|
2377
|
+
}, [pageConfig?.id]);
|
|
2378
|
+
react.useEffect(() => {
|
|
2379
|
+
if (!pageConfig) return;
|
|
2380
|
+
const t = window.setTimeout(() => {
|
|
2381
|
+
getSDK().setupComponentViewTracking();
|
|
2382
|
+
refreshEventTracking();
|
|
2383
|
+
}, 100);
|
|
2384
|
+
return () => window.clearTimeout(t);
|
|
2385
|
+
}, [variantCache, pageConfig?.id]);
|
|
2151
2386
|
react.useEffect(() => {
|
|
2152
2387
|
const isVisualEditorMode = () => {
|
|
2153
2388
|
if (typeof window === "undefined") return false;
|
|
@@ -2353,6 +2588,31 @@ function AmplifyRenderer({
|
|
|
2353
2588
|
pageConfig.layout?.header !== false;
|
|
2354
2589
|
pageConfig.layout?.footer !== false;
|
|
2355
2590
|
const renderNode = (node) => {
|
|
2591
|
+
const zoneIdFromProps = node.componentId === "AmplifyZone" ? String(node.props?.zoneId || "") : "";
|
|
2592
|
+
if (node.componentId === "AmplifyZone") {
|
|
2593
|
+
const contentSlot = node.slots?.find((s) => s.slotId === "content") || node.slots?.[0];
|
|
2594
|
+
const children = Array.isArray(contentSlot?.children) ? contentSlot.children : [];
|
|
2595
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2596
|
+
"div",
|
|
2597
|
+
{
|
|
2598
|
+
"data-node-id": node.id,
|
|
2599
|
+
"data-amplifyup-node": "",
|
|
2600
|
+
"data-amplifyup-component": "AmplifyZone",
|
|
2601
|
+
"data-amplifyup-zone": zoneIdFromProps || void 0,
|
|
2602
|
+
"data-zone-id": zoneIdFromProps || void 0,
|
|
2603
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2604
|
+
"div",
|
|
2605
|
+
{
|
|
2606
|
+
"data-slot-id": "content",
|
|
2607
|
+
"data-amplifyup-slot": "content",
|
|
2608
|
+
"data-parent-node-id": node.id,
|
|
2609
|
+
"data-parent-component-id": "AmplifyZone",
|
|
2610
|
+
children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: renderNode(child) }, child.id))
|
|
2611
|
+
}
|
|
2612
|
+
)
|
|
2613
|
+
}
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2356
2616
|
let slotChildren = {};
|
|
2357
2617
|
console.log(`[AmplifyRenderer] Rendering node ${node.id} (${node.componentId})`, {
|
|
2358
2618
|
hasSlots: !!(node.slots && node.slots.length > 0),
|