@joycostudio/iris 0.0.0-stage → 0.0.1
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 +15 -0
- package/README.md +137 -2
- package/dist/browser.cjs +466 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +69 -0
- package/dist/browser.d.ts +69 -0
- package/dist/browser.js +439 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.cjs +681 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +658 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.cjs +355 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +8 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.js +328 -0
- package/dist/core.js.map +1 -0
- package/dist/next.cjs +380 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +16 -0
- package/dist/next.d.ts +16 -0
- package/dist/next.js +352 -0
- package/dist/next.js.map +1 -0
- package/dist/node.cjs +580 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +47 -0
- package/dist/node.d.ts +47 -0
- package/dist/node.js +542 -0
- package/dist/node.js.map +1 -0
- package/dist/policy-types-LoD2Ldcl.d.cts +147 -0
- package/dist/policy-types-LoD2Ldcl.d.ts +147 -0
- package/dist/react.cjs +628 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +42 -0
- package/dist/react.d.ts +42 -0
- package/dist/react.js +611 -0
- package/dist/react.js.map +1 -0
- package/dist/types-Dv3DS4OX.d.cts +17 -0
- package/dist/types-Dv3DS4OX.d.ts +17 -0
- package/package.json +102 -4
- package/skills/iris-audit/SKILL.md +77 -0
package/dist/next.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// packages/next/index.tsx
|
|
4
|
+
import NextImage, { getImageProps } from "next/image.js";
|
|
5
|
+
import {
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useLayoutEffect,
|
|
9
|
+
useRef,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
|
|
13
|
+
// packages/core/placeholder.ts
|
|
14
|
+
function placeholderSettings(input) {
|
|
15
|
+
if (!input || input === "none") return null;
|
|
16
|
+
const options = input === "blur" ? {} : input;
|
|
17
|
+
return {
|
|
18
|
+
width: options.width ?? 10,
|
|
19
|
+
quality: options.quality ?? 40,
|
|
20
|
+
blur: options.blur ?? 12
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function resolvePlaceholder({
|
|
24
|
+
asset,
|
|
25
|
+
placeholder
|
|
26
|
+
}) {
|
|
27
|
+
const settings = placeholderSettings(placeholder);
|
|
28
|
+
if (!settings) return null;
|
|
29
|
+
const url = asset.placeholders?.find(
|
|
30
|
+
(item) => item.width === settings.width && item.quality === settings.quality
|
|
31
|
+
)?.url ?? (settings.width === 10 && settings.quality === 40 ? asset.placeholder : void 0);
|
|
32
|
+
return url ? { url, blur: settings.blur } : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// packages/next/index.tsx
|
|
36
|
+
import { useIrisDebugger } from "@joycostudio/iris/react";
|
|
37
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
38
|
+
var Image = "default" in NextImage ? NextImage.default : NextImage;
|
|
39
|
+
var EMPTY_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
|
|
40
|
+
function isEmptyImage(image) {
|
|
41
|
+
return (image.currentSrc || image.src) === EMPTY_IMAGE;
|
|
42
|
+
}
|
|
43
|
+
function createIrisNextImage({
|
|
44
|
+
iris,
|
|
45
|
+
catalog
|
|
46
|
+
}) {
|
|
47
|
+
return function IrisImage({
|
|
48
|
+
recipe: override,
|
|
49
|
+
usage,
|
|
50
|
+
...props
|
|
51
|
+
}) {
|
|
52
|
+
const src = typeof props.src === "string" ? props.src : props.src && "src" in props.src ? props.src.src : null;
|
|
53
|
+
const asset = src ? catalog[src] : void 0;
|
|
54
|
+
if (!src || !asset)
|
|
55
|
+
return /* @__PURE__ */ jsx(
|
|
56
|
+
Image,
|
|
57
|
+
{
|
|
58
|
+
...props,
|
|
59
|
+
"data-iris": props["data-iris"] || props.alt || src || void 0
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
const contextUsage = {
|
|
63
|
+
width: props.width ? Number(props.width) : void 0,
|
|
64
|
+
...usage,
|
|
65
|
+
priority: Boolean(props.priority || props.preload || usage?.priority)
|
|
66
|
+
};
|
|
67
|
+
const selected = iris.select({
|
|
68
|
+
asset,
|
|
69
|
+
usage: contextUsage,
|
|
70
|
+
recipe: override
|
|
71
|
+
});
|
|
72
|
+
if (!selected.ok) throw new Error(`Iris: ${selected.error.message}`);
|
|
73
|
+
const { name, recipe } = selected.data;
|
|
74
|
+
const animated = asset.animated || /\.(?:gif|svg)(?:[?#]|$)/i.test(src);
|
|
75
|
+
const direct = props.unoptimized || animated;
|
|
76
|
+
const sizes = props.sizes || (props.width ? `${props.width}px` : "100vw");
|
|
77
|
+
const normalProps = {
|
|
78
|
+
...props,
|
|
79
|
+
src,
|
|
80
|
+
sizes,
|
|
81
|
+
unoptimized: direct,
|
|
82
|
+
placeholder: "empty"
|
|
83
|
+
};
|
|
84
|
+
const { props: normal } = getImageProps(normalProps);
|
|
85
|
+
const liveProgressive = Boolean(
|
|
86
|
+
normal.src === src && !normal.srcSet && asset.progressive
|
|
87
|
+
);
|
|
88
|
+
const preview = !direct && !liveProgressive ? previewImage({ recipe, asset, props: normalProps }) : void 0;
|
|
89
|
+
const progressiveDelivery = liveProgressive;
|
|
90
|
+
const placeholder = !liveProgressive ? resolvePlaceholder({ asset, placeholder: recipe.placeholder }) : null;
|
|
91
|
+
const previewSettings = recipe.preview && recipe.preview !== "none" ? recipe.preview : null;
|
|
92
|
+
const loadPreviewFirst = Boolean(preview && previewSettings?.loadFirst);
|
|
93
|
+
const key = JSON.stringify([
|
|
94
|
+
src,
|
|
95
|
+
name,
|
|
96
|
+
sizes,
|
|
97
|
+
props.quality,
|
|
98
|
+
previewSettings,
|
|
99
|
+
liveProgressive,
|
|
100
|
+
loadPreviewFirst
|
|
101
|
+
]);
|
|
102
|
+
return /* @__PURE__ */ jsx(
|
|
103
|
+
DeliveryImage,
|
|
104
|
+
{
|
|
105
|
+
...normalProps,
|
|
106
|
+
src,
|
|
107
|
+
source: src,
|
|
108
|
+
unoptimized: Boolean(direct),
|
|
109
|
+
recipeName: name,
|
|
110
|
+
preview,
|
|
111
|
+
loadPreviewFirst,
|
|
112
|
+
previewMinDisplayMs: previewSettings?.minDisplayMs ?? 0,
|
|
113
|
+
blurDataURL: placeholder?.url,
|
|
114
|
+
blurRadius: placeholder?.blur ?? 0,
|
|
115
|
+
progressiveDelivery
|
|
116
|
+
},
|
|
117
|
+
key
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function previewImage({
|
|
122
|
+
recipe,
|
|
123
|
+
asset,
|
|
124
|
+
props
|
|
125
|
+
}) {
|
|
126
|
+
const preview = recipe.preview;
|
|
127
|
+
if (!preview || preview === "none") return void 0;
|
|
128
|
+
if (preview.url)
|
|
129
|
+
return preview.url === asset.src ? void 0 : { src: preview.url, unoptimized: true };
|
|
130
|
+
const quality = preview.quality ?? props.quality;
|
|
131
|
+
const { props: candidates } = getImageProps({
|
|
132
|
+
...props,
|
|
133
|
+
quality,
|
|
134
|
+
width: 1,
|
|
135
|
+
height: 1,
|
|
136
|
+
fill: false,
|
|
137
|
+
sizes: "1px",
|
|
138
|
+
placeholder: "empty",
|
|
139
|
+
overrideSrc: void 0
|
|
140
|
+
});
|
|
141
|
+
const widths = (candidates.srcSet?.split(", ") ?? []).flatMap((item) => {
|
|
142
|
+
const match = item.match(/^(.*) (\d+)w$/);
|
|
143
|
+
return match ? [{ url: match[1], width: Number(match[2]) }] : [];
|
|
144
|
+
});
|
|
145
|
+
if (!widths.length) return void 0;
|
|
146
|
+
const loader = ({ width }) => {
|
|
147
|
+
const cap = preview.ratio === void 0 ? Math.min(width, preview.maxWidth ?? 640) : Math.min(
|
|
148
|
+
Math.floor(width * preview.ratio),
|
|
149
|
+
preview.maxWidth ?? Infinity
|
|
150
|
+
);
|
|
151
|
+
const smaller = widths.filter((candidate) => candidate.width < width);
|
|
152
|
+
const selected = smaller.filter((candidate) => candidate.width <= cap).at(-1) ?? smaller[0] ?? widths[0];
|
|
153
|
+
return selected.url;
|
|
154
|
+
};
|
|
155
|
+
return { src: asset.src, loader, quality, unoptimized: false };
|
|
156
|
+
}
|
|
157
|
+
function DeliveryImage({
|
|
158
|
+
source,
|
|
159
|
+
recipeName,
|
|
160
|
+
preview,
|
|
161
|
+
loadPreviewFirst,
|
|
162
|
+
previewMinDisplayMs,
|
|
163
|
+
progressiveDelivery,
|
|
164
|
+
style,
|
|
165
|
+
onLoad,
|
|
166
|
+
onError,
|
|
167
|
+
onLoadCapture,
|
|
168
|
+
blurDataURL,
|
|
169
|
+
blurRadius,
|
|
170
|
+
...props
|
|
171
|
+
}) {
|
|
172
|
+
const [loaded, setLoaded] = useState(false);
|
|
173
|
+
const [previewLoaded, setPreviewLoaded] = useState(false);
|
|
174
|
+
const [finalStarted, setFinalStarted] = useState(!loadPreviewFirst);
|
|
175
|
+
const layerZIndex = typeof style?.zIndex === "number" ? style.zIndex : 0;
|
|
176
|
+
const iris = useIrisDebugger();
|
|
177
|
+
const finalRef = useRef(null);
|
|
178
|
+
const previewRef = useRef(null);
|
|
179
|
+
const previewMarked = useRef(false);
|
|
180
|
+
const attachFinal = useCallback((image) => {
|
|
181
|
+
finalRef.current = image;
|
|
182
|
+
if (image?.complete && image.naturalWidth && !isEmptyImage(image))
|
|
183
|
+
setLoaded(true);
|
|
184
|
+
}, []);
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
let timer;
|
|
187
|
+
let observer;
|
|
188
|
+
const startFallback = () => {
|
|
189
|
+
timer ?? (timer = setTimeout(() => setFinalStarted(true), 3e3));
|
|
190
|
+
};
|
|
191
|
+
if (loadPreviewFirst && !finalStarted && previewLoaded) {
|
|
192
|
+
timer = setTimeout(() => setFinalStarted(true), previewMinDisplayMs);
|
|
193
|
+
} else if (loadPreviewFirst && !finalStarted && previewRef.current) {
|
|
194
|
+
if (typeof IntersectionObserver === "undefined") startFallback();
|
|
195
|
+
else {
|
|
196
|
+
observer = new IntersectionObserver((entries) => {
|
|
197
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
198
|
+
startFallback();
|
|
199
|
+
observer?.disconnect();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
observer.observe(previewRef.current);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return () => {
|
|
206
|
+
observer?.disconnect();
|
|
207
|
+
if (timer) clearTimeout(timer);
|
|
208
|
+
};
|
|
209
|
+
}, [loadPreviewFirst, finalStarted, previewLoaded, previewMinDisplayMs]);
|
|
210
|
+
const revealPreview = useCallback(
|
|
211
|
+
(image) => {
|
|
212
|
+
if (!image.isConnected || !image.naturalWidth || previewMarked.current)
|
|
213
|
+
return;
|
|
214
|
+
previewMarked.current = true;
|
|
215
|
+
setPreviewLoaded(true);
|
|
216
|
+
if (finalRef.current) iris?.markPreview(finalRef.current, image);
|
|
217
|
+
},
|
|
218
|
+
[iris]
|
|
219
|
+
);
|
|
220
|
+
const attachPreview = useCallback(
|
|
221
|
+
(image) => {
|
|
222
|
+
previewRef.current = image;
|
|
223
|
+
if (image?.complete && image.naturalWidth) revealPreview(image);
|
|
224
|
+
},
|
|
225
|
+
[revealPreview]
|
|
226
|
+
);
|
|
227
|
+
useLayoutEffect(() => {
|
|
228
|
+
if (iris && finalRef.current) {
|
|
229
|
+
iris.startTimeline(finalRef.current);
|
|
230
|
+
if (finalRef.current.complete && finalRef.current.naturalWidth && !isEmptyImage(finalRef.current))
|
|
231
|
+
iris.markFinal(finalRef.current);
|
|
232
|
+
}
|
|
233
|
+
}, [iris, source]);
|
|
234
|
+
useLayoutEffect(() => {
|
|
235
|
+
const image = finalRef.current;
|
|
236
|
+
if (finalStarted && image?.complete && image.naturalWidth && !isEmptyImage(image)) {
|
|
237
|
+
setLoaded(true);
|
|
238
|
+
iris?.markFinal(image);
|
|
239
|
+
}
|
|
240
|
+
}, [finalStarted, iris]);
|
|
241
|
+
const layers = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
242
|
+
/* @__PURE__ */ jsx(
|
|
243
|
+
Image,
|
|
244
|
+
{
|
|
245
|
+
...props,
|
|
246
|
+
src: finalStarted ? props.src : EMPTY_IMAGE,
|
|
247
|
+
unoptimized: finalStarted ? props.unoptimized : true,
|
|
248
|
+
loader: finalStarted ? props.loader : void 0,
|
|
249
|
+
overrideSrc: finalStarted ? props.overrideSrc : void 0,
|
|
250
|
+
priority: finalStarted ? props.priority : false,
|
|
251
|
+
preload: finalStarted ? props.preload : false,
|
|
252
|
+
fetchPriority: finalStarted ? props.fetchPriority : "auto",
|
|
253
|
+
ref: attachFinal,
|
|
254
|
+
"data-iris": props["data-iris"] || props.alt || source,
|
|
255
|
+
"data-iris-src": source,
|
|
256
|
+
"data-iris-recipe": recipeName,
|
|
257
|
+
"data-iris-delivery": progressiveDelivery ? "progressive" : void 0,
|
|
258
|
+
placeholder: "empty",
|
|
259
|
+
style: {
|
|
260
|
+
...style,
|
|
261
|
+
...preview || blurDataURL ? { zIndex: layerZIndex + 2 } : {},
|
|
262
|
+
...loaded ? { backgroundImage: "none" } : {}
|
|
263
|
+
},
|
|
264
|
+
onLoadCapture: (event) => {
|
|
265
|
+
if (isEmptyImage(event.currentTarget)) return;
|
|
266
|
+
event.currentTarget.style.backgroundImage = "none";
|
|
267
|
+
setLoaded(true);
|
|
268
|
+
onLoadCapture?.(event);
|
|
269
|
+
},
|
|
270
|
+
onLoad: (event) => {
|
|
271
|
+
if (isEmptyImage(event.currentTarget)) return;
|
|
272
|
+
setLoaded(true);
|
|
273
|
+
iris?.markFinal(event.currentTarget);
|
|
274
|
+
onLoad?.(event);
|
|
275
|
+
},
|
|
276
|
+
onError: (event) => {
|
|
277
|
+
if (isEmptyImage(event.currentTarget)) return;
|
|
278
|
+
onError?.(event);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
),
|
|
282
|
+
preview && !loaded && /* @__PURE__ */ jsx(
|
|
283
|
+
Image,
|
|
284
|
+
{
|
|
285
|
+
...props,
|
|
286
|
+
src: preview.src,
|
|
287
|
+
loader: preview.loader,
|
|
288
|
+
overrideSrc: void 0,
|
|
289
|
+
ref: attachPreview,
|
|
290
|
+
unoptimized: preview.unoptimized,
|
|
291
|
+
quality: preview.quality,
|
|
292
|
+
fill: true,
|
|
293
|
+
width: void 0,
|
|
294
|
+
height: void 0,
|
|
295
|
+
alt: "",
|
|
296
|
+
"aria-hidden": "true",
|
|
297
|
+
"data-iris": void 0,
|
|
298
|
+
"data-slot": "image-preview",
|
|
299
|
+
priority: false,
|
|
300
|
+
preload: false,
|
|
301
|
+
fetchPriority: "auto",
|
|
302
|
+
placeholder: "empty",
|
|
303
|
+
style: {
|
|
304
|
+
...style,
|
|
305
|
+
pointerEvents: "none",
|
|
306
|
+
zIndex: layerZIndex + 1,
|
|
307
|
+
backgroundImage: "none"
|
|
308
|
+
},
|
|
309
|
+
onLoadCapture: (event) => revealPreview(event.currentTarget),
|
|
310
|
+
onError: () => setFinalStarted(true)
|
|
311
|
+
}
|
|
312
|
+
),
|
|
313
|
+
!loaded && !previewLoaded && blurDataURL && /* @__PURE__ */ jsx(
|
|
314
|
+
"span",
|
|
315
|
+
{
|
|
316
|
+
"aria-hidden": "true",
|
|
317
|
+
"data-slot": "image-placeholder",
|
|
318
|
+
"data-stage": "blur",
|
|
319
|
+
style: {
|
|
320
|
+
position: "absolute",
|
|
321
|
+
inset: 0,
|
|
322
|
+
...style,
|
|
323
|
+
pointerEvents: "none",
|
|
324
|
+
zIndex: layerZIndex,
|
|
325
|
+
backgroundImage: `url(${JSON.stringify(blurDataURL)})`,
|
|
326
|
+
backgroundSize: style?.objectFit === "contain" ? "contain" : style?.objectFit === "cover" ? "cover" : "100% 100%",
|
|
327
|
+
backgroundPosition: style?.objectPosition ?? "center",
|
|
328
|
+
backgroundRepeat: "no-repeat",
|
|
329
|
+
filter: `blur(${blurRadius}px)`,
|
|
330
|
+
clipPath: "inset(0)"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
] });
|
|
335
|
+
return preview || blurDataURL ? /* @__PURE__ */ jsx(
|
|
336
|
+
"span",
|
|
337
|
+
{
|
|
338
|
+
"data-slot": "iris-image",
|
|
339
|
+
style: props.fill ? { position: "absolute", inset: 0, isolation: "isolate" } : {
|
|
340
|
+
position: "relative",
|
|
341
|
+
display: "inline-grid",
|
|
342
|
+
maxWidth: "100%",
|
|
343
|
+
isolation: "isolate"
|
|
344
|
+
},
|
|
345
|
+
children: layers
|
|
346
|
+
}
|
|
347
|
+
) : layers;
|
|
348
|
+
}
|
|
349
|
+
export {
|
|
350
|
+
createIrisNextImage
|
|
351
|
+
};
|
|
352
|
+
//# sourceMappingURL=next.js.map
|
package/dist/next.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../packages/next/index.tsx","../packages/core/placeholder.ts"],"sourcesContent":["\"use client\"\n\nimport NextImage, { getImageProps, type ImageProps } from \"next/image.js\"\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\"\nimport type {\n IrisCatalogAsset,\n IrisPolicy,\n IrisPolicyUsage,\n IrisRecipe,\n} from \"../core\"\nimport { resolvePlaceholder } from \"../core/placeholder\"\nimport { useIrisDebugger } from \"@joycostudio/iris/react\"\n\n// Next exposes a CommonJS entry; native ESM and bundlers unwrap it differently.\nconst Image = (\n \"default\" in NextImage ? NextImage.default : NextImage\n) as typeof NextImage\nconst EMPTY_IMAGE = \"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\"\n\nfunction isEmptyImage(image: HTMLImageElement) {\n return (image.currentSrc || image.src) === EMPTY_IMAGE\n}\n\nexport type IrisNextImageProps<Custom = Record<string, unknown>> =\n ImageProps & {\n recipe?: string\n usage?: IrisPolicyUsage<Custom>\n \"data-iris\"?: string\n }\n\n/** Next owns responsive widths, optimizer URLs and allowed quality values. */\nexport function createIrisNextImage<Custom>({\n iris,\n catalog,\n}: {\n iris: IrisPolicy<Custom>\n catalog: Readonly<Record<string, IrisCatalogAsset>>\n}) {\n return function IrisImage({\n recipe: override,\n usage,\n ...props\n }: IrisNextImageProps<Custom>) {\n const src =\n typeof props.src === \"string\"\n ? props.src\n : props.src && \"src\" in props.src\n ? props.src.src\n : null\n const asset = src ? catalog[src] : undefined\n if (!src || !asset)\n return (\n <Image\n {...props}\n data-iris={props[\"data-iris\"] || props.alt || src || undefined}\n />\n )\n const contextUsage = {\n width: props.width ? Number(props.width) : undefined,\n ...usage,\n priority: Boolean(props.priority || props.preload || usage?.priority),\n }\n const selected = iris.select({\n asset,\n usage: contextUsage,\n recipe: override,\n })\n if (!selected.ok) throw new Error(`Iris: ${selected.error.message}`)\n const { name, recipe } = selected.data\n const animated = asset.animated || /\\.(?:gif|svg)(?:[?#]|$)/i.test(src)\n const direct = props.unoptimized || animated\n const sizes = props.sizes || (props.width ? `${props.width}px` : \"100vw\")\n const normalProps = {\n ...props,\n src,\n sizes,\n unoptimized: direct,\n placeholder: \"empty\" as const,\n }\n const { props: normal } = getImageProps(normalProps)\n // Source metadata describes the served file only when Next passes it through.\n const liveProgressive = Boolean(\n normal.src === src && !normal.srcSet && asset.progressive\n )\n const preview =\n !direct && !liveProgressive\n ? previewImage({ recipe, asset, props: normalProps })\n : undefined\n const progressiveDelivery = liveProgressive\n const placeholder = !liveProgressive\n ? resolvePlaceholder({ asset, placeholder: recipe.placeholder })\n : null\n const previewSettings =\n recipe.preview && recipe.preview !== \"none\" ? recipe.preview : null\n const loadPreviewFirst = Boolean(preview && previewSettings?.loadFirst)\n const key = JSON.stringify([\n src,\n name,\n sizes,\n props.quality,\n previewSettings,\n liveProgressive,\n loadPreviewFirst,\n ])\n return (\n <DeliveryImage\n key={key}\n {...normalProps}\n src={src}\n source={src}\n unoptimized={Boolean(direct)}\n recipeName={name}\n preview={preview}\n loadPreviewFirst={loadPreviewFirst}\n previewMinDisplayMs={previewSettings?.minDisplayMs ?? 0}\n blurDataURL={placeholder?.url}\n blurRadius={placeholder?.blur ?? 0}\n progressiveDelivery={progressiveDelivery}\n />\n )\n }\n}\n\ntype PreviewImage = {\n src: string\n loader?: NonNullable<ImageProps[\"loader\"]>\n quality?: ImageProps[\"quality\"]\n unoptimized: boolean\n}\n\nfunction previewImage({\n recipe,\n asset,\n props,\n}: {\n recipe: IrisRecipe\n asset: IrisCatalogAsset\n props: ImageProps\n}): PreviewImage | undefined {\n const preview = recipe.preview\n if (!preview || preview === \"none\") return undefined\n if (preview.url)\n return preview.url === asset.src\n ? undefined\n : { src: preview.url, unoptimized: true }\n\n // Next knows the optimizer's allowed widths (and any custom loader). Build\n // those URLs once, then map each responsive final descriptor to a smaller\n // preview URL. The browser applies the same `sizes` to both images, so a\n // ratio follows the width it actually selects at each viewport and DPR.\n const quality = preview.quality ?? props.quality\n const { props: candidates } = getImageProps({\n ...props,\n quality,\n width: 1,\n height: 1,\n fill: false,\n sizes: \"1px\",\n placeholder: \"empty\",\n overrideSrc: undefined,\n })\n const widths = (candidates.srcSet?.split(\", \") ?? []).flatMap((item) => {\n const match = item.match(/^(.*) (\\d+)w$/)\n return match ? [{ url: match[1], width: Number(match[2]) }] : []\n })\n if (!widths.length) return undefined\n const loader: NonNullable<ImageProps[\"loader\"]> = ({ width }) => {\n const cap =\n preview.ratio === undefined\n ? Math.min(width, preview.maxWidth ?? 640)\n : Math.min(\n Math.floor(width * preview.ratio),\n preview.maxWidth ?? Infinity\n )\n const smaller = widths.filter((candidate) => candidate.width < width)\n const selected =\n smaller.filter((candidate) => candidate.width <= cap).at(-1) ??\n smaller[0] ??\n widths[0]\n return selected.url\n }\n return { src: asset.src, loader, quality, unoptimized: false }\n}\n\nfunction DeliveryImage({\n source,\n recipeName,\n preview,\n loadPreviewFirst,\n previewMinDisplayMs,\n progressiveDelivery,\n style,\n onLoad,\n onError,\n onLoadCapture,\n blurDataURL,\n blurRadius,\n ...props\n}: ImageProps & {\n source: string\n recipeName: string\n preview?: PreviewImage\n loadPreviewFirst: boolean\n previewMinDisplayMs: number\n blurRadius: number\n progressiveDelivery: boolean\n \"data-iris\"?: string\n}) {\n const [loaded, setLoaded] = useState(false)\n const [previewLoaded, setPreviewLoaded] = useState(false)\n const [finalStarted, setFinalStarted] = useState(!loadPreviewFirst)\n // Keep each fallback behind the final image. Browsers can paint an image as\n // soon as it decodes, even before React hydrates and receives its load event.\n // Covering the final with a blur made already-loaded images wait for hydration.\n const layerZIndex = typeof style?.zIndex === \"number\" ? style.zIndex : 0\n const iris = useIrisDebugger()\n const finalRef = useRef<HTMLImageElement | null>(null)\n const previewRef = useRef<HTMLImageElement | null>(null)\n const previewMarked = useRef(false)\n const attachFinal = useCallback((image: HTMLImageElement | null) => {\n finalRef.current = image\n if (image?.complete && image.naturalWidth && !isEmptyImage(image))\n setLoaded(true)\n }, [])\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined\n let observer: IntersectionObserver | undefined\n const startFallback = () => {\n timer ??= setTimeout(() => setFinalStarted(true), 3000)\n }\n if (loadPreviewFirst && !finalStarted && previewLoaded) {\n timer = setTimeout(() => setFinalStarted(true), previewMinDisplayMs)\n } else if (loadPreviewFirst && !finalStarted && previewRef.current) {\n if (typeof IntersectionObserver === \"undefined\") startFallback()\n else {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n startFallback()\n observer?.disconnect()\n }\n })\n observer.observe(previewRef.current)\n }\n }\n return () => {\n observer?.disconnect()\n if (timer) clearTimeout(timer)\n }\n }, [loadPreviewFirst, finalStarted, previewLoaded, previewMinDisplayMs])\n const revealPreview = useCallback(\n (image: HTMLImageElement) => {\n if (!image.isConnected || !image.naturalWidth || previewMarked.current)\n return\n previewMarked.current = true\n setPreviewLoaded(true)\n if (finalRef.current) iris?.markPreview(finalRef.current, image)\n },\n [iris]\n )\n const attachPreview = useCallback(\n (image: HTMLImageElement | null) => {\n previewRef.current = image\n if (image?.complete && image.naturalWidth) revealPreview(image)\n },\n [revealPreview]\n )\n useLayoutEffect(() => {\n if (iris && finalRef.current) {\n iris.startTimeline(finalRef.current)\n if (\n finalRef.current.complete &&\n finalRef.current.naturalWidth &&\n !isEmptyImage(finalRef.current)\n )\n iris.markFinal(finalRef.current)\n }\n }, [iris, source])\n useLayoutEffect(() => {\n const image = finalRef.current\n if (\n finalStarted &&\n image?.complete &&\n image.naturalWidth &&\n !isEmptyImage(image)\n ) {\n setLoaded(true)\n iris?.markFinal(image)\n }\n }, [finalStarted, iris])\n const layers = (\n <>\n <Image\n {...props}\n src={finalStarted ? props.src : EMPTY_IMAGE}\n unoptimized={finalStarted ? props.unoptimized : true}\n loader={finalStarted ? props.loader : undefined}\n overrideSrc={finalStarted ? props.overrideSrc : undefined}\n priority={finalStarted ? props.priority : false}\n preload={finalStarted ? props.preload : false}\n fetchPriority={finalStarted ? props.fetchPriority : \"auto\"}\n ref={attachFinal}\n data-iris={props[\"data-iris\"] || props.alt || source}\n data-iris-src={source}\n data-iris-recipe={recipeName}\n data-iris-delivery={progressiveDelivery ? \"progressive\" : undefined}\n placeholder=\"empty\"\n style={{\n ...style,\n ...(preview || blurDataURL ? { zIndex: layerZIndex + 2 } : {}),\n ...(loaded ? { backgroundImage: \"none\" } : {}),\n }}\n onLoadCapture={(event) => {\n if (isEmptyImage(event.currentTarget)) return\n event.currentTarget.style.backgroundImage = \"none\"\n setLoaded(true)\n onLoadCapture?.(event)\n }}\n onLoad={(event) => {\n if (isEmptyImage(event.currentTarget)) return\n setLoaded(true)\n iris?.markFinal(event.currentTarget)\n onLoad?.(event)\n }}\n onError={(event) => {\n if (isEmptyImage(event.currentTarget)) return\n onError?.(event)\n }}\n />\n {preview && !loaded && (\n <Image\n {...props}\n src={preview.src}\n loader={preview.loader}\n overrideSrc={undefined}\n ref={attachPreview}\n unoptimized={preview.unoptimized}\n quality={preview.quality}\n fill\n width={undefined}\n height={undefined}\n alt=\"\"\n aria-hidden=\"true\"\n data-iris={undefined}\n data-slot=\"image-preview\"\n priority={false}\n preload={false}\n fetchPriority=\"auto\"\n placeholder=\"empty\"\n style={{\n ...style,\n pointerEvents: \"none\",\n zIndex: layerZIndex + 1,\n backgroundImage: \"none\",\n }}\n onLoadCapture={(event) => revealPreview(event.currentTarget)}\n onError={() => setFinalStarted(true)}\n />\n )}\n {!loaded && !previewLoaded && blurDataURL && (\n <span\n aria-hidden=\"true\"\n data-slot=\"image-placeholder\"\n data-stage=\"blur\"\n style={{\n position: \"absolute\",\n inset: 0,\n ...style,\n pointerEvents: \"none\",\n zIndex: layerZIndex,\n backgroundImage: `url(${JSON.stringify(blurDataURL)})`,\n backgroundSize:\n style?.objectFit === \"contain\"\n ? \"contain\"\n : style?.objectFit === \"cover\"\n ? \"cover\"\n : \"100% 100%\",\n backgroundPosition: style?.objectPosition ?? \"center\",\n backgroundRepeat: \"no-repeat\",\n filter: `blur(${blurRadius}px)`,\n clipPath: \"inset(0)\",\n }}\n />\n )}\n </>\n )\n // Isolate the layers so their z-index cannot cover captions or controls in\n // the parent. Keep the containing block mounted after load to avoid shifts.\n return preview || blurDataURL ? (\n <span\n data-slot=\"iris-image\"\n style={\n props.fill\n ? { position: \"absolute\", inset: 0, isolation: \"isolate\" }\n : {\n position: \"relative\",\n display: \"inline-grid\",\n maxWidth: \"100%\",\n isolation: \"isolate\",\n }\n }\n >\n {layers}\n </span>\n ) : (\n layers\n )\n}\n","import type { IrisCatalogAsset, IrisRecipe } from \"./policy-types\"\n\nexport function placeholderSettings(input: IrisRecipe[\"placeholder\"]) {\n if (!input || input === \"none\") return null\n const options = input === \"blur\" ? {} : input\n return {\n width: options.width ?? 10,\n quality: options.quality ?? 40,\n blur: options.blur ?? 12,\n }\n}\n\nexport function resolvePlaceholder({\n asset,\n placeholder,\n}: {\n asset: IrisCatalogAsset\n placeholder: IrisRecipe[\"placeholder\"]\n}) {\n const settings = placeholderSettings(placeholder)\n if (!settings) return null\n const url =\n asset.placeholders?.find(\n (item) =>\n item.width === settings.width && item.quality === settings.quality\n )?.url ??\n (settings.width === 10 && settings.quality === 40\n ? asset.placeholder\n : undefined)\n return url ? { url, blur: settings.blur } : null\n}\n"],"mappings":"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","names":[]}
|