payaza-storefront-layouts 1.0.11 → 1.0.13
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,2CAgO/G"}
|
|
@@ -18,20 +18,33 @@ 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;
|
|
24
26
|
}, [children]);
|
|
27
|
+
// Main effect: Create shadow root and React root on mount
|
|
25
28
|
useEffect(() => {
|
|
26
29
|
if (!shadowHostRef.current)
|
|
27
30
|
return;
|
|
31
|
+
// Reset unmounting flag when mounting
|
|
32
|
+
isUnmountingRef.current = false;
|
|
33
|
+
isMountedRef.current = true;
|
|
28
34
|
// Check if shadow root already exists
|
|
29
35
|
const existingShadowRoot = shadowHostRef.current.shadowRoot;
|
|
30
36
|
if (existingShadowRoot) {
|
|
31
37
|
shadowRootRef.current = existingShadowRoot;
|
|
32
|
-
// Update content if shadow root already exists
|
|
33
38
|
const container = existingShadowRoot.getElementById('shadow-preview-container');
|
|
34
|
-
|
|
39
|
+
containerRef.current = container;
|
|
40
|
+
// If React root doesn't exist, create it
|
|
41
|
+
if (!reactRootRef.current && container) {
|
|
42
|
+
const root = createRoot(container);
|
|
43
|
+
reactRootRef.current = root;
|
|
44
|
+
root.render(childrenRef.current);
|
|
45
|
+
}
|
|
46
|
+
else if (reactRootRef.current && container && !isUnmountingRef.current) {
|
|
47
|
+
// Update content if root exists
|
|
35
48
|
reactRootRef.current.render(childrenRef.current);
|
|
36
49
|
}
|
|
37
50
|
onReady?.();
|
|
@@ -68,81 +81,67 @@ export function ShadowDOMWrapper({ children, className, onReady, onLinkClick, st
|
|
|
68
81
|
// Create React root and render children
|
|
69
82
|
const root = createRoot(container);
|
|
70
83
|
reactRootRef.current = root;
|
|
84
|
+
// Always render on initial mount
|
|
71
85
|
root.render(childrenRef.current);
|
|
72
|
-
// Set up link click interception inside Shadow DOM
|
|
73
|
-
if (onLinkClick) {
|
|
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
|
|
123
|
-
}
|
|
124
86
|
onReady?.();
|
|
125
87
|
}
|
|
126
88
|
catch (err) {
|
|
127
89
|
console.error('[ShadowDOMWrapper] Failed to create shadow root:', err);
|
|
128
90
|
}
|
|
129
91
|
return () => {
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
92
|
+
// Mark as unmounting to prevent concurrent renders
|
|
93
|
+
isUnmountingRef.current = true;
|
|
94
|
+
isMountedRef.current = false;
|
|
95
|
+
// Defer unmounting to avoid race condition with React's rendering cycle
|
|
96
|
+
// Use setTimeout to ensure React finishes its current render before unmounting
|
|
97
|
+
const rootToUnmount = reactRootRef.current;
|
|
98
|
+
reactRootRef.current = null;
|
|
99
|
+
if (rootToUnmount) {
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
try {
|
|
102
|
+
rootToUnmount.unmount();
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
// Ignore errors during unmount - root may already be unmounted
|
|
106
|
+
console.warn('[ShadowDOMWrapper] Unmount warning (safe to ignore):', e);
|
|
107
|
+
}
|
|
108
|
+
}, 0);
|
|
139
109
|
}
|
|
140
110
|
};
|
|
141
|
-
|
|
111
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
|
+
}, []); // Run only on mount - shadow root should persist across re-renders
|
|
142
113
|
// Update content when children change
|
|
143
114
|
useEffect(() => {
|
|
115
|
+
// Guard: Don't render if unmounting
|
|
116
|
+
if (isUnmountingRef.current) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Only render if React root and container exist
|
|
144
120
|
if (reactRootRef.current && containerRef.current) {
|
|
145
|
-
|
|
121
|
+
try {
|
|
122
|
+
reactRootRef.current.render(childrenRef.current);
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
// Ignore render errors if we're unmounting
|
|
126
|
+
if (!isUnmountingRef.current) {
|
|
127
|
+
console.warn('[ShadowDOMWrapper] Render error:', e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (shadowRootRef.current && !reactRootRef.current) {
|
|
132
|
+
// If shadow root exists but React root doesn't, try to recreate it
|
|
133
|
+
const container = shadowRootRef.current.getElementById('shadow-preview-container');
|
|
134
|
+
if (container) {
|
|
135
|
+
try {
|
|
136
|
+
const root = createRoot(container);
|
|
137
|
+
reactRootRef.current = root;
|
|
138
|
+
containerRef.current = container;
|
|
139
|
+
root.render(childrenRef.current);
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
console.warn('[ShadowDOMWrapper] Failed to recreate React root:', e);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
146
145
|
}
|
|
147
146
|
}, [children]);
|
|
148
147
|
// Set up link click handler when shadow root and props are ready
|