Setting the file. One moment.
Media · Wix Headless Templates · wix/skills · Skills Docs
ContentsBack to the top of the page shared/rest/ media.ts
TypeScript · 92 lines · 5 KB
fill
\/
w_
\d
+
,h_
\d
+
/
;
11 /** A bare Wix media file id: no scheme, no path, an extension — `e6a89e_06cf…~mv2.png`, `11062b_27ca…~mv2.jpg`. */
12 const BARE_FILE_ID = / ^ [\w-] + ~mv2 \. [a-z0-9] +$ / i ;
13
14 export type MediaLike = string | null | undefined | { image ?: unknown ; url ?: string | null ; id ?: string | null };
15
16 function rawOf ( value : unknown ) : string {
17 if ( ! value) return "" ;
18 if ( typeof value === "string" ) return value;
19 const o = value as { image ?: unknown ; url ?: string | null ; id ?: string | null };
20 if (o.image != null && typeof o.image === "object" ) return rawOf (o.image); // { image: { id, url } }
21 return ( typeof o.image === "string" ? o.image : null ) ?? o.url ?? o.id ?? "" ;
22 }
23
24 /** The file id behind any raw form (a wix:image id, a bare file id, a static.wixstatic.com URL); "" otherwise. */
25 function fileOf ( v : string ) : string {
26 if (v. startsWith ( "wix:image://" )) return v. slice ( "wix:image://v1/" . length ). split ( "/" )[ 0 ]. split ( "#" )[ 0 ];
27 if ( BARE_FILE_ID . test (v)) return v;
28 const m = v. match ( / ^ https: \/\/ static \. wixstatic \. com \/ media \/ ( [ ^ /?#] + )/ );
29 return m ? m[ 1 ] : "" ;
30 }
31
32 /** Resolve any Wix media value to a URL sized w×h ("" when absent). */
33 export function imgSrc ( value : unknown , width = 600 , height = 600 ) : string {
34 const v = rawOf (value);
35 if ( ! v) return "" ;
36 // A wix:image id, a bare file id, or an absolute Wix media URL (bare, or already scaled to some
37 // other size): every one re-issued through the scaler at the requested size, one shape.
38 const file = fileOf (v);
39 if (file) return `${ STATIC }/${ file }/v1/fill/w_${ width },h_${ height },al_c,q_90/${ file }` ;
40 return v;
41 }
42
43 /** srcset candidates at several widths; `ratio` is height/width. "" only when there is no image. */
44 export function imgSrcSet ( value : unknown , widths : number [] = [ 320 , 480 , 640 , 960 ], ratio = 1 ) : string {
45 const v = rawOf (value);
46 if ( ! v) return "" ;
47 if (v. startsWith ( "wix:image://" ) || BARE_FILE_ID . test (v)) return widths. map (( w ) => `${ imgSrc ( value , w , Math . round ( w * ratio )) } ${ w }w` ). join ( ", " );
48 if (v. includes ( "static.wixstatic.com/" ) && FILL . test (v)) {
49 return widths. map (( w ) => `${ v . replace ( FILL , `/v1/fill/w_${ w },h_${ Math . round ( w * ratio ) }` ) } ${ w }w` ). join ( ", " );
50 }
51 return v;
52 }
53
54 /**
55 * Everything an <img> needs for one Wix image, so a tile can never ship `srcset` without `src`.
56 * Attribute names as HTML spells them — spread into a template or apply with setAttribute:
57 * `<img ${attrs(imgAttrs(p.imageUrl, "(min-width: 1024px) 25vw, 50vw"))} alt="…">`
58 * `sizes` is the width the image renders at; `ratio` is height/width. {} when there is no image.
59 */
60 export function imgAttrs ( value : unknown , sizes : string , ratio = 1 ) : Record < string , string > {
61 const src = imgSrc (value, 640 , Math. round ( 640 * ratio));
62 if ( ! src) return {};
63 return { src, srcset: imgSrcSet (value, undefined , ratio), sizes, loading: "lazy" , decoding: "async" };
64 }
65
66 /**
67 * Height/width of a Wix image when the value carries its size: a raw
68 * `wix:image://…#originWidth=W&originHeight=H` id (the natural size) or a resolved `/v1/fill/w_W,h_H/`
69 * URL (the size it was scaled to). null when neither is present. Pass it as `ratio` to keep a
70 * srcset at the image's own aspect instead of the square default:
71 * imgAttrs(item.photo, "33vw", imgRatio(item.photo) ?? 1)
72 */
73 export function imgRatio ( value : unknown ) : number | null {
74 const v = rawOf (value);
75 if ( ! v) return null ;
76 const size = v. startsWith ( "wix:image://" )
77 ? [v. match ( / [#&] originWidth=( \d + )/ )?.[ 1 ], v. match ( / [#&] originHeight=( \d + )/ )?.[ 1 ]]
78 : (v. match ( / \/ v1 \/ fill \/ w_( \d + ),h_( \d + )/ )?. slice ( 1 ) ?? []);
79 const w = Number (size[ 0 ]);
80 const h = Number (size[ 1 ]);
81 return w > 0 && h > 0 ? h / w : null ;
82 }
83
84 /** The media identity before scaling — de-duplicate galleries on this, never on a resolved URL. */
85 export function mediaKey ( value : unknown ) : string {
86 const v = rawOf (value);
87 if ( ! v) return "" ;
88 // The file id, whichever form the value takes — a raw id and a resolved URL of one photo share it.
89 if (v. startsWith ( "wix:image://" )) return v. slice ( "wix:image://v1/" . length ). split ( "/" )[ 0 ]. split ( "#" )[ 0 ];
90 const m = v. match ( / ^ https: \/\/ static \. wixstatic \. com \/ media \/ ( [ ^ /?#] + )/ );
91 return m ? m[ 1 ] : v;
92 }