payaza-storefront-layouts 1.0.11 → 1.0.12
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShadowDOMWrapper.d.ts","sourceRoot":"","sources":["../../src/preview/ShadowDOMWrapper.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrD,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"ShadowDOMWrapper.d.ts","sourceRoot":"","sources":["../../src/preview/ShadowDOMWrapper.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrD,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,qBAAqB,2CA2M/G"}
|
|
@@ -18,6 +18,8 @@ export function ShadowDOMWrapper({ children, className, onReady, onLinkClick, st
|
|
|
18
18
|
const reactRootRef = useRef(null);
|
|
19
19
|
const containerRef = useRef(null);
|
|
20
20
|
const childrenRef = useRef(children);
|
|
21
|
+
const isUnmountingRef = useRef(false);
|
|
22
|
+
const isMountedRef = useRef(false);
|
|
21
23
|
// Keep children ref updated
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
childrenRef.current = children;
|
|
@@ -25,13 +27,16 @@ export function ShadowDOMWrapper({ children, className, onReady, onLinkClick, st
|
|
|
25
27
|
useEffect(() => {
|
|
26
28
|
if (!shadowHostRef.current)
|
|
27
29
|
return;
|
|
30
|
+
// Reset unmounting flag when mounting
|
|
31
|
+
isUnmountingRef.current = false;
|
|
32
|
+
isMountedRef.current = true;
|
|
28
33
|
// Check if shadow root already exists
|
|
29
34
|
const existingShadowRoot = shadowHostRef.current.shadowRoot;
|
|
30
35
|
if (existingShadowRoot) {
|
|
31
36
|
shadowRootRef.current = existingShadowRoot;
|
|
32
37
|
// Update content if shadow root already exists
|
|
33
38
|
const container = existingShadowRoot.getElementById('shadow-preview-container');
|
|
34
|
-
if (container && reactRootRef.current) {
|
|
39
|
+
if (container && reactRootRef.current && !isUnmountingRef.current) {
|
|
35
40
|
reactRootRef.current.render(childrenRef.current);
|
|
36
41
|
}
|
|
37
42
|
onReady?.();
|
|
@@ -68,58 +73,9 @@ export function ShadowDOMWrapper({ children, className, onReady, onLinkClick, st
|
|
|
68
73
|
// Create React root and render children
|
|
69
74
|
const root = createRoot(container);
|
|
70
75
|
reactRootRef.current = root;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const handleClick = (e) => {
|
|
75
|
-
const target = e.target;
|
|
76
|
-
const link = target.closest('a[href]');
|
|
77
|
-
if (!link || !link.href)
|
|
78
|
-
return;
|
|
79
|
-
try {
|
|
80
|
-
const url = new URL(link.href, window.location.origin);
|
|
81
|
-
const pathname = url.pathname;
|
|
82
|
-
// Only intercept internal links
|
|
83
|
-
if (url.origin !== window.location.origin) {
|
|
84
|
-
return; // External link, allow default behavior
|
|
85
|
-
}
|
|
86
|
-
// Extract route from href (remove store slug prefix if present)
|
|
87
|
-
let route = pathname;
|
|
88
|
-
// Check if pathname starts with store slug (e.g., /modern-eats/contact)
|
|
89
|
-
if (storeSlug && pathname.startsWith(`/${storeSlug}`)) {
|
|
90
|
-
// Remove the store slug prefix: /modern-eats/contact -> /contact
|
|
91
|
-
route = pathname.slice(storeSlug.length + 1);
|
|
92
|
-
// If route is empty after removing slug, it's the homepage
|
|
93
|
-
if (!route || route === '') {
|
|
94
|
-
route = '/';
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (pathname === '/' || pathname === '') {
|
|
98
|
-
// Homepage link
|
|
99
|
-
route = '/';
|
|
100
|
-
}
|
|
101
|
-
// Normalize route (ensure it starts with /)
|
|
102
|
-
if (route && !route.startsWith('/')) {
|
|
103
|
-
route = `/${route}`;
|
|
104
|
-
}
|
|
105
|
-
// Ensure route is not empty
|
|
106
|
-
if (!route) {
|
|
107
|
-
route = '/';
|
|
108
|
-
}
|
|
109
|
-
// Note: We don't preserve query string and hash here because
|
|
110
|
-
// the route is stored as a query param. Query strings and hash
|
|
111
|
-
// should be handled separately if needed.
|
|
112
|
-
// Prevent default navigation and call handler
|
|
113
|
-
e.preventDefault();
|
|
114
|
-
e.stopPropagation();
|
|
115
|
-
onLinkClick(route);
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
// If URL parsing fails, allow default behavior
|
|
119
|
-
console.warn('[ShadowDOMWrapper] Failed to parse link URL:', err, link.href);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
// Handler will be set up in separate useEffect to handle prop changes
|
|
76
|
+
// Only render if not unmounting
|
|
77
|
+
if (!isUnmountingRef.current) {
|
|
78
|
+
root.render(childrenRef.current);
|
|
123
79
|
}
|
|
124
80
|
onReady?.();
|
|
125
81
|
}
|
|
@@ -127,22 +83,42 @@ export function ShadowDOMWrapper({ children, className, onReady, onLinkClick, st
|
|
|
127
83
|
console.error('[ShadowDOMWrapper] Failed to create shadow root:', err);
|
|
128
84
|
}
|
|
129
85
|
return () => {
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
86
|
+
// Mark as unmounting to prevent concurrent renders
|
|
87
|
+
isUnmountingRef.current = true;
|
|
88
|
+
isMountedRef.current = false;
|
|
89
|
+
// Defer unmounting to avoid race condition with React's rendering cycle
|
|
90
|
+
// Use setTimeout to ensure React finishes its current render before unmounting
|
|
91
|
+
const rootToUnmount = reactRootRef.current;
|
|
92
|
+
reactRootRef.current = null;
|
|
93
|
+
if (rootToUnmount) {
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
try {
|
|
96
|
+
rootToUnmount.unmount();
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
// Ignore errors during unmount - root may already be unmounted
|
|
100
|
+
console.warn('[ShadowDOMWrapper] Unmount warning (safe to ignore):', e);
|
|
101
|
+
}
|
|
102
|
+
}, 0);
|
|
139
103
|
}
|
|
140
104
|
};
|
|
141
105
|
}, [onReady]);
|
|
142
106
|
// Update content when children change
|
|
143
107
|
useEffect(() => {
|
|
108
|
+
// Guard: Don't render if unmounting or not mounted
|
|
109
|
+
if (isUnmountingRef.current || !isMountedRef.current) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
144
112
|
if (reactRootRef.current && containerRef.current) {
|
|
145
|
-
|
|
113
|
+
try {
|
|
114
|
+
reactRootRef.current.render(childrenRef.current);
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
// Ignore render errors if we're unmounting
|
|
118
|
+
if (!isUnmountingRef.current) {
|
|
119
|
+
console.warn('[ShadowDOMWrapper] Render error:', e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
146
122
|
}
|
|
147
123
|
}, [children]);
|
|
148
124
|
// Set up link click handler when shadow root and props are ready
|