@page-speed/img 0.4.5 → 0.4.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/README.md CHANGED
@@ -1,10 +1,8 @@
1
- ![Page Speed React Image Component](https://octane.cdn.ing/api/v1/images/transform?url=https://toastability-production.s3.amazonaws.com/gghtx0lxw9f2zigs427qc2phu024&q=85&f=avif)
1
+ # @page-speed/img
2
2
 
3
- ---
3
+ ![Page Speed React Image Component](https://octane.cdn.ing/api/v1/images/transform?url=https://toastability-production.s3.amazonaws.com/gghtx0lxw9f2zigs427qc2phu024&q=85&f=avif)
4
4
 
5
- # @page-speed/img
6
-
7
- **Performance-optimized React Image component**
5
+ > **Performance-optimized React Image component**
8
6
 
9
7
  Drop-in Image implementation of [web.dev](https://web.dev) best practices with zero configuration. Also a great alternative to [next/image](https://nextjs.org/docs/api-reference/next/image) for non-Next.js projects that still need the automated image optimization tools that the Next `Image` component provides.
10
8
 
@@ -1,2 +1,2 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).PageSpeedImg={},e.React)}(this,function(e,t){"use strict";var i=[1,2],n="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const r="dt:media-selected",o=()=>{};let s=0,d=!1;function l(e){e&&e.querySelectorAll("source").forEach(e=>{const t=e.getAttribute("srcset");t&&(e.setAttribute("data-srcset",t),e.removeAttribute("srcset"),requestAnimationFrame(()=>{e.setAttribute("srcset",t)}))})}const u="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let c;const a=e=>e??c??(()=>{var e,t,i;if("undefined"==typeof globalThis)return;const n=globalThis;return(null==(e=n.PageSpeedImgDefaults)?void 0:e.optixFlowConfig)||(null==(t=n.OpensiteImgDefaults)?void 0:t.optixFlowConfig)||(null==(i=n.PAGE_SPEED_IMG_DEFAULTS)?void 0:i.optixFlowConfig)})(),f=e=>{if(""!==e&&null!=e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e){const t=Number(e);if(Number.isFinite(t))return t}}},g=({sizes:e,loading:c,decoding:g,alt:h,title:p,src:w,eager:v,intersectionMargin:m,intersectionThreshold:b,optixFlowConfig:y,forwardedRef:E,...A})=>{const M=t.useRef(null),I=t.useRef(null),S=t.useRef(null);var L;L=I,t.useEffect(()=>{const e=L.current;e&&(e instanceof HTMLPictureElement?l(e):e.parentElement instanceof HTMLPictureElement&&l(e.parentElement))},[L]),t.useEffect(()=>{if("undefined"!=typeof window)return d||(window.addEventListener(r,o),d=!0),s+=1,()=>{s-=1,s<=0&&d&&(window.removeEventListener(r,o),d=!1)}},[]);const j=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),F=t.useMemo(()=>f(A.width),[A]),x=t.useMemo(()=>f(A.height),[A]),z=t.useMemo(()=>a(y),[y]),R=v??"eager"===c,{ref:T,src:V,srcset:C,sizes:N,loading:O,isInView:P,size:D}=function(e){const{src:r,eager:o=!1,threshold:s=.1,rootMargin:d="50px",width:l,height:u,optixFlowConfig:c}=e,a=t.useMemo(()=>null==c?void 0:c.apiKey,[null==c?void 0:c.apiKey]),f=t.useMemo(()=>!!a,[a]),[g,h]=t.useState({isLoaded:!1,isInView:!1}),[p,w]=t.useState({width:0,height:0}),v=t.useRef(null),m=t.useRef(null),b=t.useMemo(()=>({width:l??p.width,height:u??p.height}),[l,u,p.width,p.height]);n(()=>{if(!v.current)return;if(void 0!==l&&void 0!==u)return;const e=()=>{const e=v.current;if(!e)return;const t=l??(Math.round(e.clientWidth)||e.naturalWidth||0),i=u??(Math.round(e.clientHeight)||e.naturalHeight||0);(t>0||i>0)&&w(e=>e.width!==t||e.height!==i?{width:t,height:i}:e)};v.current.clientWidth>0&&e();const t=v.current;t.addEventListener("load",e);let i=null;return"undefined"!=typeof ResizeObserver&&(i=new ResizeObserver(()=>{e()}),i.observe(t)),()=>{t.removeEventListener("load",e),null==i||i.disconnect()}},[l,u]);const y=t.useCallback((e,t,i)=>{if(!f)return r;if(!e||!t)return r;const n=new URLSearchParams;return n.set("url",r),n.set("fit",String((null==c?void 0:c.objectFit)??"cover")),n.set("w",String(e)),n.set("h",String(t)),n.set("q",String((null==c?void 0:c.compressionLevel)??75)),n.set("f",i),n.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${n.toString()}`},[f,r,null==c?void 0:c.compressionLevel,a,null==c?void 0:c.objectFit]),E=t.useCallback((e,t,n)=>f&&0!==e&&0!==t?i.map(i=>{const r=Math.round(e*i),o=Math.round(t*i);return`${y(r,o,n)} ${i}x`}).join(", "):"",[f,y]),A=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return r;const t=(null==c?void 0:c.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,r,b.width,b.height,null==c?void 0:c.renderedFileType,null==c?void 0:c.compressionLevel,null==c?void 0:c.objectFit,y]),M=t.useMemo(()=>({avif:E(b.width,b.height,"avif"),webp:E(b.width,b.height,"webp"),jpeg:E(b.width,b.height,"jpeg")}),[b.width,b.height,E]),I=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&v.current){if(!o)return m.current=new IntersectionObserver(([e])=>{var t;e.isIntersecting&&(h(e=>({...e,isInView:!0})),null==(t=m.current)||t.disconnect())},{threshold:s,rootMargin:d}),m.current.observe(v.current),()=>{var e;null==(e=m.current)||e.disconnect()};h({isLoaded:!1,isInView:!0})}},[o,s,d]),t.useEffect(()=>{if(!v.current)return;const e=()=>{h(e=>({...e,isLoaded:!0}))},t=v.current;if(!t.complete)return t.addEventListener("load",e),()=>t.removeEventListener("load",e);e()},[g.isInView]),{ref:t.useCallback(e=>{v.current=e},[]),src:g.isInView||o?A:r,srcset:g.isInView||o?M:{avif:"",webp:"",jpeg:""},sizes:g.isInView||o?I:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:o?"eager":"lazy",size:b}}({src:j,eager:R,width:F,height:x,rootMargin:m??"200px",threshold:b??.1,optixFlowConfig:z}),q=((e,i,n)=>t.useCallback(t=>{e(t),n.current=t,"function"==typeof i?i(t):i&&"object"==typeof i&&(i.current=t)},[e,i,n]))(T,E,M),{width:_,height:k,...H}=A,$=e??(N||void 0),B=c??O??"lazy",G=g??"async",K=Boolean(C.avif||C.webp||C.jpeg),U=V||j||u,W=!K||C.avif||C.webp?"":C.jpeg,Q=f(_),J=f(k),X=Q??(D.width||F||void 0),Y=J??(D.height||x||void 0);return t.useEffect(()=>{if("undefined"==typeof window)return;if(!R&&!P)return;if(U===u)return;const e=[U,C.avif,C.webp,C.jpeg,$??""].join("|");S.current!==e&&(S.current=e,"undefined"!=typeof console&&console.info&&console.info("[PageSpeedImg] image request",{src:U,srcset:C,sizes:$}))},[R,U,P,$,C.avif,C.webp,C.jpeg]),K?t.createElement("picture",{ref:I},C.avif?t.createElement("source",{type:"image/avif",srcSet:C.avif,sizes:$}):null,C.webp?t.createElement("source",{type:"image/webp",srcSet:C.webp,sizes:$}):null,t.createElement("img",{ref:q,src:U,srcSet:W||void 0,sizes:W?$:void 0,loading:B,decoding:G,alt:h,title:p,width:X,height:Y,...H})):t.createElement("img",{ref:q,src:U,loading:B,decoding:G,alt:h,title:p,width:X,height:Y,...H})},h=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(g,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),p=t.memo(h);p.displayName="PageSpeedImg";const w="undefined"!=typeof globalThis?globalThis:void 0;if(w)if(w.process){const e=w.process.env??(w.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else w.process={env:{NODE_ENV:"production"}};e.Img=p,e.setDefaultOptixFlowConfig=e=>{c=e??void 0},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).PageSpeedImg={},e.React)}(this,function(e,t){"use strict";var i=[1,2],n="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const r="dt:media-selected",o=()=>{};let s=0,u=!1;function d(e){e&&e.querySelectorAll("source").forEach(e=>{const t=e.getAttribute("srcset");t&&(e.setAttribute("data-srcset",t),e.removeAttribute("srcset"),requestAnimationFrame(()=>{e.setAttribute("srcset",t)}))})}const l="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let c;const a=e=>e??c??(()=>{var e,t,i;if("undefined"==typeof globalThis)return;const n=globalThis;return(null==(e=n.PageSpeedImgDefaults)?void 0:e.optixFlowConfig)||(null==(t=n.OpensiteImgDefaults)?void 0:t.optixFlowConfig)||(null==(i=n.PAGE_SPEED_IMG_DEFAULTS)?void 0:i.optixFlowConfig)})(),f=e=>{if(""!==e&&null!=e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e){const t=Number(e);if(Number.isFinite(t))return t}}},g=({sizes:e,loading:c,decoding:g,alt:h,title:p,src:w,eager:m,width:v,height:b,fetchPriority:y,intersectionMargin:E,intersectionThreshold:M,optixFlowConfig:A,useDebugMode:I,forwardedRef:S,...L})=>{const j=t.useRef(null),x=t.useRef(null);var F;F=x,t.useEffect(()=>{const e=F.current;e&&(e instanceof HTMLPictureElement?d(e):e.parentElement instanceof HTMLPictureElement&&d(e.parentElement))},[F]),t.useEffect(()=>{if("undefined"!=typeof window)return u||(window.addEventListener(r,o),u=!0),s+=1,()=>{s-=1,s<=0&&u&&(window.removeEventListener(r,o),u=!1)}},[]);const P=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),z=t.useMemo(()=>f(v),[v]),V=t.useMemo(()=>f(b),[b]),R=t.useMemo(()=>a(A),[A]),T=t.useMemo(()=>m??"eager"===c,[m,c]),C=t.useMemo(()=>({src:P,eager:T,width:z,height:V,rootMargin:E??"200px",threshold:M??.1,optixFlowConfig:R}),[P,T,z,V,E,M,R]),{ref:N,src:O,srcset:D,sizes:q,loading:_,isInView:k,size:H}=function(e){const{src:r,eager:o=!1,threshold:s=.1,rootMargin:u="50px",width:d,height:l,optixFlowConfig:c}=e,a=t.useMemo(()=>null==c?void 0:c.apiKey,[null==c?void 0:c.apiKey]),f=t.useMemo(()=>!!a,[a]),[g,h]=t.useState({isLoaded:!1,isInView:!1}),[p,w]=t.useState({width:0,height:0}),m=t.useRef(null),v=t.useRef(null),b=t.useMemo(()=>({width:d??p.width,height:l??p.height}),[d,l,p.width,p.height]);n(()=>{if(!m.current)return;if(void 0!==d&&void 0!==l)return;const e=()=>{const e=m.current;if(!e)return;const t=d??(Math.round(e.clientWidth)||e.naturalWidth||0),i=l??(Math.round(e.clientHeight)||e.naturalHeight||0);(t>0||i>0)&&w(e=>e.width!==t||e.height!==i?{width:t,height:i}:e)};m.current.clientWidth>0&&e();const t=m.current;t.addEventListener("load",e);let i=null;return"undefined"!=typeof ResizeObserver&&(i=new ResizeObserver(()=>{e()}),i.observe(t)),()=>{t.removeEventListener("load",e),null==i||i.disconnect()}},[d,l]);const y=t.useCallback((e,t,i)=>{if(!f)return r;if(!e||!t)return r;const n=new URLSearchParams;return n.set("url",r),n.set("fit",String((null==c?void 0:c.objectFit)??"cover")),n.set("w",String(e)),n.set("h",String(t)),n.set("q",String((null==c?void 0:c.compressionLevel)??75)),n.set("f",i),n.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${n.toString()}`},[f,r,null==c?void 0:c.compressionLevel,a,null==c?void 0:c.objectFit]),E=t.useCallback((e,t,n)=>f&&0!==e&&0!==t?i.map(i=>{const r=Math.round(e*i),o=Math.round(t*i);return`${y(r,o,n)} ${i}x`}).join(", "):"",[f,y]),M=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return r;const t=(null==c?void 0:c.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,r,b.width,b.height,null==c?void 0:c.renderedFileType,null==c?void 0:c.compressionLevel,null==c?void 0:c.objectFit,y]),A=t.useMemo(()=>({avif:E(b.width,b.height,"avif"),webp:E(b.width,b.height,"webp"),jpeg:E(b.width,b.height,"jpeg")}),[b.width,b.height,E]),I=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&m.current){if(!o)return v.current=new IntersectionObserver(([e])=>{var t;e.isIntersecting&&(h(e=>({...e,isInView:!0})),null==(t=v.current)||t.disconnect())},{threshold:s,rootMargin:u}),v.current.observe(m.current),()=>{var e;null==(e=v.current)||e.disconnect()};h({isLoaded:!1,isInView:!0})}},[o,s,u]),t.useEffect(()=>{if(!m.current)return;const e=()=>{h(e=>({...e,isLoaded:!0}))},t=m.current;if(!t.complete)return t.addEventListener("load",e),()=>t.removeEventListener("load",e);e()},[g.isInView]),{ref:t.useCallback(e=>{m.current=e},[]),src:g.isInView||o?M:r,srcset:g.isInView||o?A:{avif:"",webp:"",jpeg:""},sizes:g.isInView||o?I:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:o?"eager":"lazy",size:b}}(C),$=((e,i,n)=>t.useCallback(t=>{e(t),n.current=t,"function"==typeof i?i(t):i&&"object"==typeof i&&(i.current=t)},[e,i,n]))(N,S,j),B=t.useMemo(()=>e??(q||void 0),[e,q]),G=t.useMemo(()=>c??_??"lazy",[c,_]),K=t.useMemo(()=>g??"async",[g]),U=t.useMemo(()=>y??(T?"high":void 0),[y,T]),W=t.useMemo(()=>Boolean(D.avif||D.webp||D.jpeg),[D.avif,D.webp,D.jpeg]),Q=t.useMemo(()=>O||P||l,[O,P]),J=t.useMemo(()=>!W||D.avif||D.webp?"":D.jpeg,[W,D.avif,D.webp,D.jpeg]),X=t.useMemo(()=>z??(H.width||void 0),[z,null==H?void 0:H.width]),Y=t.useMemo(()=>V??(H.height||void 0),[V,null==H?void 0:H.height]);return function({enabled:e,eagerLoad:i,isInView:n,imgSrc:r,transparentPixel:o,srcset:s,sizesAttr:u}){const d=t.useRef(null);t.useEffect(()=>{if(!e)return;if("undefined"==typeof window)return;if(!i&&!n)return;if(!r||r===o)return;const t=[r,s.avif,s.webp,s.jpeg,u??""].join("|");d.current!==t&&(d.current=t,"undefined"!=typeof console&&console.info&&console.info("[PageSpeedImg] image request",{src:r,srcset:s,sizes:u}))},[e,i,r,n,u,s.avif,s.webp,s.jpeg,o])}({enabled:I??!1,eagerLoad:T,isInView:k,imgSrc:Q,transparentPixel:l,srcset:D,sizesAttr:B}),W?t.createElement("picture",{ref:x},D.avif?t.createElement("source",{type:"image/avif",srcSet:D.avif,sizes:B}):null,D.webp?t.createElement("source",{type:"image/webp",srcSet:D.webp,sizes:B}):null,t.createElement("img",{ref:$,src:Q,srcSet:J||void 0,sizes:J?B:void 0,loading:G,decoding:K,fetchPriority:U,alt:h,title:p,width:X,height:Y,...L})):t.createElement("img",{ref:$,src:Q,loading:G,decoding:K,fetchPriority:U,alt:h,title:p,width:X,height:Y,...L})},h=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(g,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),p=t.memo(h);p.displayName="PageSpeedImg";const w="undefined"!=typeof globalThis?globalThis:void 0;if(w)if(w.process){const e=w.process.env??(w.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else w.process={env:{NODE_ENV:"production"}};e.Img=p,e.setDefaultOptixFlowConfig=e=>{c=e??void 0},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
2
2
  //# sourceMappingURL=page-speed-img.umd.js.map
@@ -1,2 +1,2 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).PageSpeedImg={},e.React)}(this,function(e,t){"use strict";var i=[1,2],n="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const r="dt:media-selected",o=()=>{};let s=0,d=!1;function l(e){e&&e.querySelectorAll("source").forEach(e=>{const t=e.getAttribute("srcset");t&&(e.setAttribute("data-srcset",t),e.removeAttribute("srcset"),requestAnimationFrame(()=>{e.setAttribute("srcset",t)}))})}const u="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let c;const a=e=>e??c??(()=>{var e,t,i;if("undefined"==typeof globalThis)return;const n=globalThis;return(null==(e=n.PageSpeedImgDefaults)?void 0:e.optixFlowConfig)||(null==(t=n.OpensiteImgDefaults)?void 0:t.optixFlowConfig)||(null==(i=n.PAGE_SPEED_IMG_DEFAULTS)?void 0:i.optixFlowConfig)})(),f=e=>{if(""!==e&&null!=e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e){const t=Number(e);if(Number.isFinite(t))return t}}},g=({sizes:e,loading:c,decoding:g,alt:h,title:p,src:w,eager:v,intersectionMargin:m,intersectionThreshold:b,optixFlowConfig:y,forwardedRef:E,...A})=>{const M=t.useRef(null),I=t.useRef(null),S=t.useRef(null);var L;L=I,t.useEffect(()=>{const e=L.current;e&&(e instanceof HTMLPictureElement?l(e):e.parentElement instanceof HTMLPictureElement&&l(e.parentElement))},[L]),t.useEffect(()=>{if("undefined"!=typeof window)return d||(window.addEventListener(r,o),d=!0),s+=1,()=>{s-=1,s<=0&&d&&(window.removeEventListener(r,o),d=!1)}},[]);const j=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),F=t.useMemo(()=>f(A.width),[A]),x=t.useMemo(()=>f(A.height),[A]),z=t.useMemo(()=>a(y),[y]),R=v??"eager"===c,{ref:T,src:V,srcset:C,sizes:N,loading:O,isInView:P,size:D}=function(e){const{src:r,eager:o=!1,threshold:s=.1,rootMargin:d="50px",width:l,height:u,optixFlowConfig:c}=e,a=t.useMemo(()=>null==c?void 0:c.apiKey,[null==c?void 0:c.apiKey]),f=t.useMemo(()=>!!a,[a]),[g,h]=t.useState({isLoaded:!1,isInView:!1}),[p,w]=t.useState({width:0,height:0}),v=t.useRef(null),m=t.useRef(null),b=t.useMemo(()=>({width:l??p.width,height:u??p.height}),[l,u,p.width,p.height]);n(()=>{if(!v.current)return;if(void 0!==l&&void 0!==u)return;const e=()=>{const e=v.current;if(!e)return;const t=l??(Math.round(e.clientWidth)||e.naturalWidth||0),i=u??(Math.round(e.clientHeight)||e.naturalHeight||0);(t>0||i>0)&&w(e=>e.width!==t||e.height!==i?{width:t,height:i}:e)};v.current.clientWidth>0&&e();const t=v.current;t.addEventListener("load",e);let i=null;return"undefined"!=typeof ResizeObserver&&(i=new ResizeObserver(()=>{e()}),i.observe(t)),()=>{t.removeEventListener("load",e),null==i||i.disconnect()}},[l,u]);const y=t.useCallback((e,t,i)=>{if(!f)return r;if(!e||!t)return r;const n=new URLSearchParams;return n.set("url",r),n.set("fit",String((null==c?void 0:c.objectFit)??"cover")),n.set("w",String(e)),n.set("h",String(t)),n.set("q",String((null==c?void 0:c.compressionLevel)??75)),n.set("f",i),n.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${n.toString()}`},[f,r,null==c?void 0:c.compressionLevel,a,null==c?void 0:c.objectFit]),E=t.useCallback((e,t,n)=>f&&0!==e&&0!==t?i.map(i=>{const r=Math.round(e*i),o=Math.round(t*i);return`${y(r,o,n)} ${i}x`}).join(", "):"",[f,y]),A=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return r;const t=(null==c?void 0:c.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,r,b.width,b.height,null==c?void 0:c.renderedFileType,null==c?void 0:c.compressionLevel,null==c?void 0:c.objectFit,y]),M=t.useMemo(()=>({avif:E(b.width,b.height,"avif"),webp:E(b.width,b.height,"webp"),jpeg:E(b.width,b.height,"jpeg")}),[b.width,b.height,E]),I=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&v.current){if(!o)return m.current=new IntersectionObserver(([e])=>{var t;e.isIntersecting&&(h(e=>({...e,isInView:!0})),null==(t=m.current)||t.disconnect())},{threshold:s,rootMargin:d}),m.current.observe(v.current),()=>{var e;null==(e=m.current)||e.disconnect()};h({isLoaded:!1,isInView:!0})}},[o,s,d]),t.useEffect(()=>{if(!v.current)return;const e=()=>{h(e=>({...e,isLoaded:!0}))},t=v.current;if(!t.complete)return t.addEventListener("load",e),()=>t.removeEventListener("load",e);e()},[g.isInView]),{ref:t.useCallback(e=>{v.current=e},[]),src:g.isInView||o?A:r,srcset:g.isInView||o?M:{avif:"",webp:"",jpeg:""},sizes:g.isInView||o?I:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:o?"eager":"lazy",size:b}}({src:j,eager:R,width:F,height:x,rootMargin:m??"200px",threshold:b??.1,optixFlowConfig:z}),q=((e,i,n)=>t.useCallback(t=>{e(t),n.current=t,"function"==typeof i?i(t):i&&"object"==typeof i&&(i.current=t)},[e,i,n]))(T,E,M),{width:_,height:k,...H}=A,$=e??(N||void 0),B=c??O??"lazy",G=g??"async",K=Boolean(C.avif||C.webp||C.jpeg),U=V||j||u,W=!K||C.avif||C.webp?"":C.jpeg,Q=f(_),J=f(k),X=Q??(D.width||F||void 0),Y=J??(D.height||x||void 0);return t.useEffect(()=>{if("undefined"==typeof window)return;if(!R&&!P)return;if(U===u)return;const e=[U,C.avif,C.webp,C.jpeg,$??""].join("|");S.current!==e&&(S.current=e,"undefined"!=typeof console&&console.info&&console.info("[PageSpeedImg] image request",{src:U,srcset:C,sizes:$}))},[R,U,P,$,C.avif,C.webp,C.jpeg]),K?t.createElement("picture",{ref:I},C.avif?t.createElement("source",{type:"image/avif",srcSet:C.avif,sizes:$}):null,C.webp?t.createElement("source",{type:"image/webp",srcSet:C.webp,sizes:$}):null,t.createElement("img",{ref:q,src:U,srcSet:W||void 0,sizes:W?$:void 0,loading:B,decoding:G,alt:h,title:p,width:X,height:Y,...H})):t.createElement("img",{ref:q,src:U,loading:B,decoding:G,alt:h,title:p,width:X,height:Y,...H})},h=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(g,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),p=t.memo(h);p.displayName="PageSpeedImg";const w="undefined"!=typeof globalThis?globalThis:void 0;if(w)if(w.process){const e=w.process.env??(w.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else w.process={env:{NODE_ENV:"production"}};e.Img=p,e.setDefaultOptixFlowConfig=e=>{c=e??void 0},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).PageSpeedImg={},e.React)}(this,function(e,t){"use strict";var i=[1,2],n="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const r="dt:media-selected",o=()=>{};let s=0,u=!1;function d(e){e&&e.querySelectorAll("source").forEach(e=>{const t=e.getAttribute("srcset");t&&(e.setAttribute("data-srcset",t),e.removeAttribute("srcset"),requestAnimationFrame(()=>{e.setAttribute("srcset",t)}))})}const l="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let c;const a=e=>e??c??(()=>{var e,t,i;if("undefined"==typeof globalThis)return;const n=globalThis;return(null==(e=n.PageSpeedImgDefaults)?void 0:e.optixFlowConfig)||(null==(t=n.OpensiteImgDefaults)?void 0:t.optixFlowConfig)||(null==(i=n.PAGE_SPEED_IMG_DEFAULTS)?void 0:i.optixFlowConfig)})(),f=e=>{if(""!==e&&null!=e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e){const t=Number(e);if(Number.isFinite(t))return t}}},g=({sizes:e,loading:c,decoding:g,alt:h,title:p,src:w,eager:m,width:v,height:b,fetchPriority:y,intersectionMargin:E,intersectionThreshold:M,optixFlowConfig:A,useDebugMode:I,forwardedRef:S,...L})=>{const j=t.useRef(null),x=t.useRef(null);var F;F=x,t.useEffect(()=>{const e=F.current;e&&(e instanceof HTMLPictureElement?d(e):e.parentElement instanceof HTMLPictureElement&&d(e.parentElement))},[F]),t.useEffect(()=>{if("undefined"!=typeof window)return u||(window.addEventListener(r,o),u=!0),s+=1,()=>{s-=1,s<=0&&u&&(window.removeEventListener(r,o),u=!1)}},[]);const P=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),z=t.useMemo(()=>f(v),[v]),V=t.useMemo(()=>f(b),[b]),R=t.useMemo(()=>a(A),[A]),T=t.useMemo(()=>m??"eager"===c,[m,c]),C=t.useMemo(()=>({src:P,eager:T,width:z,height:V,rootMargin:E??"200px",threshold:M??.1,optixFlowConfig:R}),[P,T,z,V,E,M,R]),{ref:N,src:O,srcset:D,sizes:q,loading:_,isInView:k,size:H}=function(e){const{src:r,eager:o=!1,threshold:s=.1,rootMargin:u="50px",width:d,height:l,optixFlowConfig:c}=e,a=t.useMemo(()=>null==c?void 0:c.apiKey,[null==c?void 0:c.apiKey]),f=t.useMemo(()=>!!a,[a]),[g,h]=t.useState({isLoaded:!1,isInView:!1}),[p,w]=t.useState({width:0,height:0}),m=t.useRef(null),v=t.useRef(null),b=t.useMemo(()=>({width:d??p.width,height:l??p.height}),[d,l,p.width,p.height]);n(()=>{if(!m.current)return;if(void 0!==d&&void 0!==l)return;const e=()=>{const e=m.current;if(!e)return;const t=d??(Math.round(e.clientWidth)||e.naturalWidth||0),i=l??(Math.round(e.clientHeight)||e.naturalHeight||0);(t>0||i>0)&&w(e=>e.width!==t||e.height!==i?{width:t,height:i}:e)};m.current.clientWidth>0&&e();const t=m.current;t.addEventListener("load",e);let i=null;return"undefined"!=typeof ResizeObserver&&(i=new ResizeObserver(()=>{e()}),i.observe(t)),()=>{t.removeEventListener("load",e),null==i||i.disconnect()}},[d,l]);const y=t.useCallback((e,t,i)=>{if(!f)return r;if(!e||!t)return r;const n=new URLSearchParams;return n.set("url",r),n.set("fit",String((null==c?void 0:c.objectFit)??"cover")),n.set("w",String(e)),n.set("h",String(t)),n.set("q",String((null==c?void 0:c.compressionLevel)??75)),n.set("f",i),n.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${n.toString()}`},[f,r,null==c?void 0:c.compressionLevel,a,null==c?void 0:c.objectFit]),E=t.useCallback((e,t,n)=>f&&0!==e&&0!==t?i.map(i=>{const r=Math.round(e*i),o=Math.round(t*i);return`${y(r,o,n)} ${i}x`}).join(", "):"",[f,y]),M=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return r;const t=(null==c?void 0:c.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,r,b.width,b.height,null==c?void 0:c.renderedFileType,null==c?void 0:c.compressionLevel,null==c?void 0:c.objectFit,y]),A=t.useMemo(()=>({avif:E(b.width,b.height,"avif"),webp:E(b.width,b.height,"webp"),jpeg:E(b.width,b.height,"jpeg")}),[b.width,b.height,E]),I=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&m.current){if(!o)return v.current=new IntersectionObserver(([e])=>{var t;e.isIntersecting&&(h(e=>({...e,isInView:!0})),null==(t=v.current)||t.disconnect())},{threshold:s,rootMargin:u}),v.current.observe(m.current),()=>{var e;null==(e=v.current)||e.disconnect()};h({isLoaded:!1,isInView:!0})}},[o,s,u]),t.useEffect(()=>{if(!m.current)return;const e=()=>{h(e=>({...e,isLoaded:!0}))},t=m.current;if(!t.complete)return t.addEventListener("load",e),()=>t.removeEventListener("load",e);e()},[g.isInView]),{ref:t.useCallback(e=>{m.current=e},[]),src:g.isInView||o?M:r,srcset:g.isInView||o?A:{avif:"",webp:"",jpeg:""},sizes:g.isInView||o?I:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:o?"eager":"lazy",size:b}}(C),$=((e,i,n)=>t.useCallback(t=>{e(t),n.current=t,"function"==typeof i?i(t):i&&"object"==typeof i&&(i.current=t)},[e,i,n]))(N,S,j),B=t.useMemo(()=>e??(q||void 0),[e,q]),G=t.useMemo(()=>c??_??"lazy",[c,_]),K=t.useMemo(()=>g??"async",[g]),U=t.useMemo(()=>y??(T?"high":void 0),[y,T]),W=t.useMemo(()=>Boolean(D.avif||D.webp||D.jpeg),[D.avif,D.webp,D.jpeg]),Q=t.useMemo(()=>O||P||l,[O,P]),J=t.useMemo(()=>!W||D.avif||D.webp?"":D.jpeg,[W,D.avif,D.webp,D.jpeg]),X=t.useMemo(()=>z??(H.width||void 0),[z,null==H?void 0:H.width]),Y=t.useMemo(()=>V??(H.height||void 0),[V,null==H?void 0:H.height]);return function({enabled:e,eagerLoad:i,isInView:n,imgSrc:r,transparentPixel:o,srcset:s,sizesAttr:u}){const d=t.useRef(null);t.useEffect(()=>{if(!e)return;if("undefined"==typeof window)return;if(!i&&!n)return;if(!r||r===o)return;const t=[r,s.avif,s.webp,s.jpeg,u??""].join("|");d.current!==t&&(d.current=t,"undefined"!=typeof console&&console.info&&console.info("[PageSpeedImg] image request",{src:r,srcset:s,sizes:u}))},[e,i,r,n,u,s.avif,s.webp,s.jpeg,o])}({enabled:I??!1,eagerLoad:T,isInView:k,imgSrc:Q,transparentPixel:l,srcset:D,sizesAttr:B}),W?t.createElement("picture",{ref:x},D.avif?t.createElement("source",{type:"image/avif",srcSet:D.avif,sizes:B}):null,D.webp?t.createElement("source",{type:"image/webp",srcSet:D.webp,sizes:B}):null,t.createElement("img",{ref:$,src:Q,srcSet:J||void 0,sizes:J?B:void 0,loading:G,decoding:K,fetchPriority:U,alt:h,title:p,width:X,height:Y,...L})):t.createElement("img",{ref:$,src:Q,loading:G,decoding:K,fetchPriority:U,alt:h,title:p,width:X,height:Y,...L})},h=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(g,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),p=t.memo(h);p.displayName="PageSpeedImg";const w="undefined"!=typeof globalThis?globalThis:void 0;if(w)if(w.process){const e=w.process.env??(w.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else w.process={env:{NODE_ENV:"production"}};e.Img=p,e.setDefaultOptixFlowConfig=e=>{c=e??void 0},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
2
2
  //# sourceMappingURL=page-speed-img.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-speed-img.umd.js","sources":["../../node_modules/.pnpm/@page-speed+hooks@0.4.5_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@page-speed/hooks/dist/chunk-ZTHTGLZO.js","../../src/core/useMediaSelectionEffect.ts","../../src/core/useResponsiveReset.ts","../../src/core/Img.tsx","../../src/index.ts"],"sourcesContent":["import { useMemo, useState, useRef, useLayoutEffect, useEffect, useCallback } from 'react';\n\nvar BASE_URL = \"https://octane.cdn.ing/api/v1/images/transform?\";\nvar DPR_MULTIPLIERS = [1, 2];\nvar useIsomorphicLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\nfunction useOptimizedImage(options) {\n const {\n src,\n eager = false,\n threshold = 0.1,\n rootMargin = \"50px\",\n width,\n height,\n optixFlowConfig\n } = options;\n const optixFlowApiKey = useMemo(() => {\n return optixFlowConfig?.apiKey;\n }, [optixFlowConfig?.apiKey]);\n const useOptixFlow = useMemo(() => {\n return optixFlowApiKey ? true : false;\n }, [optixFlowApiKey]);\n const [state, setState] = useState({\n isLoaded: false,\n isInView: false\n });\n const [measuredSize, setMeasuredSize] = useState({\n width: 0,\n height: 0\n });\n const imgRef = useRef(null);\n const observerRef = useRef(null);\n const size = useMemo(\n () => ({\n width: width ?? measuredSize.width,\n height: height ?? measuredSize.height\n }),\n [width, height, measuredSize.width, measuredSize.height]\n );\n useIsomorphicLayoutEffect(() => {\n if (!imgRef.current) return;\n if (width !== void 0 && height !== void 0) return;\n const calculateRenderedSize = () => {\n const img2 = imgRef.current;\n if (!img2) return;\n const renderedWidth = width ?? (Math.round(img2.clientWidth) || img2.naturalWidth || 0);\n const renderedHeight = height ?? (Math.round(img2.clientHeight) || img2.naturalHeight || 0);\n if (renderedWidth > 0 || renderedHeight > 0) {\n setMeasuredSize((prev) => {\n if (prev.width !== renderedWidth || prev.height !== renderedHeight) {\n return { width: renderedWidth, height: renderedHeight };\n }\n return prev;\n });\n }\n };\n if (imgRef.current.clientWidth > 0) {\n calculateRenderedSize();\n }\n const img = imgRef.current;\n img.addEventListener(\"load\", calculateRenderedSize);\n let resizeObserver = null;\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(() => {\n calculateRenderedSize();\n });\n resizeObserver.observe(img);\n }\n return () => {\n img.removeEventListener(\"load\", calculateRenderedSize);\n resizeObserver?.disconnect();\n };\n }, [width, height]);\n const buildOptixFlowUrl = useCallback(\n (imgWidth, imgHeight, format) => {\n if (!useOptixFlow) return src;\n if (!imgWidth || !imgHeight) return src;\n const params = new URLSearchParams();\n params.set(\"url\", src);\n params.set(\"fit\", String(optixFlowConfig?.objectFit ?? \"cover\"));\n params.set(\"w\", String(imgWidth));\n params.set(\"h\", String(imgHeight));\n params.set(\"q\", String(optixFlowConfig?.compressionLevel ?? 75));\n params.set(\"f\", format);\n params.set(\"apiKey\", optixFlowApiKey);\n return `${BASE_URL}${params.toString()}`;\n },\n [\n useOptixFlow,\n src,\n optixFlowConfig?.compressionLevel,\n optixFlowApiKey,\n optixFlowConfig?.objectFit\n ]\n );\n const generateSrcset = useCallback(\n (baseWidth, baseHeight, format) => {\n if (!useOptixFlow || baseWidth === 0 || baseHeight === 0) return \"\";\n return DPR_MULTIPLIERS.map((dpr) => {\n const scaledWidth = Math.round(baseWidth * dpr);\n const scaledHeight = Math.round(baseHeight * dpr);\n const url = buildOptixFlowUrl(scaledWidth, scaledHeight, format);\n return `${url} ${dpr}x`;\n }).join(\", \");\n },\n [useOptixFlow, buildOptixFlowUrl]\n );\n const primarySrc = useMemo(() => {\n const hasDimensions = size.width > 0 && size.height > 0;\n if (!useOptixFlow || !hasDimensions) return src;\n const fallbackFormat = optixFlowConfig?.renderedFileType ?? \"jpeg\";\n return buildOptixFlowUrl(size.width, size.height, fallbackFormat);\n }, [\n useOptixFlow,\n src,\n size.width,\n size.height,\n optixFlowConfig?.renderedFileType,\n optixFlowConfig?.compressionLevel,\n optixFlowConfig?.objectFit,\n buildOptixFlowUrl\n ]);\n const srcset = useMemo(() => {\n return {\n avif: generateSrcset(size.width, size.height, \"avif\"),\n webp: generateSrcset(size.width, size.height, \"webp\"),\n jpeg: generateSrcset(size.width, size.height, \"jpeg\")\n };\n }, [size.width, size.height, generateSrcset]);\n const sizes = useMemo(() => {\n if (size.width === 0) return \"\";\n return `${size.width}px`;\n }, [size.width]);\n useEffect(() => {\n if (typeof window === \"undefined\" || !imgRef.current) {\n return;\n }\n if (eager) {\n setState({ isLoaded: false, isInView: true });\n return;\n }\n observerRef.current = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setState((prev) => ({ ...prev, isInView: true }));\n observerRef.current?.disconnect();\n }\n },\n { threshold, rootMargin }\n );\n observerRef.current.observe(imgRef.current);\n return () => {\n observerRef.current?.disconnect();\n };\n }, [eager, threshold, rootMargin]);\n useEffect(() => {\n if (!imgRef.current) return;\n const handleLoad = () => {\n setState((prev) => ({ ...prev, isLoaded: true }));\n };\n const img = imgRef.current;\n if (img.complete) {\n handleLoad();\n } else {\n img.addEventListener(\"load\", handleLoad);\n return () => img.removeEventListener(\"load\", handleLoad);\n }\n }, [state.isInView]);\n const ref = useCallback((node) => {\n imgRef.current = node;\n }, []);\n const emptySrcset = { avif: \"\", webp: \"\", jpeg: \"\" };\n return {\n ref,\n // Primary src uses exact rendered dimensions for Lighthouse \"Properly size images\" compliance\n src: state.isInView || eager ? primarySrc : src,\n // Srcset with format variants and DPR multipliers for <picture> element\n srcset: state.isInView || eager ? srcset : emptySrcset,\n // Sizes attribute for responsive image selection\n sizes: state.isInView || eager ? sizes : \"\",\n isLoaded: state.isLoaded,\n isInView: state.isInView,\n loading: eager ? \"eager\" : \"lazy\",\n size\n };\n}\n\nexport { useOptimizedImage };\n//# sourceMappingURL=chunk-ZTHTGLZO.js.map\n//# sourceMappingURL=chunk-ZTHTGLZO.js.map","import { useEffect } from 'react';\n\nconst MEDIA_SELECTED_EVENT = 'dt:media-selected';\nconst mediaSelectionHandler = () => {\n // no-op: the real handler is attached in the builder via addEventListener\n};\n\nlet mediaSelectionListenerCount = 0;\nlet isMediaSelectionListenerAttached = false;\n\nexport function sendMediaSelection(blockId: string, payload: unknown) {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(\n new CustomEvent(MEDIA_SELECTED_EVENT, {\n detail: { blockId, payload },\n })\n );\n}\n\nexport function useMediaSelectionEffect() {\n useEffect(() => {\n if (typeof window === 'undefined') return;\n if (!isMediaSelectionListenerAttached) {\n window.addEventListener(MEDIA_SELECTED_EVENT, mediaSelectionHandler);\n isMediaSelectionListenerAttached = true;\n }\n mediaSelectionListenerCount += 1;\n\n return () => {\n mediaSelectionListenerCount -= 1;\n if (mediaSelectionListenerCount <= 0 && isMediaSelectionListenerAttached) {\n window.removeEventListener(MEDIA_SELECTED_EVENT, mediaSelectionHandler);\n isMediaSelectionListenerAttached = false;\n }\n };\n }, []);\n}\n","import { useEffect } from 'react';\n\nexport function resetResponsivePictureState(element: HTMLPictureElement | null) {\n if (!element) return;\n element.querySelectorAll('source').forEach((source) => {\n // force browser to reconsider responsive sources\n const srcset = source.getAttribute('srcset');\n if (srcset) {\n source.setAttribute('data-srcset', srcset);\n source.removeAttribute('srcset');\n requestAnimationFrame(() => {\n source.setAttribute('srcset', srcset);\n });\n }\n });\n}\n\nexport function useResponsiveReset(ref: React.RefObject<HTMLPictureElement | HTMLImageElement>) {\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n if (element instanceof HTMLPictureElement) {\n resetResponsivePictureState(element);\n } else if (element.parentElement instanceof HTMLPictureElement) {\n resetResponsivePictureState(element.parentElement);\n }\n }, [ref]);\n}\n\n","\"use client\";\n\nimport React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useOptimizedImage } from \"@page-speed/hooks/media\";\nimport type { UseOptimizedImageOptions } from \"@page-speed/hooks/media\";\nimport { useMediaSelectionEffect } from \"./useMediaSelectionEffect.js\";\nimport { useResponsiveReset } from \"./useResponsiveReset.js\";\n\ntype NativeImgProps = Omit<\n React.ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"srcSet\" | \"sizes\"\n> & {\n src?: string;\n};\n\nexport type ImgProps = NativeImgProps & {\n /** Explicit sizes attribute (otherwise derived from useOptimizedImage) */\n sizes?: string;\n /** Force eager load (alias for loading=\"eager\") */\n eager?: boolean;\n /** Intersection observer threshold for lazy loading */\n intersectionThreshold?: number;\n /** Intersection observer root margin for lazy loading */\n intersectionMargin?: string;\n /** OptixFlow integration options */\n optixFlowConfig?: UseOptimizedImageOptions[\"optixFlowConfig\"];\n};\n\ntype ForwardedImgProps = ImgProps & {\n forwardedRef: React.Ref<HTMLImageElement | null>;\n};\n\nconst TRANSPARENT_PIXEL =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==\";\n\nlet defaultOptixFlowConfig:\n | UseOptimizedImageOptions[\"optixFlowConfig\"]\n | undefined;\n\nconst readGlobalOptixFlowConfig = ():\n | UseOptimizedImageOptions[\"optixFlowConfig\"]\n | undefined => {\n if (typeof globalThis === \"undefined\") return undefined;\n const globalAny = globalThis as any;\n return (\n globalAny.PageSpeedImgDefaults?.optixFlowConfig ||\n globalAny.OpensiteImgDefaults?.optixFlowConfig ||\n globalAny.PAGE_SPEED_IMG_DEFAULTS?.optixFlowConfig\n );\n};\n\nconst resolveOptixFlowConfig = (\n config?: UseOptimizedImageOptions[\"optixFlowConfig\"],\n): UseOptimizedImageOptions[\"optixFlowConfig\"] | undefined => {\n return config ?? defaultOptixFlowConfig ?? readGlobalOptixFlowConfig();\n};\n\nexport const setDefaultOptixFlowConfig = (\n config?: UseOptimizedImageOptions[\"optixFlowConfig\"] | null,\n) => {\n defaultOptixFlowConfig = config ?? undefined;\n};\n\nconst isUrlString = (value: unknown): value is string =>\n typeof value === \"string\" && value.trim().length > 0;\n\nconst parseDimension = (value: unknown): number | undefined => {\n if (value === \"\" || value === null || typeof value === \"undefined\")\n return undefined;\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\") {\n const numeric = Number(value);\n if (Number.isFinite(numeric)) return numeric;\n }\n return undefined;\n};\n\nconst composeRefs = (\n hookRef: (node: HTMLImageElement | null) => void,\n forwardedRef: React.Ref<HTMLImageElement | null>,\n localRef: React.RefObject<HTMLImageElement>,\n) =>\n useCallback(\n (node: HTMLImageElement | null) => {\n hookRef(node);\n // eslint-disable-next-line no-param-reassign\n (localRef as any).current = node;\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef && typeof (forwardedRef as any) === \"object\") {\n (forwardedRef as any).current = node;\n }\n },\n [hookRef, forwardedRef, localRef],\n );\n\nconst ModernImg: React.FC<ForwardedImgProps> = ({\n sizes,\n loading,\n decoding,\n alt,\n title,\n src: directSrc,\n eager,\n intersectionMargin,\n intersectionThreshold,\n optixFlowConfig,\n forwardedRef,\n ...rest\n}) => {\n const imgRef = useRef<HTMLImageElement | null>(null);\n const pictureRef = useRef<HTMLPictureElement | null>(null);\n const logKeyRef = useRef<string | null>(null);\n\n useResponsiveReset(pictureRef);\n useMediaSelectionEffect();\n\n const normalizedSrc = useMemo(\n () => (typeof directSrc === \"string\" ? directSrc.trim() : \"\"),\n [directSrc],\n );\n const numericWidth = useMemo(\n () => parseDimension((rest as any).width),\n [rest],\n );\n const numericHeight = useMemo(\n () => parseDimension((rest as any).height),\n [rest],\n );\n const resolvedOptixConfig = useMemo(\n () => resolveOptixFlowConfig(optixFlowConfig),\n [optixFlowConfig],\n );\n const eagerLoad = eager ?? loading === \"eager\";\n\n const {\n ref: hookRef,\n src,\n srcset,\n sizes: computedSizes,\n loading: hookLoading,\n isInView,\n size,\n } = useOptimizedImage({\n src: normalizedSrc,\n eager: eagerLoad,\n width: numericWidth,\n height: numericHeight,\n rootMargin: intersectionMargin ?? \"200px\",\n threshold: intersectionThreshold ?? 0.1,\n optixFlowConfig: resolvedOptixConfig,\n });\n\n const mergedRef = composeRefs(hookRef, forwardedRef, imgRef);\n const { width, height, ...restProps } = rest as Record<string, unknown>;\n const sizesAttr = sizes ?? (computedSizes || undefined);\n const loadingAttr = loading ?? hookLoading ?? \"lazy\";\n const decodingAttr = decoding ?? \"async\";\n const hasSrcSet = Boolean(srcset.avif || srcset.webp || srcset.jpeg);\n const imgSrc = src || normalizedSrc || TRANSPARENT_PIXEL;\n const inlineSrcSet =\n hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : \"\";\n const parsedWidth = parseDimension(width);\n const parsedHeight = parseDimension(height);\n const widthAttr = parsedWidth ?? (size.width || numericWidth || undefined);\n const heightAttr =\n parsedHeight ?? (size.height || numericHeight || undefined);\n\n // Temporary logging to detect repeated transform requests and URL churn.\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!eagerLoad && !isInView) return;\n if (!imgSrc || imgSrc === TRANSPARENT_PIXEL) return;\n\n const logKey = [\n imgSrc,\n srcset.avif,\n srcset.webp,\n srcset.jpeg,\n sizesAttr ?? \"\",\n ].join(\"|\");\n\n if (logKeyRef.current === logKey) return;\n logKeyRef.current = logKey;\n\n if (typeof console !== \"undefined\" && console.info) {\n console.info(\"[PageSpeedImg] image request\", {\n src: imgSrc,\n srcset,\n sizes: sizesAttr,\n });\n }\n }, [\n eagerLoad,\n imgSrc,\n isInView,\n sizesAttr,\n srcset.avif,\n srcset.webp,\n srcset.jpeg,\n ]);\n\n if (!hasSrcSet) {\n return (\n <img\n ref={mergedRef}\n src={imgSrc}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={alt}\n title={title}\n width={widthAttr}\n height={heightAttr}\n {...restProps}\n />\n );\n }\n\n return (\n <picture ref={pictureRef}>\n {srcset.avif ? (\n <source type=\"image/avif\" srcSet={srcset.avif} sizes={sizesAttr} />\n ) : null}\n {srcset.webp ? (\n <source type=\"image/webp\" srcSet={srcset.webp} sizes={sizesAttr} />\n ) : null}\n <img\n ref={mergedRef}\n src={imgSrc}\n srcSet={inlineSrcSet || undefined}\n sizes={inlineSrcSet ? sizesAttr : undefined}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={alt}\n title={title}\n width={widthAttr}\n height={heightAttr}\n {...restProps}\n />\n </picture>\n );\n};\n\nconst ImgBase = forwardRef<HTMLImageElement, ImgProps>(\n function Img(props, ref) {\n const hasSrc = typeof props.src === \"string\" && props.src.trim().length > 0;\n if (!hasSrc) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\"<Img /> requires src. No src provided, rendering null.\");\n }\n return null;\n }\n\n return <ModernImg {...props} forwardedRef={ref} />;\n },\n);\n\nexport const Img = memo(ImgBase);\nImg.displayName = \"PageSpeedImg\";\n","// Ensure process.env exists when the module is loaded directly in the browser UMD build.\ntype GlobalWithProcess = typeof globalThis & { process?: NodeJS.Process };\n\nconst globalObject =\n typeof globalThis !== 'undefined' ? (globalThis as GlobalWithProcess) : undefined;\n\nif (globalObject) {\n if (!globalObject.process) {\n globalObject.process = {\n env: { NODE_ENV: 'production' } as NodeJS.ProcessEnv,\n } as NodeJS.Process;\n } else {\n const env = globalObject.process.env ?? (globalObject.process.env = {} as NodeJS.ProcessEnv);\n if (typeof env.NODE_ENV === 'undefined') {\n env.NODE_ENV = 'production';\n }\n }\n}\n\nimport type { UseOptimizedImageOptions } from '@page-speed/hooks/media';\n\nexport * from './core/index.js';\nexport type {\n ImageFormat,\n SrcsetByFormat,\n UseOptimizedImageOptions,\n UseOptimizedImageState,\n} from '@page-speed/hooks/media';\nexport type OptixFlowConfig = UseOptimizedImageOptions['optixFlowConfig'];\n"],"names":["DPR_MULTIPLIERS","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","MEDIA_SELECTED_EVENT","mediaSelectionHandler","mediaSelectionListenerCount","isMediaSelectionListenerAttached","resetResponsivePictureState","element","querySelectorAll","forEach","source","srcset","getAttribute","setAttribute","removeAttribute","requestAnimationFrame","TRANSPARENT_PIXEL","defaultOptixFlowConfig","resolveOptixFlowConfig","config","globalThis","globalAny","_a","PageSpeedImgDefaults","optixFlowConfig","_b","OpensiteImgDefaults","_c","PAGE_SPEED_IMG_DEFAULTS","readGlobalOptixFlowConfig","parseDimension","value","Number","isFinite","numeric","ModernImg","sizes","loading","decoding","alt","title","src","directSrc","eager","intersectionMargin","intersectionThreshold","forwardedRef","rest","imgRef","useRef","pictureRef","logKeyRef","ref","current","HTMLPictureElement","parentElement","addEventListener","removeEventListener","normalizedSrc","useMemo","trim","numericWidth","width","numericHeight","height","resolvedOptixConfig","eagerLoad","hookRef","computedSizes","hookLoading","isInView","size","options","threshold","rootMargin","optixFlowApiKey","apiKey","useOptixFlow","state","setState","useState","isLoaded","measuredSize","setMeasuredSize","observerRef","calculateRenderedSize","img2","renderedWidth","Math","round","clientWidth","naturalWidth","renderedHeight","clientHeight","naturalHeight","prev","img","resizeObserver","ResizeObserver","observe","disconnect","buildOptixFlowUrl","useCallback","imgWidth","imgHeight","format","params","URLSearchParams","set","String","objectFit","compressionLevel","toString","generateSrcset","baseWidth","baseHeight","map","dpr","scaledWidth","scaledHeight","join","primarySrc","hasDimensions","fallbackFormat","renderedFileType","avif","webp","jpeg","IntersectionObserver","entry","isIntersecting","handleLoad","complete","node","useOptimizedImage","mergedRef","localRef","composeRefs","restProps","sizesAttr","loadingAttr","decodingAttr","hasSrcSet","Boolean","imgSrc","inlineSrcSet","parsedWidth","parsedHeight","widthAttr","heightAttr","logKey","console","info","createElement","React","type","srcSet","ImgBase","forwardRef","props","length","warn","Img","memo","displayName","globalObject","process","env","NODE_ENV"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"page-speed-img.umd.js","sources":["../../node_modules/.pnpm/@page-speed+hooks@0.4.5_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@page-speed/hooks/dist/chunk-ZTHTGLZO.js","../../src/core/useMediaSelectionEffect.ts","../../src/core/useResponsiveReset.ts","../../src/core/Img.tsx","../../src/core/useImgDebugLog.ts","../../src/index.ts"],"sourcesContent":["import { useMemo, useState, useRef, useLayoutEffect, useEffect, useCallback } from 'react';\n\nvar BASE_URL = \"https://octane.cdn.ing/api/v1/images/transform?\";\nvar DPR_MULTIPLIERS = [1, 2];\nvar useIsomorphicLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\nfunction useOptimizedImage(options) {\n const {\n src,\n eager = false,\n threshold = 0.1,\n rootMargin = \"50px\",\n width,\n height,\n optixFlowConfig\n } = options;\n const optixFlowApiKey = useMemo(() => {\n return optixFlowConfig?.apiKey;\n }, [optixFlowConfig?.apiKey]);\n const useOptixFlow = useMemo(() => {\n return optixFlowApiKey ? true : false;\n }, [optixFlowApiKey]);\n const [state, setState] = useState({\n isLoaded: false,\n isInView: false\n });\n const [measuredSize, setMeasuredSize] = useState({\n width: 0,\n height: 0\n });\n const imgRef = useRef(null);\n const observerRef = useRef(null);\n const size = useMemo(\n () => ({\n width: width ?? measuredSize.width,\n height: height ?? measuredSize.height\n }),\n [width, height, measuredSize.width, measuredSize.height]\n );\n useIsomorphicLayoutEffect(() => {\n if (!imgRef.current) return;\n if (width !== void 0 && height !== void 0) return;\n const calculateRenderedSize = () => {\n const img2 = imgRef.current;\n if (!img2) return;\n const renderedWidth = width ?? (Math.round(img2.clientWidth) || img2.naturalWidth || 0);\n const renderedHeight = height ?? (Math.round(img2.clientHeight) || img2.naturalHeight || 0);\n if (renderedWidth > 0 || renderedHeight > 0) {\n setMeasuredSize((prev) => {\n if (prev.width !== renderedWidth || prev.height !== renderedHeight) {\n return { width: renderedWidth, height: renderedHeight };\n }\n return prev;\n });\n }\n };\n if (imgRef.current.clientWidth > 0) {\n calculateRenderedSize();\n }\n const img = imgRef.current;\n img.addEventListener(\"load\", calculateRenderedSize);\n let resizeObserver = null;\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(() => {\n calculateRenderedSize();\n });\n resizeObserver.observe(img);\n }\n return () => {\n img.removeEventListener(\"load\", calculateRenderedSize);\n resizeObserver?.disconnect();\n };\n }, [width, height]);\n const buildOptixFlowUrl = useCallback(\n (imgWidth, imgHeight, format) => {\n if (!useOptixFlow) return src;\n if (!imgWidth || !imgHeight) return src;\n const params = new URLSearchParams();\n params.set(\"url\", src);\n params.set(\"fit\", String(optixFlowConfig?.objectFit ?? \"cover\"));\n params.set(\"w\", String(imgWidth));\n params.set(\"h\", String(imgHeight));\n params.set(\"q\", String(optixFlowConfig?.compressionLevel ?? 75));\n params.set(\"f\", format);\n params.set(\"apiKey\", optixFlowApiKey);\n return `${BASE_URL}${params.toString()}`;\n },\n [\n useOptixFlow,\n src,\n optixFlowConfig?.compressionLevel,\n optixFlowApiKey,\n optixFlowConfig?.objectFit\n ]\n );\n const generateSrcset = useCallback(\n (baseWidth, baseHeight, format) => {\n if (!useOptixFlow || baseWidth === 0 || baseHeight === 0) return \"\";\n return DPR_MULTIPLIERS.map((dpr) => {\n const scaledWidth = Math.round(baseWidth * dpr);\n const scaledHeight = Math.round(baseHeight * dpr);\n const url = buildOptixFlowUrl(scaledWidth, scaledHeight, format);\n return `${url} ${dpr}x`;\n }).join(\", \");\n },\n [useOptixFlow, buildOptixFlowUrl]\n );\n const primarySrc = useMemo(() => {\n const hasDimensions = size.width > 0 && size.height > 0;\n if (!useOptixFlow || !hasDimensions) return src;\n const fallbackFormat = optixFlowConfig?.renderedFileType ?? \"jpeg\";\n return buildOptixFlowUrl(size.width, size.height, fallbackFormat);\n }, [\n useOptixFlow,\n src,\n size.width,\n size.height,\n optixFlowConfig?.renderedFileType,\n optixFlowConfig?.compressionLevel,\n optixFlowConfig?.objectFit,\n buildOptixFlowUrl\n ]);\n const srcset = useMemo(() => {\n return {\n avif: generateSrcset(size.width, size.height, \"avif\"),\n webp: generateSrcset(size.width, size.height, \"webp\"),\n jpeg: generateSrcset(size.width, size.height, \"jpeg\")\n };\n }, [size.width, size.height, generateSrcset]);\n const sizes = useMemo(() => {\n if (size.width === 0) return \"\";\n return `${size.width}px`;\n }, [size.width]);\n useEffect(() => {\n if (typeof window === \"undefined\" || !imgRef.current) {\n return;\n }\n if (eager) {\n setState({ isLoaded: false, isInView: true });\n return;\n }\n observerRef.current = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setState((prev) => ({ ...prev, isInView: true }));\n observerRef.current?.disconnect();\n }\n },\n { threshold, rootMargin }\n );\n observerRef.current.observe(imgRef.current);\n return () => {\n observerRef.current?.disconnect();\n };\n }, [eager, threshold, rootMargin]);\n useEffect(() => {\n if (!imgRef.current) return;\n const handleLoad = () => {\n setState((prev) => ({ ...prev, isLoaded: true }));\n };\n const img = imgRef.current;\n if (img.complete) {\n handleLoad();\n } else {\n img.addEventListener(\"load\", handleLoad);\n return () => img.removeEventListener(\"load\", handleLoad);\n }\n }, [state.isInView]);\n const ref = useCallback((node) => {\n imgRef.current = node;\n }, []);\n const emptySrcset = { avif: \"\", webp: \"\", jpeg: \"\" };\n return {\n ref,\n // Primary src uses exact rendered dimensions for Lighthouse \"Properly size images\" compliance\n src: state.isInView || eager ? primarySrc : src,\n // Srcset with format variants and DPR multipliers for <picture> element\n srcset: state.isInView || eager ? srcset : emptySrcset,\n // Sizes attribute for responsive image selection\n sizes: state.isInView || eager ? sizes : \"\",\n isLoaded: state.isLoaded,\n isInView: state.isInView,\n loading: eager ? \"eager\" : \"lazy\",\n size\n };\n}\n\nexport { useOptimizedImage };\n//# sourceMappingURL=chunk-ZTHTGLZO.js.map\n//# sourceMappingURL=chunk-ZTHTGLZO.js.map","import { useEffect } from 'react';\n\nconst MEDIA_SELECTED_EVENT = 'dt:media-selected';\nconst mediaSelectionHandler = () => {\n // no-op: the real handler is attached in the builder via addEventListener\n};\n\nlet mediaSelectionListenerCount = 0;\nlet isMediaSelectionListenerAttached = false;\n\nexport function sendMediaSelection(blockId: string, payload: unknown) {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(\n new CustomEvent(MEDIA_SELECTED_EVENT, {\n detail: { blockId, payload },\n })\n );\n}\n\nexport function useMediaSelectionEffect() {\n useEffect(() => {\n if (typeof window === 'undefined') return;\n if (!isMediaSelectionListenerAttached) {\n window.addEventListener(MEDIA_SELECTED_EVENT, mediaSelectionHandler);\n isMediaSelectionListenerAttached = true;\n }\n mediaSelectionListenerCount += 1;\n\n return () => {\n mediaSelectionListenerCount -= 1;\n if (mediaSelectionListenerCount <= 0 && isMediaSelectionListenerAttached) {\n window.removeEventListener(MEDIA_SELECTED_EVENT, mediaSelectionHandler);\n isMediaSelectionListenerAttached = false;\n }\n };\n }, []);\n}\n","import { useEffect } from 'react';\n\nexport function resetResponsivePictureState(element: HTMLPictureElement | null) {\n if (!element) return;\n element.querySelectorAll('source').forEach((source) => {\n // force browser to reconsider responsive sources\n const srcset = source.getAttribute('srcset');\n if (srcset) {\n source.setAttribute('data-srcset', srcset);\n source.removeAttribute('srcset');\n requestAnimationFrame(() => {\n source.setAttribute('srcset', srcset);\n });\n }\n });\n}\n\nexport function useResponsiveReset(ref: React.RefObject<HTMLPictureElement | HTMLImageElement>) {\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n if (element instanceof HTMLPictureElement) {\n resetResponsivePictureState(element);\n } else if (element.parentElement instanceof HTMLPictureElement) {\n resetResponsivePictureState(element.parentElement);\n }\n }, [ref]);\n}\n\n","\"use client\";\n\nimport React, { forwardRef, memo, useCallback, useMemo, useRef } from \"react\";\nimport { useOptimizedImage } from \"@page-speed/hooks/media\";\nimport type { UseOptimizedImageOptions } from \"@page-speed/hooks/media\";\nimport { useImgDebugLog } from \"./useImgDebugLog.js\";\nimport { useMediaSelectionEffect } from \"./useMediaSelectionEffect.js\";\nimport { useResponsiveReset } from \"./useResponsiveReset.js\";\n\ntype NativeImgProps = Omit<\n React.ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"srcSet\" | \"sizes\"\n> & {\n src?: string;\n};\n\nexport type ImgProps = NativeImgProps & {\n /** Explicit sizes attribute (otherwise derived from useOptimizedImage) */\n sizes?: string;\n /** Force eager load (alias for loading=\"eager\") */\n eager?: boolean;\n /** Intersection observer threshold for lazy loading */\n intersectionThreshold?: number;\n /** Intersection observer root margin for lazy loading */\n intersectionMargin?: string;\n /** OptixFlow integration options */\n optixFlowConfig?: UseOptimizedImageOptions[\"optixFlowConfig\"];\n /** Enable debug logging for image requests */\n useDebugMode?: boolean;\n};\n\ntype ForwardedImgProps = ImgProps & {\n forwardedRef: React.Ref<HTMLImageElement | null>;\n};\n\nconst TRANSPARENT_PIXEL =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==\";\n\nlet defaultOptixFlowConfig:\n | UseOptimizedImageOptions[\"optixFlowConfig\"]\n | undefined;\n\nconst readGlobalOptixFlowConfig = ():\n | UseOptimizedImageOptions[\"optixFlowConfig\"]\n | undefined => {\n if (typeof globalThis === \"undefined\") return undefined;\n const globalAny = globalThis as any;\n return (\n globalAny.PageSpeedImgDefaults?.optixFlowConfig ||\n globalAny.OpensiteImgDefaults?.optixFlowConfig ||\n globalAny.PAGE_SPEED_IMG_DEFAULTS?.optixFlowConfig\n );\n};\n\nconst resolveOptixFlowConfig = (\n config?: UseOptimizedImageOptions[\"optixFlowConfig\"],\n): UseOptimizedImageOptions[\"optixFlowConfig\"] | undefined => {\n return config ?? defaultOptixFlowConfig ?? readGlobalOptixFlowConfig();\n};\n\nexport const setDefaultOptixFlowConfig = (\n config?: UseOptimizedImageOptions[\"optixFlowConfig\"] | null,\n) => {\n defaultOptixFlowConfig = config ?? undefined;\n};\n\nconst parseDimension = (value: unknown): number | undefined => {\n if (value === \"\" || value === null || typeof value === \"undefined\")\n return undefined;\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\") {\n const numeric = Number(value);\n if (Number.isFinite(numeric)) return numeric;\n }\n return undefined;\n};\n\nconst composeRefs = (\n hookRef: (node: HTMLImageElement | null) => void,\n forwardedRef: React.Ref<HTMLImageElement | null>,\n localRef: React.RefObject<HTMLImageElement>,\n) =>\n useCallback(\n (node: HTMLImageElement | null) => {\n hookRef(node);\n // eslint-disable-next-line no-param-reassign\n (localRef as any).current = node;\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef && typeof (forwardedRef as any) === \"object\") {\n (forwardedRef as any).current = node;\n }\n },\n [hookRef, forwardedRef, localRef],\n );\n\nconst ModernImg: React.FC<ForwardedImgProps> = ({\n sizes,\n loading,\n decoding,\n alt,\n title,\n src: directSrc,\n eager,\n width,\n height,\n fetchPriority,\n intersectionMargin,\n intersectionThreshold,\n optixFlowConfig,\n useDebugMode,\n forwardedRef,\n ...restProps\n}) => {\n const imgRef = useRef<HTMLImageElement | null>(null);\n const pictureRef = useRef<HTMLPictureElement | null>(null);\n\n useResponsiveReset(pictureRef);\n useMediaSelectionEffect();\n\n const normalizedSrc = useMemo(\n () => (typeof directSrc === \"string\" ? directSrc.trim() : \"\"),\n [directSrc],\n );\n const numericWidth = useMemo(() => parseDimension(width), [width]);\n const numericHeight = useMemo(() => parseDimension(height), [height]);\n const resolvedOptixConfig = useMemo(\n () => resolveOptixFlowConfig(optixFlowConfig),\n [optixFlowConfig],\n );\n const eagerLoad = useMemo(() => {\n return eager ?? loading === \"eager\";\n }, [eager, loading]);\n\n const hookOptions = useMemo(\n () => ({\n src: normalizedSrc,\n eager: eagerLoad,\n width: numericWidth,\n height: numericHeight,\n rootMargin: intersectionMargin ?? \"200px\",\n threshold: intersectionThreshold ?? 0.1,\n optixFlowConfig: resolvedOptixConfig,\n }),\n [\n normalizedSrc,\n eagerLoad,\n numericWidth,\n numericHeight,\n intersectionMargin,\n intersectionThreshold,\n resolvedOptixConfig,\n ],\n );\n\n const {\n ref: hookRef,\n src,\n srcset,\n sizes: computedSizes,\n loading: hookLoading,\n isInView,\n size,\n } = useOptimizedImage(hookOptions);\n\n const mergedRef = composeRefs(hookRef, forwardedRef, imgRef);\n\n const sizesAttr = useMemo(() => {\n return sizes ?? (computedSizes || undefined);\n }, [sizes, computedSizes]);\n const loadingAttr = useMemo(() => {\n return loading ?? hookLoading ?? \"lazy\";\n }, [loading, hookLoading]);\n const decodingAttr = useMemo(() => {\n return decoding ?? \"async\";\n }, [decoding]);\n const fetchPriorityAttr = useMemo(() => {\n return fetchPriority ?? (eagerLoad ? \"high\" : undefined);\n }, [fetchPriority, eagerLoad]);\n\n const hasSrcSet = useMemo(() => {\n return Boolean(srcset.avif || srcset.webp || srcset.jpeg);\n }, [srcset.avif, srcset.webp, srcset.jpeg]);\n const imgSrc = useMemo(() => {\n return src || normalizedSrc || TRANSPARENT_PIXEL;\n }, [src, normalizedSrc]);\n const inlineSrcSet = useMemo(() => {\n return hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : \"\";\n }, [hasSrcSet, srcset.avif, srcset.webp, srcset.jpeg]);\n\n const widthAttr = useMemo(() => {\n return numericWidth ?? (size.width || undefined);\n }, [numericWidth, size?.width]);\n const heightAttr = useMemo(() => {\n return numericHeight ?? (size.height || undefined);\n }, [numericHeight, size?.height]);\n\n useImgDebugLog({\n enabled: useDebugMode ?? false,\n eagerLoad,\n isInView,\n imgSrc,\n transparentPixel: TRANSPARENT_PIXEL,\n srcset,\n sizesAttr,\n });\n\n if (!hasSrcSet) {\n return (\n <img\n ref={mergedRef}\n src={imgSrc}\n loading={loadingAttr}\n decoding={decodingAttr}\n fetchPriority={fetchPriorityAttr}\n alt={alt}\n title={title}\n width={widthAttr}\n height={heightAttr}\n {...restProps}\n />\n );\n }\n\n return (\n <picture ref={pictureRef}>\n {srcset.avif ? (\n <source type=\"image/avif\" srcSet={srcset.avif} sizes={sizesAttr} />\n ) : null}\n {srcset.webp ? (\n <source type=\"image/webp\" srcSet={srcset.webp} sizes={sizesAttr} />\n ) : null}\n <img\n ref={mergedRef}\n src={imgSrc}\n srcSet={inlineSrcSet || undefined}\n sizes={inlineSrcSet ? sizesAttr : undefined}\n loading={loadingAttr}\n decoding={decodingAttr}\n fetchPriority={fetchPriorityAttr}\n alt={alt}\n title={title}\n width={widthAttr}\n height={heightAttr}\n {...restProps}\n />\n </picture>\n );\n};\n\nconst ImgBase = forwardRef<HTMLImageElement, ImgProps>(\n function Img(props, ref) {\n const hasSrc = typeof props.src === \"string\" && props.src.trim().length > 0;\n if (!hasSrc) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\"<Img /> requires src. No src provided, rendering null.\");\n }\n return null;\n }\n\n return <ModernImg {...props} forwardedRef={ref} />;\n },\n);\n\nexport const Img = memo(ImgBase);\nImg.displayName = \"PageSpeedImg\";\n","import { useEffect, useRef } from \"react\";\n\ninterface ImgDebugLogParams {\n enabled: boolean;\n eagerLoad: boolean;\n isInView: boolean;\n imgSrc: string;\n transparentPixel: string;\n srcset: { avif: string; webp: string; jpeg: string };\n sizesAttr: string | undefined;\n}\n\n/**\n * Logs image-request details to the console when `enabled` is true.\n * When disabled (the default), the hook short-circuits on the very first\n * line so there is no meaningful runtime cost.\n */\nexport function useImgDebugLog({\n enabled,\n eagerLoad,\n isInView,\n imgSrc,\n transparentPixel,\n srcset,\n sizesAttr,\n}: ImgDebugLogParams): void {\n const logKeyRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n if (typeof window === \"undefined\") return;\n if (!eagerLoad && !isInView) return;\n if (!imgSrc || imgSrc === transparentPixel) return;\n\n const logKey = [\n imgSrc,\n srcset.avif,\n srcset.webp,\n srcset.jpeg,\n sizesAttr ?? \"\",\n ].join(\"|\");\n\n if (logKeyRef.current === logKey) return;\n logKeyRef.current = logKey;\n\n if (typeof console !== \"undefined\" && console.info) {\n console.info(\"[PageSpeedImg] image request\", {\n src: imgSrc,\n srcset,\n sizes: sizesAttr,\n });\n }\n }, [\n enabled,\n eagerLoad,\n imgSrc,\n isInView,\n sizesAttr,\n srcset.avif,\n srcset.webp,\n srcset.jpeg,\n transparentPixel,\n ]);\n}\n","// Ensure process.env exists when the module is loaded directly in the browser UMD build.\ntype GlobalWithProcess = typeof globalThis & { process?: NodeJS.Process };\n\nconst globalObject =\n typeof globalThis !== 'undefined' ? (globalThis as GlobalWithProcess) : undefined;\n\nif (globalObject) {\n if (!globalObject.process) {\n globalObject.process = {\n env: { NODE_ENV: 'production' } as NodeJS.ProcessEnv,\n } as NodeJS.Process;\n } else {\n const env = globalObject.process.env ?? (globalObject.process.env = {} as NodeJS.ProcessEnv);\n if (typeof env.NODE_ENV === 'undefined') {\n env.NODE_ENV = 'production';\n }\n }\n}\n\nimport type { UseOptimizedImageOptions } from '@page-speed/hooks/media';\n\nexport * from './core/index.js';\nexport type {\n ImageFormat,\n SrcsetByFormat,\n UseOptimizedImageOptions,\n UseOptimizedImageState,\n} from '@page-speed/hooks/media';\nexport type OptixFlowConfig = UseOptimizedImageOptions['optixFlowConfig'];\n"],"names":["DPR_MULTIPLIERS","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","MEDIA_SELECTED_EVENT","mediaSelectionHandler","mediaSelectionListenerCount","isMediaSelectionListenerAttached","resetResponsivePictureState","element","querySelectorAll","forEach","source","srcset","getAttribute","setAttribute","removeAttribute","requestAnimationFrame","TRANSPARENT_PIXEL","defaultOptixFlowConfig","resolveOptixFlowConfig","config","globalThis","globalAny","_a","PageSpeedImgDefaults","optixFlowConfig","_b","OpensiteImgDefaults","_c","PAGE_SPEED_IMG_DEFAULTS","readGlobalOptixFlowConfig","parseDimension","value","Number","isFinite","numeric","ModernImg","sizes","loading","decoding","alt","title","src","directSrc","eager","width","height","fetchPriority","intersectionMargin","intersectionThreshold","useDebugMode","forwardedRef","restProps","imgRef","useRef","pictureRef","ref","current","HTMLPictureElement","parentElement","addEventListener","removeEventListener","normalizedSrc","useMemo","trim","numericWidth","numericHeight","resolvedOptixConfig","eagerLoad","hookOptions","rootMargin","threshold","hookRef","computedSizes","hookLoading","isInView","size","options","optixFlowApiKey","apiKey","useOptixFlow","state","setState","useState","isLoaded","measuredSize","setMeasuredSize","observerRef","calculateRenderedSize","img2","renderedWidth","Math","round","clientWidth","naturalWidth","renderedHeight","clientHeight","naturalHeight","prev","img","resizeObserver","ResizeObserver","observe","disconnect","buildOptixFlowUrl","useCallback","imgWidth","imgHeight","format","params","URLSearchParams","set","String","objectFit","compressionLevel","toString","generateSrcset","baseWidth","baseHeight","map","dpr","scaledWidth","scaledHeight","join","primarySrc","hasDimensions","fallbackFormat","renderedFileType","avif","webp","jpeg","IntersectionObserver","entry","isIntersecting","handleLoad","complete","node","useOptimizedImage","mergedRef","localRef","composeRefs","sizesAttr","loadingAttr","decodingAttr","fetchPriorityAttr","hasSrcSet","Boolean","imgSrc","inlineSrcSet","widthAttr","heightAttr","enabled","transparentPixel","logKeyRef","logKey","console","info","useImgDebugLog","createElement","React","type","srcSet","ImgBase","forwardRef","props","length","warn","Img","memo","displayName","globalObject","process","env","NODE_ENV"],"mappings":"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","x_google_ignoreList":[0]}
package/dist/core/Img.cjs CHANGED
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from "react";
3
+ import { forwardRef, memo, useCallback, useMemo, useRef } from "react";
4
4
  import { useOptimizedImage } from "@page-speed/hooks/media";
5
+ import { useImgDebugLog } from "./useImgDebugLog.js";
5
6
  import { useMediaSelectionEffect } from "./useMediaSelectionEffect.js";
6
7
  import { useResponsiveReset } from "./useResponsiveReset.js";
7
8
  const TRANSPARENT_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
@@ -20,7 +21,6 @@ const resolveOptixFlowConfig = (config) => {
20
21
  export const setDefaultOptixFlowConfig = (config) => {
21
22
  defaultOptixFlowConfig = config ?? undefined;
22
23
  };
23
- const isUrlString = (value) => typeof value === "string" && value.trim().length > 0;
24
24
  const parseDimension = (value) => {
25
25
  if (value === "" || value === null || typeof value === "undefined")
26
26
  return undefined;
@@ -44,18 +44,19 @@ const composeRefs = (hookRef, forwardedRef, localRef) => useCallback((node) => {
44
44
  forwardedRef.current = node;
45
45
  }
46
46
  }, [hookRef, forwardedRef, localRef]);
47
- const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager, intersectionMargin, intersectionThreshold, optixFlowConfig, forwardedRef, ...rest }) => {
47
+ const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager, width, height, fetchPriority, intersectionMargin, intersectionThreshold, optixFlowConfig, useDebugMode, forwardedRef, ...restProps }) => {
48
48
  const imgRef = useRef(null);
49
49
  const pictureRef = useRef(null);
50
- const logKeyRef = useRef(null);
51
50
  useResponsiveReset(pictureRef);
52
51
  useMediaSelectionEffect();
53
52
  const normalizedSrc = useMemo(() => (typeof directSrc === "string" ? directSrc.trim() : ""), [directSrc]);
54
- const numericWidth = useMemo(() => parseDimension(rest.width), [rest]);
55
- const numericHeight = useMemo(() => parseDimension(rest.height), [rest]);
53
+ const numericWidth = useMemo(() => parseDimension(width), [width]);
54
+ const numericHeight = useMemo(() => parseDimension(height), [height]);
56
55
  const resolvedOptixConfig = useMemo(() => resolveOptixFlowConfig(optixFlowConfig), [optixFlowConfig]);
57
- const eagerLoad = eager ?? loading === "eager";
58
- const { ref: hookRef, src, srcset, sizes: computedSizes, loading: hookLoading, isInView, size, } = useOptimizedImage({
56
+ const eagerLoad = useMemo(() => {
57
+ return eager ?? loading === "eager";
58
+ }, [eager, loading]);
59
+ const hookOptions = useMemo(() => ({
59
60
  src: normalizedSrc,
60
61
  eager: eagerLoad,
61
62
  width: numericWidth,
@@ -63,57 +64,57 @@ const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager
63
64
  rootMargin: intersectionMargin ?? "200px",
64
65
  threshold: intersectionThreshold ?? 0.1,
65
66
  optixFlowConfig: resolvedOptixConfig,
66
- });
67
+ }), [
68
+ normalizedSrc,
69
+ eagerLoad,
70
+ numericWidth,
71
+ numericHeight,
72
+ intersectionMargin,
73
+ intersectionThreshold,
74
+ resolvedOptixConfig,
75
+ ]);
76
+ const { ref: hookRef, src, srcset, sizes: computedSizes, loading: hookLoading, isInView, size, } = useOptimizedImage(hookOptions);
67
77
  const mergedRef = composeRefs(hookRef, forwardedRef, imgRef);
68
- const { width, height, ...restProps } = rest;
69
- const sizesAttr = sizes ?? (computedSizes || undefined);
70
- const loadingAttr = loading ?? hookLoading ?? "lazy";
71
- const decodingAttr = decoding ?? "async";
72
- const hasSrcSet = Boolean(srcset.avif || srcset.webp || srcset.jpeg);
73
- const imgSrc = src || normalizedSrc || TRANSPARENT_PIXEL;
74
- const inlineSrcSet = hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : "";
75
- const parsedWidth = parseDimension(width);
76
- const parsedHeight = parseDimension(height);
77
- const widthAttr = parsedWidth ?? (size.width || numericWidth || undefined);
78
- const heightAttr = parsedHeight ?? (size.height || numericHeight || undefined);
79
- // Temporary logging to detect repeated transform requests and URL churn.
80
- useEffect(() => {
81
- if (typeof window === "undefined")
82
- return;
83
- if (!eagerLoad && !isInView)
84
- return;
85
- if (!imgSrc || imgSrc === TRANSPARENT_PIXEL)
86
- return;
87
- const logKey = [
88
- imgSrc,
89
- srcset.avif,
90
- srcset.webp,
91
- srcset.jpeg,
92
- sizesAttr ?? "",
93
- ].join("|");
94
- if (logKeyRef.current === logKey)
95
- return;
96
- logKeyRef.current = logKey;
97
- if (typeof console !== "undefined" && console.info) {
98
- console.info("[PageSpeedImg] image request", {
99
- src: imgSrc,
100
- srcset,
101
- sizes: sizesAttr,
102
- });
103
- }
104
- }, [
78
+ const sizesAttr = useMemo(() => {
79
+ return sizes ?? (computedSizes || undefined);
80
+ }, [sizes, computedSizes]);
81
+ const loadingAttr = useMemo(() => {
82
+ return loading ?? hookLoading ?? "lazy";
83
+ }, [loading, hookLoading]);
84
+ const decodingAttr = useMemo(() => {
85
+ return decoding ?? "async";
86
+ }, [decoding]);
87
+ const fetchPriorityAttr = useMemo(() => {
88
+ return fetchPriority ?? (eagerLoad ? "high" : undefined);
89
+ }, [fetchPriority, eagerLoad]);
90
+ const hasSrcSet = useMemo(() => {
91
+ return Boolean(srcset.avif || srcset.webp || srcset.jpeg);
92
+ }, [srcset.avif, srcset.webp, srcset.jpeg]);
93
+ const imgSrc = useMemo(() => {
94
+ return src || normalizedSrc || TRANSPARENT_PIXEL;
95
+ }, [src, normalizedSrc]);
96
+ const inlineSrcSet = useMemo(() => {
97
+ return hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : "";
98
+ }, [hasSrcSet, srcset.avif, srcset.webp, srcset.jpeg]);
99
+ const widthAttr = useMemo(() => {
100
+ return numericWidth ?? (size.width || undefined);
101
+ }, [numericWidth, size?.width]);
102
+ const heightAttr = useMemo(() => {
103
+ return numericHeight ?? (size.height || undefined);
104
+ }, [numericHeight, size?.height]);
105
+ useImgDebugLog({
106
+ enabled: useDebugMode ?? false,
105
107
  eagerLoad,
106
- imgSrc,
107
108
  isInView,
109
+ imgSrc,
110
+ transparentPixel: TRANSPARENT_PIXEL,
111
+ srcset,
108
112
  sizesAttr,
109
- srcset.avif,
110
- srcset.webp,
111
- srcset.jpeg,
112
- ]);
113
+ });
113
114
  if (!hasSrcSet) {
114
- return (_jsx("img", { ref: mergedRef, src: imgSrc, loading: loadingAttr, decoding: decodingAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps }));
115
+ return (_jsx("img", { ref: mergedRef, src: imgSrc, loading: loadingAttr, decoding: decodingAttr, fetchPriority: fetchPriorityAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps }));
115
116
  }
116
- return (_jsxs("picture", { ref: pictureRef, children: [srcset.avif ? (_jsx("source", { type: "image/avif", srcSet: srcset.avif, sizes: sizesAttr })) : null, srcset.webp ? (_jsx("source", { type: "image/webp", srcSet: srcset.webp, sizes: sizesAttr })) : null, _jsx("img", { ref: mergedRef, src: imgSrc, srcSet: inlineSrcSet || undefined, sizes: inlineSrcSet ? sizesAttr : undefined, loading: loadingAttr, decoding: decodingAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps })] }));
117
+ return (_jsxs("picture", { ref: pictureRef, children: [srcset.avif ? (_jsx("source", { type: "image/avif", srcSet: srcset.avif, sizes: sizesAttr })) : null, srcset.webp ? (_jsx("source", { type: "image/webp", srcSet: srcset.webp, sizes: sizesAttr })) : null, _jsx("img", { ref: mergedRef, src: imgSrc, srcSet: inlineSrcSet || undefined, sizes: inlineSrcSet ? sizesAttr : undefined, loading: loadingAttr, decoding: decodingAttr, fetchPriority: fetchPriorityAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps })] }));
117
118
  };
