@shopware/helpers 1.5.0 → 1.7.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/README.md +95 -2
- package/dist/index.d.mts +128 -5
- package/dist/index.d.ts +128 -5
- package/dist/index.mjs +85 -4
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -30,14 +30,107 @@ export default defineConfig({
|
|
|
30
30
|
});
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
## `getBackgroundImageUrl` helper
|
|
34
|
+
|
|
35
|
+
The `getBackgroundImageUrl` function generates optimized CSS `url()` values for CMS background images. It extracts the raw URL, calculates the appropriate dimensions based on the media metadata, and applies image transformation parameters.
|
|
36
|
+
|
|
37
|
+
### Usage
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { getBackgroundImageUrl } from "@shopware/helpers";
|
|
41
|
+
|
|
42
|
+
const optimizedUrl = getBackgroundImageUrl(
|
|
43
|
+
"url(https://cdn.shopware.store/.../image.jpg)",
|
|
44
|
+
cmsBlockOrSection, // object with backgroundMedia.metaData.width/height
|
|
45
|
+
{ format: "webp", quality: 85 }, // optional
|
|
46
|
+
);
|
|
47
|
+
// => 'url("https://cdn.shopware.store/.../image.jpg?width=1000&fit=crop,smart&format=webp&quality=85")'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Parameters
|
|
51
|
+
|
|
52
|
+
| Parameter | Type | Description |
|
|
53
|
+
|-----------|------|-------------|
|
|
54
|
+
| `url` | `string` | CSS `url()` string containing the background image URL |
|
|
55
|
+
| `element` | `{ backgroundMedia?: { metaData?: { width?: number; height?: number } } }` | CMS section or block object with media metadata |
|
|
56
|
+
| `options` | `BackgroundImageOptions` (optional) | Format and quality settings |
|
|
57
|
+
|
|
58
|
+
### `BackgroundImageOptions`
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
type BackgroundImageOptions = {
|
|
62
|
+
format?: string; // "webp" | "avif" | "jpg" | "png"
|
|
63
|
+
quality?: number; // 0-100
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
When `format` or `quality` are provided, they are appended as query parameters to the image URL. If omitted, only the dimension and fit parameters are applied.
|
|
68
|
+
|
|
69
|
+
## `generateCdnSrcSet` helper
|
|
70
|
+
|
|
71
|
+
Generates an HTML `srcset` string using CDN width-based resizing. Useful as a fallback when media has no pre-generated thumbnails — the CDN handles on-the-fly resizing via query parameters.
|
|
72
|
+
|
|
73
|
+
### Usage
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { generateCdnSrcSet } from "@shopware/helpers";
|
|
77
|
+
|
|
78
|
+
const srcset = generateCdnSrcSet(
|
|
79
|
+
"https://cdn.shopware.store/.../image.jpg",
|
|
80
|
+
[400, 800, 1200, 1600], // optional, these are the defaults
|
|
81
|
+
{ format: "webp", quality: 85 }, // optional
|
|
82
|
+
);
|
|
83
|
+
// => "https://cdn.shopware.store/.../image.jpg?width=400&fit=crop,smart&format=webp&quality=85 400w, ...800w, ...1200w, ...1600w"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Parameters
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Description |
|
|
89
|
+
|-----------|------|-------------|
|
|
90
|
+
| `src` | `string \| undefined` | Base image URL |
|
|
91
|
+
| `widths` | `number[]` (optional) | Array of widths to generate (default: `[400, 800, 1200, 1600]`) |
|
|
92
|
+
| `options` | `{ format?: string; quality?: number }` (optional) | Format and quality settings |
|
|
93
|
+
|
|
94
|
+
Returns `undefined` if `src` is falsy or URL parsing fails.
|
|
95
|
+
|
|
96
|
+
## `buildCdnImageUrl` helper
|
|
97
|
+
|
|
98
|
+
Builds an optimized CDN image URL with size parameters based on rendered element dimensions. Adds `width` or `height` (whichever is larger) rounded up to the nearest 100px, plus `fit=crop,smart`.
|
|
99
|
+
|
|
100
|
+
### Usage
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { buildCdnImageUrl } from "@shopware/helpers";
|
|
104
|
+
|
|
105
|
+
const url = buildCdnImageUrl(
|
|
106
|
+
"https://cdn.shopware.store/.../image.jpg",
|
|
107
|
+
{ width: 724, height: 760 },
|
|
108
|
+
);
|
|
109
|
+
// => "https://cdn.shopware.store/.../image.jpg?height=800&fit=crop,smart"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Parameters
|
|
113
|
+
|
|
114
|
+
| Parameter | Type | Description |
|
|
115
|
+
|-----------|------|-------------|
|
|
116
|
+
| `src` | `string \| undefined` | Base image URL |
|
|
117
|
+
| `dimensions` | `{ width: number; height: number }` | Rendered element dimensions in pixels |
|
|
118
|
+
| `options` | `{ format?: string; quality?: number }` (optional) | Format and quality settings |
|
|
119
|
+
|
|
120
|
+
Returns an empty string if `src` is falsy. Returns the original `src` if URL parsing fails.
|
|
121
|
+
|
|
33
122
|
<!-- AUTO GENERATED CHANGELOG -->
|
|
34
123
|
|
|
35
124
|
## Changelog
|
|
36
125
|
|
|
37
126
|
Full changelog for stable version is available [here](https://github.com/shopware/frontends/blob/main/packages/helpers/CHANGELOG.md)
|
|
38
127
|
|
|
39
|
-
### Latest changes: 1.
|
|
128
|
+
### Latest changes: 1.7.0
|
|
40
129
|
|
|
41
130
|
### Minor Changes
|
|
42
131
|
|
|
43
|
-
- [#
|
|
132
|
+
- [#2287](https://github.com/shopware/frontends/pull/2287) [`c9bde38`](https://github.com/shopware/frontends/commit/c9bde38d497d5c6c2fbd97700a362eb44ce8881f) Thanks [@mkucmus](https://github.com/mkucmus)! - Add generateCdnSrcSet and buildCdnImageUrl helpers for synthetic responsive image srcset generation via CDN query params
|
|
133
|
+
|
|
134
|
+
### Patch Changes
|
|
135
|
+
|
|
136
|
+
- [#2320](https://github.com/shopware/frontends/pull/2320) [`a871c7b`](https://github.com/shopware/frontends/commit/a871c7b6256b75c2e40d93fc0354ba1971420062) Thanks [@mdanilowicz](https://github.com/mdanilowicz)! - Improve getSmallestThumbnailUrl - add media.url fallback when thumbnails are missing or empty
|
package/dist/index.d.mts
CHANGED
|
@@ -22,7 +22,7 @@ declare function getProductFreeShipping<T extends {
|
|
|
22
22
|
* @category Product
|
|
23
23
|
*/
|
|
24
24
|
declare function getMainImageUrl<T extends {
|
|
25
|
-
cover
|
|
25
|
+
cover: {
|
|
26
26
|
media?: {
|
|
27
27
|
url: string;
|
|
28
28
|
};
|
|
@@ -34,9 +34,11 @@ declare function getMainImageUrl<T extends {
|
|
|
34
34
|
};
|
|
35
35
|
}>;
|
|
36
36
|
} | {
|
|
37
|
-
cover
|
|
37
|
+
cover: {
|
|
38
38
|
url: string;
|
|
39
39
|
};
|
|
40
|
+
} | {
|
|
41
|
+
cover: null;
|
|
40
42
|
}>(object: T): string;
|
|
41
43
|
|
|
42
44
|
/**
|
|
@@ -205,6 +207,18 @@ declare function getProductFromPrice<T extends {
|
|
|
205
207
|
calculatedPrices?: CalculatedPrice[];
|
|
206
208
|
}>(product: T): number | undefined;
|
|
207
209
|
|
|
210
|
+
interface ProductWithManufacturer {
|
|
211
|
+
manufacturer?: {
|
|
212
|
+
translated?: {
|
|
213
|
+
name?: string;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Gets the translated name of the product manufacturer
|
|
219
|
+
*/
|
|
220
|
+
declare function getProductManufacturerName(product: ProductWithManufacturer): string;
|
|
221
|
+
|
|
208
222
|
/**
|
|
209
223
|
* Get product route information for Vue router.
|
|
210
224
|
*
|
|
@@ -228,6 +242,24 @@ declare function getProductRoute<T extends {
|
|
|
228
242
|
};
|
|
229
243
|
};
|
|
230
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Checks if a product is on sale based on its price percentage
|
|
247
|
+
*/
|
|
248
|
+
declare function isProductOnSale(product: {
|
|
249
|
+
calculatedPrice: {
|
|
250
|
+
listPrice?: {
|
|
251
|
+
percentage?: number;
|
|
252
|
+
} | null;
|
|
253
|
+
};
|
|
254
|
+
}): boolean;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Checks if a product is marked as a top seller
|
|
258
|
+
*/
|
|
259
|
+
declare function isProductTopSeller(product: {
|
|
260
|
+
markAsTopseller?: boolean;
|
|
261
|
+
}): boolean;
|
|
262
|
+
|
|
231
263
|
/**
|
|
232
264
|
* Get URL for category.
|
|
233
265
|
* Some link {@link isLinkCategory}
|
|
@@ -365,6 +397,10 @@ type LayoutConfiguration = {
|
|
|
365
397
|
*/
|
|
366
398
|
declare function getCmsLayoutConfiguration<T extends CmsBlock | CmsSection | CmsSlot>(content: T): LayoutConfiguration;
|
|
367
399
|
|
|
400
|
+
type BackgroundImageOptions = {
|
|
401
|
+
format?: string;
|
|
402
|
+
quality?: number;
|
|
403
|
+
};
|
|
368
404
|
declare function getBackgroundImageUrl<T extends {
|
|
369
405
|
backgroundMedia?: {
|
|
370
406
|
metaData?: {
|
|
@@ -372,7 +408,7 @@ declare function getBackgroundImageUrl<T extends {
|
|
|
372
408
|
height?: number;
|
|
373
409
|
};
|
|
374
410
|
};
|
|
375
|
-
}>(url: string, element: T): string;
|
|
411
|
+
}>(url: string, element: T, options?: BackgroundImageOptions): string;
|
|
376
412
|
|
|
377
413
|
type UrlRoute = {
|
|
378
414
|
path?: string;
|
|
@@ -418,6 +454,35 @@ declare function getCmsBreadcrumbs<T extends {
|
|
|
418
454
|
name: string;
|
|
419
455
|
}[];
|
|
420
456
|
|
|
457
|
+
type CmsPageStructure = {
|
|
458
|
+
sections: Array<{
|
|
459
|
+
blocks?: Array<{
|
|
460
|
+
slots?: Array<{
|
|
461
|
+
type?: string;
|
|
462
|
+
data?: unknown;
|
|
463
|
+
[key: string]: unknown;
|
|
464
|
+
}>;
|
|
465
|
+
[key: string]: unknown;
|
|
466
|
+
}>;
|
|
467
|
+
[key: string]: unknown;
|
|
468
|
+
}>;
|
|
469
|
+
[key: string]: unknown;
|
|
470
|
+
};
|
|
471
|
+
/**
|
|
472
|
+
* Extracts the product listing data from a CMS page structure.
|
|
473
|
+
* Useful for SSR to get listing data early before components render.
|
|
474
|
+
*
|
|
475
|
+
* @param cmsPage - The CMS page object (Schemas["CmsPage"])
|
|
476
|
+
* @returns The product listing result or null if not found
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```ts
|
|
480
|
+
* const listing = getProductListingFromCmsPage(cmsPage);
|
|
481
|
+
* createCategoryListingContext(listing);
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function getProductListingFromCmsPage<T = unknown>(cmsPage: CmsPageStructure): T | null;
|
|
485
|
+
|
|
421
486
|
type Category = {
|
|
422
487
|
apiAlias: "category";
|
|
423
488
|
};
|
|
@@ -475,6 +540,18 @@ type ListingFilter = {
|
|
|
475
540
|
code: string;
|
|
476
541
|
id: string;
|
|
477
542
|
name: string;
|
|
543
|
+
options?: Array<{
|
|
544
|
+
id: string;
|
|
545
|
+
translated?: {
|
|
546
|
+
name?: string;
|
|
547
|
+
};
|
|
548
|
+
}>;
|
|
549
|
+
entities?: Array<{
|
|
550
|
+
id: string;
|
|
551
|
+
translated?: {
|
|
552
|
+
name?: string;
|
|
553
|
+
};
|
|
554
|
+
}>;
|
|
478
555
|
};
|
|
479
556
|
/**
|
|
480
557
|
* @beta
|
|
@@ -543,7 +620,7 @@ declare function getMedia<T extends {
|
|
|
543
620
|
}>(lineItem: T): ProductMedia[];
|
|
544
621
|
|
|
545
622
|
/**
|
|
546
|
-
* Returns the smallest thumbnail url from the media object
|
|
623
|
+
* Returns the smallest thumbnail url from the media object or the media.url if no thumbnails are available
|
|
547
624
|
*
|
|
548
625
|
* @param media image object
|
|
549
626
|
*
|
|
@@ -555,8 +632,54 @@ declare function getSmallestThumbnailUrl<T extends {
|
|
|
555
632
|
width: number;
|
|
556
633
|
url: string;
|
|
557
634
|
}>;
|
|
635
|
+
url?: string;
|
|
558
636
|
}>(media?: T): string | undefined;
|
|
559
637
|
|
|
638
|
+
/**
|
|
639
|
+
* Encodes URL pathname to handle special characters (spaces, commas, etc.)
|
|
640
|
+
*
|
|
641
|
+
* @param urlString - The URL string to encode
|
|
642
|
+
* @returns The URL with encoded pathname
|
|
643
|
+
*
|
|
644
|
+
* @public
|
|
645
|
+
* @category Media
|
|
646
|
+
*/
|
|
647
|
+
declare function encodeUrlPath(urlString: string): string;
|
|
648
|
+
/**
|
|
649
|
+
* Generates a srcset string using CDN width-based resizing.
|
|
650
|
+
* Useful as a fallback when media has no pre-generated thumbnails.
|
|
651
|
+
*
|
|
652
|
+
* @param src - Base image URL
|
|
653
|
+
* @param widths - Array of widths to generate (default: [400, 800, 1200, 1600])
|
|
654
|
+
* @param options - Optional format and quality params
|
|
655
|
+
* @returns srcset string or undefined if src is invalid
|
|
656
|
+
*
|
|
657
|
+
* @public
|
|
658
|
+
* @category Media
|
|
659
|
+
*/
|
|
660
|
+
declare function generateCdnSrcSet(src: string | undefined, widths?: number[], options?: {
|
|
661
|
+
format?: string;
|
|
662
|
+
quality?: number;
|
|
663
|
+
}): string | undefined;
|
|
664
|
+
/**
|
|
665
|
+
* Builds an optimized CDN image URL with size parameters.
|
|
666
|
+
* Adds width or height (whichever is larger, width if equal)
|
|
667
|
+
* rounded up to the nearest 100px.
|
|
668
|
+
*
|
|
669
|
+
* @param src - Base image URL
|
|
670
|
+
* @param dimensions - Rendered element dimensions (width and height)
|
|
671
|
+
* @returns Optimized image URL string
|
|
672
|
+
*
|
|
673
|
+
* @public
|
|
674
|
+
* @category Media
|
|
675
|
+
*/
|
|
676
|
+
declare function buildCdnImageUrl(src: string | undefined, dimensions: {
|
|
677
|
+
width: number;
|
|
678
|
+
height: number;
|
|
679
|
+
}, options?: {
|
|
680
|
+
format?: string;
|
|
681
|
+
quality?: number;
|
|
682
|
+
}): string;
|
|
560
683
|
/**
|
|
561
684
|
* Returns the srcset attribute for the image, for available breakpoints
|
|
562
685
|
*
|
|
@@ -632,4 +755,4 @@ declare function canUseQuoteActions<T extends {
|
|
|
632
755
|
};
|
|
633
756
|
}>(quote: T): boolean;
|
|
634
757
|
|
|
635
|
-
export { type HelpersCssClasses, type LayoutConfiguration, type TierPrice, type UiMediaGalleryItem, type UiMediaGalleryItemUrl, type UiProductOption, type UiProductProperty, type UiProductReview, buildUrlPrefix, canUseQuoteActions, downloadFile, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, relativeUrlSlash, urlIsAbsolute };
|
|
758
|
+
export { type BackgroundImageOptions, type HelpersCssClasses, type LayoutConfiguration, type TierPrice, type UiMediaGalleryItem, type UiMediaGalleryItemUrl, type UiProductOption, type UiProductProperty, type UiProductReview, type UrlRouteOutput, buildCdnImageUrl, buildUrlPrefix, canUseQuoteActions, downloadFile, encodeUrlPath, generateCdnSrcSet, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductListingFromCmsPage, getProductManufacturerName, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, isProductOnSale, isProductTopSeller, relativeUrlSlash, urlIsAbsolute };
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ declare function getProductFreeShipping<T extends {
|
|
|
22
22
|
* @category Product
|
|
23
23
|
*/
|
|
24
24
|
declare function getMainImageUrl<T extends {
|
|
25
|
-
cover
|
|
25
|
+
cover: {
|
|
26
26
|
media?: {
|
|
27
27
|
url: string;
|
|
28
28
|
};
|
|
@@ -34,9 +34,11 @@ declare function getMainImageUrl<T extends {
|
|
|
34
34
|
};
|
|
35
35
|
}>;
|
|
36
36
|
} | {
|
|
37
|
-
cover
|
|
37
|
+
cover: {
|
|
38
38
|
url: string;
|
|
39
39
|
};
|
|
40
|
+
} | {
|
|
41
|
+
cover: null;
|
|
40
42
|
}>(object: T): string;
|
|
41
43
|
|
|
42
44
|
/**
|
|
@@ -205,6 +207,18 @@ declare function getProductFromPrice<T extends {
|
|
|
205
207
|
calculatedPrices?: CalculatedPrice[];
|
|
206
208
|
}>(product: T): number | undefined;
|
|
207
209
|
|
|
210
|
+
interface ProductWithManufacturer {
|
|
211
|
+
manufacturer?: {
|
|
212
|
+
translated?: {
|
|
213
|
+
name?: string;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Gets the translated name of the product manufacturer
|
|
219
|
+
*/
|
|
220
|
+
declare function getProductManufacturerName(product: ProductWithManufacturer): string;
|
|
221
|
+
|
|
208
222
|
/**
|
|
209
223
|
* Get product route information for Vue router.
|
|
210
224
|
*
|
|
@@ -228,6 +242,24 @@ declare function getProductRoute<T extends {
|
|
|
228
242
|
};
|
|
229
243
|
};
|
|
230
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Checks if a product is on sale based on its price percentage
|
|
247
|
+
*/
|
|
248
|
+
declare function isProductOnSale(product: {
|
|
249
|
+
calculatedPrice: {
|
|
250
|
+
listPrice?: {
|
|
251
|
+
percentage?: number;
|
|
252
|
+
} | null;
|
|
253
|
+
};
|
|
254
|
+
}): boolean;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Checks if a product is marked as a top seller
|
|
258
|
+
*/
|
|
259
|
+
declare function isProductTopSeller(product: {
|
|
260
|
+
markAsTopseller?: boolean;
|
|
261
|
+
}): boolean;
|
|
262
|
+
|
|
231
263
|
/**
|
|
232
264
|
* Get URL for category.
|
|
233
265
|
* Some link {@link isLinkCategory}
|
|
@@ -365,6 +397,10 @@ type LayoutConfiguration = {
|
|
|
365
397
|
*/
|
|
366
398
|
declare function getCmsLayoutConfiguration<T extends CmsBlock | CmsSection | CmsSlot>(content: T): LayoutConfiguration;
|
|
367
399
|
|
|
400
|
+
type BackgroundImageOptions = {
|
|
401
|
+
format?: string;
|
|
402
|
+
quality?: number;
|
|
403
|
+
};
|
|
368
404
|
declare function getBackgroundImageUrl<T extends {
|
|
369
405
|
backgroundMedia?: {
|
|
370
406
|
metaData?: {
|
|
@@ -372,7 +408,7 @@ declare function getBackgroundImageUrl<T extends {
|
|
|
372
408
|
height?: number;
|
|
373
409
|
};
|
|
374
410
|
};
|
|
375
|
-
}>(url: string, element: T): string;
|
|
411
|
+
}>(url: string, element: T, options?: BackgroundImageOptions): string;
|
|
376
412
|
|
|
377
413
|
type UrlRoute = {
|
|
378
414
|
path?: string;
|
|
@@ -418,6 +454,35 @@ declare function getCmsBreadcrumbs<T extends {
|
|
|
418
454
|
name: string;
|
|
419
455
|
}[];
|
|
420
456
|
|
|
457
|
+
type CmsPageStructure = {
|
|
458
|
+
sections: Array<{
|
|
459
|
+
blocks?: Array<{
|
|
460
|
+
slots?: Array<{
|
|
461
|
+
type?: string;
|
|
462
|
+
data?: unknown;
|
|
463
|
+
[key: string]: unknown;
|
|
464
|
+
}>;
|
|
465
|
+
[key: string]: unknown;
|
|
466
|
+
}>;
|
|
467
|
+
[key: string]: unknown;
|
|
468
|
+
}>;
|
|
469
|
+
[key: string]: unknown;
|
|
470
|
+
};
|
|
471
|
+
/**
|
|
472
|
+
* Extracts the product listing data from a CMS page structure.
|
|
473
|
+
* Useful for SSR to get listing data early before components render.
|
|
474
|
+
*
|
|
475
|
+
* @param cmsPage - The CMS page object (Schemas["CmsPage"])
|
|
476
|
+
* @returns The product listing result or null if not found
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```ts
|
|
480
|
+
* const listing = getProductListingFromCmsPage(cmsPage);
|
|
481
|
+
* createCategoryListingContext(listing);
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function getProductListingFromCmsPage<T = unknown>(cmsPage: CmsPageStructure): T | null;
|
|
485
|
+
|
|
421
486
|
type Category = {
|
|
422
487
|
apiAlias: "category";
|
|
423
488
|
};
|
|
@@ -475,6 +540,18 @@ type ListingFilter = {
|
|
|
475
540
|
code: string;
|
|
476
541
|
id: string;
|
|
477
542
|
name: string;
|
|
543
|
+
options?: Array<{
|
|
544
|
+
id: string;
|
|
545
|
+
translated?: {
|
|
546
|
+
name?: string;
|
|
547
|
+
};
|
|
548
|
+
}>;
|
|
549
|
+
entities?: Array<{
|
|
550
|
+
id: string;
|
|
551
|
+
translated?: {
|
|
552
|
+
name?: string;
|
|
553
|
+
};
|
|
554
|
+
}>;
|
|
478
555
|
};
|
|
479
556
|
/**
|
|
480
557
|
* @beta
|
|
@@ -543,7 +620,7 @@ declare function getMedia<T extends {
|
|
|
543
620
|
}>(lineItem: T): ProductMedia[];
|
|
544
621
|
|
|
545
622
|
/**
|
|
546
|
-
* Returns the smallest thumbnail url from the media object
|
|
623
|
+
* Returns the smallest thumbnail url from the media object or the media.url if no thumbnails are available
|
|
547
624
|
*
|
|
548
625
|
* @param media image object
|
|
549
626
|
*
|
|
@@ -555,8 +632,54 @@ declare function getSmallestThumbnailUrl<T extends {
|
|
|
555
632
|
width: number;
|
|
556
633
|
url: string;
|
|
557
634
|
}>;
|
|
635
|
+
url?: string;
|
|
558
636
|
}>(media?: T): string | undefined;
|
|
559
637
|
|
|
638
|
+
/**
|
|
639
|
+
* Encodes URL pathname to handle special characters (spaces, commas, etc.)
|
|
640
|
+
*
|
|
641
|
+
* @param urlString - The URL string to encode
|
|
642
|
+
* @returns The URL with encoded pathname
|
|
643
|
+
*
|
|
644
|
+
* @public
|
|
645
|
+
* @category Media
|
|
646
|
+
*/
|
|
647
|
+
declare function encodeUrlPath(urlString: string): string;
|
|
648
|
+
/**
|
|
649
|
+
* Generates a srcset string using CDN width-based resizing.
|
|
650
|
+
* Useful as a fallback when media has no pre-generated thumbnails.
|
|
651
|
+
*
|
|
652
|
+
* @param src - Base image URL
|
|
653
|
+
* @param widths - Array of widths to generate (default: [400, 800, 1200, 1600])
|
|
654
|
+
* @param options - Optional format and quality params
|
|
655
|
+
* @returns srcset string or undefined if src is invalid
|
|
656
|
+
*
|
|
657
|
+
* @public
|
|
658
|
+
* @category Media
|
|
659
|
+
*/
|
|
660
|
+
declare function generateCdnSrcSet(src: string | undefined, widths?: number[], options?: {
|
|
661
|
+
format?: string;
|
|
662
|
+
quality?: number;
|
|
663
|
+
}): string | undefined;
|
|
664
|
+
/**
|
|
665
|
+
* Builds an optimized CDN image URL with size parameters.
|
|
666
|
+
* Adds width or height (whichever is larger, width if equal)
|
|
667
|
+
* rounded up to the nearest 100px.
|
|
668
|
+
*
|
|
669
|
+
* @param src - Base image URL
|
|
670
|
+
* @param dimensions - Rendered element dimensions (width and height)
|
|
671
|
+
* @returns Optimized image URL string
|
|
672
|
+
*
|
|
673
|
+
* @public
|
|
674
|
+
* @category Media
|
|
675
|
+
*/
|
|
676
|
+
declare function buildCdnImageUrl(src: string | undefined, dimensions: {
|
|
677
|
+
width: number;
|
|
678
|
+
height: number;
|
|
679
|
+
}, options?: {
|
|
680
|
+
format?: string;
|
|
681
|
+
quality?: number;
|
|
682
|
+
}): string;
|
|
560
683
|
/**
|
|
561
684
|
* Returns the srcset attribute for the image, for available breakpoints
|
|
562
685
|
*
|
|
@@ -632,4 +755,4 @@ declare function canUseQuoteActions<T extends {
|
|
|
632
755
|
};
|
|
633
756
|
}>(quote: T): boolean;
|
|
634
757
|
|
|
635
|
-
export { type HelpersCssClasses, type LayoutConfiguration, type TierPrice, type UiMediaGalleryItem, type UiMediaGalleryItemUrl, type UiProductOption, type UiProductProperty, type UiProductReview, buildUrlPrefix, canUseQuoteActions, downloadFile, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, relativeUrlSlash, urlIsAbsolute };
|
|
758
|
+
export { type BackgroundImageOptions, type HelpersCssClasses, type LayoutConfiguration, type TierPrice, type UiMediaGalleryItem, type UiMediaGalleryItemUrl, type UiProductOption, type UiProductProperty, type UiProductReview, type UrlRouteOutput, buildCdnImageUrl, buildUrlPrefix, canUseQuoteActions, downloadFile, encodeUrlPath, generateCdnSrcSet, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductListingFromCmsPage, getProductManufacturerName, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, isProductOnSale, isProductTopSeller, relativeUrlSlash, urlIsAbsolute };
|
package/dist/index.mjs
CHANGED
|
@@ -91,6 +91,10 @@ function getProductFromPrice(product) {
|
|
|
91
91
|
return void 0;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
function getProductManufacturerName(product) {
|
|
95
|
+
return product.manufacturer?.translated?.name || "";
|
|
96
|
+
}
|
|
97
|
+
|
|
94
98
|
function getProductRoute(product) {
|
|
95
99
|
return {
|
|
96
100
|
path: getProductUrl(product),
|
|
@@ -101,6 +105,14 @@ function getProductRoute(product) {
|
|
|
101
105
|
};
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
function isProductOnSale(product) {
|
|
109
|
+
return (product.calculatedPrice?.listPrice?.percentage ?? 0) > 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isProductTopSeller(product) {
|
|
113
|
+
return !!product.markAsTopseller;
|
|
114
|
+
}
|
|
115
|
+
|
|
104
116
|
function getEntityPrefix(category) {
|
|
105
117
|
switch (category.linkType) {
|
|
106
118
|
case "category":
|
|
@@ -248,12 +260,18 @@ const getUrlFromBackgroundImage = (url) => {
|
|
|
248
260
|
const match = url.match(regex);
|
|
249
261
|
return !match ? url : match[1];
|
|
250
262
|
};
|
|
251
|
-
function getBackgroundImageUrl(url, element) {
|
|
263
|
+
function getBackgroundImageUrl(url, element, options) {
|
|
252
264
|
const backgroundImage = getUrlFromBackgroundImage(url);
|
|
253
265
|
const width = element.backgroundMedia?.metaData?.width ?? 0;
|
|
254
266
|
const height = element.backgroundMedia?.metaData?.height ?? 0;
|
|
255
267
|
const biggestParam = width > height ? `width=${roundUp(width > 1920 ? 1900 : width)}` : `height=${roundUp(height > 1920 ? 1900 : height)}`;
|
|
256
|
-
|
|
268
|
+
let srcPath = `${backgroundImage}?${biggestParam}&fit=crop,smart`;
|
|
269
|
+
if (options?.format) {
|
|
270
|
+
srcPath += `&format=${options.format}`;
|
|
271
|
+
}
|
|
272
|
+
if (options?.quality) {
|
|
273
|
+
srcPath += `&quality=${options.quality}`;
|
|
274
|
+
}
|
|
257
275
|
return `url("${srcPath}")`;
|
|
258
276
|
}
|
|
259
277
|
|
|
@@ -308,6 +326,12 @@ function getCmsBreadcrumbs(page) {
|
|
|
308
326
|
];
|
|
309
327
|
}
|
|
310
328
|
|
|
329
|
+
function getProductListingFromCmsPage(cmsPage) {
|
|
330
|
+
const slot = cmsPage.sections.flatMap((section) => section.blocks ?? []).flatMap((block) => block.slots ?? []).find((slot2) => slot2.type === "product-listing");
|
|
331
|
+
const listing = slot?.data?.listing;
|
|
332
|
+
return listing ?? null;
|
|
333
|
+
}
|
|
334
|
+
|
|
311
335
|
function getCmsEntityObject(response) {
|
|
312
336
|
switch (response.resourceType) {
|
|
313
337
|
case "frontend.detail.page":
|
|
@@ -410,6 +434,9 @@ function getMedia(lineItem) {
|
|
|
410
434
|
|
|
411
435
|
function getSmallestThumbnailUrl(media) {
|
|
412
436
|
if (!media || !media?.thumbnails?.length) {
|
|
437
|
+
if (media?.url) {
|
|
438
|
+
return media.url;
|
|
439
|
+
}
|
|
413
440
|
return;
|
|
414
441
|
}
|
|
415
442
|
const lowest = media.thumbnails.reduce((previous, current) => {
|
|
@@ -418,12 +445,66 @@ function getSmallestThumbnailUrl(media) {
|
|
|
418
445
|
return lowest?.url;
|
|
419
446
|
}
|
|
420
447
|
|
|
448
|
+
function encodeUrlPath(urlString) {
|
|
449
|
+
try {
|
|
450
|
+
const url = new URL(urlString);
|
|
451
|
+
url.pathname = url.pathname.split("/").map((segment) => encodeURIComponent(decodeURIComponent(segment))).join("/");
|
|
452
|
+
return url.toString();
|
|
453
|
+
} catch {
|
|
454
|
+
return urlString;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function generateCdnSrcSet(src, widths = [400, 800, 1200, 1600], options) {
|
|
458
|
+
if (!src) return void 0;
|
|
459
|
+
try {
|
|
460
|
+
return widths.map((w) => {
|
|
461
|
+
const url = new URL(encodeUrlPath(src));
|
|
462
|
+
url.searchParams.set("width", String(w));
|
|
463
|
+
url.searchParams.set("fit", "crop,smart");
|
|
464
|
+
if (options?.format) {
|
|
465
|
+
url.searchParams.set("format", options.format);
|
|
466
|
+
}
|
|
467
|
+
if (options?.quality) {
|
|
468
|
+
url.searchParams.set("quality", String(options.quality));
|
|
469
|
+
}
|
|
470
|
+
return `${url.toString()} ${w}w`;
|
|
471
|
+
}).join(", ");
|
|
472
|
+
} catch {
|
|
473
|
+
return void 0;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function buildCdnImageUrl(src, dimensions, options) {
|
|
477
|
+
if (!src) return "";
|
|
478
|
+
try {
|
|
479
|
+
const url = new URL(encodeUrlPath(src));
|
|
480
|
+
const DEFAULT_SIZE = 10;
|
|
481
|
+
const w = dimensions.width ? Math.ceil(dimensions.width / 100) * 100 : DEFAULT_SIZE;
|
|
482
|
+
const h = dimensions.height ? Math.ceil(dimensions.height / 100) * 100 : DEFAULT_SIZE;
|
|
483
|
+
if (w > DEFAULT_SIZE || h > DEFAULT_SIZE) {
|
|
484
|
+
if (dimensions.width >= dimensions.height) {
|
|
485
|
+
url.searchParams.set("width", String(w));
|
|
486
|
+
} else {
|
|
487
|
+
url.searchParams.set("height", String(h));
|
|
488
|
+
}
|
|
489
|
+
url.searchParams.set("fit", "crop,smart");
|
|
490
|
+
}
|
|
491
|
+
if (options?.format) {
|
|
492
|
+
url.searchParams.set("format", options.format);
|
|
493
|
+
}
|
|
494
|
+
if (options?.quality) {
|
|
495
|
+
url.searchParams.set("quality", String(options.quality));
|
|
496
|
+
}
|
|
497
|
+
return url.toString();
|
|
498
|
+
} catch {
|
|
499
|
+
return src;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
421
502
|
function getSrcSetForMedia(media) {
|
|
422
503
|
if (!media?.thumbnails?.length) {
|
|
423
504
|
return;
|
|
424
505
|
}
|
|
425
506
|
return media.thumbnails.map((thumbnail) => {
|
|
426
|
-
return thumbnail.url ? `${thumbnail.url} ${thumbnail.width}w` : void 0;
|
|
507
|
+
return thumbnail.url ? `${encodeUrlPath(thumbnail.url)} ${thumbnail.width}w` : void 0;
|
|
427
508
|
}).filter((value) => !!value).join(", ");
|
|
428
509
|
}
|
|
429
510
|
|
|
@@ -455,4 +536,4 @@ function canUseQuoteActions(quote) {
|
|
|
455
536
|
return ["replied"].includes(quote.stateMachineState?.technicalName ?? "");
|
|
456
537
|
}
|
|
457
538
|
|
|
458
|
-
export { buildUrlPrefix, canUseQuoteActions, downloadFile, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, relativeUrlSlash, urlIsAbsolute };
|
|
539
|
+
export { buildCdnImageUrl, buildUrlPrefix, canUseQuoteActions, downloadFile, encodeUrlPath, generateCdnSrcSet, getBackgroundImageUrl, getBiggestThumbnailUrl, getCategoryBreadcrumbs, getCategoryImageUrl, getCategoryRoute, getCategoryUrl, getCmsBreadcrumbs, getCmsEntityObject, getCmsLayoutConfiguration, getCmsTranslate, getFormattedPrice, getLanguageName, getListingFilters, getMainImageUrl, getMedia, getPaymentMethodIcon, getProductCalculatedListingPrice, getProductFreeShipping, getProductFromPrice, getProductListingFromCmsPage, getProductManufacturerName, getProductName, getProductRatingAverage, getProductReviews, getProductRoute, getProductTierPrices, getProductUrl, getShippingMethodDeliveryTime, getShippingMethodIcon, getSmallestThumbnailUrl, getSrcSetForMedia, getTranslatedProperty, helpersCssClasses, isCategory, isLandingPage, isMaintenanceMode, isProduct, isProductOnSale, isProductTopSeller, relativeUrlSlash, urlIsAbsolute };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopware/helpers",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Shopware helpers for accessing API data",
|
|
5
5
|
"author": "Shopware",
|
|
6
6
|
"type": "module",
|
|
@@ -33,19 +33,20 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@biomejs/biome": "1.8.3",
|
|
36
|
-
"@
|
|
37
|
-
"
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260111.1",
|
|
37
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
38
|
+
"happy-dom": "20.8.9",
|
|
38
39
|
"unbuild": "2.0.0",
|
|
39
|
-
"vitest": "
|
|
40
|
+
"vitest": "4.0.18",
|
|
40
41
|
"tsconfig": "0.0.0"
|
|
41
42
|
},
|
|
42
43
|
"scripts": {
|
|
43
44
|
"build": "unbuild && pnpm build:types",
|
|
44
|
-
"build:types": "
|
|
45
|
+
"build:types": "tsgo ./src/*.ts --ignoreConfig --declaration --allowJs --emitDeclarationOnly --outDir ./temp --skipLibCheck",
|
|
45
46
|
"dev": "unbuild --stub",
|
|
46
47
|
"lint": "biome check .",
|
|
47
48
|
"lint:fix": "biome check . --write && pnpm run typecheck",
|
|
48
|
-
"typecheck": "
|
|
49
|
+
"typecheck": "tsgo --noEmit",
|
|
49
50
|
"test": "vitest run",
|
|
50
51
|
"test:watch": "vitest"
|
|
51
52
|
}
|