@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 CHANGED
@@ -1,36 +1,12 @@
1
1
  # @akinon/pz-theme
2
2
 
3
- ## 2.0.70-rc.0
4
-
5
- ### Patch Changes
6
-
7
- - Updated dependencies [0cf9ea239]
8
- - Updated dependencies [324f97d55]
9
- - Updated dependencies [51ea06888]
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-rc.0",
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-rc.0",
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-rc.0",
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-rc.0",
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
- if (tag === 'a' && href) {
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
- return (
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
- </Tag>
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,