@akinon/pz-theme 2.0.6-rc.1 → 2.0.6
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 -29
- package/package.json +3 -3
- package/src/blocks/image-block.tsx +26 -1
- package/src/blocks/slider-block.tsx +41 -31
- package/src/sections/posts-slider-section.tsx +9 -3
- package/src/utils/index.ts +73 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,37 +1,15 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.6
|
|
3
|
+
## 2.0.6
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- Updated dependencies [0cf9ea23]
|
|
15
|
-
- Updated dependencies [324f97d5]
|
|
16
|
-
- Updated dependencies
|
|
17
|
-
- Updated dependencies [b55acb768]
|
|
18
|
-
- Updated dependencies [760258c1]
|
|
19
|
-
- Updated dependencies [143be2b9]
|
|
20
|
-
- Updated dependencies [7889b08f]
|
|
21
|
-
- Updated dependencies [9f8cd3bc5]
|
|
22
|
-
- Updated dependencies [bfafa3f4]
|
|
23
|
-
- Updated dependencies [57d7eb30]
|
|
24
|
-
- Updated dependencies [d99a6a7d]
|
|
25
|
-
- Updated dependencies [9db81a71]
|
|
26
|
-
- Updated dependencies [591e345e]
|
|
27
|
-
- Updated dependencies [4de5303c5]
|
|
28
|
-
- Updated dependencies [95b139dc]
|
|
29
|
-
- Updated dependencies [1d00f2d0]
|
|
30
|
-
- Updated dependencies [4ac7b2a1]
|
|
31
|
-
- Updated dependencies [4998a963]
|
|
32
|
-
- Updated dependencies [3909d322]
|
|
33
|
-
- Updated dependencies [e18836b2]
|
|
34
|
-
- @akinon/next@2.0.6-rc.0
|
|
7
|
+
- 8ae85c5a: ZERO-4382: Add lazy load and fetch priority support
|
|
8
|
+
- Updated dependencies [89deabe5]
|
|
9
|
+
- Updated dependencies [1a345c47]
|
|
10
|
+
- Updated dependencies [1f1ae44e]
|
|
11
|
+
- Updated dependencies [8d8fefbe]
|
|
12
|
+
- @akinon/next@2.0.6
|
|
35
13
|
|
|
36
14
|
## 2.0.5
|
|
37
15
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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.6
|
|
4
|
+
"version": "2.0.6",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"peerDependencies": {
|
|
8
|
-
"@akinon/next": "2.0.6
|
|
8
|
+
"@akinon/next": "2.0.6",
|
|
9
9
|
"react": "^18.0.0 || ^19.0.0",
|
|
10
10
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
11
11
|
},
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"tailwind-merge": "^2.5.4"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@akinon/next": "2.0.6
|
|
18
|
+
"@akinon/next": "2.0.6",
|
|
19
19
|
"@types/node": "^18.7.8",
|
|
20
20
|
"@types/react": "^18.0.17",
|
|
21
21
|
"@types/react-dom": "^18.0.6",
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
IMAGE_FETCH_PRIORITIES,
|
|
5
|
+
IMAGE_LOADING_STRATEGIES,
|
|
6
|
+
type ImageFetchPriority,
|
|
7
|
+
type ImageLoadingStrategy,
|
|
8
|
+
getResponsiveValue,
|
|
9
|
+
resolveOption
|
|
10
|
+
} from '../utils';
|
|
4
11
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
5
12
|
|
|
6
13
|
const pickImageSource = (value: unknown, currentBreakpoint: string): string => {
|
|
@@ -72,6 +79,22 @@ const ImageBlock = ({
|
|
|
72
79
|
}, [block.value, block.properties?.alt, currentBreakpoint]);
|
|
73
80
|
|
|
74
81
|
const { url: src, alt } = imageValue;
|
|
82
|
+
const loadingStrategyValue =
|
|
83
|
+
block.properties?.loadingStrategy ?? block.styles?.loadingStrategy;
|
|
84
|
+
const priorityValue = block.properties?.priority ?? block.styles?.priority;
|
|
85
|
+
|
|
86
|
+
const loadingStrategy = resolveOption<ImageLoadingStrategy>(
|
|
87
|
+
loadingStrategyValue,
|
|
88
|
+
currentBreakpoint,
|
|
89
|
+
'lazy',
|
|
90
|
+
IMAGE_LOADING_STRATEGIES
|
|
91
|
+
);
|
|
92
|
+
const priority = resolveOption<ImageFetchPriority>(
|
|
93
|
+
priorityValue,
|
|
94
|
+
currentBreakpoint,
|
|
95
|
+
'auto',
|
|
96
|
+
IMAGE_FETCH_PRIORITIES
|
|
97
|
+
);
|
|
75
98
|
|
|
76
99
|
const width = getResponsiveValue(
|
|
77
100
|
block.styles?.width,
|
|
@@ -125,6 +148,8 @@ const ImageBlock = ({
|
|
|
125
148
|
key={src}
|
|
126
149
|
src={src}
|
|
127
150
|
alt={alt}
|
|
151
|
+
loading={loadingStrategy}
|
|
152
|
+
fetchPriority={priority}
|
|
128
153
|
style={{
|
|
129
154
|
display: 'block',
|
|
130
155
|
width: width ?? '100%',
|
|
@@ -7,6 +7,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
7
7
|
import ThemeBlock from '../theme-block';
|
|
8
8
|
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
9
9
|
import {
|
|
10
|
+
applyFirstSlideImageLoading,
|
|
10
11
|
getCSSStyles,
|
|
11
12
|
getResponsiveValue,
|
|
12
13
|
resolveThemeCssVariables
|
|
@@ -481,37 +482,46 @@ const SliderBlock: React.FC<BlockRendererProps> = ({
|
|
|
481
482
|
!isDesigner && showArrows ? <CustomRightArrow /> : undefined
|
|
482
483
|
}
|
|
483
484
|
>
|
|
484
|
-
{sortedBlocks.map((childBlock) =>
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
blockAction('
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
485
|
+
{sortedBlocks.map((childBlock, index) => {
|
|
486
|
+
const renderedChildBlock =
|
|
487
|
+
index === 0
|
|
488
|
+
? applyFirstSlideImageLoading(childBlock)
|
|
489
|
+
: childBlock;
|
|
490
|
+
|
|
491
|
+
return (
|
|
492
|
+
<div
|
|
493
|
+
key={childBlock.id}
|
|
494
|
+
style={{
|
|
495
|
+
paddingLeft: slidePadding,
|
|
496
|
+
paddingRight: slidePadding
|
|
497
|
+
}}
|
|
498
|
+
>
|
|
499
|
+
<ThemeBlock
|
|
500
|
+
block={renderedChildBlock}
|
|
501
|
+
placeholderId={placeholderId}
|
|
502
|
+
sectionId={sectionId}
|
|
503
|
+
isDesigner={isDesigner}
|
|
504
|
+
isSelected={selectedBlockId === childBlock.id}
|
|
505
|
+
selectedBlockId={selectedBlockId}
|
|
506
|
+
currentBreakpoint={currentBreakpoint}
|
|
507
|
+
onMoveUp={() => blockAction('MOVE_BLOCK_UP', childBlock.id)}
|
|
508
|
+
onMoveDown={() =>
|
|
509
|
+
blockAction('MOVE_BLOCK_DOWN', childBlock.id)
|
|
510
|
+
}
|
|
511
|
+
onDuplicate={() =>
|
|
512
|
+
blockAction('DUPLICATE_BLOCK', childBlock.id)
|
|
513
|
+
}
|
|
514
|
+
onToggleVisibility={() =>
|
|
515
|
+
blockAction('TOGGLE_BLOCK_VISIBILITY', childBlock.id)
|
|
516
|
+
}
|
|
517
|
+
onDelete={() => blockAction('DELETE_BLOCK', childBlock.id)}
|
|
518
|
+
onRename={(newLabel: string) =>
|
|
519
|
+
blockAction('RENAME_BLOCK', childBlock.id, newLabel)
|
|
520
|
+
}
|
|
521
|
+
/>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
524
|
+
})}
|
|
515
525
|
</Carousel>
|
|
516
526
|
|
|
517
527
|
{isDesigner &&
|
|
@@ -6,7 +6,11 @@ import { twMerge } from 'tailwind-merge';
|
|
|
6
6
|
|
|
7
7
|
import ThemeBlock from '../theme-block';
|
|
8
8
|
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
applyFirstSlideImageLoading,
|
|
11
|
+
getCSSStyles,
|
|
12
|
+
getResponsiveValue
|
|
13
|
+
} from '../utils';
|
|
10
14
|
|
|
11
15
|
interface PostsSliderSectionProps {
|
|
12
16
|
section: any;
|
|
@@ -424,9 +428,11 @@ const PostsSliderSection: React.FC<PostsSliderSectionProps> = ({
|
|
|
424
428
|
containerClass="posts-slider-carousel"
|
|
425
429
|
dotListClass="posts-slider-dots"
|
|
426
430
|
>
|
|
427
|
-
{expandedBlocks.map((block) => {
|
|
431
|
+
{expandedBlocks.map((block, index) => {
|
|
428
432
|
const controlBlockId = block.__iteratorParentId || block.id;
|
|
429
433
|
const isIteratorClone = Boolean(block.__fromIterator);
|
|
434
|
+
const renderedBlock =
|
|
435
|
+
index === 0 ? applyFirstSlideImageLoading(block) : block;
|
|
430
436
|
|
|
431
437
|
return (
|
|
432
438
|
<div
|
|
@@ -437,7 +443,7 @@ const PostsSliderSection: React.FC<PostsSliderSectionProps> = ({
|
|
|
437
443
|
}}
|
|
438
444
|
>
|
|
439
445
|
<ThemeBlock
|
|
440
|
-
block={
|
|
446
|
+
block={renderedBlock}
|
|
441
447
|
placeholderId={placeholderId}
|
|
442
448
|
sectionId={section.id}
|
|
443
449
|
isDesigner={isDesigner && !isIteratorClone}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { Block as ThemeBlockData } from '../theme-block';
|
|
3
|
+
|
|
2
4
|
export * from './publish-window';
|
|
3
5
|
|
|
6
|
+
export type ImageLoadingStrategy = 'eager' | 'lazy';
|
|
7
|
+
export type ImageFetchPriority = 'high' | 'auto' | 'low';
|
|
8
|
+
|
|
9
|
+
export const IMAGE_LOADING_STRATEGIES: ImageLoadingStrategy[] = [
|
|
10
|
+
'eager',
|
|
11
|
+
'lazy'
|
|
12
|
+
];
|
|
13
|
+
export const IMAGE_FETCH_PRIORITIES: ImageFetchPriority[] = [
|
|
14
|
+
'high',
|
|
15
|
+
'auto',
|
|
16
|
+
'low'
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const FIRST_SLIDE_IMAGE_LOADING = {
|
|
20
|
+
loadingStrategy: 'eager',
|
|
21
|
+
priority: 'high'
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
const hasOwnProperty = (value: unknown, key: string) =>
|
|
25
|
+
Boolean(
|
|
26
|
+
value &&
|
|
27
|
+
typeof value === 'object' &&
|
|
28
|
+
Object.prototype.hasOwnProperty.call(value, key)
|
|
29
|
+
);
|
|
30
|
+
|
|
4
31
|
type ThemeSettings = Record<string, unknown> | null;
|
|
5
32
|
|
|
6
33
|
const THEME_CSS_VARIABLE_MAP: Record<string, string> = {
|
|
@@ -160,6 +187,51 @@ export const getResponsiveValue = (
|
|
|
160
187
|
return value;
|
|
161
188
|
};
|
|
162
189
|
|
|
190
|
+
export const resolveOption = <T extends string>(
|
|
191
|
+
value: unknown,
|
|
192
|
+
currentBreakpoint: string,
|
|
193
|
+
fallback: T,
|
|
194
|
+
allowedValues: T[]
|
|
195
|
+
): T => {
|
|
196
|
+
const candidate = getResponsiveValue(value, currentBreakpoint, fallback);
|
|
197
|
+
|
|
198
|
+
if (typeof candidate === 'string' && allowedValues.includes(candidate as T)) {
|
|
199
|
+
return candidate as T;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return fallback;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const applyFirstSlideImageLoading = (
|
|
206
|
+
slideBlock: ThemeBlockData
|
|
207
|
+
): ThemeBlockData => {
|
|
208
|
+
const applyToBlock = (candidate: ThemeBlockData): ThemeBlockData => {
|
|
209
|
+
const nextChildren = candidate.blocks?.map(applyToBlock);
|
|
210
|
+
|
|
211
|
+
if (candidate.type !== 'image') {
|
|
212
|
+
return nextChildren ? { ...candidate, blocks: nextChildren } : candidate;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const properties = candidate.properties || {};
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
...candidate,
|
|
219
|
+
properties: {
|
|
220
|
+
...properties,
|
|
221
|
+
...(!hasOwnProperty(properties, 'loadingStrategy')
|
|
222
|
+
? { loadingStrategy: FIRST_SLIDE_IMAGE_LOADING.loadingStrategy }
|
|
223
|
+
: {}),
|
|
224
|
+
...(!hasOwnProperty(properties, 'priority')
|
|
225
|
+
? { priority: FIRST_SLIDE_IMAGE_LOADING.priority }
|
|
226
|
+
: {})
|
|
227
|
+
},
|
|
228
|
+
...(nextChildren ? { blocks: nextChildren } : {})
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return applyToBlock(slideBlock);
|
|
233
|
+
};
|
|
234
|
+
|
|
163
235
|
const kebabToCamel = (str: string): string => {
|
|
164
236
|
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
165
237
|
};
|
|
@@ -756,9 +828,7 @@ const collectBlockCSS = (
|
|
|
756
828
|
|
|
757
829
|
blocks.forEach((block) => {
|
|
758
830
|
if (block.styles && Object.keys(block.styles).length > 0) {
|
|
759
|
-
const selector = `[data-block-id="${
|
|
760
|
-
block.styleSourceId || block.id
|
|
761
|
-
}"]`;
|
|
831
|
+
const selector = `[data-block-id="${block.styleSourceId || block.id}"]`;
|
|
762
832
|
css += generateElementCSS(selector, block.styles, targetBreakpoint);
|
|
763
833
|
}
|
|
764
834
|
|