@se-studio/core-ui 1.30.2 → 1.31.0
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 +6 -0
- package/dist/components/PictureComponent.d.ts +5 -2
- package/dist/components/PictureComponent.d.ts.map +1 -1
- package/dist/components/PictureComponent.js +29 -3
- package/dist/components/PictureComponent.js.map +1 -1
- package/dist/utils/boundedImageSrcSet.d.ts +28 -0
- package/dist/utils/boundedImageSrcSet.d.ts.map +1 -0
- package/dist/utils/boundedImageSrcSet.js +104 -0
- package/dist/utils/boundedImageSrcSet.js.map +1 -0
- package/docs/llms.md +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @se-studio/core-ui
|
|
2
2
|
|
|
3
|
+
## 1.31.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- afaa382: Bound listing-card `next/image` srcset in PictureComponent via `getImageProps` + a configured-width filter (`cardVisualSizes` px/`min()` caps). Heroes and unconstrained visuals keep the full ladder. Requests stay on `/_next/image`.
|
|
8
|
+
|
|
3
9
|
## 1.30.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type IPicture } from '@se-studio/core-data-types';
|
|
2
2
|
import { type IImageProps } from './Visual';
|
|
3
|
-
declare function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, ...rest }: {
|
|
3
|
+
declare function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, fetchPriority, priority, preload, ...rest }: {
|
|
4
4
|
image: IPicture;
|
|
5
|
-
} & Omit<IImageProps, 'analytics' | 'componentLabel'>
|
|
5
|
+
} & Omit<IImageProps, 'analytics' | 'componentLabel'> & {
|
|
6
|
+
priority?: boolean;
|
|
7
|
+
preload?: boolean;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
6
9
|
export default PictureComponent;
|
|
7
10
|
//# sourceMappingURL=PictureComponent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PictureComponent.d.ts","sourceRoot":"","sources":["../../src/components/PictureComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAmC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"PictureComponent.d.ts","sourceRoot":"","sources":["../../src/components/PictureComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAmC,MAAM,4BAA4B,CAAC;AAG5F,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AA+BlE,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EACR,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,gBAAgB,CAAC,GAAG;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,+BAmCF;eACc,gBAAgB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { processSizes } from '@se-studio/core-data-types';
|
|
3
|
-
import Image from 'next/image';
|
|
3
|
+
import Image, { getImageProps } from 'next/image';
|
|
4
|
+
import { filterBoundedSrcSet, isCappedVisualSizes } from '../utils/boundedImageSrcSet';
|
|
4
5
|
import { calculateCropDetails } from './Visual';
|
|
5
6
|
function calculateSizes(visualSizes) {
|
|
6
7
|
if (!visualSizes) {
|
|
@@ -28,11 +29,36 @@ function isGifPicture(image) {
|
|
|
28
29
|
const path = image.src.split('?')[0]?.toLowerCase() ?? '';
|
|
29
30
|
return path.endsWith('.gif');
|
|
30
31
|
}
|
|
31
|
-
function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, ...rest }) {
|
|
32
|
+
function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, fetchPriority, priority, preload, ...rest }) {
|
|
32
33
|
const cropProperties = calculateCropDetails(image);
|
|
33
34
|
const useImageBlur = Boolean(image.blurDataURL) && placeholder === undefined && blurDataURL === undefined;
|
|
34
35
|
const gifUnoptimized = isGifPicture(image);
|
|
35
|
-
|
|
36
|
+
const sizes = calculateSizes(visualSizes);
|
|
37
|
+
const keepFullImageLadder = gifUnoptimized || fetchPriority === 'high' || priority === true || preload === true;
|
|
38
|
+
const imageElementProps = {
|
|
39
|
+
src: image.src,
|
|
40
|
+
width: image.width,
|
|
41
|
+
height: image.height,
|
|
42
|
+
style: { ...style, ...cropProperties },
|
|
43
|
+
alt: image.description ?? image.name,
|
|
44
|
+
sizes,
|
|
45
|
+
placeholder: useImageBlur ? 'blur' : placeholder,
|
|
46
|
+
blurDataURL: useImageBlur ? image.blurDataURL : blurDataURL,
|
|
47
|
+
fetchPriority,
|
|
48
|
+
priority,
|
|
49
|
+
preload,
|
|
50
|
+
...rest,
|
|
51
|
+
unoptimized: gifUnoptimized || undefined,
|
|
52
|
+
};
|
|
53
|
+
if (!keepFullImageLadder && isCappedVisualSizes(visualSizes)) {
|
|
54
|
+
const { props } = getImageProps(imageElementProps);
|
|
55
|
+
const filtered = props.srcSet ? filterBoundedSrcSet(props.srcSet) : undefined;
|
|
56
|
+
if (filtered) {
|
|
57
|
+
// biome-ignore lint/performance/noImgElement: filtered getImageProps; Image would rebuild the full srcset
|
|
58
|
+
return _jsx("img", { ...props, alt: props.alt, srcSet: filtered.srcSet, src: filtered.src });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return _jsx(Image, { ...imageElementProps });
|
|
36
62
|
}
|
|
37
63
|
export default PictureComponent;
|
|
38
64
|
//# sourceMappingURL=PictureComponent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PictureComponent.js","sourceRoot":"","sources":["../../src/components/PictureComponent.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAoC,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC5F,OAAO,KAAK,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PictureComponent.js","sourceRoot":"","sources":["../../src/components/PictureComponent.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAoC,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC5F,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAoB,MAAM,UAAU,CAAC;AAElE,SAAS,cAAc,CAAC,WAA0B;IAChD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,MAAM,GACV,YAAY,CAAC,WAAW,CAAC;QACvB,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;SACrD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,eAAe,QAAQ,OAAO,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7E,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;SAAM,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,aAAa,IAAI,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,YAAY,CAAC,KAAe;IACnC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC1D,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EAIN;IACD,MAAM,cAAc,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,YAAY,GAChB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,CAAC;IACvF,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,mBAAmB,GACvB,cAAc,IAAI,aAAa,KAAK,MAAM,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;IAEtF,MAAM,iBAAiB,GAAG;QACxB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,cAAc,EAAE;QACtC,GAAG,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI;QACpC,KAAK;QACL,WAAW,EAAE,YAAY,CAAC,CAAC,CAAE,MAAgB,CAAC,CAAC,CAAC,WAAW;QAC3D,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;QAC3D,aAAa;QACb,QAAQ;QACR,OAAO;QACP,GAAG,IAAI;QACP,WAAW,EAAE,cAAc,IAAI,SAAS;KACzC,CAAC;IAEF,IAAI,CAAC,mBAAmB,IAAI,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,IAAI,QAAQ,EAAE,CAAC;YACb,0GAA0G;YAC1G,OAAO,iBAAS,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,GAAI,CAAC;QACxF,CAAC;IACH,CAAC;IAED,OAAO,KAAC,KAAK,OAAK,iBAAiB,GAAI,CAAC;AAC1C,CAAC;AACD,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IVisualSizes } from '@se-studio/core-data-types';
|
|
2
|
+
/** Widths already in typical Next `imageSizes` / `deviceSizes` — never invent others. */
|
|
3
|
+
export declare const CARD_SRCSET_CORE_WIDTHS: readonly [384, 640, 828, 1080];
|
|
4
|
+
/** Drop 1920+ on cards; keep one candidate in this range for mobile `100vw`. */
|
|
5
|
+
export declare const CARD_SRCSET_MAX_LARGE_WIDTH = 1504;
|
|
6
|
+
/**
|
|
7
|
+
* True when `visualSizes` looks like `cardVisualSizes` (desktop `Npx` / `min(…, Npx)`).
|
|
8
|
+
* Uses `size` / `defaultSize` / `defaultPixels` only — ignore breakpoint `pixels`
|
|
9
|
+
* (`calculateVisualSizes` always sets `pixels` on vw slots; that would false-cap heroes).
|
|
10
|
+
* A hand-written `min(100vw, 1440px)` hero is treated as capped.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isCappedVisualSizes(visualSizes?: IVisualSizes): boolean;
|
|
13
|
+
export interface SrcSetCandidate {
|
|
14
|
+
url: string;
|
|
15
|
+
width: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseSrcSet(srcSet: string): SrcSetCandidate[];
|
|
18
|
+
export interface FilteredSrcSet {
|
|
19
|
+
srcSet: string;
|
|
20
|
+
src: string;
|
|
21
|
+
widths: number[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Keep a small subset of widths that already appear in `srcSet`.
|
|
25
|
+
* Drops icon buckets (16–256) and 1920+; keeps 384, 640, 828, 1080 plus one large ≤1504.
|
|
26
|
+
*/
|
|
27
|
+
export declare function filterBoundedSrcSet(srcSet: string): FilteredSrcSet | undefined;
|
|
28
|
+
//# sourceMappingURL=boundedImageSrcSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundedImageSrcSet.d.ts","sourceRoot":"","sources":["../../src/utils/boundedImageSrcSet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,yFAAyF;AACzF,eAAO,MAAM,uBAAuB,YAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAU,CAAC;AAEtE,gFAAgF;AAChF,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAgBhD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,YAAY,GAAG,OAAO,CAWvE;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAmB7D;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAoD9E"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/** Widths already in typical Next `imageSizes` / `deviceSizes` — never invent others. */
|
|
2
|
+
export const CARD_SRCSET_CORE_WIDTHS = [384, 640, 828, 1080];
|
|
3
|
+
/** Drop 1920+ on cards; keep one candidate in this range for mobile `100vw`. */
|
|
4
|
+
export const CARD_SRCSET_MAX_LARGE_WIDTH = 1504;
|
|
5
|
+
const ICON_MAX_WIDTH = 256;
|
|
6
|
+
const CORE_MAX_WIDTH = 1080;
|
|
7
|
+
function isPixelOrMinSize(size) {
|
|
8
|
+
if (!size) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const trimmed = size.trim();
|
|
12
|
+
if (/^\d+(?:\.\d+)?px$/i.test(trimmed)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return /\bmin\s*\(/i.test(trimmed);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* True when `visualSizes` looks like `cardVisualSizes` (desktop `Npx` / `min(…, Npx)`).
|
|
19
|
+
* Uses `size` / `defaultSize` / `defaultPixels` only — ignore breakpoint `pixels`
|
|
20
|
+
* (`calculateVisualSizes` always sets `pixels` on vw slots; that would false-cap heroes).
|
|
21
|
+
* A hand-written `min(100vw, 1440px)` hero is treated as capped.
|
|
22
|
+
*/
|
|
23
|
+
export function isCappedVisualSizes(visualSizes) {
|
|
24
|
+
if (!visualSizes) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (isPixelOrMinSize(visualSizes.defaultSize)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (visualSizes.defaultPixels != null && !visualSizes.defaultSize) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return visualSizes.breakpoints?.some((breakpoint) => isPixelOrMinSize(breakpoint.size)) ?? false;
|
|
34
|
+
}
|
|
35
|
+
export function parseSrcSet(srcSet) {
|
|
36
|
+
const candidates = [];
|
|
37
|
+
for (const part of srcSet.split(',')) {
|
|
38
|
+
const trimmed = part.trim();
|
|
39
|
+
if (!trimmed) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const match = /^(.+?)\s+(\d+)w$/i.exec(trimmed);
|
|
43
|
+
if (!match) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const url = match[1]?.trim();
|
|
47
|
+
const widthRaw = match[2];
|
|
48
|
+
if (!url || widthRaw === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
candidates.push({ url, width: Number(widthRaw) });
|
|
52
|
+
}
|
|
53
|
+
return candidates;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Keep a small subset of widths that already appear in `srcSet`.
|
|
57
|
+
* Drops icon buckets (16–256) and 1920+; keeps 384, 640, 828, 1080 plus one large ≤1504.
|
|
58
|
+
*/
|
|
59
|
+
export function filterBoundedSrcSet(srcSet) {
|
|
60
|
+
const candidates = parseSrcSet(srcSet);
|
|
61
|
+
if (candidates.length === 0) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const byWidth = new Map();
|
|
65
|
+
for (const candidate of candidates) {
|
|
66
|
+
if (!byWidth.has(candidate.width)) {
|
|
67
|
+
byWidth.set(candidate.width, candidate.url);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const kept = [];
|
|
71
|
+
for (const width of CARD_SRCSET_CORE_WIDTHS) {
|
|
72
|
+
if (byWidth.has(width)) {
|
|
73
|
+
kept.push(width);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const large = [...byWidth.keys()].filter((width) => width > CORE_MAX_WIDTH && width <= CARD_SRCSET_MAX_LARGE_WIDTH);
|
|
77
|
+
if (large.length > 0) {
|
|
78
|
+
kept.push(Math.max(...large));
|
|
79
|
+
}
|
|
80
|
+
if (kept.length === 0) {
|
|
81
|
+
const fallback = [...byWidth.keys()]
|
|
82
|
+
.filter((width) => width > ICON_MAX_WIDTH && width <= CARD_SRCSET_MAX_LARGE_WIDTH)
|
|
83
|
+
.sort((a, b) => a - b);
|
|
84
|
+
if (fallback.length === 0) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
kept.push(...fallback);
|
|
88
|
+
}
|
|
89
|
+
const widths = [...new Set(kept)].sort((a, b) => a - b);
|
|
90
|
+
const largest = widths[widths.length - 1];
|
|
91
|
+
if (largest === undefined) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
const src = byWidth.get(largest);
|
|
95
|
+
if (!src) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
srcSet: widths.map((width) => `${byWidth.get(width)} ${width}w`).join(', '),
|
|
100
|
+
src,
|
|
101
|
+
widths,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=boundedImageSrcSet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundedImageSrcSet.js","sourceRoot":"","sources":["../../src/utils/boundedImageSrcSet.ts"],"names":[],"mappings":"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"}
|
package/docs/llms.md
CHANGED
|
@@ -120,6 +120,8 @@ Keep the default `next/image` loader. Set `images.minimumCacheTTL: 2_678_400` (3
|
|
|
120
120
|
|
|
121
121
|
Pass `visualSizes` on every `Visual` / `ResponsiveVisual` with images. Use `cardVisualSizes({ columns, mobileColumns })` for card grids (match the real column counts), `heroVisualSizes()` for full-bleed (`defaultSize` `100vw`, no breakpoints), and `calculateVisualSizes(...)` for other vw ratios. **Never `calculateVisualSizes(1)` for Explore-style / in-card GIFs** — that tells the optimizer the image is full viewport and inflates GIF/WebP requests. Use `cardVisualSizes` (or a matching column ratio) instead.
|
|
122
122
|
|
|
123
|
+
Capped card `visualSizes` (`Npx` / `min(…, Npx)` from `cardVisualSizes`) make `PictureComponent` emit a short `/_next/image` srcset (384, 640, 828, 1080, plus one large ≤1504 already in the app `imageSizes`/`deviceSizes`). Heroes, missing `visualSizes`, vw-only sizes, and GIF `unoptimized` keep the full next/image ladder. Do not shrink global `deviceSizes` to trim cards.
|
|
124
|
+
|
|
123
125
|
If a site already uses a custom `next/image` loader that rewrites `w`, **keep the existing `fm` query param**. Stripping `fm=webp` from GIF origins fetches the GIF master.
|
|
124
126
|
|
|
125
127
|
## TrackedLink and dest `asChild`
|