@akinon/pz-theme 2.0.70-rc.0 → 2.0.70
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/CHANGELOG.md +7 -31
- package/package.json +4 -4
- package/src/blocks/group-block.tsx +26 -7
- package/src/theme-placeholder-wrapper.tsx +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,36 +1,12 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.70
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- Updated dependencies
|
|
11
|
-
- Updated dependencies [2fea4143]
|
|
12
|
-
- Updated dependencies [b55acb768]
|
|
13
|
-
- Updated dependencies [760258c1c]
|
|
14
|
-
- Updated dependencies [143be2b9d]
|
|
15
|
-
- Updated dependencies [7889b08fe]
|
|
16
|
-
- Updated dependencies [9f8cd3bc5]
|
|
17
|
-
- Updated dependencies [bfafa3f49]
|
|
18
|
-
- Updated dependencies [57d7eb305]
|
|
19
|
-
- Updated dependencies [d99a6a7d5]
|
|
20
|
-
- Updated dependencies [9db81a714]
|
|
21
|
-
- Updated dependencies [591e345e1]
|
|
22
|
-
- Updated dependencies [4de5303c5]
|
|
23
|
-
- Updated dependencies [95b139dc1]
|
|
24
|
-
- Updated dependencies [1d00f2d06]
|
|
25
|
-
- Updated dependencies [4ac7b2a1e]
|
|
26
|
-
- Updated dependencies [e9598c71]
|
|
27
|
-
- Updated dependencies [4998a9631]
|
|
28
|
-
- Updated dependencies [804d2bd6]
|
|
29
|
-
- Updated dependencies [3909d3224]
|
|
30
|
-
- Updated dependencies [6a3d8a63]
|
|
31
|
-
- Updated dependencies [e18836b20]
|
|
32
|
-
- @akinon/next@2.0.70-rc.0
|
|
33
|
-
- @akinon/theme-contract@2.0.70-rc.0
|
|
3
|
+
## 2.0.70
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 93a05ef: ZERO-4856: Enhance GroupBlock to use Next.js Link for internal navigation and add bfcache reload listener in ThemePlaceholderWrapper
|
|
8
|
+
- @akinon/next@2.0.70
|
|
9
|
+
- @akinon/theme-contract@2.0.70
|
|
34
10
|
|
|
35
11
|
## 2.0.69
|
|
36
12
|
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/pz-theme",
|
|
3
3
|
"description": "Theme package for Project Zero Next — ThemePlaceholder system and theme editor infrastructure",
|
|
4
|
-
"version": "2.0.70
|
|
4
|
+
"version": "2.0.70",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "jest"
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@akinon/next": "2.0.70
|
|
11
|
+
"@akinon/next": "2.0.70",
|
|
12
12
|
"react": "^18.0.0 || ^19.0.0",
|
|
13
13
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@akinon/theme-contract": "2.0.70
|
|
16
|
+
"@akinon/theme-contract": "2.0.70",
|
|
17
17
|
"clsx": "2.1.1",
|
|
18
18
|
"lottie-web": "^5.13.0",
|
|
19
19
|
"tailwind-merge": "^2.5.4",
|
|
20
20
|
"zod": "4.4.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@akinon/next": "2.0.70
|
|
23
|
+
"@akinon/next": "2.0.70",
|
|
24
24
|
"@testing-library/jest-dom": "5.16.4",
|
|
25
25
|
"@testing-library/react": "16.3.2",
|
|
26
26
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import NextLink from 'next/link';
|
|
2
3
|
import { getResponsiveValue } from '../utils';
|
|
3
4
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
4
5
|
import ThemeBlock from '../theme-block';
|
|
5
6
|
|
|
6
7
|
import { postToEditor } from '../editor-bridge';
|
|
7
8
|
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Composed anchors to the storefront's own routes navigate client-side. A
|
|
12
|
+
* plain <a> makes every product-card click a full page load, and coming BACK
|
|
13
|
+
* from it re-enters through the browser's history cache, where client-fetched
|
|
14
|
+
* composition data (wishlist context, carousel items) does not reliably
|
|
15
|
+
* survive. Router navigation keeps the app state alive in both directions.
|
|
16
|
+
* External hrefs keep the plain anchor — the router cannot take those anyway.
|
|
17
|
+
*/
|
|
18
|
+
const isInternalHref = (href: unknown): href is string =>
|
|
19
|
+
typeof href === 'string' && href.startsWith('/') && !href.startsWith('//');
|
|
8
20
|
const GroupBlock = ({
|
|
9
21
|
block,
|
|
10
22
|
placeholderId,
|
|
@@ -24,7 +36,8 @@ const GroupBlock = ({
|
|
|
24
36
|
const tagProps: Record<string, unknown> = {
|
|
25
37
|
className: 'contents'
|
|
26
38
|
};
|
|
27
|
-
|
|
39
|
+
const useRouterLink = tag === 'a' && !isDesigner && isInternalHref(href);
|
|
40
|
+
if (tag === 'a' && href && !useRouterLink) {
|
|
28
41
|
tagProps.href = href;
|
|
29
42
|
}
|
|
30
43
|
if (tag === 'form') {
|
|
@@ -55,9 +68,7 @@ const GroupBlock = ({
|
|
|
55
68
|
);
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
<Tag {...tagProps}>
|
|
60
|
-
{block.blocks
|
|
71
|
+
const renderedChildren = block.blocks
|
|
61
72
|
.filter((childBlock) => (isDesigner ? true : !childBlock.hidden))
|
|
62
73
|
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
63
74
|
.map((childBlock, index) => {
|
|
@@ -109,9 +120,17 @@ const GroupBlock = ({
|
|
|
109
120
|
onRename={handleRename}
|
|
110
121
|
/>
|
|
111
122
|
);
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
)
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (useRouterLink) {
|
|
126
|
+
return (
|
|
127
|
+
<NextLink href={href as string} prefetch={false} className="contents">
|
|
128
|
+
{renderedChildren}
|
|
129
|
+
</NextLink>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return <Tag {...tagProps}>{renderedChildren}</Tag>;
|
|
115
134
|
};
|
|
116
135
|
|
|
117
136
|
export default GroupBlock;
|
|
@@ -24,6 +24,9 @@ import { parseEditorMessage, postToEditor } from './editor-bridge';
|
|
|
24
24
|
import { useBrowseMode } from './browse-mode';
|
|
25
25
|
import { neutralizeStyleTagBreakout } from './utils/css-safety';
|
|
26
26
|
|
|
27
|
+
// One pageshow listener per page, not per placeholder — see the effect below.
|
|
28
|
+
let bfcacheReloadListenerArmed = false;
|
|
29
|
+
|
|
27
30
|
// Helper function to inject theme colors as CSS custom properties
|
|
28
31
|
const injectThemeColors = (settings: Record<string, unknown>) => {
|
|
29
32
|
if (!settings) return;
|
|
@@ -339,6 +342,29 @@ export default function ThemePlaceholderWrapper({
|
|
|
339
342
|
// visibility rules apply) without disturbing anything above.
|
|
340
343
|
const isBrowseMode = useBrowseMode();
|
|
341
344
|
const isEditing = isDesigner && !isBrowseMode;
|
|
345
|
+
|
|
346
|
+
// A bfcache restore resumes the frozen page instead of loading it: the
|
|
347
|
+
// client-fetched composition data (wishlist page context, carousel items)
|
|
348
|
+
// does not reliably survive the freeze, and the page comes back with its
|
|
349
|
+
// data-driven sections blank until a manual refresh. Reloading once on a
|
|
350
|
+
// persisted pageshow trades the bfcache speedup for a page that is correct.
|
|
351
|
+
// Guarded at module level — a page hosts several placeholders and one
|
|
352
|
+
// listener is enough.
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
if (isDesigner) return;
|
|
355
|
+
if (bfcacheReloadListenerArmed) return;
|
|
356
|
+
bfcacheReloadListenerArmed = true;
|
|
357
|
+
|
|
358
|
+
const onPageShow = (event: PageTransitionEvent) => {
|
|
359
|
+
if (event.persisted) window.location.reload();
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
window.addEventListener('pageshow', onPageShow);
|
|
363
|
+
return () => {
|
|
364
|
+
window.removeEventListener('pageshow', onPageShow);
|
|
365
|
+
bfcacheReloadListenerArmed = false;
|
|
366
|
+
};
|
|
367
|
+
}, [isDesigner]);
|
|
342
368
|
const [dataSources, setDataSources] = useState<any[]>(initialDataSources);
|
|
343
369
|
const [themeSettings, setThemeSettings] = useState<Record<
|
|
344
370
|
string,
|