@se-studio/core-ui 1.30.1 → 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 CHANGED
@@ -1,5 +1,19 @@
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
+
9
+ ## 1.30.2
10
+
11
+ ### Patch Changes
12
+
13
+ - c3f9c5e: GIF origin bandwidth: default Images API `fm=webp` + `w≤1280` for `image/gif` on images/assets.ctfassets.net, with `gifTransform: 'off'` opt-out. PictureComponent sets `unoptimized` for GIF mime so next/image does not srcSet the GIF master. Blur enricher skips GIFs. Custom loaders must preserve `fm`.
14
+ - Updated dependencies [c3f9c5e]
15
+ - @se-studio/contentful-rest-api@1.28.0
16
+
3
17
  ## 1.30.1
4
18
 
5
19
  ### 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'>): import("react").JSX.Element;
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;AAE5F,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAsBlE,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,GAAG,IAAI,EACR,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,gBAAgB,CAAC,+BAkBzE;eACc,gBAAgB"}
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) {
@@ -20,10 +21,44 @@ function calculateSizes(visualSizes) {
20
21
  }
21
22
  return result.join(',');
22
23
  }
23
- function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, ...rest }) {
24
+ function isGifPicture(image) {
25
+ const mime = image.mimeType?.toLowerCase() ?? '';
26
+ if (mime === 'image/gif') {
27
+ return true;
28
+ }
29
+ const path = image.src.split('?')[0]?.toLowerCase() ?? '';
30
+ return path.endsWith('.gif');
31
+ }
32
+ function PictureComponent({ image, style, visualSizes, placeholder, blurDataURL, fetchPriority, priority, preload, ...rest }) {
24
33
  const cropProperties = calculateCropDetails(image);
25
34
  const useImageBlur = Boolean(image.blurDataURL) && placeholder === undefined && blurDataURL === undefined;
26
- return (_jsx(Image, { src: image.src, width: image.width, height: image.height, style: { ...style, ...cropProperties }, alt: image.description ?? image.name, sizes: calculateSizes(visualSizes), placeholder: useImageBlur ? 'blur' : placeholder, blurDataURL: useImageBlur ? image.blurDataURL : blurDataURL, ...rest }));
35
+ const gifUnoptimized = isGifPicture(image);
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 });
27
62
  }
28
63
  export default PictureComponent;
29
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;AAC/B,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,gBAAgB,CAAC,EACxB,KAAK,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,GAAG,IAAI,EACiE;IACxE,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;IAEvF,OAAO,CACL,KAAC,KAAK,IACJ,GAAG,EAAE,KAAK,CAAC,GAAG,EACd,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,cAAc,EAAE,EACtC,GAAG,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,EACpC,KAAK,EAAE,cAAc,CAAC,WAAW,CAAC,EAClC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAChD,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,KACvD,IAAI,GACR,CACH,CAAC;AACJ,CAAC;AACD,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"PictureComponent.js","sourceRoot":"","sources":["../../src/components/PictureComponent.tsx"],"names":[],"mappings":"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"}
@@ -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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"}
@@ -19,6 +19,7 @@ export declare function heroVisualSizes(): IVisualSizes;
19
19
  /**
20
20
  * Card-grid `visualSizes`: mobile column vw, laptop column vw capped at the
21
21
  * content-max px slot, desktop px cap (`contentMax / columns`).
22
+ * Use this (not `calculateVisualSizes(1)`) for Explore-style in-card GIFs.
22
23
  */
23
24
  export declare function cardVisualSizes({ columns, contentMax, mobileColumns, breakpoints, }: CardVisualSizesOptions): IVisualSizes;
24
25
  //# sourceMappingURL=visualSizes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"visualSizes.d.ts","sourceRoot":"","sources":["../../src/utils/visualSizes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAItE,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,YAAY,CAsBd;AAaD,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,UAAgC,EAChC,aAAiB,EACjB,WAAiC,GAClC,EAAE,sBAAsB,GAAG,YAAY,CA+BvC"}
1
+ {"version":3,"file":"visualSizes.d.ts","sourceRoot":"","sources":["../../src/utils/visualSizes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAItE,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,YAAY,CAsBd;AAaD,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,UAAgC,EAChC,aAAiB,EACjB,WAAiC,GAClC,EAAE,sBAAsB,GAAG,YAAY,CA+BvC"}
@@ -39,6 +39,7 @@ export function heroVisualSizes() {
39
39
  /**
40
40
  * Card-grid `visualSizes`: mobile column vw, laptop column vw capped at the
41
41
  * content-max px slot, desktop px cap (`contentMax / columns`).
42
+ * Use this (not `calculateVisualSizes(1)`) for Explore-style in-card GIFs.
42
43
  */
43
44
  export function cardVisualSizes({ columns, contentMax = DEFAULT_CONTENT_MAX, mobileColumns = 1, breakpoints = DEFAULT_BREAKPOINTS, }) {
44
45
  if (!(columns >= 1)) {
@@ -1 +1 @@
1
- {"version":3,"file":"visualSizes.js","sourceRoot":"","sources":["../../src/utils/visualSizes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"visualSizes.js","sourceRoot":"","sources":["../../src/utils/visualSizes.ts"],"names":[],"mappings":"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"}
package/docs/llms.md CHANGED
@@ -116,9 +116,13 @@ import { ResponsiveVisual, ContainedVisual } from '@se-studio/core-ui';
116
116
  <ResponsiveVisual visual={responsiveVisual} className="w-full" />
117
117
  ```
118
118
 
119
- Keep the default `next/image` loader. Set `images.minimumCacheTTL: 2_678_400` (31 days) in the app `next.config`. Raster CMS pictures already have Contentful Images API `w`/`fm`/`q` on `src` from `@se-studio/contentful-rest-api`.
119
+ Keep the default `next/image` loader. Set `images.minimumCacheTTL: 2_678_400` (31 days) in the app `next.config`. Raster CMS pictures already have Contentful Images API `w`/`fm`/`q` on `src` from `@se-studio/contentful-rest-api`. GIF pictures use origin `fm=webp` and `PictureComponent` sets `unoptimized` so Next does not srcSet a GIF master.
120
120
 
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.
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
+
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
+
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.
122
126
 
123
127
  ## TrackedLink and dest `asChild`
124
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/core-ui",
3
- "version": "1.30.1",
3
+ "version": "1.31.0",
4
4
  "description": "Shared React UI component library with Tailwind CSS v4 for SE Studio applications",
5
5
  "repository": {
6
6
  "type": "git",
@@ -76,7 +76,7 @@
76
76
  "@contentful/rich-text-react-renderer": "^16.2.2",
77
77
  "@contentful/rich-text-types": "^17.2.7",
78
78
  "@radix-ui/react-slot": "1.3.3",
79
- "@se-studio/contentful-rest-api": "1.27.2",
79
+ "@se-studio/contentful-rest-api": "1.28.0",
80
80
  "@se-studio/core-data-types": "1.13.5",
81
81
  "@types/mustache": "4.2.6",
82
82
  "@vimeo/player": "^2.30.4",