@page-speed/img 0.4.6 → 0.4.7

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2025, OpenSite AI. All rights reserved.
3
+ Copyright (c) 2026, OpenSite AI. All rights reserved.
4
4
 
5
5
  Redistribution and use in source and binary forms, with or without
6
6
  modification, are permitted provided that the following conditions are met:
package/README.md CHANGED
@@ -1,24 +1,21 @@
1
1
  # ⚡ @page-speed/img
2
2
 
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)
3
+ ## Performance-optimized React Image component - 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. Utilized throughout the [OpenSite Semantic UI Platform](https://opensite.ai).
4
4
 
5
- > **Performance-optimized React Image component**
6
-
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.
5
+ ![Page Speed React Image Component](https://octane.cdn.ing/api/v1/images/transform?url=https://toastability-production.s3.amazonaws.com/gghtx0lxw9f2zigs427qc2phu024&f=webp)
8
6
 
9
7
  [![npm version](https://img.shields.io/npm/v/@page-speed/img?style=flat-square)](https://www.npmjs.com/package/@page-speed/hooks)
10
8
  [![npm downloads](https://img.shields.io/npm/dm/@page-speed/img?style=flat-square)](https://www.npmjs.com/package/@page-speed/hooks)
11
9
  [![License](https://img.shields.io/npm/l/@page-speed/img?style=flat-square)](./LICENSE)
12
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square)](./tsconfig.json)
13
- [![Tree-Shakeable](https://img.shields.io/badge/Tree%20Shakeable-Yes-brightgreen?style=flat-square)](#tree-shaking)
14
11
 
15
- [Documentation](#documentation) · [Quick Start](#quick-start) · [Hooks](#hooks) · [Examples](#examples) · [Contributing](./CONTRIBUTING.md)
12
+ [Documentation](#documentation) · [Quick Start](#quick-start) · [Global Defaults](#setting-global-defaults) · [Examples](#examples) · [Contributing](./CONTRIBUTING.md)
16
13
 
17
14
  ---
18
15
 
19
16
  ## Documentation
20
17
 
21
- `@page-speed/img` is a React-first, OptixFlow-enabled image component that ships Lighthouse-friendly markup by default. It uses `useOptimizedImage` from `@page-speed/hooks` to compute pixel-perfect `src`, DPR-aware `srcset`, and `sizes` on the client. Tree shaking keeps the bundle lean—only the media hook is pulled in.
18
+ `@page-speed/img` is a React-first, OptixFlow-enabled image component that ships Lighthouse-friendly markup by default. It uses `useOptimizedImage` from `@page-speed/hooks` to compute pixel-perfect `src`, DPR-aware `srcset`, and `sizes` on the client. Tree shaking keeps the bundle lean only the media hook is pulled in.
22
19
 
23
20
  ### Installation
24
21
 
@@ -28,13 +25,103 @@ pnpm add @page-speed/img
28
25
 
29
26
  Peer deps: `react` and `react-dom` (17+). For OptixFlow optimization, supply an API key.
30
27
 
28
+ ---
29
+
31
30
  ### Usage (React / Next.js)
32
31
 
32
+ ```tsx
33
+ import { Img } from "@page-speed/img";
34
+
35
+ export function HeroImage() {
36
+ return (
37
+ <Img
38
+ src="https://images.example.com/hero.jpg"
39
+ alt="Hero"
40
+ width={1280}
41
+ height={720}
42
+ eager
43
+ />
44
+ );
45
+ }
46
+ ```
47
+
48
+ What you get automatically:
49
+
50
+ - Pixel-perfect primary `src` sized to the rendered element (Lighthouse "Properly size images" pass).
51
+ - DPR-aware `srcset` (1x/2x) for AVIF, WebP, and JPEG.
52
+ - Lazy loading via IntersectionObserver; set `eager` for above-the-fold images.
53
+ - Optional OptixFlow compression and format selection with a single prop.
54
+
55
+ ---
56
+
57
+ ### Setting Global Defaults
58
+
59
+ When all or most images in your app share the same OptixFlow configuration, you can set it once globally instead of repeating `optixFlowConfig` on every `<Img />`.
60
+
61
+ #### ✅ Recommended: `<OptixFlowConfig />` component (SSR-safe)
62
+
63
+ The `OptixFlowConfig` component is the preferred approach for React and Next.js apps. It applies the default config inside a `useEffect`, which means it **never runs during server-side rendering** — making it safe to place in any server component tree without wrapping in a `"use client"` boundary at the call site.
64
+
65
+ **As a wrapper around your app:**
66
+
67
+ ```tsx
68
+ // app/layout.tsx (Next.js App Router) or src/App.tsx
69
+ import { OptixFlowConfig } from "@page-speed/img";
70
+
71
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
72
+ return (
73
+ <html lang="en">
74
+ <body>
75
+ <OptixFlowConfig config={{ apiKey: process.env.NEXT_PUBLIC_OPTIX_API_KEY!, compressionLevel: 80 }}>
76
+ {children}
77
+ </OptixFlowConfig>
78
+ </body>
79
+ </html>
80
+ );
81
+ }
82
+ ```
83
+
84
+ **Standalone (no children required):**
85
+
86
+ ```tsx
87
+ // Place anywhere in the tree; renders null, no visual output
88
+ import { OptixFlowConfig } from "@page-speed/img";
89
+
90
+ export function Providers({ children }: { children: React.ReactNode }) {
91
+ return (
92
+ <>
93
+ <OptixFlowConfig config={{ apiKey: process.env.NEXT_PUBLIC_OPTIX_API_KEY! }} />
94
+ {children}
95
+ </>
96
+ );
97
+ }
98
+ ```
99
+
100
+ Individual `<Img />` components can always override the default with their own `optixFlowConfig` prop:
101
+
102
+ ```tsx
103
+ <Img
104
+ src="https://images.example.com/hero.jpg"
105
+ alt="Hero"
106
+ width={1280}
107
+ height={720}
108
+ // Overrides the global default for this image only
109
+ optixFlowConfig={{ renderedFileType: "jpeg", objectFit: "cover" }}
110
+ />
111
+ ```
112
+
113
+ #### Alternative: `setDefaultOptixFlowConfig()` function
114
+
115
+ For purely client-side apps, scripts, or imperative initialization (e.g. outside of React's render tree), the `setDefaultOptixFlowConfig` function is available. Call it once at app startup before any `<Img />` components mount.
116
+
33
117
  ```tsx
34
118
  import { Img, setDefaultOptixFlowConfig } from "@page-speed/img";
35
119
 
36
- // Optional: set once at app start
37
- setDefaultOptixFlowConfig({ apiKey: process.env.NEXT_PUBLIC_OPTIX_API_KEY!, compressionLevel: 80 });
120
+ // Call once, e.g. in main.tsx / index.tsx before rendering
121
+ setDefaultOptixFlowConfig({
122
+ apiKey: process.env.VITE_OPTIX_API_KEY!,
123
+ compressionLevel: 80,
124
+ });
38
125
 
39
126
  export function HeroImage() {
40
127
  return (
@@ -43,33 +130,22 @@ export function HeroImage() {
43
130
  alt="Hero"
44
131
  width={1280}
45
132
  height={720}
46
- // Per-image override (optional)
47
- optixFlowConfig={{ renderedFileType: "jpeg", objectFit: "cover" }}
48
133
  />
49
134
  );
50
135
  }
51
136
  ```
52
137
 
53
- What you get:
54
- - Pixel-perfect primary `src` sized to the rendered element (Lighthouse “Properly size images” pass).
55
- - DPR-aware `srcset` (1x/2x) for AVIF/WebP/JPEG.
56
- - Lazy loading with IntersectionObserver; set `eager` for above-the-fold.
57
- - Optional OptixFlow compression/format selection with a single prop.
138
+ > **Note:** `setDefaultOptixFlowConfig` is not SSR-safe on its own. In server-rendered environments (Next.js, Remix, etc.) prefer the `<OptixFlowConfig />` component, which handles the client/server boundary automatically.
58
139
 
59
- ### Props
140
+ To clear or reset the global default at any point:
60
141
 
61
- - `src` (string, required): Image URL.
62
- - `alt`, `title`, standard `<img>` attributes.
63
- - `width`, `height`: Set for CLS prevention; used as hints for sizing. Actual rendered size is measured to generate the pixel-perfect URL.
64
- - `loading`, `decoding`: Defaults `lazy` / `async`. Set `eager` to force above-the-fold fetch.
65
- - `sizes`: Override the auto-generated `sizes` from `useOptimizedImage`.
66
- - `intersectionMargin`, `intersectionThreshold`: Tweak lazy-load observer.
67
- - `optixFlowConfig`: `{ apiKey: string; compressionLevel?: number; renderedFileType?: 'avif' | 'webp' | 'jpeg' | 'png'; objectFit?: 'cover' | 'contain' | 'fill'; }`.
142
+ ```ts
143
+ setDefaultOptixFlowConfig(null);
144
+ ```
68
145
 
69
- ### Global defaults (React & UMD)
146
+ #### Browser global (UMD / inline script)
70
147
 
71
- - Programmatic: `setDefaultOptixFlowConfig({ apiKey: '...' })` once during app init.
72
- - Browser global (UMD/inline):
148
+ For vanilla HTML pages or CMS integrations using the UMD build, set the global before the component renders:
73
149
 
74
150
  ```html
75
151
  <script>
@@ -85,12 +161,52 @@ What you get:
85
161
 
86
162
  `window.OpensiteImgDefaults` and `window.PAGE_SPEED_IMG_DEFAULTS` are also honored for backward compatibility.
87
163
 
164
+ ---
165
+
166
+ ### `<Img />` Props
167
+
168
+ | Prop | Type | Default | Description |
169
+ |---|---|---|---|
170
+ | `src` | `string` | — | **(Required)** Image URL. |
171
+ | `alt` | `string` | — | Alt text (passed through to `<img>`). |
172
+ | `width` | `number \| string` | — | Hint for sizing and CLS prevention. |
173
+ | `height` | `number \| string` | — | Hint for sizing and CLS prevention. |
174
+ | `eager` | `boolean` | `false` | Force eager loading (above-the-fold). Equivalent to `loading="eager"`. |
175
+ | `loading` | `"lazy" \| "eager"` | `"lazy"` | Native loading attribute. `eager` prop takes precedence. |
176
+ | `decoding` | `"async" \| "sync" \| "auto"` | `"async"` | Native decoding attribute. |
177
+ | `fetchPriority` | `"high" \| "low" \| "auto"` | `"high"` when eager | Native fetch priority. |
178
+ | `sizes` | `string` | auto-computed | Override the `sizes` attribute generated by `useOptimizedImage`. |
179
+ | `intersectionMargin` | `string` | `"200px"` | Root margin for the lazy-load IntersectionObserver. |
180
+ | `intersectionThreshold` | `number` | `0.1` | Threshold for the lazy-load IntersectionObserver. |
181
+ | `optixFlowConfig` | `OptixFlowConfig` | global default | Per-image OptixFlow config. Overrides any global default. |
182
+ | `useDebugMode` | `boolean` | `false` | Log image request details to the console. |
183
+
184
+ **`optixFlowConfig` shape:**
185
+
186
+ ```ts
187
+ {
188
+ apiKey: string;
189
+ compressionLevel?: number; // 1–100
190
+ renderedFileType?: "avif" | "webp" | "jpeg" | "png";
191
+ objectFit?: "cover" | "contain" | "fill";
192
+ }
193
+ ```
194
+
195
+ ### `<OptixFlowConfig />` Props
196
+
197
+ | Prop | Type | Description |
198
+ |---|---|---|
199
+ | `config` | `OptixFlowConfig` | The OptixFlow configuration to apply as the global default. |
200
+ | `children` | `React.ReactNode` | Optional. When provided, children are rendered; otherwise the component renders `null`. |
201
+
202
+ ---
203
+
88
204
  ### UMD usage
89
205
 
90
206
  ```html
91
207
  <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
92
208
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
93
- <script src="https://cdn.jsdelivr.net/npm/@page-speed/img@0.0.2/dist/browser/page-speed-img.umd.js" crossorigin></script>
209
+ <script src="https://cdn.jsdelivr.net/npm/@page-speed/img@0.4.7/dist/browser/page-speed-img.umd.js" crossorigin></script>
94
210
 
95
211
  <div id="app"></div>
96
212
  <script>
@@ -107,14 +223,21 @@ What you get:
107
223
  </script>
108
224
  ```
109
225
 
226
+ ---
227
+
110
228
  ### SSR considerations
111
229
 
112
- - The component is client-only (`"use client"`). For SSR apps, render it in client components/entry points.
113
- - Safe in non-browser contexts: guards exist for `window`/`IntersectionObserver`.
230
+ - `<Img />` is marked `"use client"`. In Next.js App Router, place it inside a Client Component or a shared layout where the `"use client"` boundary is already established.
231
+ - `<OptixFlowConfig />` is also marked `"use client"` and applies its config exclusively via `useEffect`, so it is safe to import and render from a Server Component tree — the config call never executes on the server.
232
+ - Guards exist for `window` and `IntersectionObserver` throughout the library, so modules can be imported safely in SSR environments without crashing.
233
+
234
+ ---
114
235
 
115
236
  ### Tree shaking
116
237
 
117
- `@page-speed/img` only imports `useOptimizedImage` from `@page-speed/hooks`, keeping bundles small. Both ESM and CJS builds are emitted; UMD is externalized to React/ReactDOM.
238
+ `@page-speed/img` only imports `useOptimizedImage` from `@page-speed/hooks`, keeping bundles small. Both ESM and CJS builds are emitted; the UMD build externalizes React and ReactDOM.
239
+
240
+ ---
118
241
 
119
242
  ### Testing
120
243
 
@@ -122,12 +245,18 @@ What you get:
122
245
  pnpm test
123
246
  ```
124
247
 
248
+ ---
249
+
125
250
  ### Roadmap
126
251
 
127
- - Add storybook examples for common layouts (hero, gallery, card).
252
+ - Add Storybook examples for common layouts (hero, gallery, card).
128
253
 
129
254
  ---
130
255
 
131
256
  ## Contributing
132
257
 
133
- PRs welcome. Please run `pnpm test` before submitting.
258
+ PRs welcome. Please run `pnpm test` before submitting. See [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
259
+
260
+ ## License
261
+
262
+ BSD 3-Clause
@@ -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,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"})});
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";function i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const n=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,n.get?n:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const n=i(t);var r=[1,2],o="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const s="dt:media-selected",u=()=>{};let l=0,c=!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 a="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let f;const g=e=>e??f??(()=>{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)})(),h=e=>{f=e??void 0},p=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}}},w=({sizes:e,loading:i,decoding:n,alt:f,title:h,src:w,eager:m,width:v,height:b,fetchPriority:y,intersectionMargin:E,intersectionThreshold:M,optixFlowConfig:A,useDebugMode:S,forwardedRef:I,...j})=>{const L=t.useRef(null),F=t.useRef(null);var P;P=F,t.useEffect(()=>{const e=P.current;e&&(e instanceof HTMLPictureElement?d(e):e.parentElement instanceof HTMLPictureElement&&d(e.parentElement))},[P]),t.useEffect(()=>{if("undefined"!=typeof window)return c||(window.addEventListener(s,u),c=!0),l+=1,()=>{l-=1,l<=0&&c&&(window.removeEventListener(s,u),c=!1)}},[]);const x=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),O=t.useMemo(()=>p(v),[v]),z=t.useMemo(()=>p(b),[b]),V=t.useMemo(()=>g(A),[A]),T=t.useMemo(()=>m??"eager"===i,[m,i]),C=t.useMemo(()=>({src:x,eager:T,width:O,height:z,rootMargin:E??"200px",threshold:M??.1,optixFlowConfig:V}),[x,T,O,z,E,M,V]),{ref:R,src:D,srcset:N,sizes:q,loading:_,isInView:k,size:H}=function(e){const{src:i,eager:n=!1,threshold:s=.1,rootMargin:u="50px",width:l,height:c,optixFlowConfig:d}=e,a=t.useMemo(()=>null==d?void 0:d.apiKey,[null==d?void 0:d.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:l??p.width,height:c??p.height}),[l,c,p.width,p.height]);o(()=>{if(!m.current)return;if(void 0!==l&&void 0!==c)return;const e=()=>{const e=m.current;if(!e)return;const t=l??(Math.round(e.clientWidth)||e.naturalWidth||0),i=c??(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()}},[l,c]);const y=t.useCallback((e,t,n)=>{if(!f)return i;if(!e||!t)return i;const r=new URLSearchParams;return r.set("url",i),r.set("fit",String((null==d?void 0:d.objectFit)??"cover")),r.set("w",String(e)),r.set("h",String(t)),r.set("q",String((null==d?void 0:d.compressionLevel)??75)),r.set("f",n),r.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${r.toString()}`},[f,i,null==d?void 0:d.compressionLevel,a,null==d?void 0:d.objectFit]),E=t.useCallback((e,t,i)=>f&&0!==e&&0!==t?r.map(n=>{const r=Math.round(e*n),o=Math.round(t*n);return`${y(r,o,i)} ${n}x`}).join(", "):"",[f,y]),M=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return i;const t=(null==d?void 0:d.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,i,b.width,b.height,null==d?void 0:d.renderedFileType,null==d?void 0:d.compressionLevel,null==d?void 0:d.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]),S=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&m.current){if(!n)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})}},[n,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||n?M:i,srcset:g.isInView||n?A:{avif:"",webp:"",jpeg:""},sizes:g.isInView||n?S:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:n?"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]))(R,I,L),B=t.useMemo(()=>e??(q||void 0),[e,q]),G=t.useMemo(()=>i??_??"lazy",[i,_]),K=t.useMemo(()=>n??"async",[n]),U=t.useMemo(()=>y??(T?"high":void 0),[y,T]),W=t.useMemo(()=>Boolean(N.avif||N.webp||N.jpeg),[N.avif,N.webp,N.jpeg]),Q=t.useMemo(()=>D||x||a,[D,x]),J=t.useMemo(()=>!W||N.avif||N.webp?"":N.jpeg,[W,N.avif,N.webp,N.jpeg]),X=t.useMemo(()=>O??(H.width||void 0),[O,null==H?void 0:H.width]),Y=t.useMemo(()=>z??(H.height||void 0),[z,null==H?void 0:H.height]);return function({enabled:e,eagerLoad:i,isInView:n,imgSrc:r,transparentPixel:o,srcset:s,sizesAttr:u}){const l=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("|");l.current!==t&&(l.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:S??!1,eagerLoad:T,isInView:k,imgSrc:Q,transparentPixel:a,srcset:N,sizesAttr:B}),W?t.createElement("picture",{ref:F},N.avif?t.createElement("source",{type:"image/avif",srcSet:N.avif,sizes:B}):null,N.webp?t.createElement("source",{type:"image/webp",srcSet:N.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:f,title:h,width:X,height:Y,...j})):t.createElement("img",{ref:$,src:Q,loading:G,decoding:K,fetchPriority:U,alt:f,title:h,width:X,height:Y,...j})},m=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(w,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),v=t.memo(m);v.displayName="PageSpeedImg";const b="undefined"!=typeof globalThis?globalThis:void 0;if(b)if(b.process){const e=b.process.env??(b.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else b.process={env:{NODE_ENV:"production"}};e.Img=v,e.OptixFlowConfig=function({config:e,children:t}){return n.useEffect(()=>{h(e??null)},[e]),t?n.createElement(n.Fragment,null,t):null},e.setDefaultOptixFlowConfig=h,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,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"})});
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";function i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const n=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,n.get?n:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const n=i(t);var r=[1,2],o="undefined"!=typeof window?t.useLayoutEffect:t.useEffect;const s="dt:media-selected",u=()=>{};let l=0,c=!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 a="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";let f;const g=e=>e??f??(()=>{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)})(),h=e=>{f=e??void 0},p=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}}},w=({sizes:e,loading:i,decoding:n,alt:f,title:h,src:w,eager:m,width:v,height:b,fetchPriority:y,intersectionMargin:E,intersectionThreshold:M,optixFlowConfig:A,useDebugMode:S,forwardedRef:I,...j})=>{const L=t.useRef(null),F=t.useRef(null);var P;P=F,t.useEffect(()=>{const e=P.current;e&&(e instanceof HTMLPictureElement?d(e):e.parentElement instanceof HTMLPictureElement&&d(e.parentElement))},[P]),t.useEffect(()=>{if("undefined"!=typeof window)return c||(window.addEventListener(s,u),c=!0),l+=1,()=>{l-=1,l<=0&&c&&(window.removeEventListener(s,u),c=!1)}},[]);const x=t.useMemo(()=>"string"==typeof w?w.trim():"",[w]),O=t.useMemo(()=>p(v),[v]),z=t.useMemo(()=>p(b),[b]),V=t.useMemo(()=>g(A),[A]),T=t.useMemo(()=>m??"eager"===i,[m,i]),C=t.useMemo(()=>({src:x,eager:T,width:O,height:z,rootMargin:E??"200px",threshold:M??.1,optixFlowConfig:V}),[x,T,O,z,E,M,V]),{ref:R,src:D,srcset:N,sizes:q,loading:_,isInView:k,size:H}=function(e){const{src:i,eager:n=!1,threshold:s=.1,rootMargin:u="50px",width:l,height:c,optixFlowConfig:d}=e,a=t.useMemo(()=>null==d?void 0:d.apiKey,[null==d?void 0:d.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:l??p.width,height:c??p.height}),[l,c,p.width,p.height]);o(()=>{if(!m.current)return;if(void 0!==l&&void 0!==c)return;const e=()=>{const e=m.current;if(!e)return;const t=l??(Math.round(e.clientWidth)||e.naturalWidth||0),i=c??(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()}},[l,c]);const y=t.useCallback((e,t,n)=>{if(!f)return i;if(!e||!t)return i;const r=new URLSearchParams;return r.set("url",i),r.set("fit",String((null==d?void 0:d.objectFit)??"cover")),r.set("w",String(e)),r.set("h",String(t)),r.set("q",String((null==d?void 0:d.compressionLevel)??75)),r.set("f",n),r.set("apiKey",a),`https://octane.cdn.ing/api/v1/images/transform?${r.toString()}`},[f,i,null==d?void 0:d.compressionLevel,a,null==d?void 0:d.objectFit]),E=t.useCallback((e,t,i)=>f&&0!==e&&0!==t?r.map(n=>{const r=Math.round(e*n),o=Math.round(t*n);return`${y(r,o,i)} ${n}x`}).join(", "):"",[f,y]),M=t.useMemo(()=>{const e=b.width>0&&b.height>0;if(!f||!e)return i;const t=(null==d?void 0:d.renderedFileType)??"jpeg";return y(b.width,b.height,t)},[f,i,b.width,b.height,null==d?void 0:d.renderedFileType,null==d?void 0:d.compressionLevel,null==d?void 0:d.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]),S=t.useMemo(()=>0===b.width?"":`${b.width}px`,[b.width]);return t.useEffect(()=>{if("undefined"!=typeof window&&m.current){if(!n)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})}},[n,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||n?M:i,srcset:g.isInView||n?A:{avif:"",webp:"",jpeg:""},sizes:g.isInView||n?S:"",isLoaded:g.isLoaded,isInView:g.isInView,loading:n?"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]))(R,I,L),B=t.useMemo(()=>e??(q||void 0),[e,q]),G=t.useMemo(()=>i??_??"lazy",[i,_]),K=t.useMemo(()=>n??"async",[n]),U=t.useMemo(()=>y??(T?"high":void 0),[y,T]),W=t.useMemo(()=>Boolean(N.avif||N.webp||N.jpeg),[N.avif,N.webp,N.jpeg]),Q=t.useMemo(()=>D||x||a,[D,x]),J=t.useMemo(()=>!W||N.avif||N.webp?"":N.jpeg,[W,N.avif,N.webp,N.jpeg]),X=t.useMemo(()=>O??(H.width||void 0),[O,null==H?void 0:H.width]),Y=t.useMemo(()=>z??(H.height||void 0),[z,null==H?void 0:H.height]);return function({enabled:e,eagerLoad:i,isInView:n,imgSrc:r,transparentPixel:o,srcset:s,sizesAttr:u}){const l=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("|");l.current!==t&&(l.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:S??!1,eagerLoad:T,isInView:k,imgSrc:Q,transparentPixel:a,srcset:N,sizesAttr:B}),W?t.createElement("picture",{ref:F},N.avif?t.createElement("source",{type:"image/avif",srcSet:N.avif,sizes:B}):null,N.webp?t.createElement("source",{type:"image/webp",srcSet:N.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:f,title:h,width:X,height:Y,...j})):t.createElement("img",{ref:$,src:Q,loading:G,decoding:K,fetchPriority:U,alt:f,title:h,width:X,height:Y,...j})},m=t.forwardRef(function(e,i){return"string"==typeof e.src&&e.src.trim().length>0?t.createElement(w,{...e,forwardedRef:i}):("undefined"!=typeof console&&console.warn&&console.warn("<Img /> requires src. No src provided, rendering null."),null)}),v=t.memo(m);v.displayName="PageSpeedImg";const b="undefined"!=typeof globalThis?globalThis:void 0;if(b)if(b.process){const e=b.process.env??(b.process.env={});void 0===e.NODE_ENV&&(e.NODE_ENV="production")}else b.process={env:{NODE_ENV:"production"}};e.Img=v,e.OptixFlowConfig=function({config:e,children:t}){return n.useEffect(()=>{h(e??null)},[e]),t?n.createElement(n.Fragment,null,t):null},e.setDefaultOptixFlowConfig=h,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/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]}
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","../../src/core/OptixFlowConfig.tsx"],"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// Re-export specific items for clarity and CDN usage\nexport { Img, setDefaultOptixFlowConfig, OptixFlowConfig } from './core/index.js';\nexport type { ImgProps, OptixFlowConfigProps } from './core/index.js';\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { UseOptimizedImageOptions } from \"@page-speed/hooks/media\";\nimport { setDefaultOptixFlowConfig } from \"./Img.js\";\n\n/**\n * Props for the OptixFlowConfig component\n */\nexport interface OptixFlowConfigProps {\n /**\n * OptixFlow configuration to set as default for all images\n * @example { apiKey: 'your-api-key', compressionLevel: 80 }\n */\n config: UseOptimizedImageOptions[\"optixFlowConfig\"];\n /**\n * Optional children (component returns null regardless)\n */\n children?: React.ReactNode;\n}\n\n/**\n * A component that sets the default OptixFlow configuration for all Img components\n * in an SSR-safe way. This component should be rendered once at the app root level.\n *\n * The config is applied inside a useEffect, which means it only runs on the client\n * and is never executed during server-side rendering.\n *\n * @example\n * ```tsx\n * // In your app root\n * <OptixFlowConfig config={{ apiKey: 'your-api-key' }}>\n * <App />\n * </OptixFlowConfig>\n * ```\n *\n * Or without children:\n * ```tsx\n * <OptixFlowConfig config={{ apiKey: 'your-api-key' }} />\n * ```\n */\nexport function OptixFlowConfig({\n config,\n children,\n}: OptixFlowConfigProps): React.ReactElement | null {\n React.useEffect(() => {\n setDefaultOptixFlowConfig(config ?? null);\n }, [config]);\n\n return children ? <>{children}</> : null;\n}\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","setDefaultOptixFlowConfig","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","children","Fragment"],"mappings":"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","x_google_ignoreList":[0]}
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { setDefaultOptixFlowConfig } from "./Img.js";
5
+ /**
6
+ * A component that sets the default OptixFlow configuration for all Img components
7
+ * in an SSR-safe way. This component should be rendered once at the app root level.
8
+ *
9
+ * The config is applied inside a useEffect, which means it only runs on the client
10
+ * and is never executed during server-side rendering.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * // In your app root
15
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }}>
16
+ * <App />
17
+ * </OptixFlowConfig>
18
+ * ```
19
+ *
20
+ * Or without children:
21
+ * ```tsx
22
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }} />
23
+ * ```
24
+ */
25
+ export function OptixFlowConfig({ config, children, }) {
26
+ React.useEffect(() => {
27
+ setDefaultOptixFlowConfig(config ?? null);
28
+ }, [config]);
29
+ return children ? _jsx(_Fragment, { children: children }) : null;
30
+ }
@@ -0,0 +1,37 @@
1
+ import * as React from "react";
2
+ import type { UseOptimizedImageOptions } from "@page-speed/hooks/media";
3
+ /**
4
+ * Props for the OptixFlowConfig component
5
+ */
6
+ export interface OptixFlowConfigProps {
7
+ /**
8
+ * OptixFlow configuration to set as default for all images
9
+ * @example { apiKey: 'your-api-key', compressionLevel: 80 }
10
+ */
11
+ config: UseOptimizedImageOptions["optixFlowConfig"];
12
+ /**
13
+ * Optional children (component returns null regardless)
14
+ */
15
+ children?: React.ReactNode;
16
+ }
17
+ /**
18
+ * A component that sets the default OptixFlow configuration for all Img components
19
+ * in an SSR-safe way. This component should be rendered once at the app root level.
20
+ *
21
+ * The config is applied inside a useEffect, which means it only runs on the client
22
+ * and is never executed during server-side rendering.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * // In your app root
27
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }}>
28
+ * <App />
29
+ * </OptixFlowConfig>
30
+ * ```
31
+ *
32
+ * Or without children:
33
+ * ```tsx
34
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }} />
35
+ * ```
36
+ */
37
+ export declare function OptixFlowConfig({ config, children, }: OptixFlowConfigProps): React.ReactElement | null;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { setDefaultOptixFlowConfig } from "./Img.js";
5
+ /**
6
+ * A component that sets the default OptixFlow configuration for all Img components
7
+ * in an SSR-safe way. This component should be rendered once at the app root level.
8
+ *
9
+ * The config is applied inside a useEffect, which means it only runs on the client
10
+ * and is never executed during server-side rendering.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * // In your app root
15
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }}>
16
+ * <App />
17
+ * </OptixFlowConfig>
18
+ * ```
19
+ *
20
+ * Or without children:
21
+ * ```tsx
22
+ * <OptixFlowConfig config={{ apiKey: 'your-api-key' }} />
23
+ * ```
24
+ */
25
+ export function OptixFlowConfig({ config, children, }) {
26
+ React.useEffect(() => {
27
+ setDefaultOptixFlowConfig(config ?? null);
28
+ }, [config]);
29
+ return children ? _jsx(_Fragment, { children: children }) : null;
30
+ }
@@ -1 +1,2 @@
1
- export { Img, setDefaultOptixFlowConfig } from './Img.js';
1
+ export { Img, setDefaultOptixFlowConfig } from "./Img.js";
2
+ export { OptixFlowConfig } from "./OptixFlowConfig.js";
@@ -1 +1,4 @@
1
- export { Img, setDefaultOptixFlowConfig } from './Img.js';
1
+ export { Img, setDefaultOptixFlowConfig } from "./Img.js";
2
+ export type { ImgProps } from "./Img.js";
3
+ export { OptixFlowConfig } from "./OptixFlowConfig.js";
4
+ export type { OptixFlowConfigProps } from "./OptixFlowConfig.js";
@@ -1 +1,2 @@
1
- export { Img, setDefaultOptixFlowConfig } from './Img.js';
1
+ export { Img, setDefaultOptixFlowConfig } from "./Img.js";
2
+ export { OptixFlowConfig } from "./OptixFlowConfig.js";
package/dist/index.cjs CHANGED
@@ -13,3 +13,5 @@ if (globalObject) {
13
13
  }
14
14
  }
15
15
  export * from './core/index.js';
16
+ // Re-export specific items for clarity and CDN usage
17
+ export { Img, setDefaultOptixFlowConfig, OptixFlowConfig } from './core/index.js';
package/dist/index.d.ts CHANGED
@@ -2,3 +2,5 @@ import type { UseOptimizedImageOptions } from '@page-speed/hooks/media';
2
2
  export * from './core/index.js';
3
3
  export type { ImageFormat, SrcsetByFormat, UseOptimizedImageOptions, UseOptimizedImageState, } from '@page-speed/hooks/media';
4
4
  export type OptixFlowConfig = UseOptimizedImageOptions['optixFlowConfig'];
5
+ export { Img, setDefaultOptixFlowConfig, OptixFlowConfig } from './core/index.js';
6
+ export type { ImgProps, OptixFlowConfigProps } from './core/index.js';
package/dist/index.js CHANGED
@@ -13,3 +13,5 @@ if (globalObject) {
13
13
  }
14
14
  }
15
15
  export * from './core/index.js';
16
+ // Re-export specific items for clarity and CDN usage
17
+ export { Img, setDefaultOptixFlowConfig, OptixFlowConfig } from './core/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-speed/img",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
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",
@@ -25,7 +25,7 @@
25
25
  "url": "https://github.com/opensite-ai/page-speed-img/issues"
26
26
  },
