@akinon/pz-theme 2.0.35-rc.0 → 2.0.35
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 +12 -28
- package/package.json +4 -3
- package/src/__tests__/theme-contract.test.ts +130 -0
- package/src/blocks/__tests__/text-block.test.tsx +8 -1
- package/src/blocks/__tests__/video-block.test.tsx +14 -7
- package/src/blocks/counter-block.tsx +44 -56
- package/src/blocks/group-block.tsx +23 -22
- package/src/blocks/hotspot-block.tsx +171 -80
- package/src/blocks/input-block.tsx +15 -17
- package/src/blocks/link-block.tsx +18 -21
- package/src/blocks/slider-block.tsx +15 -12
- package/src/components/with-designer-features.tsx +2 -0
- package/src/editor-bridge.ts +160 -0
- package/src/hooks/use-designer-features.tsx +30 -37
- package/src/placeholder-registry.ts +5 -7
- package/src/sections/__tests__/countdown-campaign-banner-section.test.tsx +8 -4
- package/src/sections/__tests__/coupon-banner-section.test.tsx +4 -2
- package/src/sections/before-after-section.tsx +189 -134
- package/src/sections/contact-form-section.tsx +185 -60
- package/src/sections/countdown-campaign-banner-section.tsx +73 -27
- package/src/sections/coupon-banner-section.tsx +152 -48
- package/src/sections/featured-product-spotlight-section.tsx +67 -66
- package/src/sections/find-in-store-section.tsx +37 -25
- package/src/sections/hover-showcase-section.tsx +221 -89
- package/src/sections/image-hotspot-section.tsx +208 -94
- package/src/sections/installment-options-section.tsx +268 -259
- package/src/sections/notification-banner-section.tsx +111 -25
- package/src/sections/order-tracking-lookup-section.tsx +272 -247
- package/src/sections/posts-slider-section.tsx +17 -16
- package/src/sections/pre-order-launch-banner-section.tsx +31 -50
- package/src/sections/section-wrapper.tsx +9 -10
- package/src/sections/shipping-threshold-progress-section.tsx +72 -29
- package/src/sections/stats-counter-section.tsx +68 -30
- package/src/sections/tabs-section.tsx +124 -147
- package/src/theme-placeholder-client.tsx +11 -14
- package/src/theme-placeholder-wrapper.tsx +42 -51
- package/src/theme-section.tsx +27 -34
- package/src/utils/__tests__/transform-styles.test.ts +97 -0
- package/src/utils/index.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.35
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
- Updated dependencies [
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- Updated dependencies [9f8cd3bc5]
|
|
16
|
-
- Updated dependencies [bfafa3f49]
|
|
17
|
-
- Updated dependencies [57d7eb30]
|
|
18
|
-
- Updated dependencies [d99a6a7d5]
|
|
19
|
-
- Updated dependencies [9db81a71]
|
|
20
|
-
- Updated dependencies [591e345e1]
|
|
21
|
-
- Updated dependencies [4de5303c5]
|
|
22
|
-
- Updated dependencies [95b139dc1]
|
|
23
|
-
- Updated dependencies [1d00f2d0]
|
|
24
|
-
- Updated dependencies [4ac7b2a1e]
|
|
25
|
-
- Updated dependencies [4998a9631]
|
|
26
|
-
- Updated dependencies [804d2bd6]
|
|
27
|
-
- Updated dependencies [3909d3224]
|
|
28
|
-
- Updated dependencies [6a3d8a63]
|
|
29
|
-
- Updated dependencies [e18836b20]
|
|
30
|
-
- @akinon/next@2.0.35-rc.0
|
|
3
|
+
## 2.0.35
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2f500a32: ZERO-4657: Render scale, rotate and translate style keys from the theme editor and skip them in inline styles to prevent double application
|
|
8
|
+
- 8dca03f2: ZERO-4663: introduce shared wire contract for theme editor and storefront
|
|
9
|
+
|
|
10
|
+
New `@akinon/theme-contract` package: shared wire types, versioned postMessage envelope (`protocolVersion`), runtime validation (`parseThemeMessage`) and origin helpers. `@akinon/pz-theme` now routes all designer postMessage traffic through an origin-guarded `editor-bridge` — inbound designer messages are validated against the editor-origin allowlist (`NEXT_PUBLIC_THEME_EDITOR_ORIGINS`, localhost auto-trusted outside production) and nothing is posted to `'*'` anymore.
|
|
11
|
+
|
|
12
|
+
- Updated dependencies [8dca03f2]
|
|
13
|
+
- @akinon/next@2.0.35
|
|
14
|
+
- @akinon/theme-contract@2.0.35
|
|
31
15
|
|
|
32
16
|
## 2.0.34
|
|
33
17
|
|
package/package.json
CHANGED
|
@@ -1,25 +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.35
|
|
4
|
+
"version": "2.0.35",
|
|
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.35
|
|
11
|
+
"@akinon/next": "2.0.35",
|
|
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.35",
|
|
16
17
|
"clsx": "2.1.1",
|
|
17
18
|
"lottie-web": "^5.13.0",
|
|
18
19
|
"tailwind-merge": "^2.5.4",
|
|
19
20
|
"zod": "4.4.1"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
|
-
"@akinon/next": "2.0.35
|
|
23
|
+
"@akinon/next": "2.0.35",
|
|
23
24
|
"@testing-library/jest-dom": "5.16.4",
|
|
24
25
|
"@testing-library/react": "16.3.2",
|
|
25
26
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEGACY_PROTOCOL_VERSION,
|
|
3
|
+
ParsedThemeMessageRejected,
|
|
4
|
+
THEME_CONTRACT_PROTOCOL_VERSION,
|
|
5
|
+
createOriginGuard,
|
|
6
|
+
isKnownThemeMessageType,
|
|
7
|
+
parseOriginList,
|
|
8
|
+
parseThemeMessage,
|
|
9
|
+
safeOrigin,
|
|
10
|
+
stampThemeMessage
|
|
11
|
+
} from '@akinon/theme-contract';
|
|
12
|
+
|
|
13
|
+
describe('theme-contract envelope', () => {
|
|
14
|
+
it('stamps outbound messages with the current protocol version, preserving legacy top-level fields', () => {
|
|
15
|
+
const stamped = stampThemeMessage({
|
|
16
|
+
type: 'ROUTE_CHANGE_COMPLETE',
|
|
17
|
+
url: '/en/tr/',
|
|
18
|
+
layoutSegment: 'pages'
|
|
19
|
+
});
|
|
20
|
+
expect(stamped).toEqual({
|
|
21
|
+
type: 'ROUTE_CHANGE_COMPLETE',
|
|
22
|
+
url: '/en/tr/',
|
|
23
|
+
layoutSegment: 'pages',
|
|
24
|
+
protocolVersion: THEME_CONTRACT_PROTOCOL_VERSION
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('round-trips a stamped message through parseThemeMessage', () => {
|
|
29
|
+
const parsed = parseThemeMessage(
|
|
30
|
+
stampThemeMessage({ type: 'UPDATE_THEME', data: { theme: {} } })
|
|
31
|
+
);
|
|
32
|
+
expect(parsed.ok).toBe(true);
|
|
33
|
+
if (parsed.ok) {
|
|
34
|
+
expect(parsed.message.type).toBe('UPDATE_THEME');
|
|
35
|
+
expect(parsed.remoteVersion).toBe(THEME_CONTRACT_PROTOCOL_VERSION);
|
|
36
|
+
expect(parsed.versionMismatch).toBe(false);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('accepts pre-contract messages (no protocolVersion) as the legacy version', () => {
|
|
41
|
+
const parsed = parseThemeMessage({ type: 'IFRAME_READY' });
|
|
42
|
+
expect(parsed.ok).toBe(true);
|
|
43
|
+
if (parsed.ok) {
|
|
44
|
+
expect(parsed.remoteVersion).toBe(LEGACY_PROTOCOL_VERSION);
|
|
45
|
+
expect(parsed.versionMismatch).toBe(false);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('flags a version mismatch but still returns the message', () => {
|
|
50
|
+
const parsed = parseThemeMessage({
|
|
51
|
+
type: 'UPDATE_THEME',
|
|
52
|
+
data: {},
|
|
53
|
+
protocolVersion: THEME_CONTRACT_PROTOCOL_VERSION + 1
|
|
54
|
+
});
|
|
55
|
+
expect(parsed.ok).toBe(true);
|
|
56
|
+
if (parsed.ok) {
|
|
57
|
+
expect(parsed.versionMismatch).toBe(true);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it.each([
|
|
62
|
+
[null, 'not-an-object'],
|
|
63
|
+
['LOAD_THEME', 'not-an-object'],
|
|
64
|
+
[['LOAD_THEME'], 'not-an-object'],
|
|
65
|
+
[{}, 'missing-type'],
|
|
66
|
+
[{ type: 42 }, 'missing-type'],
|
|
67
|
+
[{ type: 'WIDGET_COPY' }, 'unknown-type'],
|
|
68
|
+
[{ type: 'LOAD_THEME', data: 'nope' }, 'invalid-data']
|
|
69
|
+
])('rejects %j with reason %s', (raw, reason) => {
|
|
70
|
+
const parsed = parseThemeMessage(raw);
|
|
71
|
+
expect(parsed.ok).toBe(false);
|
|
72
|
+
// Cast instead of narrowing — this tsconfig compiles with strict off,
|
|
73
|
+
// where the boolean-discriminant union does not narrow.
|
|
74
|
+
expect((parsed as ParsedThemeMessageRejected).reason).toBe(reason);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('accepts the legacy boolean data used by SET_THEME_EDITOR_COOKIE', () => {
|
|
78
|
+
expect(
|
|
79
|
+
parseThemeMessage({ type: 'SET_THEME_EDITOR_COOKIE', data: true }).ok
|
|
80
|
+
).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('knows both directions of the protocol', () => {
|
|
84
|
+
expect(isKnownThemeMessageType('SCROLL_TO_SECTION')).toBe(true);
|
|
85
|
+
expect(isKnownThemeMessageType('REGISTER_NATIVE_WIDGETS')).toBe(true);
|
|
86
|
+
expect(isKnownThemeMessageType('WIDGET_MOVE')).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('theme-contract origin helpers', () => {
|
|
91
|
+
it('derives origins the same way on both sides', () => {
|
|
92
|
+
expect(safeOrigin('https://shop.example.com/en/page?x=1')).toBe(
|
|
93
|
+
'https://shop.example.com'
|
|
94
|
+
);
|
|
95
|
+
expect(safeOrigin('not a url')).toBeNull();
|
|
96
|
+
expect(safeOrigin('')).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('parses env-style origin lists', () => {
|
|
100
|
+
expect(
|
|
101
|
+
parseOriginList(
|
|
102
|
+
'https://editor.akinon.com, https://staging-editor.akinon.com/path'
|
|
103
|
+
)
|
|
104
|
+
).toEqual([
|
|
105
|
+
'https://editor.akinon.com',
|
|
106
|
+
'https://staging-editor.akinon.com'
|
|
107
|
+
]);
|
|
108
|
+
expect(parseOriginList(undefined)).toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('trusts only allowlisted origins by default', () => {
|
|
112
|
+
const guard = createOriginGuard({
|
|
113
|
+
allowedOrigins: ['https://editor.akinon.com']
|
|
114
|
+
});
|
|
115
|
+
expect(guard.isTrusted('https://editor.akinon.com')).toBe(true);
|
|
116
|
+
expect(guard.isTrusted('https://evil.example.com')).toBe(false);
|
|
117
|
+
expect(guard.isTrusted('http://localhost:5173')).toBe(false);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('additionally trusts localhost when allowLocalDev is on', () => {
|
|
121
|
+
const guard = createOriginGuard({
|
|
122
|
+
allowedOrigins: [],
|
|
123
|
+
allowLocalDev: true
|
|
124
|
+
});
|
|
125
|
+
expect(guard.isTrusted('http://localhost:5173')).toBe(true);
|
|
126
|
+
expect(guard.isTrusted('http://127.0.0.1:3000')).toBe(true);
|
|
127
|
+
expect(guard.isTrusted('https://evil.example.com')).toBe(false);
|
|
128
|
+
expect(guard.isTrusted('http://localhost.evil.com')).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -8,7 +8,14 @@ import TextBlock from '../text-block';
|
|
|
8
8
|
|
|
9
9
|
const renderBlock = (value: unknown, styles?: Record<string, unknown>) => {
|
|
10
10
|
const block: any = { id: 'b1', type: 'text', value, styles };
|
|
11
|
-
return render(
|
|
11
|
+
return render(
|
|
12
|
+
<TextBlock
|
|
13
|
+
block={block}
|
|
14
|
+
placeholderId="p1"
|
|
15
|
+
sectionId="s1"
|
|
16
|
+
isDesigner={false}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
12
19
|
};
|
|
13
20
|
|
|
14
21
|
describe('TextBlock value-shape resolution', () => {
|
|
@@ -3,7 +3,14 @@ import { render, screen } from '@testing-library/react';
|
|
|
3
3
|
import VideoBlock from '../video-block';
|
|
4
4
|
|
|
5
5
|
const renderBlock = (value: any, properties?: any) =>
|
|
6
|
-
render(
|
|
6
|
+
render(
|
|
7
|
+
<VideoBlock
|
|
8
|
+
block={{ value, properties } as any}
|
|
9
|
+
placeholderId="p1"
|
|
10
|
+
sectionId="s1"
|
|
11
|
+
isDesigner={false}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
7
14
|
|
|
8
15
|
describe('VideoBlock', () => {
|
|
9
16
|
describe('YouTube URLs -> iframe', () => {
|
|
@@ -115,9 +122,9 @@ describe('VideoBlock', () => {
|
|
|
115
122
|
'https://www.youtube.com/watch?v=abc123',
|
|
116
123
|
{ muted: true }
|
|
117
124
|
);
|
|
118
|
-
expect(
|
|
119
|
-
|
|
120
|
-
)
|
|
125
|
+
expect(container.querySelector('iframe')?.getAttribute('src')).toContain(
|
|
126
|
+
'mute=1'
|
|
127
|
+
);
|
|
121
128
|
});
|
|
122
129
|
|
|
123
130
|
it('appends controls=0 only when controls === false', () => {
|
|
@@ -125,9 +132,9 @@ describe('VideoBlock', () => {
|
|
|
125
132
|
'https://www.youtube.com/watch?v=abc123',
|
|
126
133
|
{ controls: false }
|
|
127
134
|
);
|
|
128
|
-
expect(
|
|
129
|
-
|
|
130
|
-
)
|
|
135
|
+
expect(container.querySelector('iframe')?.getAttribute('src')).toContain(
|
|
136
|
+
'controls=0'
|
|
137
|
+
);
|
|
131
138
|
});
|
|
132
139
|
|
|
133
140
|
it('does not append controls when controls is true', () => {
|
|
@@ -7,6 +7,8 @@ import { useThemeSettingsContext } from '../theme-settings-context';
|
|
|
7
7
|
import { getCSSStyles, getResponsiveValue } from '../utils';
|
|
8
8
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
9
9
|
|
|
10
|
+
import { postToEditor } from '../editor-bridge';
|
|
11
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
10
12
|
type CounterUnit = 'days' | 'hours' | 'minutes' | 'seconds';
|
|
11
13
|
|
|
12
14
|
type CounterValues = Record<CounterUnit, string>;
|
|
@@ -170,18 +172,15 @@ const CounterBlock = ({
|
|
|
170
172
|
if (onCompleteAction === 'hide_self') {
|
|
171
173
|
// In designer (iframe) mode: use editor's show/hide so the user can still select/manage it
|
|
172
174
|
if (isDesigner && window.parent && window.parent !== window) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
'*'
|
|
184
|
-
);
|
|
175
|
+
postToEditor({
|
|
176
|
+
type: 'SET_BLOCK_VISIBILITY',
|
|
177
|
+
data: {
|
|
178
|
+
placeholderId,
|
|
179
|
+
sectionId,
|
|
180
|
+
blockId: block.id,
|
|
181
|
+
hidden: true
|
|
182
|
+
}
|
|
183
|
+
});
|
|
185
184
|
return;
|
|
186
185
|
}
|
|
187
186
|
|
|
@@ -198,17 +197,14 @@ const CounterBlock = ({
|
|
|
198
197
|
if (onCompleteAction === 'hide_section') {
|
|
199
198
|
// In designer (iframe) mode: use editor's show/hide
|
|
200
199
|
if (isDesigner && window.parent && window.parent !== window) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
},
|
|
210
|
-
'*'
|
|
211
|
-
);
|
|
200
|
+
postToEditor({
|
|
201
|
+
type: 'SET_SECTION_VISIBILITY',
|
|
202
|
+
data: {
|
|
203
|
+
placeholderId,
|
|
204
|
+
sectionId,
|
|
205
|
+
hidden: true
|
|
206
|
+
}
|
|
207
|
+
});
|
|
212
208
|
return;
|
|
213
209
|
}
|
|
214
210
|
|
|
@@ -242,18 +238,15 @@ const CounterBlock = ({
|
|
|
242
238
|
if (didAutoShowRef.current) return;
|
|
243
239
|
didAutoShowRef.current = true;
|
|
244
240
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
},
|
|
255
|
-
'*'
|
|
256
|
-
);
|
|
241
|
+
postToEditor({
|
|
242
|
+
type: 'SET_BLOCK_VISIBILITY',
|
|
243
|
+
data: {
|
|
244
|
+
placeholderId,
|
|
245
|
+
sectionId,
|
|
246
|
+
blockId: block.id,
|
|
247
|
+
hidden: false
|
|
248
|
+
}
|
|
249
|
+
});
|
|
257
250
|
}, [
|
|
258
251
|
block.hidden,
|
|
259
252
|
block.id,
|
|
@@ -289,36 +282,31 @@ const CounterBlock = ({
|
|
|
289
282
|
return (
|
|
290
283
|
<div style={innerStyles}>
|
|
291
284
|
{renderedBlocks.map((childBlock) => {
|
|
292
|
-
const createActionHandler =
|
|
293
|
-
|
|
294
|
-
window.parent
|
|
295
|
-
{
|
|
285
|
+
const createActionHandler =
|
|
286
|
+
(actionType: PreviewToEditorMessageType) => () => {
|
|
287
|
+
if (window.parent) {
|
|
288
|
+
postToEditor({
|
|
296
289
|
type: actionType,
|
|
297
290
|
data: {
|
|
298
291
|
placeholderId,
|
|
299
292
|
sectionId,
|
|
300
293
|
blockId: childBlock.id
|
|
301
294
|
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
};
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
};
|
|
307
298
|
|
|
308
299
|
const handleRename = (newLabel: string) => {
|
|
309
300
|
if (window.parent) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
},
|
|
320
|
-
'*'
|
|
321
|
-
);
|
|
301
|
+
postToEditor({
|
|
302
|
+
type: 'RENAME_BLOCK',
|
|
303
|
+
data: {
|
|
304
|
+
placeholderId,
|
|
305
|
+
sectionId,
|
|
306
|
+
blockId: childBlock.id,
|
|
307
|
+
label: newLabel
|
|
308
|
+
}
|
|
309
|
+
});
|
|
322
310
|
}
|
|
323
311
|
};
|
|
324
312
|
|
|
@@ -3,6 +3,8 @@ import { getResponsiveValue } from '../utils';
|
|
|
3
3
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
4
4
|
import ThemeBlock from '../theme-block';
|
|
5
5
|
|
|
6
|
+
import { postToEditor } from '../editor-bridge';
|
|
7
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
6
8
|
const GroupBlock = ({
|
|
7
9
|
block,
|
|
8
10
|
placeholderId,
|
|
@@ -11,7 +13,11 @@ const GroupBlock = ({
|
|
|
11
13
|
selectedBlockId,
|
|
12
14
|
currentBreakpoint = 'desktop'
|
|
13
15
|
}: BlockRendererProps) => {
|
|
14
|
-
const tag = getResponsiveValue(
|
|
16
|
+
const tag = getResponsiveValue(
|
|
17
|
+
block.properties?.tag,
|
|
18
|
+
currentBreakpoint,
|
|
19
|
+
'div'
|
|
20
|
+
);
|
|
15
21
|
const Tag = tag as keyof React.JSX.IntrinsicElements;
|
|
16
22
|
const href = tag === 'a' ? block.properties?.href : undefined;
|
|
17
23
|
|
|
@@ -55,36 +61,31 @@ const GroupBlock = ({
|
|
|
55
61
|
.filter((childBlock) => (isDesigner ? true : !childBlock.hidden))
|
|
56
62
|
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
57
63
|
.map((childBlock, index) => {
|
|
58
|
-
const createActionHandler =
|
|
59
|
-
|
|
60
|
-
window.parent
|
|
61
|
-
{
|
|
64
|
+
const createActionHandler =
|
|
65
|
+
(actionType: PreviewToEditorMessageType) => () => {
|
|
66
|
+
if (window.parent) {
|
|
67
|
+
postToEditor({
|
|
62
68
|
type: actionType,
|
|
63
69
|
data: {
|
|
64
70
|
placeholderId,
|
|
65
71
|
sectionId,
|
|
66
72
|
blockId: childBlock.id
|
|
67
73
|
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
73
77
|
|
|
74
78
|
const handleRename = (newLabel: string) => {
|
|
75
79
|
if (window.parent) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
'*'
|
|
87
|
-
);
|
|
80
|
+
postToEditor({
|
|
81
|
+
type: 'RENAME_BLOCK',
|
|
82
|
+
data: {
|
|
83
|
+
placeholderId,
|
|
84
|
+
sectionId,
|
|
85
|
+
blockId: childBlock.id,
|
|
86
|
+
label: newLabel
|
|
87
|
+
}
|
|
88
|
+
});
|
|
88
89
|
}
|
|
89
90
|
};
|
|
90
91
|
|