@akinon/pz-theme 2.0.97-rc.0 → 2.0.97
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,38 +1,15 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.97
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- Updated dependencies [b55acb768]
|
|
14
|
-
- Updated dependencies [760258c1c]
|
|
15
|
-
- Updated dependencies [143be2b9d]
|
|
16
|
-
- Updated dependencies [7889b08fe]
|
|
17
|
-
- Updated dependencies [9f8cd3bc5]
|
|
18
|
-
- Updated dependencies [bfafa3f49]
|
|
19
|
-
- Updated dependencies [57d7eb305]
|
|
20
|
-
- Updated dependencies [d99a6a7d5]
|
|
21
|
-
- Updated dependencies [9db81a714]
|
|
22
|
-
- Updated dependencies [591e345e1]
|
|
23
|
-
- Updated dependencies [4de5303c5]
|
|
24
|
-
- Updated dependencies [95b139dc1]
|
|
25
|
-
- Updated dependencies [1d00f2d06]
|
|
26
|
-
- Updated dependencies [4ac7b2a1e]
|
|
27
|
-
- Updated dependencies [e9598c71d]
|
|
28
|
-
- Updated dependencies [4998a9631]
|
|
29
|
-
- Updated dependencies [804d2bd6c]
|
|
30
|
-
- Updated dependencies [3909d3224]
|
|
31
|
-
- Updated dependencies [6a3d8a631]
|
|
32
|
-
- Updated dependencies [e18836b20]
|
|
33
|
-
- Updated dependencies [b1111d7b]
|
|
34
|
-
- @akinon/next@2.0.97-rc.0
|
|
35
|
-
- @akinon/theme-contract@2.0.97-rc.0
|
|
3
|
+
## 2.0.97
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d4fe7b15: ZERO-5013: Hide the empty Group block placeholder from shoppers
|
|
8
|
+
|
|
9
|
+
An empty `group` rendered the literal string "Empty group block" on the live storefront with no designer guard. Every shipped section layout template seeds its columns with `blocks: []`, so a half-filled layout leaked grey debug text to real visitors. The chip now only draws on the canvas, matching `ContainerBlock`; the storefront keeps the group's own element (`display: contents`) so an `<a>` or `<form>` group survives being empty.
|
|
10
|
+
|
|
11
|
+
- @akinon/next@2.0.97
|
|
12
|
+
- @akinon/theme-contract@2.0.97
|
|
36
13
|
|
|
37
14
|
## 2.0.96
|
|
38
15
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
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.97
|
|
4
|
+
"version": "2.0.97",
|
|
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.97
|
|
11
|
+
"@akinon/next": "2.0.97",
|
|
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.97
|
|
16
|
+
"@akinon/theme-contract": "2.0.97",
|
|
17
17
|
"clsx": "2.1.1",
|
|
18
18
|
"lottie-web": "^5.13.0",
|
|
19
19
|
"react-multi-carousel": "2.8.4",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"zod": "4.4.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@akinon/next": "2.0.97
|
|
24
|
+
"@akinon/next": "2.0.97",
|
|
25
25
|
"@testing-library/jest-dom": "5.16.4",
|
|
26
26
|
"@testing-library/react": "16.3.2",
|
|
27
27
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -87,21 +87,60 @@ describe('GroupBlock — ordering', () => {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
describe('GroupBlock — empty states', () => {
|
|
90
|
-
it('
|
|
90
|
+
it('shows the designer placeholder when there are no children', () => {
|
|
91
91
|
const block = { ...props().block, blocks: [] };
|
|
92
|
-
const { container } = render(
|
|
93
|
-
|
|
92
|
+
const { container } = render(
|
|
93
|
+
<GroupBlock {...props({ block, isDesigner: true })} />
|
|
94
|
+
);
|
|
95
|
+
expect(container.textContent).toContain('Group (drop blocks here)');
|
|
96
|
+
expect(
|
|
97
|
+
container.querySelector('[data-group-placeholder]')
|
|
98
|
+
).toBeInTheDocument();
|
|
94
99
|
expect(markers(container)).toHaveLength(0);
|
|
95
100
|
});
|
|
96
101
|
|
|
102
|
+
/*
|
|
103
|
+
* Every shipped layout template seeds its columns with `blocks: []`, so a
|
|
104
|
+
* half-filled layout section put this branch straight in front of real
|
|
105
|
+
* shoppers. Nothing about it may be readable.
|
|
106
|
+
*/
|
|
107
|
+
it('shows a shopper no debug text at all when there are no children', () => {
|
|
108
|
+
const block = { ...props().block, blocks: [] };
|
|
109
|
+
const { container } = render(
|
|
110
|
+
<GroupBlock {...props({ block, isDesigner: false })} />
|
|
111
|
+
);
|
|
112
|
+
expect(container.textContent).toBe('');
|
|
113
|
+
expect(
|
|
114
|
+
container.querySelector('[data-theme-block-placeholder]')
|
|
115
|
+
).toBeNull();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it.each([
|
|
119
|
+
['a', { tag: 'a', href: 'https://kargotakip.example.com' }, 'A'],
|
|
120
|
+
['form', { tag: 'form' }, 'FORM']
|
|
121
|
+
])(
|
|
122
|
+
'keeps the group element on the storefront so an empty <%s> survives',
|
|
123
|
+
(_name, properties, expectedTag) => {
|
|
124
|
+
const block = { ...props().block, blocks: [], properties };
|
|
125
|
+
const { container } = render(
|
|
126
|
+
<GroupBlock {...props({ block, isDesigner: false })} />
|
|
127
|
+
);
|
|
128
|
+
const wrapper = container.querySelector('.contents') as HTMLElement;
|
|
129
|
+
expect(wrapper.tagName).toBe(expectedTag);
|
|
130
|
+
expect(wrapper).toBeEmptyDOMElement();
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
97
134
|
it('renders an empty tag (no placeholder text) for visual-utility groups', () => {
|
|
98
135
|
const block = {
|
|
99
136
|
...props().block,
|
|
100
137
|
blocks: [],
|
|
101
138
|
properties: { shippingRole: 'progress-fill' }
|
|
102
139
|
};
|
|
103
|
-
const { container } = render(
|
|
104
|
-
|
|
140
|
+
const { container } = render(
|
|
141
|
+
<GroupBlock {...props({ block, isDesigner: true })} />
|
|
142
|
+
);
|
|
143
|
+
expect(container.textContent).toBe('');
|
|
105
144
|
expect(container.querySelector('.contents')).toBeInTheDocument();
|
|
106
145
|
});
|
|
107
146
|
});
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
readItemsCurrency
|
|
8
8
|
} from '../utils/analytics';
|
|
9
9
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
10
|
-
import { useThemeItemScope } from './product-block-utils';
|
|
10
|
+
import { DesignerPlaceholder, useThemeItemScope } from './product-block-utils';
|
|
11
11
|
import { renderComposedChildren } from './render-composed-children';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -83,8 +83,28 @@ const GroupBlock = ({
|
|
|
83
83
|
return <Tag {...tagProps} />;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/*
|
|
87
|
+
* Empty is a legitimate PUBLISHED state, not a mistake to shout about:
|
|
88
|
+
* every shipped layout template seeds its columns with `blocks: []`, so a
|
|
89
|
+
* half-filled layout used to leak grey debug text to real shoppers. The
|
|
90
|
+
* chip belongs behind the designer guard, the way ContainerBlock's does.
|
|
91
|
+
*
|
|
92
|
+
* The live branch still renders the tag rather than returning null. The
|
|
93
|
+
* tag is `display: contents`, so an empty one draws nothing either way,
|
|
94
|
+
* but it is the group's only element: `tag` can make it an `<a>` or a
|
|
95
|
+
* `<form>`, and a brand's CSS or script written against that element
|
|
96
|
+
* would lose it. Keeping it makes the empty case a true no-op instead of
|
|
97
|
+
* a structural change, and matches the visual-utility branch above.
|
|
98
|
+
*/
|
|
86
99
|
return (
|
|
87
|
-
<
|
|
100
|
+
<Tag {...tagProps}>
|
|
101
|
+
{isDesigner ? (
|
|
102
|
+
<DesignerPlaceholder
|
|
103
|
+
label="Group (drop blocks here)"
|
|
104
|
+
attribute="data-group-placeholder"
|
|
105
|
+
/>
|
|
106
|
+
) : null}
|
|
107
|
+
</Tag>
|
|
88
108
|
);
|
|
89
109
|
}
|
|
90
110
|
|
|
@@ -103,10 +103,12 @@ const releaseSlot = (
|
|
|
103
103
|
*
|
|
104
104
|
* EMPTY BEHAVES DIFFERENTLY PER SIDE. The designer draws a dashed band so the
|
|
105
105
|
* hole is visible and droppable; the live storefront renders nothing at all.
|
|
106
|
-
* That distinction is the whole point of the split
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
106
|
+
* That distinction is the whole point of the split, and it is the rule across
|
|
107
|
+
* the package rather than a local habit: the empty branches of `GroupBlock`
|
|
108
|
+
* and `ContainerBlock` (blocks/) put their chip behind the same guard, after
|
|
109
|
+
* `GroupBlock` was found shipping a literal "Empty group block" string to
|
|
110
|
+
* shoppers (ZERO-5013). A placeholder that is not guarded is a live defect,
|
|
111
|
+
* not a rough edge.
|
|
110
112
|
*/
|
|
111
113
|
export function ThemeSlot({ label, name }: ThemeSlotProps) {
|
|
112
114
|
const context = useCustomBlockContext();
|