118
119
  const ImgBase = forwardRef(function Img(props, ref) {
119
120
  const hasSrc = typeof props.src === "string" && props.src.trim().length > 0;
@@ -14,6 +14,8 @@ export type ImgProps = NativeImgProps & {
14
14
  intersectionMargin?: string;
15
15
  /** OptixFlow integration options */
16
16
  optixFlowConfig?: UseOptimizedImageOptions["optixFlowConfig"];
17
+ /** Enable debug logging for image requests */
18
+ useDebugMode?: boolean;
17
19
  };
18
20
  export declare const setDefaultOptixFlowConfig: (config?: UseOptimizedImageOptions["optixFlowConfig"] | null) => void;
19
21
  export declare const Img: React.MemoExoticComponent<React.ForwardRefExoticComponent<Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "srcSet" | "sizes"> & {
@@ -29,5 +31,7 @@ export declare const Img: React.MemoExoticComponent<React.ForwardRefExoticCompon
29
31
  intersectionMargin?: string;
30
32
  /** OptixFlow integration options */
31
33
  optixFlowConfig?: UseOptimizedImageOptions["optixFlowConfig"];
34
+ /** Enable debug logging for image requests */
35
+ useDebugMode?: boolean;
32
36
  } & React.RefAttributes<HTMLImageElement>>>;
33
37
  export {};
package/dist/core/Img.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from "react";
3
+ import { forwardRef, memo, useCallback, useMemo, useRef } from "react";
4
4
  import { useOptimizedImage } from "@page-speed/hooks/media";
5
+ import { useImgDebugLog } from "./useImgDebugLog.js";
5
6
  import { useMediaSelectionEffect } from "./useMediaSelectionEffect.js";
6
7
  import { useResponsiveReset } from "./useResponsiveReset.js";
7
8
  const TRANSPARENT_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
@@ -20,7 +21,6 @@ const resolveOptixFlowConfig = (config) => {
20
21
  export const setDefaultOptixFlowConfig = (config) => {
21
22
  defaultOptixFlowConfig = config ?? undefined;
22
23
  };
23
- const isUrlString = (value) => typeof value === "string" && value.trim().length > 0;
24
24
  const parseDimension = (value) => {
25
25
  if (value === "" || value === null || typeof value === "undefined")
26
26
  return undefined;
@@ -44,18 +44,19 @@ const composeRefs = (hookRef, forwardedRef, localRef) => useCallback((node) => {
44
44
  forwardedRef.current = node;
45
45
  }
46
46
  }, [hookRef, forwardedRef, localRef]);
47
- const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager, intersectionMargin, intersectionThreshold, optixFlowConfig, forwardedRef, ...rest }) => {
47
+ const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager, width, height, fetchPriority, intersectionMargin, intersectionThreshold, optixFlowConfig, useDebugMode, forwardedRef, ...restProps }) => {
48
48
  const imgRef = useRef(null);
49
49
  const pictureRef = useRef(null);
50
- const logKeyRef = useRef(null);
51
50
  useResponsiveReset(pictureRef);
52
51
  useMediaSelectionEffect();
53
52
  const normalizedSrc = useMemo(() => (typeof directSrc === "string" ? directSrc.trim() : ""), [directSrc]);
54
- const numericWidth = useMemo(() => parseDimension(rest.width), [rest]);
55
- const numericHeight = useMemo(() => parseDimension(rest.height), [rest]);
53
+ const numericWidth = useMemo(() => parseDimension(width), [width]);
54
+ const numericHeight = useMemo(() => parseDimension(height), [height]);
56
55
  const resolvedOptixConfig = useMemo(() => resolveOptixFlowConfig(optixFlowConfig), [optixFlowConfig]);
57
- const eagerLoad = eager ?? loading === "eager";
58
- const { ref: hookRef, src, srcset, sizes: computedSizes, loading: hookLoading, isInView, size, } = useOptimizedImage({
56
+ const eagerLoad = useMemo(() => {
57
+ return eager ?? loading === "eager";
58
+ }, [eager, loading]);
59
+ const hookOptions = useMemo(() => ({
59
60
  src: normalizedSrc,
60
61
  eager: eagerLoad,
61
62
  width: numericWidth,
@@ -63,57 +64,57 @@ const ModernImg = ({ sizes, loading, decoding, alt, title, src: directSrc, eager
63
64
  rootMargin: intersectionMargin ?? "200px",
64
65
  threshold: intersectionThreshold ?? 0.1,
65
66
  optixFlowConfig: resolvedOptixConfig,
66
- });
67
+ }), [
68
+ normalizedSrc,
69
+ eagerLoad,
70
+ numericWidth,
71
+ numericHeight,
72
+ intersectionMargin,
73
+ intersectionThreshold,
74
+ resolvedOptixConfig,
75
+ ]);
76
+ const { ref: hookRef, src, srcset, sizes: computedSizes, loading: hookLoading, isInView, size, } = useOptimizedImage(hookOptions);
67
77
  const mergedRef = composeRefs(hookRef, forwardedRef, imgRef);
68
- const { width, height, ...restProps } = rest;
69
- const sizesAttr = sizes ?? (computedSizes || undefined);
70
- const loadingAttr = loading ?? hookLoading ?? "lazy";
71
- const decodingAttr = decoding ?? "async";
72
- const hasSrcSet = Boolean(srcset.avif || srcset.webp || srcset.jpeg);
73
- const imgSrc = src || normalizedSrc || TRANSPARENT_PIXEL;
74
- const inlineSrcSet = hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : "";
75
- const parsedWidth = parseDimension(width);
76
- const parsedHeight = parseDimension(height);
77
- const widthAttr = parsedWidth ?? (size.width || numericWidth || undefined);
78
- const heightAttr = parsedHeight ?? (size.height || numericHeight || undefined);
79
- // Temporary logging to detect repeated transform requests and URL churn.
80
- useEffect(() => {
81
- if (typeof window === "undefined")
82
- return;
83
- if (!eagerLoad && !isInView)
84
- return;
85
- if (!imgSrc || imgSrc === TRANSPARENT_PIXEL)
86
- return;
87
- const logKey = [
88
- imgSrc,
89
- srcset.avif,
90
- srcset.webp,
91
- srcset.jpeg,
92
- sizesAttr ?? "",
93
- ].join("|");
94
- if (logKeyRef.current === logKey)
95
- return;
96
- logKeyRef.current = logKey;
97
- if (typeof console !== "undefined" && console.info) {
98
- console.info("[PageSpeedImg] image request", {
99
- src: imgSrc,
100
- srcset,
101
- sizes: sizesAttr,
102
- });
103
- }
104
- }, [
78
+ const sizesAttr = useMemo(() => {
79
+ return sizes ?? (computedSizes || undefined);
80
+ }, [sizes, computedSizes]);
81
+ const loadingAttr = useMemo(() => {
82
+ return loading ?? hookLoading ?? "lazy";
83
+ }, [loading, hookLoading]);
84
+ const decodingAttr = useMemo(() => {
85
+ return decoding ?? "async";
86
+ }, [decoding]);
87
+ const fetchPriorityAttr = useMemo(() => {
88
+ return fetchPriority ?? (eagerLoad ? "high" : undefined);
89
+ }, [fetchPriority, eagerLoad]);
90
+ const hasSrcSet = useMemo(() => {
91
+ return Boolean(srcset.avif || srcset.webp || srcset.jpeg);
92
+ }, [srcset.avif, srcset.webp, srcset.jpeg]);
93
+ const imgSrc = useMemo(() => {
94
+ return src || normalizedSrc || TRANSPARENT_PIXEL;
95
+ }, [src, normalizedSrc]);
96
+ const inlineSrcSet = useMemo(() => {
97
+ return hasSrcSet && !srcset.avif && !srcset.webp ? srcset.jpeg : "";
98
+ }, [hasSrcSet, srcset.avif, srcset.webp, srcset.jpeg]);
99
+ const widthAttr = useMemo(() => {
100
+ return numericWidth ?? (size.width || undefined);
101
+ }, [numericWidth, size?.width]);
102
+ const heightAttr = useMemo(() => {
103
+ return numericHeight ?? (size.height || undefined);
104
+ }, [numericHeight, size?.height]);
105
+ useImgDebugLog({
106
+ enabled: useDebugMode ?? false,
105
107
  eagerLoad,
106
- imgSrc,
107
108
  isInView,
109
+ imgSrc,
110
+ transparentPixel: TRANSPARENT_PIXEL,
111
+ srcset,
108
112
  sizesAttr,
109
- srcset.avif,
110
- srcset.webp,
111
- srcset.jpeg,
112
- ]);
113
+ });
113
114
  if (!hasSrcSet) {
114
- return (_jsx("img", { ref: mergedRef, src: imgSrc, loading: loadingAttr, decoding: decodingAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps }));
115
+ return (_jsx("img", { ref: mergedRef, src: imgSrc, loading: loadingAttr, decoding: decodingAttr, fetchPriority: fetchPriorityAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps }));
115
116
  }
116
- return (_jsxs("picture", { ref: pictureRef, children: [srcset.avif ? (_jsx("source", { type: "image/avif", srcSet: srcset.avif, sizes: sizesAttr })) : null, srcset.webp ? (_jsx("source", { type: "image/webp", srcSet: srcset.webp, sizes: sizesAttr })) : null, _jsx("img", { ref: mergedRef, src: imgSrc, srcSet: inlineSrcSet || undefined, sizes: inlineSrcSet ? sizesAttr : undefined, loading: loadingAttr, decoding: decodingAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps })] }));
117
+ return (_jsxs("picture", { ref: pictureRef, children: [srcset.avif ? (_jsx("source", { type: "image/avif", srcSet: srcset.avif, sizes: sizesAttr })) : null, srcset.webp ? (_jsx("source", { type: "image/webp", srcSet: srcset.webp, sizes: sizesAttr })) : null, _jsx("img", { ref: mergedRef, src: imgSrc, srcSet: inlineSrcSet || undefined, sizes: inlineSrcSet ? sizesAttr : undefined, loading: loadingAttr, decoding: decodingAttr, fetchPriority: fetchPriorityAttr, alt: alt, title: title, width: widthAttr, height: heightAttr, ...restProps })] }));
117
118
  };
118
119
  const ImgBase = forwardRef(function Img(props, ref) {
119
120
  const hasSrc = typeof props.src === "string" && props.src.trim().length > 0;
@@ -0,0 +1,46 @@
1
+ import { useEffect, useRef } from "react";
2
+ /**
3
+ * Logs image-request details to the console when `enabled` is true.
4
+ * When disabled (the default), the hook short-circuits on the very first
5
+ * line so there is no meaningful runtime cost.
6
+ */
7
+ export function useImgDebugLog({ enabled, eagerLoad, isInView, imgSrc, transparentPixel, srcset, sizesAttr, }) {
8
+ const logKeyRef = useRef(null);
9
+ useEffect(() => {
10
+ if (!enabled)
11
+ return;
12
+ if (typeof window === "undefined")
13
+ return;
14
+ if (!eagerLoad && !isInView)
15
+ return;
16
+ if (!imgSrc || imgSrc === transparentPixel)
17
+ return;
18
+ const logKey = [
19
+ imgSrc,
20
+ srcset.avif,
21
+ srcset.webp,
22
+ srcset.jpeg,
23
+ sizesAttr ?? "",
24
+ ].join("|");
25
+ if (logKeyRef.current === logKey)
26
+ return;
27
+ logKeyRef.current = logKey;
28
+ if (typeof console !== "undefined" && console.info) {
29
+ console.info("[PageSpeedImg] image request", {
30
+ src: imgSrc,
31
+ srcset,
32
+ sizes: sizesAttr,
33
+ });
34
+ }
35
+ }, [
36
+ enabled,
37
+ eagerLoad,
38
+ imgSrc,
39
+ isInView,
40
+ sizesAttr,
41
+ srcset.avif,
42
+ srcset.webp,
43
+ srcset.jpeg,
44
+ transparentPixel,
45
+ ]);
46
+ }
@@ -0,0 +1,20 @@
1
+ interface ImgDebugLogParams {
2
+ enabled: boolean;
3
+ eagerLoad: boolean;
4
+ isInView: boolean;
5
+ imgSrc: string;
6
+ transparentPixel: string;
7
+ srcset: {
8
+ avif: string;
9
+ webp: string;
10
+ jpeg: string;
11
+ };
12
+ sizesAttr: string | undefined;
13
+ }
14
+ /**
15
+ * Logs image-request details to the console when `enabled` is true.
16
+ * When disabled (the default), the hook short-circuits on the very first
17
+ * line so there is no meaningful runtime cost.
18
+ */
19
+ export declare function useImgDebugLog({ enabled, eagerLoad, isInView, imgSrc, transparentPixel, srcset, sizesAttr, }: ImgDebugLogParams): void;
20
+ export {};
@@ -0,0 +1,46 @@
1
+ import { useEffect, useRef } from "react";
2
+ /**
3
+ * Logs image-request details to the console when `enabled` is true.
4
+ * When disabled (the default), the hook short-circuits on the very first
5
+ * line so there is no meaningful runtime cost.
6
+ */
7
+ export function useImgDebugLog({ enabled, eagerLoad, isInView, imgSrc, transparentPixel, srcset, sizesAttr, }) {
8
+ const logKeyRef = useRef(null);
9
+ useEffect(() => {
10
+ if (!enabled)
11
+ return;
12
+ if (typeof window === "undefined")
13
+ return;
14
+ if (!eagerLoad && !isInView)
15
+ return;
16
+ if (!imgSrc || imgSrc === transparentPixel)
17
+ return;
18
+ const logKey = [
19
+ imgSrc,
20
+ srcset.avif,
21
+ srcset.webp,
22
+ srcset.jpeg,
23
+ sizesAttr ?? "",
24
+ ].join("|");
25
+ if (logKeyRef.current === logKey)
26
+ return;
27
+ logKeyRef.current = logKey;
28
+ if (typeof console !== "undefined" && console.info) {
29
+ console.info("[PageSpeedImg] image request", {
30
+ src: imgSrc,
31
+ srcset,
32
+ sizes: sizesAttr,
33
+ });
34
+ }
35
+ }, [
36
+ enabled,
37
+ eagerLoad,
38
+ imgSrc,
39
+ isInView,
40
+ sizesAttr,
41
+ srcset.avif,
42
+ srcset.webp,
43
+ srcset.jpeg,
44
+ transparentPixel,
45
+ ]);
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-speed/img",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Performance-optimized React Image component. Drop-in image implementation of web.dev best practices with zero configuration.",
5
5
  "keywords": [
6
6
  "react",
@@ -90,7 +90,7 @@
90
90
  "vitest": "^3.2.4"
91
91
  },
92
92
  "dependencies": {
93
- "@opensite/hooks": "2.0.3",
93
+ "@opensite/hooks": "2.0.8",
94
94
  "@page-speed/hooks": "0.4.5"
95
95
  },
96
96
  "packageManager": "pnpm@10.24.0",
@@ -1,2 +0,0 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).OpensiteImg={},t.React)}(this,function(t,e){"use strict";const n=new Map;function i(t,e){n.set(t,e)}const r="https://cdn.ing";function l(t){return(t??r).replace(/\/$/,"")}function o(t,e){return`${l(e)}/assets/images/${t}`}function s(t,e){return`${l(e)}/i/r/${t}`}function a(t){return!!t&&["AVIF","WEBP","JPEG"].some(e=>{const n=null==t?void 0:t[e];return!!(i=n)&&[i.sm,i.md,i.lg,i.full].some(t=>"string"==typeof t&&t.trim().length>0);var i})}function u(t){return"string"==typeof t&&t.trim().length>0}function d(t){var e;if(!t)return!1;if(a((null==(e=t.variants_data)?void 0:e.variants)??null))return!0;const n=t;return[n.img_url,n.file_data_url,n.file_data_thumbnail_url,n.img_src,n.med_src,n.thumb_src,n.low_res_thumb].some(u)}async function c(t,e){const n=await fetch(t,{signal:e});if(!n.ok){const e=new Error(`Failed to fetch image data (status ${n.status}) from ${t}`);throw e.status=n.status,e}return await n.json()}async function f(t,e={}){if(!Number.isFinite(t))throw new Error("Invalid mediaId provided to fetchImageData");const r=l(e.cdnHost),a=`image:${r}:${t}`;if(!e.bypassCache){const t=(u=a,n.get(u));if(t)return t}var u;const f=[o(t,r),s(t,r)];let m;for(const n of f)try{const t=await c(n,e.signal);return d(t)&&i(a,t),t}catch(v){if("AbortError"===(null==v?void 0:v.name))throw v;m=v}if(m instanceof Error)throw m;throw new Error(`Failed to fetch image data for mediaId ${t}`)}const m="dt:media-selected";function v(t){t&&t.querySelectorAll("source").forEach(t=>{const e=t.getAttribute("srcset");e&&(t.setAttribute("data-srcset",e),t.removeAttribute("srcset"),requestAnimationFrame(()=>{t.setAttribute("srcset",e)}))})}const g={sm:640,md:1024,lg:1536,full:2560},h=t=>"string"==typeof t&&t.trim().length>0;function p(t){const e=null==t?void 0:t.widths;return e?{sm:e.small??e.sm??g.sm,md:e.medium??e.md??g.md,lg:e.large??e.lg??g.lg,full:e.full_size??e.full??g.full}:null}function w(t){if(t)return t.md||t.lg||t.sm||t.full||Object.values(t).find(Boolean)}const _=e.forwardRef(function({mediaId:t,cdnHost:n,sizes:i,onImageData:o,loading:s,decoding:u,alt:d,title:c,src:_,...E},b){const y=e.useRef(null);e.useImperativeHandle(b,()=>y.current);!function(t){e.useEffect(()=>{const e=t.current;e&&(e instanceof HTMLPictureElement?v(e):e.parentElement instanceof HTMLPictureElement&&v(e.parentElement))},[t])}(e.useRef(null)),e.useEffect(()=>{if("undefined"==typeof window)return;const t=()=>{};return window.addEventListener(m,t),()=>window.removeEventListener(m,t)},[]);const[$,I]=e.useState(null),[S,M]=e.useState(0),x=Number.isFinite(t),z=s??"lazy",A=u??"async",[O,N]=e.useState(()=>!x||"lazy"!==z),P=e.useMemo(()=>(n??r).replace(/\/$/,""),[n]);e.useEffect(()=>{if(!x)return I(null),void M(0);I(null),M(0)},[x,t,n]),e.useEffect(()=>{if(!x)return;const e=new AbortController;return f(t,{cdnHost:n,signal:e.signal,bypassCache:S>0}).then(t=>{I(t),null==o||o(t)}).catch(t=>{"AbortError"!==(null==t?void 0:t.name)&&console.warn("Image data fetch failed:",t)}),()=>e.abort()},[x,t,n,o,S]),e.useEffect(()=>{N(!x||"lazy"!==z)},[x,t,z]),e.useEffect(()=>{if(!x||"lazy"!==z||O)return;if("undefined"==typeof window||void 0===window.IntersectionObserver)return void N(!0);const t=y.current;if(!t)return;const e=new IntersectionObserver(t=>{t.some(t=>t.isIntersecting)&&(N(!0),e.disconnect())},{rootMargin:"200px"});return e.observe(t),()=>e.disconnect()},[x,z,O]);const T=e.useMemo(()=>{var t,e,n;if(!$)return null;const i=(null==(t=$.variants_data)?void 0:t.variants)??{},r=i.WEBP,l=i.AVIF,o=i.JPEG,s=p(null==(e=i.WEBP)?void 0:e.metadata)||p(null==(n=i.JPEG)?void 0:n.metadata)||{...g},a=t=>(t=>{if(h(t))return/^https?:\/\//i.test(t)||t.startsWith("data:")?t:t.startsWith("//")?`https:${t}`:t.startsWith("/")?`${P}${t}`:`${P}/${t}`})("string"==typeof t?t:void 0),u=[w(r),w(o),w(l),null==r?void 0:r.sm,null==r?void 0:r.md,null==r?void 0:r.lg,null==r?void 0:r.full,null==o?void 0:o.sm,null==o?void 0:o.md,null==o?void 0:o.lg,null==o?void 0:o.full,null==l?void 0:l.sm,null==l?void 0:l.md,null==l?void 0:l.lg,null==l?void 0:l.full].map(t=>a(t??void 0)).filter(h),d=$,c=[d.img_url,d.file_data_url,d.file_data_thumbnail_url,d.img_src,d.med_src,d.thumb_src,d.low_res_thumb].map(t=>h(t)?a(t):void 0).filter(h),f=d.fallback_url?[a(d.fallback_url)].filter(h):[],m=[...u,...c,...f][0];if(!m)return null;return{webp:r,avif:l,jpeg:o,toSrcSet:t=>{if(!t)return;const e=[],n=(t,n)=>{const i=a(t);i&&n&&e.push(`${i} ${n}w`)};return n(t.sm,s.sm),n(t.md,s.md),n(t.lg,s.lg),n(t.full,s.full),e.length?e.join(", "):void 0},fallback:m,widths:s,hasVariantSource:u.length>0}},[$,P]),j=e.useMemo(()=>{var t;return a((null==(t=null==$?void 0:$.variants_data)?void 0:t.variants)??null)},[$]),F=e.useMemo(()=>{var t;const e=(null==(t=null==$?void 0:$.variants_data)?void 0:t.status)??(null==$?void 0:$.variants_status)??"";return"string"==typeof e?e.toLowerCase():""},[$]),k="failed"===F||"error"===F,H=x&&Boolean($)&&!k&&!j&&S<5;e.useEffect(()=>{if(!H)return;if("undefined"==typeof window)return;const t=window.setTimeout(()=>{M(t=>t+1)},3e3);return()=>window.clearTimeout(t)},[H]);const L=e.useMemo(()=>{var t,e;return"string"==typeof d?d:(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.summary)??void 0},[d,$]),V=e.useMemo(()=>{var t,e;return"string"==typeof c?c:(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.title)??void 0},[c,$]),W=e.useMemo(()=>{var t,e,n,i;return(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.sizing)?void 0:e.width)??(null==(i=null==(n=null==$?void 0:$.variants_data)?void 0:n.metadata)?void 0:i.width)??void 0},[$]),B=e.useMemo(()=>{var t,e,n,i;return(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.sizing)?void 0:e.height)??(null==(i=null==(n=null==$?void 0:$.variants_data)?void 0:n.metadata)?void 0:i.height)??void 0},[$]),C=e.useMemo(()=>{var t,e;const n=null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.optimized_filename;if(!n)return;const i=null==T?void 0:T.fallback;if(!i)return;const r=i.lastIndexOf(".");return`${n}.${r>-1?i.slice(r+1).toLowerCase():"jpg"}`},[$,T]);if(!x){const t={...E};return e.createElement("img",{ref:y,src:_,loading:z,decoding:A,alt:L,title:V,width:t.width,height:t.height,...t})}const D=function(t,e){return`${l(e)}/assets/low_res_thumb/${t}`}(t,n);if(!$||!T||!O){const t={...E};return e.createElement("img",{ref:y,src:D,loading:z,decoding:A,alt:L,title:V,width:t.width??W,height:t.height??B,...t})}const R=i??"(max-width:640px) 640px, (max-width:1024px) 1024px, 1536px",{webp:q,avif:G,jpeg:J,toSrcSet:K,fallback:Q}=T,U=K(q),X=K(G),Y=K(J);return U||X||Y?e.createElement("picture",null,X?e.createElement("source",{type:"image/avif",srcSet:X,sizes:R}):null,U?e.createElement("source",{type:"image/webp",srcSet:U,sizes:R}):null,e.createElement("img",{ref:y,src:Q,srcSet:!Y||U||X?void 0:Y,sizes:!Y||U||X?void 0:R,loading:z,decoding:A,alt:L,title:V,width:W,height:B,"data-filename":C,...E})):e.createElement("img",{ref:y,src:Q,loading:z,decoding:A,alt:L,title:V,width:W,height:B,"data-filename":C,...E})}),E=e.memo(_);E.displayName="OpenSiteImg";const b="undefined"!=typeof globalThis?globalThis:void 0;if(b)if(b.process){const t=b.process.env??(b.process.env={});void 0===t.NODE_ENV&&(t.NODE_ENV="production")}else b.process={env:{NODE_ENV:"production"}};t.Img=E,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
2
- //# sourceMappingURL=opensite-img.umd.js.map
@@ -1,2 +0,0 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).OpensiteImg={},t.React)}(this,function(t,e){"use strict";const n=new Map;function i(t,e){n.set(t,e)}const r="https://cdn.ing";function l(t){return(t??r).replace(/\/$/,"")}function o(t,e){return`${l(e)}/assets/images/${t}`}function s(t,e){return`${l(e)}/i/r/${t}`}function a(t){return!!t&&["AVIF","WEBP","JPEG"].some(e=>{const n=null==t?void 0:t[e];return!!(i=n)&&[i.sm,i.md,i.lg,i.full].some(t=>"string"==typeof t&&t.trim().length>0);var i})}function u(t){return"string"==typeof t&&t.trim().length>0}function d(t){var e;if(!t)return!1;if(a((null==(e=t.variants_data)?void 0:e.variants)??null))return!0;const n=t;return[n.img_url,n.file_data_url,n.file_data_thumbnail_url,n.img_src,n.med_src,n.thumb_src,n.low_res_thumb].some(u)}async function c(t,e){const n=await fetch(t,{signal:e});if(!n.ok){const e=new Error(`Failed to fetch image data (status ${n.status}) from ${t}`);throw e.status=n.status,e}return await n.json()}async function f(t,e={}){if(!Number.isFinite(t))throw new Error("Invalid mediaId provided to fetchImageData");const r=l(e.cdnHost),a=`image:${r}:${t}`;if(!e.bypassCache){const t=(u=a,n.get(u));if(t)return t}var u;const f=[o(t,r),s(t,r)];let m;for(const n of f)try{const t=await c(n,e.signal);return d(t)&&i(a,t),t}catch(v){if("AbortError"===(null==v?void 0:v.name))throw v;m=v}if(m instanceof Error)throw m;throw new Error(`Failed to fetch image data for mediaId ${t}`)}const m="dt:media-selected";function v(t){t&&t.querySelectorAll("source").forEach(t=>{const e=t.getAttribute("srcset");e&&(t.setAttribute("data-srcset",e),t.removeAttribute("srcset"),requestAnimationFrame(()=>{t.setAttribute("srcset",e)}))})}const g={sm:640,md:1024,lg:1536,full:2560},h=t=>"string"==typeof t&&t.trim().length>0;function p(t){const e=null==t?void 0:t.widths;return e?{sm:e.small??e.sm??g.sm,md:e.medium??e.md??g.md,lg:e.large??e.lg??g.lg,full:e.full_size??e.full??g.full}:null}function w(t){if(t)return t.md||t.lg||t.sm||t.full||Object.values(t).find(Boolean)}const _=e.forwardRef(function({mediaId:t,cdnHost:n,sizes:i,onImageData:o,loading:s,decoding:u,alt:d,title:c,src:_,...E},b){const y=e.useRef(null);e.useImperativeHandle(b,()=>y.current);!function(t){e.useEffect(()=>{const e=t.current;e&&(e instanceof HTMLPictureElement?v(e):e.parentElement instanceof HTMLPictureElement&&v(e.parentElement))},[t])}(e.useRef(null)),e.useEffect(()=>{if("undefined"==typeof window)return;const t=()=>{};return window.addEventListener(m,t),()=>window.removeEventListener(m,t)},[]);const[$,I]=e.useState(null),[S,M]=e.useState(0),x=Number.isFinite(t),z=s??"lazy",A=u??"async",[O,N]=e.useState(()=>!x||"lazy"!==z),P=e.useMemo(()=>(n??r).replace(/\/$/,""),[n]);e.useEffect(()=>{if(!x)return I(null),void M(0);I(null),M(0)},[x,t,n]),e.useEffect(()=>{if(!x)return;const e=new AbortController;return f(t,{cdnHost:n,signal:e.signal,bypassCache:S>0}).then(t=>{I(t),null==o||o(t)}).catch(t=>{"AbortError"!==(null==t?void 0:t.name)&&console.warn("Image data fetch failed:",t)}),()=>e.abort()},[x,t,n,o,S]),e.useEffect(()=>{N(!x||"lazy"!==z)},[x,t,z]),e.useEffect(()=>{if(!x||"lazy"!==z||O)return;if("undefined"==typeof window||void 0===window.IntersectionObserver)return void N(!0);const t=y.current;if(!t)return;const e=new IntersectionObserver(t=>{t.some(t=>t.isIntersecting)&&(N(!0),e.disconnect())},{rootMargin:"200px"});return e.observe(t),()=>e.disconnect()},[x,z,O]);const T=e.useMemo(()=>{var t,e,n;if(!$)return null;const i=(null==(t=$.variants_data)?void 0:t.variants)??{},r=i.WEBP,l=i.AVIF,o=i.JPEG,s=p(null==(e=i.WEBP)?void 0:e.metadata)||p(null==(n=i.JPEG)?void 0:n.metadata)||{...g},a=t=>(t=>{if(h(t))return/^https?:\/\//i.test(t)||t.startsWith("data:")?t:t.startsWith("//")?`https:${t}`:t.startsWith("/")?`${P}${t}`:`${P}/${t}`})("string"==typeof t?t:void 0),u=[w(r),w(o),w(l),null==r?void 0:r.sm,null==r?void 0:r.md,null==r?void 0:r.lg,null==r?void 0:r.full,null==o?void 0:o.sm,null==o?void 0:o.md,null==o?void 0:o.lg,null==o?void 0:o.full,null==l?void 0:l.sm,null==l?void 0:l.md,null==l?void 0:l.lg,null==l?void 0:l.full].map(t=>a(t??void 0)).filter(h),d=$,c=[d.img_url,d.file_data_url,d.file_data_thumbnail_url,d.img_src,d.med_src,d.thumb_src,d.low_res_thumb].map(t=>h(t)?a(t):void 0).filter(h),f=d.fallback_url?[a(d.fallback_url)].filter(h):[],m=[...u,...c,...f][0];if(!m)return null;return{webp:r,avif:l,jpeg:o,toSrcSet:t=>{if(!t)return;const e=[],n=(t,n)=>{const i=a(t);i&&n&&e.push(`${i} ${n}w`)};return n(t.sm,s.sm),n(t.md,s.md),n(t.lg,s.lg),n(t.full,s.full),e.length?e.join(", "):void 0},fallback:m,widths:s,hasVariantSource:u.length>0}},[$,P]),j=e.useMemo(()=>{var t;return a((null==(t=null==$?void 0:$.variants_data)?void 0:t.variants)??null)},[$]),F=e.useMemo(()=>{var t;const e=(null==(t=null==$?void 0:$.variants_data)?void 0:t.status)??(null==$?void 0:$.variants_status)??"";return"string"==typeof e?e.toLowerCase():""},[$]),k="failed"===F||"error"===F,H=x&&Boolean($)&&!k&&!j&&S<5;e.useEffect(()=>{if(!H)return;if("undefined"==typeof window)return;const t=window.setTimeout(()=>{M(t=>t+1)},3e3);return()=>window.clearTimeout(t)},[H]);const L=e.useMemo(()=>{var t,e;return"string"==typeof d?d:(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.summary)??void 0},[d,$]),V=e.useMemo(()=>{var t,e;return"string"==typeof c?c:(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.title)??void 0},[c,$]),W=e.useMemo(()=>{var t,e,n,i;return(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.sizing)?void 0:e.width)??(null==(i=null==(n=null==$?void 0:$.variants_data)?void 0:n.metadata)?void 0:i.width)??void 0},[$]),B=e.useMemo(()=>{var t,e,n,i;return(null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.sizing)?void 0:e.height)??(null==(i=null==(n=null==$?void 0:$.variants_data)?void 0:n.metadata)?void 0:i.height)??void 0},[$]),C=e.useMemo(()=>{var t,e;const n=null==(e=null==(t=null==$?void 0:$.meta)?void 0:t.content_manifest)?void 0:e.optimized_filename;if(!n)return;const i=null==T?void 0:T.fallback;if(!i)return;const r=i.lastIndexOf(".");return`${n}.${r>-1?i.slice(r+1).toLowerCase():"jpg"}`},[$,T]);if(!x){const t={...E};return e.createElement("img",{ref:y,src:_,loading:z,decoding:A,alt:L,title:V,width:t.width,height:t.height,...t})}const D=function(t,e){return`${l(e)}/assets/low_res_thumb/${t}`}(t,n);if(!$||!T||!O){const t={...E};return e.createElement("img",{ref:y,src:D,loading:z,decoding:A,alt:L,title:V,width:t.width??W,height:t.height??B,...t})}const R=i??"(max-width:640px) 640px, (max-width:1024px) 1024px, 1536px",{webp:q,avif:G,jpeg:J,toSrcSet:K,fallback:Q}=T,U=K(q),X=K(G),Y=K(J);return U||X||Y?e.createElement("picture",null,X?e.createElement("source",{type:"image/avif",srcSet:X,sizes:R}):null,U?e.createElement("source",{type:"image/webp",srcSet:U,sizes:R}):null,e.createElement("img",{ref:y,src:Q,srcSet:!Y||U||X?void 0:Y,sizes:!Y||U||X?void 0:R,loading:z,decoding:A,alt:L,title:V,width:W,height:B,"data-filename":C,...E})):e.createElement("img",{ref:y,src:Q,loading:z,decoding:A,alt:L,title:V,width:W,height:B,"data-filename":C,...E})}),E=e.memo(_);E.displayName="OpenSiteImg";const b="undefined"!=typeof globalThis?globalThis:void 0;if(b)if(b.process){const t=b.process.env??(b.process.env={});void 0===t.NODE_ENV&&(t.NODE_ENV="production")}else b.process={env:{NODE_ENV:"production"}};t.Img=E,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
2
- //# sourceMappingURL=opensite-img.umd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"opensite-img.umd.js","sources":["../../src/utils/cache.ts","../../src/utils/api.ts","../../src/core/useMediaSelectionEffect.ts","../../src/core/useResponsiveReset.ts","../../src/core/Img.tsx","../../src/index.ts"],"sourcesContent":["// Lightweight multi-level cache inspired by ecosystem guidelines\n// L1 (instance) will be handled in components via refs/state; this is L2 (module-level) cache\n\nconst l2Cache = new Map<string, any>();\n\nexport function cacheGet<T>(key: string): T | undefined {\n return l2Cache.get(key) as T | undefined;\n}\n\nexport function cacheSet<T>(key: string, value: T) {\n l2Cache.set(key, value);\n}\n\nexport function cacheHas(key: string) {\n return l2Cache.has(key);\n}\n\n","import { cacheGet, cacheSet } from './cache.js';\nimport type { ImageData, ImageVariantsMap, ProgressiveSizes } from '../types.js';\n\nexport type FetchImageOptions = {\n cdnHost?: string; // default: https://cdn.ing\n signal?: AbortSignal;\n bypassCache?: boolean;\n};\n\nexport const DEFAULT_CDN_HOST = 'https://cdn.ing';\n\nfunction normalizeHost(cdnHost?: string): string {\n return (cdnHost ?? DEFAULT_CDN_HOST).replace(/\\/$/, '');\n}\n\nfunction buildPrimaryImageUrl(mediaId: number, cdnHost?: string): string {\n const host = normalizeHost(cdnHost);\n return `${host}/assets/images/${mediaId}`;\n}\n\nfunction buildLegacyImageUrl(mediaId: number, cdnHost?: string): string {\n const host = normalizeHost(cdnHost);\n return `${host}/i/r/${mediaId}`;\n}\n\nexport function buildPlaceholderImageUrl(mediaId: number, cdnHost?: string): string {\n const host = normalizeHost(cdnHost);\n return `${host}/assets/low_res_thumb/${mediaId}`;\n}\n\nfunction hasRenderableUrlVariant(variant?: ProgressiveSizes | null): boolean {\n if (!variant) return false;\n const candidates = [variant.sm, variant.md, variant.lg, variant.full];\n return candidates.some((value) => typeof value === 'string' && value.trim().length > 0);\n}\n\nexport function imageVariantsHaveRenderableSource(variants?: ImageVariantsMap | null): boolean {\n if (!variants) return false;\n return ['AVIF', 'WEBP', 'JPEG'].some((format) => {\n const entry = variants?.[format as keyof ImageVariantsMap] as ProgressiveSizes | undefined;\n return hasRenderableUrlVariant(entry);\n });\n}\n\nfunction hasUrlValue(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nexport function imageDataHasRenderableSource(data: ImageData): boolean {\n if (!data) return false;\n if (imageVariantsHaveRenderableSource(data.variants_data?.variants ?? null)) {\n return true;\n }\n const raw = data as any;\n const directFields = [\n raw.img_url,\n raw.file_data_url,\n raw.file_data_thumbnail_url,\n raw.img_src,\n raw.med_src,\n raw.thumb_src,\n raw.low_res_thumb,\n ];\n return directFields.some(hasUrlValue);\n}\n\nasync function fetchFrom(url: string, signal?: AbortSignal): Promise<ImageData> {\n const res = await fetch(url, { signal });\n if (!res.ok) {\n const error = new Error(`Failed to fetch image data (status ${res.status}) from ${url}`);\n (error as any).status = res.status;\n throw error;\n }\n return (await res.json()) as ImageData;\n}\n\nexport async function fetchImageData(\n mediaId: number,\n options: FetchImageOptions = {}\n): Promise<ImageData> {\n if (!Number.isFinite(mediaId)) {\n throw new Error('Invalid mediaId provided to fetchImageData');\n }\n\n const host = normalizeHost(options.cdnHost);\n const cacheKey = `image:${host}:${mediaId}`;\n if (!options.bypassCache) {\n const cached = cacheGet<ImageData>(cacheKey);\n if (cached) return cached;\n }\n\n const urls = [buildPrimaryImageUrl(mediaId, host), buildLegacyImageUrl(mediaId, host)];\n let lastError: unknown;\n\n for (const url of urls) {\n try {\n const data = await fetchFrom(url, options.signal);\n if (imageDataHasRenderableSource(data)) {\n cacheSet(cacheKey, data);\n }\n return data;\n } catch (err) {\n if ((err as any)?.name === 'AbortError') {\n throw err;\n }\n lastError = err;\n }\n }\n\n if (lastError instanceof Error) {\n throw lastError;\n }\n throw new Error(`Failed to fetch image data for mediaId ${mediaId}`);\n}\n","import { useEffect } from 'react';\n\nconst MEDIA_SELECTED_EVENT = 'dt:media-selected';\n\nexport function sendMediaSelection(blockId: string, payload: unknown) {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(\n new CustomEvent(MEDIA_SELECTED_EVENT, {\n detail: { blockId, payload },\n })\n );\n}\n\nexport function useMediaSelectionEffect() {\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const handler = () => {\n // no-op: the real handler is attached in the builder via addEventListener\n };\n window.addEventListener(MEDIA_SELECTED_EVENT, handler);\n return () => window.removeEventListener(MEDIA_SELECTED_EVENT, handler);\n }, []);\n}\n\n","import { useEffect } from 'react';\n\nexport function resetResponsivePictureState(element: HTMLPictureElement | null) {\n if (!element) return;\n element.querySelectorAll('source').forEach((source) => {\n // force browser to reconsider responsive sources\n const srcset = source.getAttribute('srcset');\n if (srcset) {\n source.setAttribute('data-srcset', srcset);\n source.removeAttribute('srcset');\n requestAnimationFrame(() => {\n source.setAttribute('srcset', srcset);\n });\n }\n });\n}\n\nexport function useResponsiveReset(ref: React.RefObject<HTMLPictureElement | HTMLImageElement>) {\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n if (element instanceof HTMLPictureElement) {\n resetResponsivePictureState(element);\n } else if (element.parentElement instanceof HTMLPictureElement) {\n resetResponsivePictureState(element.parentElement);\n }\n }, [ref]);\n}\n\n","\"use client\";\n\nimport React, { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';\nimport type { ImageData, ProgressiveSizes } from '../types.js';\nimport {\n DEFAULT_CDN_HOST,\n buildPlaceholderImageUrl,\n fetchImageData,\n imageVariantsHaveRenderableSource,\n} from '../utils/api.js';\nimport { useMediaSelectionEffect } from './useMediaSelectionEffect.js';\nimport { useResponsiveReset } from './useResponsiveReset.js';\n\ntype NativeImgProps = Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'src' | 'srcSet' | 'sizes'> & {\n src?: string;\n};\n\nexport type ImgProps = NativeImgProps & {\n mediaId?: number;\n cdnHost?: string;\n sizes?: string;\n onImageData?: (data: ImageData) => void;\n};\n\nconst DEFAULT_WIDTHS = {\n sm: 640,\n md: 1024,\n lg: 1536,\n full: 2560,\n} as const;\n\nconst MAX_VARIANT_REFRESH_ATTEMPTS = 5;\nconst VARIANT_REFRESH_DELAY_MS = 3000;\n\nconst isUrlString = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;\n\nfunction widthMapFromMetadata(v?: any): Record<'sm' | 'md' | 'lg' | 'full', number> | null {\n const w = v?.widths as any;\n if (!w) return null;\n return {\n sm: w.small ?? w.sm ?? DEFAULT_WIDTHS.sm,\n md: w.medium ?? w.md ?? DEFAULT_WIDTHS.md,\n lg: w.large ?? w.lg ?? DEFAULT_WIDTHS.lg,\n full: w.full_size ?? w.full ?? DEFAULT_WIDTHS.full,\n };\n}\n\nfunction pickBest(sizes: ProgressiveSizes | undefined): string | undefined {\n if (!sizes) return undefined;\n return sizes.md || sizes.lg || sizes.sm || sizes.full || Object.values(sizes).find(Boolean);\n}\n\nconst DEFAULT_SIZES = '(max-width:640px) 640px, (max-width:1024px) 1024px, 1536px';\n\nconst ImgBase = forwardRef<HTMLImageElement, ImgProps>(function Img(\n { mediaId, cdnHost, sizes, onImageData, loading, decoding, alt, title, src: directSrc, ...rest },\n ref,\n) {\n const imgRef = useRef<HTMLImageElement>(null);\n useImperativeHandle(ref, () => imgRef.current as HTMLImageElement);\n const pictureRef = useRef<HTMLPictureElement | null>(null);\n useResponsiveReset(pictureRef);\n useMediaSelectionEffect();\n\n const [data, setData] = useState<ImageData | null>(null);\n const [retryCount, setRetryCount] = useState(0);\n const hasMediaId = Number.isFinite(mediaId as number);\n const loadingAttr = loading ?? 'lazy';\n const decodingAttr = decoding ?? 'async';\n const [isInView, setIsInView] = useState(() => !hasMediaId || loadingAttr !== 'lazy');\n const cdnOrigin = useMemo(() => (cdnHost ?? DEFAULT_CDN_HOST).replace(/\\/$/, ''), [cdnHost]);\n\n useEffect(() => {\n if (!hasMediaId) {\n setData(null);\n setRetryCount(0);\n return;\n }\n setData(null);\n setRetryCount(0);\n }, [hasMediaId, mediaId, cdnHost]);\n\n useEffect(() => {\n if (!hasMediaId) {\n return;\n }\n const controller = new AbortController();\n fetchImageData(mediaId as number, {\n cdnHost,\n signal: controller.signal,\n bypassCache: retryCount > 0,\n })\n .then((d) => {\n setData(d);\n onImageData?.(d);\n })\n .catch((err) => {\n if (err?.name !== 'AbortError') {\n // eslint-disable-next-line no-console\n console.warn('Image data fetch failed:', err);\n }\n });\n return () => controller.abort();\n }, [hasMediaId, mediaId, cdnHost, onImageData, retryCount]);\n\n useEffect(() => {\n if (!hasMediaId || loadingAttr !== 'lazy') {\n setIsInView(true);\n return;\n }\n setIsInView(false);\n }, [hasMediaId, mediaId, loadingAttr]);\n\n useEffect(() => {\n if (!hasMediaId || loadingAttr !== 'lazy' || isInView) {\n return;\n }\n if (typeof window === 'undefined' || typeof window.IntersectionObserver === 'undefined') {\n setIsInView(true);\n return;\n }\n const node = imgRef.current;\n if (!node) {\n return;\n }\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n setIsInView(true);\n observer.disconnect();\n }\n }, { rootMargin: '200px' });\n observer.observe(node);\n return () => observer.disconnect();\n }, [hasMediaId, loadingAttr, isInView]);\n\n // Build picture/source/srcset from variants\n const picture = useMemo(() => {\n if (!data) return null;\n const v = data.variants_data?.variants ?? {};\n const webp = (v as any).WEBP as ProgressiveSizes | undefined;\n const avif = (v as any).AVIF as ProgressiveSizes | undefined;\n const jpeg = (v as any).JPEG as ProgressiveSizes | undefined;\n\n const widths =\n widthMapFromMetadata((v as any).WEBP?.metadata) ||\n widthMapFromMetadata((v as any).JPEG?.metadata) ||\n { ...DEFAULT_WIDTHS };\n\n const ensureAbsolute = (url?: string) => {\n if (!isUrlString(url)) return undefined;\n if (/^https?:\\/\\//i.test(url) || url.startsWith('data:')) return url;\n if (url.startsWith('//')) return `https:${url}`;\n if (url.startsWith('/')) return `${cdnOrigin}${url}`;\n return `${cdnOrigin}/${url}`;\n };\n\n const normalizeCandidate = (candidate?: string | null) =>\n ensureAbsolute(typeof candidate === 'string' ? candidate : undefined);\n\n const variantCandidates = [\n pickBest(webp),\n pickBest(jpeg),\n pickBest(avif),\n webp?.sm,\n webp?.md,\n webp?.lg,\n webp?.full,\n jpeg?.sm,\n jpeg?.md,\n jpeg?.lg,\n jpeg?.full,\n avif?.sm,\n avif?.md,\n avif?.lg,\n avif?.full,\n ]\n .map((candidate) => normalizeCandidate(candidate ?? undefined))\n .filter(isUrlString);\n\n const raw = data as any;\n const directCandidates = [\n raw.img_url,\n raw.file_data_url,\n raw.file_data_thumbnail_url,\n raw.img_src,\n raw.med_src,\n raw.thumb_src,\n raw.low_res_thumb,\n ]\n .map((candidate) => (isUrlString(candidate) ? normalizeCandidate(candidate) : undefined))\n .filter(isUrlString);\n\n // Add fallback_url as the final option if no variants or direct candidates\n const fallbackCandidates = raw.fallback_url ? [normalizeCandidate(raw.fallback_url)].filter(isUrlString) : [];\n\n const fallback = [...variantCandidates, ...directCandidates, ...fallbackCandidates][0];\n\n if (!fallback) {\n return null;\n }\n\n const toSrcSet = (sizes?: ProgressiveSizes) => {\n if (!sizes) return undefined;\n const entries: string[] = [];\n const push = (url?: string, width?: number) => {\n const absolute = normalizeCandidate(url);\n if (absolute && width) entries.push(`${absolute} ${width}w`);\n };\n push(sizes.sm, widths.sm);\n push(sizes.md, widths.md);\n push(sizes.lg, widths.lg);\n push(sizes.full, widths.full);\n return entries.length ? entries.join(', ') : undefined;\n };\n\n return { webp, avif, jpeg, toSrcSet, fallback, widths, hasVariantSource: variantCandidates.length > 0 } as const;\n }, [data, cdnOrigin]);\n\n const hasVariantEntries = useMemo(\n () => imageVariantsHaveRenderableSource(data?.variants_data?.variants ?? null),\n [data],\n );\n\n const variantsStatus = useMemo(() => {\n const status = (data?.variants_data?.status ?? data?.variants_status) ?? '';\n return typeof status === 'string' ? status.toLowerCase() : '';\n }, [data]);\n\n const variantsFailed = variantsStatus === 'failed' || variantsStatus === 'error';\n\n const shouldPollForVariants =\n hasMediaId && Boolean(data) && !variantsFailed && !hasVariantEntries && retryCount < MAX_VARIANT_REFRESH_ATTEMPTS;\n\n useEffect(() => {\n if (!shouldPollForVariants) {\n return;\n }\n if (typeof window === 'undefined') {\n return;\n }\n const timeoutId = window.setTimeout(() => {\n setRetryCount((count) => count + 1);\n }, VARIANT_REFRESH_DELAY_MS);\n return () => window.clearTimeout(timeoutId);\n }, [shouldPollForVariants]);\n\n // Map HTML attributes from content manifest and sizing\n const altAttr = useMemo(() => {\n if (typeof alt === 'string') return alt;\n return (data?.meta as any)?.content_manifest?.summary ?? undefined;\n }, [alt, data]);\n\n const titleAttr = useMemo(() => {\n if (typeof title === 'string') return title;\n return (data?.meta as any)?.content_manifest?.title ?? undefined;\n }, [title, data]);\n\n const widthAttr = useMemo(() => data?.meta?.sizing?.width ?? data?.variants_data?.metadata?.width ?? undefined, [data]);\n const heightAttr = useMemo(() => data?.meta?.sizing?.height ?? data?.variants_data?.metadata?.height ?? undefined, [data]);\n\n // Compute data-filename for consumers that need semantic filenames\n const dataFilename = useMemo(() => {\n const base = (data?.meta as any)?.content_manifest?.optimized_filename as string | undefined;\n if (!base) return undefined;\n // ext derived from chosen fallback url\n const href = picture?.fallback;\n if (!href) return undefined;\n const dot = href.lastIndexOf('.');\n const ext = dot > -1 ? href.slice(dot + 1).toLowerCase() : 'jpg';\n return `${base}.${ext}`;\n }, [data, picture]);\n\n // If mediaId not provided but src is, render plain img\n if (!hasMediaId) {\n const r: any = { ...rest };\n return (\n <img\n ref={imgRef}\n src={directSrc}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={altAttr}\n title={titleAttr}\n width={r.width}\n height={r.height}\n {...r}\n />\n );\n }\n\n const placeholderSrc = buildPlaceholderImageUrl(mediaId as number, cdnHost);\n\n if (!data || !picture || !isInView) {\n const r: any = { ...rest };\n return (\n <img\n ref={imgRef}\n src={placeholderSrc}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={altAttr}\n title={titleAttr}\n width={r.width ?? widthAttr}\n height={r.height ?? heightAttr}\n {...r}\n />\n );\n }\n\n const sizesAttr = sizes ?? DEFAULT_SIZES;\n const { webp, avif, jpeg, toSrcSet, fallback } = picture;\n\n const webpSet = toSrcSet(webp);\n const avifSet = toSrcSet(avif);\n const jpegSet = toSrcSet(jpeg);\n\n if (webpSet || avifSet || jpegSet) {\n return (\n <picture>\n {avifSet ? <source type=\"image/avif\" srcSet={avifSet} sizes={sizesAttr} /> : null}\n {webpSet ? <source type=\"image/webp\" srcSet={webpSet} sizes={sizesAttr} /> : null}\n <img\n ref={imgRef}\n src={fallback}\n srcSet={jpegSet && !webpSet && !avifSet ? jpegSet : undefined}\n sizes={jpegSet && !webpSet && !avifSet ? sizesAttr : undefined}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={altAttr}\n title={titleAttr}\n width={widthAttr}\n height={heightAttr}\n data-filename={dataFilename}\n {...rest}\n />\n </picture>\n );\n }\n\n return (\n <img\n ref={imgRef}\n src={fallback}\n loading={loadingAttr}\n decoding={decodingAttr}\n alt={altAttr}\n title={titleAttr}\n width={widthAttr}\n height={heightAttr}\n data-filename={dataFilename}\n {...rest}\n />\n );\n});\n\nexport const Img = memo(ImgBase);\nImg.displayName = 'OpenSiteImg';\n","// Ensure process.env exists when the module is loaded directly in the browser UMD build.\ntype GlobalWithProcess = typeof globalThis & { process?: NodeJS.Process };\n\nconst globalObject =\n typeof globalThis !== 'undefined' ? (globalThis as GlobalWithProcess) : undefined;\n\nif (globalObject) {\n if (!globalObject.process) {\n globalObject.process = {\n env: { NODE_ENV: 'production' } as NodeJS.ProcessEnv,\n } as NodeJS.Process;\n } else {\n const env = globalObject.process.env ?? (globalObject.process.env = {} as NodeJS.ProcessEnv);\n if (typeof env.NODE_ENV === 'undefined') {\n env.NODE_ENV = 'production';\n }\n }\n}\n\nexport * from './core/index.js';\nexport * from './types.js';\n"],"names":["l2Cache","Map","cacheSet","key","value","set","DEFAULT_CDN_HOST","normalizeHost","cdnHost","replace","buildPrimaryImageUrl","mediaId","buildLegacyImageUrl","imageVariantsHaveRenderableSource","variants","some","format","entry","variant","sm","md","lg","full","trim","length","hasUrlValue","imageDataHasRenderableSource","data","_a","variants_data","raw","img_url","file_data_url","file_data_thumbnail_url","img_src","med_src","thumb_src","low_res_thumb","async","fetchFrom","url","signal","res","fetch","ok","error","Error","status","json","fetchImageData","options","Number","isFinite","host","cacheKey","bypassCache","cached","get","urls","lastError","err","name","MEDIA_SELECTED_EVENT","resetResponsivePictureState","element","querySelectorAll","forEach","source","srcset","getAttribute","setAttribute","removeAttribute","requestAnimationFrame","DEFAULT_WIDTHS","isUrlString","widthMapFromMetadata","v","w","widths","small","medium","large","full_size","pickBest","sizes","Object","values","find","Boolean","ImgBase","forwardRef","onImageData","loading","decoding","alt","title","src","directSrc","rest","ref","imgRef","useRef","useImperativeHandle","current","useEffect","HTMLPictureElement","parentElement","useResponsiveReset","window","handler","addEventListener","removeEventListener","setData","useState","retryCount","setRetryCount","hasMediaId","loadingAttr","decodingAttr","isInView","setIsInView","cdnOrigin","useMemo","controller","AbortController","then","d","catch","console","warn","abort","IntersectionObserver","node","observer","entries","isIntersecting","disconnect","rootMargin","observe","picture","webp","WEBP","avif","AVIF","jpeg","JPEG","_b","metadata","_c","normalizeCandidate","candidate","test","startsWith","ensureAbsolute","variantCandidates","map","filter","directCandidates","fallbackCandidates","fallback_url","fallback","toSrcSet","push","width","absolute","join","hasVariantSource","hasVariantEntries","variantsStatus","variants_status","toLowerCase","variantsFailed","shouldPollForVariants","timeoutId","setTimeout","count","clearTimeout","altAttr","meta","content_manifest","summary","titleAttr","widthAttr","sizing","_d","heightAttr","height","dataFilename","base","optimized_filename","href","dot","lastIndexOf","slice","r","React","createElement","placeholderSrc","buildPlaceholderImageUrl","sizesAttr","webpSet","avifSet","jpegSet","type","srcSet","Img","memo","displayName","globalObject","globalThis","process","env","NODE_ENV"],"mappings":"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"}
package/dist/types.cjs DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/types.d.ts DELETED
@@ -1,6 +0,0 @@
1
- export type ImageFormat = "avif" | "webp" | "jpeg" | "png";
2
- export type OptixFlowConfig = {
3
- apiKey: string;
4
- compressionLevel?: number;
5
- renderedFileType?: ImageFormat;
6
- };
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,94 +0,0 @@
1
- import { cacheGet, cacheSet } from './cache.js';
2
- export const DEFAULT_CDN_HOST = 'https://cdn.ing';
3
- function normalizeHost(cdnHost) {
4
- return (cdnHost ?? DEFAULT_CDN_HOST).replace(/\/$/, '');
5
- }
6
- function buildPrimaryImageUrl(mediaId, cdnHost) {
7
- const host = normalizeHost(cdnHost);
8
- return `${host}/assets/images/${mediaId}`;
9
- }
10
- function buildLegacyImageUrl(mediaId, cdnHost) {
11
- const host = normalizeHost(cdnHost);
12
- return `${host}/i/r/${mediaId}`;
13
- }
14
- export function buildPlaceholderImageUrl(mediaId, cdnHost) {
15
- const host = normalizeHost(cdnHost);
16
- return `${host}/assets/low_res_thumb/${mediaId}`;
17
- }
18
- function hasRenderableUrlVariant(variant) {
19
- if (!variant)
20
- return false;
21
- const candidates = [variant.sm, variant.md, variant.lg, variant.full];
22
- return candidates.some((value) => typeof value === 'string' && value.trim().length > 0);
23
- }
24
- export function imageVariantsHaveRenderableSource(variants) {
25
- if (!variants)
26
- return false;
27
- return ['AVIF', 'WEBP', 'JPEG'].some((format) => {
28
- const entry = variants?.[format];
29
- return hasRenderableUrlVariant(entry);
30
- });
31
- }
32
- function hasUrlValue(value) {
33
- return typeof value === 'string' && value.trim().length > 0;
34
- }
35
- export function imageDataHasRenderableSource(data) {
36
- if (!data)
37
- return false;
38
- if (imageVariantsHaveRenderableSource(data.variants_data?.variants ?? null)) {
39
- return true;
40
- }
41
- const raw = data;
42
- const directFields = [
43
- raw.img_url,
44
- raw.file_data_url,
45
- raw.file_data_thumbnail_url,
46
- raw.img_src,
47
- raw.med_src,
48
- raw.thumb_src,
49
- raw.low_res_thumb,
50
- ];
51
- return directFields.some(hasUrlValue);
52
- }
53
- async function fetchFrom(url, signal) {
54
- const res = await fetch(url, { signal });
55
- if (!res.ok) {
56
- const error = new Error(`Failed to fetch image data (status ${res.status}) from ${url}`);
57
- error.status = res.status;
58
- throw error;
59
- }
60
- return (await res.json());
61
- }
62
- export async function fetchImageData(mediaId, options = {}) {
63
- if (!Number.isFinite(mediaId)) {
64
- throw new Error('Invalid mediaId provided to fetchImageData');
65
- }
66
- const host = normalizeHost(options.cdnHost);
67
- const cacheKey = `image:${host}:${mediaId}`;
68
- if (!options.bypassCache) {
69
- const cached = cacheGet(cacheKey);
70
- if (cached)
71
- return cached;
72
- }
73
- const urls = [buildPrimaryImageUrl(mediaId, host), buildLegacyImageUrl(mediaId, host)];
74
- let lastError;
75
- for (const url of urls) {
76
- try {
77
- const data = await fetchFrom(url, options.signal);
78
- if (imageDataHasRenderableSource(data)) {
79
- cacheSet(cacheKey, data);
80
- }
81
- return data;
82
- }
83
- catch (err) {
84
- if (err?.name === 'AbortError') {
85
- throw err;
86
- }
87
- lastError = err;
88
- }
89
- }
90
- if (lastError instanceof Error) {
91
- throw lastError;
92
- }
93
- throw new Error(`Failed to fetch image data for mediaId ${mediaId}`);
94
- }
@@ -1,11 +0,0 @@
1
- import type { ImageData, ImageVariantsMap } from '../types.js';
2
- export type FetchImageOptions = {
3
- cdnHost?: string;
4
- signal?: AbortSignal;
5
- bypassCache?: boolean;
6
- };
7
- export declare const DEFAULT_CDN_HOST = "https://cdn.ing";
8
- export declare function buildPlaceholderImageUrl(mediaId: number, cdnHost?: string): string;
9
- export declare function imageVariantsHaveRenderableSource(variants?: ImageVariantsMap | null): boolean;
10
- export declare function imageDataHasRenderableSource(data: ImageData): boolean;
11
- export declare function fetchImageData(mediaId: number, options?: FetchImageOptions): Promise<ImageData>;
package/dist/utils/api.js DELETED
@@ -1,94 +0,0 @@
1
- import { cacheGet, cacheSet } from './cache.js';
2
- export const DEFAULT_CDN_HOST = 'https://cdn.ing';
3
- function normalizeHost(cdnHost) {
4
- return (cdnHost ?? DEFAULT_CDN_HOST).replace(/\/$/, '');
5
- }
6
- function buildPrimaryImageUrl(mediaId, cdnHost) {
7
- const host = normalizeHost(cdnHost);
8
- return `${host}/assets/images/${mediaId}`;
9
- }
10
- function buildLegacyImageUrl(mediaId, cdnHost) {
11
- const host = normalizeHost(cdnHost);
12
- return `${host}/i/r/${mediaId}`;
13
- }
14
- export function buildPlaceholderImageUrl(mediaId, cdnHost) {
15
- const host = normalizeHost(cdnHost);
16
- return `${host}/assets/low_res_thumb/${mediaId}`;
17
- }
18
- function hasRenderableUrlVariant(variant) {
19
- if (!variant)
20
- return false;
21
- const candidates = [variant.sm, variant.md, variant.lg, variant.full];
22
- return candidates.some((value) => typeof value === 'string' && value.trim().length > 0);
23
- }
24
- export function imageVariantsHaveRenderableSource(variants) {
25
- if (!variants)
26
- return false;
27
- return ['AVIF', 'WEBP', 'JPEG'].some((format) => {
28
- const entry = variants?.[format];
29
- return hasRenderableUrlVariant(entry);
30
- });
31
- }
32
- function hasUrlValue(value) {
33
- return typeof value === 'string' && value.trim().length > 0;
34
- }
35
- export function imageDataHasRenderableSource(data) {
36
- if (!data)
37
- return false;
38
- if (imageVariantsHaveRenderableSource(data.variants_data?.variants ?? null)) {
39
- return true;
40
- }
41
- const raw = data;
42
- const directFields = [
43
- raw.img_url,
44
- raw.file_data_url,
45
- raw.file_data_thumbnail_url,
46
- raw.img_src,
47
- raw.med_src,
48
- raw.thumb_src,
49
- raw.low_res_thumb,
50
- ];
51
- return directFields.some(hasUrlValue);
52
- }
53
- async function fetchFrom(url, signal) {
54
- const res = await fetch(url, { signal });
55
- if (!res.ok) {
56
- const error = new Error(`Failed to fetch image data (status ${res.status}) from ${url}`);
57
- error.status = res.status;
58
- throw error;
59
- }
60
- return (await res.json());
61
- }
62
- export async function fetchImageData(mediaId, options = {}) {
63
- if (!Number.isFinite(mediaId)) {
64
- throw new Error('Invalid mediaId provided to fetchImageData');
65
- }
66
- const host = normalizeHost(options.cdnHost);
67
- const cacheKey = `image:${host}:${mediaId}`;
68
- if (!options.bypassCache) {
69
- const cached = cacheGet(cacheKey);
70
- if (cached)
71
- return cached;
72
- }
73
- const urls = [buildPrimaryImageUrl(mediaId, host), buildLegacyImageUrl(mediaId, host)];
74
- let lastError;
75
- for (const url of urls) {
76
- try {
77
- const data = await fetchFrom(url, options.signal);
78
- if (imageDataHasRenderableSource(data)) {
79
- cacheSet(cacheKey, data);
80
- }
81
- return data;
82
- }
83
- catch (err) {
84
- if (err?.name === 'AbortError') {
85
- throw err;
86
- }
87
- lastError = err;
88
- }
89
- }
90
- if (lastError instanceof Error) {
91
- throw lastError;
92
- }
93
- throw new Error(`Failed to fetch image data for mediaId ${mediaId}`);
94
- }
@@ -1,12 +0,0 @@
1
- // Lightweight multi-level cache inspired by ecosystem guidelines
2
- // L1 (instance) will be handled in components via refs/state; this is L2 (module-level) cache
3
- const l2Cache = new Map();
4
- export function cacheGet(key) {
5
- return l2Cache.get(key);
6
- }
7
- export function cacheSet(key, value) {
8
- l2Cache.set(key, value);
9
- }
10
- export function cacheHas(key) {
11
- return l2Cache.has(key);
12
- }
@@ -1,3 +0,0 @@
1
- export declare function cacheGet<T>(key: string): T | undefined;
2
- export declare function cacheSet<T>(key: string, value: T): void;
3
- export declare function cacheHas(key: string): boolean;
@@ -1,12 +0,0 @@
1
- // Lightweight multi-level cache inspired by ecosystem guidelines
2
- // L1 (instance) will be handled in components via refs/state; this is L2 (module-level) cache
3
- const l2Cache = new Map();
4
- export function cacheGet(key) {
5
- return l2Cache.get(key);
6
- }
7
- export function cacheSet(key, value) {
8
- l2Cache.set(key, value);
9
- }
10
- export function cacheHas(key) {
11
- return l2Cache.has(key);
12
- }