27
27
  "author": "OpenSite AI (https://opensite.ai)",
28
- "license": "BSD 3",
28
+ "license": "BSD-3-Clause",
29
29
  "private": false,
30
30
  "type": "module",
31
31
  "main": "dist/index.cjs",
@@ -66,7 +66,7 @@
66
66
  "bundle-analysis": "node scripts/analyze-bundle.js || true",
67
67
  "prepare": "husky",
68
68
  "prepack": "pnpm run build",
69
- "prepublishOnly": "pnpm run build"
69
+ "prepublishOnly": "pnpm run build && pnpm run test"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "react": ">=17.0.0",
@@ -75,6 +75,7 @@
75
75
  "devDependencies": {
76
76
  "@commitlint/cli": "^20.1.0",
77
77
  "@commitlint/config-conventional": "^20.0.0",
78
+ "@testing-library/react": "^16.3.2",
78
79
  "@types/node": "^20.17.6",
79
80
  "@types/react": "^18.3.3",
80
81
  "@types/react-dom": "^18.3.0",
@@ -90,7 +91,7 @@
90
91
  "vitest": "^3.2.4"
91
92
  },
92
93
  "dependencies": {
93
- "@opensite/hooks": "2.0.8",
94
+ "@opensite/hooks": "2.1.0",
94
95
  "@page-speed/hooks": "0.4.5"
95
96
  },
96
97
  "packageManager": "pnpm@10.24.0",